2018-07-06 04:46:36 +00:00
|
|
|
/*
|
|
|
|
* Rufus: The Reliable USB Formatting Utility
|
|
|
|
* UI-related function calls
|
[net] add Windows retail ISO downloads
* This is accomplished through Fido (https://github.com/pbatard/Fido), a *SIGNED*
PowerShell script, that is downloaded from GitHub and that resides in memory for
the duration of a session.
* The reason we use a downloaded PS script, rather than an embedded on, is because:
- Microsoft have regularly been changing the deal with regards to how retail ISOs
can be downloaded, and not for the better, so we can't simply embed a static
means of downloading ISOs and expect that to work forever.
- By using an external script, we can immediately respond to whatever new means of
*ANNOYING* their legitimate users Microsoft will come up with next, as well as
make sure that, the minute a new retail version of Windows becomes available, it
also becomes available for download in Rufus.
* Note that if you are concerned about downloading a remote PS script that is being
run at the same level as an elevated application, you should understand that:
- Only scripts downloaded from GitHub, from an account that is protected with 2FA,
are allowed to run (i.e. someone would first have to steal a *physical* 2FA key
to be in a position to upload a malicious script).
- On top of this, only scripts that are signed with a separate private key (RSA +
AES-256), that is itself also protected with a strong unique password which only
a single person knows (and must manually enter each time they want to make a new
version of the script available for download), are allowed to run.
The above means that there's about as much chance for someone to manage to upload
a malicious script on the GitHub servers, that Rufus would allow to run, as there
is for someone to upload a malicious version of Rufus itself.
Still, if you are paranoid and have concerns that, even as you can validate from
its source that Rufus does not attempt to execute any remote script unless a user
actively selected and clicked the DOWNLOAD button, you can also completely disable
the remote script download feature, if you just set the update check to disabled
(which, by the way, Rufus *EXPLICITLY* asks you to choose whether you want to
enable or not, the very first time you run the application).
* Also remove _unlinkU() which duplicates what DeleteFileU() already does.
2019-03-02 23:28:56 +00:00
|
|
|
* Copyright © 2018-2019 Pete Batard <pete@akeo.ie>
|
2018-07-06 04:46:36 +00:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Memory leaks detection - define _CRTDBG_MAP_ALLOC as preprocessor macro */
|
|
|
|
#ifdef _CRTDBG_MAP_ALLOC
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <crtdbg.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
#include <windowsx.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <winioctl.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include "rufus.h"
|
|
|
|
#include "drive.h"
|
|
|
|
#include "missing.h"
|
|
|
|
#include "resource.h"
|
|
|
|
#include "msapi_utf8.h"
|
|
|
|
#include "localization.h"
|
|
|
|
|
|
|
|
#include "ui.h"
|
|
|
|
#include "ui_data.h"
|
|
|
|
|
|
|
|
UINT_PTR UM_LANGUAGE_MENU_MAX = UM_LANGUAGE_MENU;
|
|
|
|
HIMAGELIST hUpImageList, hDownImageList;
|
2019-04-25 17:58:55 +00:00
|
|
|
extern BOOL enable_fido, use_vds;
|
2019-08-20 17:06:07 +00:00
|
|
|
// TODO: Use an enum or something
|
|
|
|
int update_progress_type = UPT_PERCENT;
|
2018-07-06 04:46:36 +00:00
|
|
|
int advanced_device_section_height, advanced_format_section_height;
|
|
|
|
// (empty) check box width, (empty) drop down width, button height (for and without dropdown match)
|
|
|
|
int cbw, ddw, ddbh = 0, bh = 0;
|
|
|
|
// Row Height, DropDown Height, Main button width, half dropdown width, full dropdown width
|
|
|
|
static int rh, ddh, bw, hw, fw;
|
|
|
|
// See GetFullWidth() for details on how these values are used
|
|
|
|
static int sw, mw, bsw, sbw, ssw, tw, dbw;
|
|
|
|
static WNDPROC progress_original_proc = NULL;
|
|
|
|
static wchar_t wtbtext[2][128];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The following is used to allocate slots within the progress bar
|
|
|
|
* 0 means unused (no operation or no progress allocated to it)
|
|
|
|
* +n means allocate exactly n bars (n percent of the progress bar)
|
|
|
|
* -n means allocate a weighted slot of n from all remaining
|
|
|
|
* bars. E.g. if 80 slots remain and the sum of all negative entries
|
|
|
|
* is 10, -4 will allocate 4/10*80 = 32 bars (32%) for OP progress
|
|
|
|
*/
|
|
|
|
static int nb_slots[OP_MAX];
|
|
|
|
static float slot_end[OP_MAX+1]; // shifted +1 so that we can subtract 1 to OP indexes
|
|
|
|
static float previous_end;
|
|
|
|
|
|
|
|
// Set the combo selection according to the data
|
|
|
|
void SetComboEntry(HWND hDlg, int data)
|
|
|
|
{
|
2019-02-01 12:34:01 +00:00
|
|
|
int i, nb_entries = ComboBox_GetCount(hDlg);
|
|
|
|
|
|
|
|
if (nb_entries <= 0)
|
|
|
|
return;
|
|
|
|
for (i = 0; i < nb_entries; i++) {
|
2018-07-06 04:46:36 +00:00
|
|
|
if (ComboBox_GetItemData(hDlg, i) == data) {
|
|
|
|
IGNORE_RETVAL(ComboBox_SetCurSel(hDlg, i));
|
2019-02-01 12:34:01 +00:00
|
|
|
return;
|
2018-07-06 04:46:36 +00:00
|
|
|
}
|
|
|
|
}
|
2019-02-01 12:34:01 +00:00
|
|
|
if (i == nb_entries)
|
2018-07-06 04:46:36 +00:00
|
|
|
IGNORE_RETVAL(ComboBox_SetCurSel(hDlg, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move a control along the Y axis
|
|
|
|
static __inline void MoveCtrlY(HWND hDlg, int nID, int vertical_shift) {
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, nID), 0, vertical_shift, 0, 0, 1.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
// https://stackoverflow.com/a/20926332/1069307
|
|
|
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb226818.aspx
|
|
|
|
void GetBasicControlsWidth(HWND hDlg)
|
|
|
|
{
|
|
|
|
int checkbox_internal_spacing = 12, dropdown_internal_spacing = 15;
|
|
|
|
RECT rc = { 0, 0, 4, 8 };
|
|
|
|
SIZE sz;
|
|
|
|
|
|
|
|
// Compute base unit sizes since GetDialogBaseUnits() returns garbage data.
|
|
|
|
// See http://support.microsoft.com/kb/125681
|
|
|
|
MapDialogRect(hDlg, &rc);
|
|
|
|
sz.cx = rc.right;
|
|
|
|
sz.cy = rc.bottom;
|
|
|
|
|
|
|
|
// TODO: figure out the specifics of each Windows version
|
|
|
|
if (nWindowsVersion == WINDOWS_10) {
|
|
|
|
checkbox_internal_spacing = 10;
|
|
|
|
dropdown_internal_spacing = 13;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Checkbox and (blank) dropdown widths
|
|
|
|
cbw = MulDiv(checkbox_internal_spacing, sz.cx, 4);
|
|
|
|
ddw = MulDiv(dropdown_internal_spacing, sz.cx, 4);
|
|
|
|
|
|
|
|
// Spacing width between half-length dropdowns (sep) as well as left margin
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, IDC_TARGET_SYSTEM), &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
sw = rc.left;
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, IDC_PARTITION_TYPE), &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
sw -= rc.right;
|
|
|
|
mw = rc.left;
|
|
|
|
|
|
|
|
// Small button width
|
|
|
|
SendMessage(hSaveToolbar, TB_GETIDEALSIZE, (WPARAM)FALSE, (LPARAM)&sz);
|
|
|
|
sbw = sz.cx;
|
|
|
|
|
|
|
|
// Small separator widths and button height
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, IDC_SAVE), &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
bh = rc.bottom - rc.top;
|
|
|
|
ssw = rc.left;
|
|
|
|
GetWindowRect(hDeviceList, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
ssw -= rc.right;
|
|
|
|
|
|
|
|
// CSM tooltip separator width
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, IDS_CSM_HELP_TXT), &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
tw = rc.left;
|
|
|
|
GetWindowRect(hTargetSystem, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
tw -= rc.right;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute the minimum size of the main buttons
|
|
|
|
void GetMainButtonsWidth(HWND hDlg)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
RECT rc;
|
[net] add Windows retail ISO downloads
* This is accomplished through Fido (https://github.com/pbatard/Fido), a *SIGNED*
PowerShell script, that is downloaded from GitHub and that resides in memory for
the duration of a session.
* The reason we use a downloaded PS script, rather than an embedded on, is because:
- Microsoft have regularly been changing the deal with regards to how retail ISOs
can be downloaded, and not for the better, so we can't simply embed a static
means of downloading ISOs and expect that to work forever.
- By using an external script, we can immediately respond to whatever new means of
*ANNOYING* their legitimate users Microsoft will come up with next, as well as
make sure that, the minute a new retail version of Windows becomes available, it
also becomes available for download in Rufus.
* Note that if you are concerned about downloading a remote PS script that is being
run at the same level as an elevated application, you should understand that:
- Only scripts downloaded from GitHub, from an account that is protected with 2FA,
are allowed to run (i.e. someone would first have to steal a *physical* 2FA key
to be in a position to upload a malicious script).
- On top of this, only scripts that are signed with a separate private key (RSA +
AES-256), that is itself also protected with a strong unique password which only
a single person knows (and must manually enter each time they want to make a new
version of the script available for download), are allowed to run.
The above means that there's about as much chance for someone to manage to upload
a malicious script on the GitHub servers, that Rufus would allow to run, as there
is for someone to upload a malicious version of Rufus itself.
Still, if you are paranoid and have concerns that, even as you can validate from
its source that Rufus does not attempt to execute any remote script unless a user
actively selected and clicked the DOWNLOAD button, you can also completely disable
the remote script download feature, if you just set the update check to disabled
(which, by the way, Rufus *EXPLICITLY* asks you to choose whether you want to
enable or not, the very first time you run the application).
* Also remove _unlinkU() which duplicates what DeleteFileU() already does.
2019-03-02 23:28:56 +00:00
|
|
|
LONG style;
|
|
|
|
char download[64];
|
2018-07-06 04:46:36 +00:00
|
|
|
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, main_button_ids[0]), &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
bw = rc.right - rc.left;
|
|
|
|
|
2019-03-16 13:01:55 +00:00
|
|
|
for (i = 0; i < ARRAYSIZE(main_button_ids); i++) {
|
|
|
|
// Make sure we add extra space for the SELECT split button (i == 0) if Fido is enabled
|
|
|
|
bw = max(bw, GetTextWidth(hDlg, main_button_ids[i]) + ((enable_fido && i == 0) ? (3 * cbw) / 2 : cbw));
|
|
|
|
}
|
[net] add Windows retail ISO downloads
* This is accomplished through Fido (https://github.com/pbatard/Fido), a *SIGNED*
PowerShell script, that is downloaded from GitHub and that resides in memory for
the duration of a session.
* The reason we use a downloaded PS script, rather than an embedded on, is because:
- Microsoft have regularly been changing the deal with regards to how retail ISOs
can be downloaded, and not for the better, so we can't simply embed a static
means of downloading ISOs and expect that to work forever.
- By using an external script, we can immediately respond to whatever new means of
*ANNOYING* their legitimate users Microsoft will come up with next, as well as
make sure that, the minute a new retail version of Windows becomes available, it
also becomes available for download in Rufus.
* Note that if you are concerned about downloading a remote PS script that is being
run at the same level as an elevated application, you should understand that:
- Only scripts downloaded from GitHub, from an account that is protected with 2FA,
are allowed to run (i.e. someone would first have to steal a *physical* 2FA key
to be in a position to upload a malicious script).
- On top of this, only scripts that are signed with a separate private key (RSA +
AES-256), that is itself also protected with a strong unique password which only
a single person knows (and must manually enter each time they want to make a new
version of the script available for download), are allowed to run.
The above means that there's about as much chance for someone to manage to upload
a malicious script on the GitHub servers, that Rufus would allow to run, as there
is for someone to upload a malicious version of Rufus itself.
Still, if you are paranoid and have concerns that, even as you can validate from
its source that Rufus does not attempt to execute any remote script unless a user
actively selected and clicked the DOWNLOAD button, you can also completely disable
the remote script download feature, if you just set the update check to disabled
(which, by the way, Rufus *EXPLICITLY* asks you to choose whether you want to
enable or not, the very first time you run the application).
* Also remove _unlinkU() which duplicates what DeleteFileU() already does.
2019-03-02 23:28:56 +00:00
|
|
|
// The 'CLOSE' button is also be used to display 'CANCEL' and we sometimes
|
|
|
|
// want to add "DOWNLOAD" into the Select split button => measure that too.
|
2018-07-06 04:46:36 +00:00
|
|
|
bw = max(bw, GetTextSize(GetDlgItem(hDlg, IDCANCEL), lmprintf(MSG_007)).cx + cbw);
|
[net] add Windows retail ISO downloads
* This is accomplished through Fido (https://github.com/pbatard/Fido), a *SIGNED*
PowerShell script, that is downloaded from GitHub and that resides in memory for
the duration of a session.
* The reason we use a downloaded PS script, rather than an embedded on, is because:
- Microsoft have regularly been changing the deal with regards to how retail ISOs
can be downloaded, and not for the better, so we can't simply embed a static
means of downloading ISOs and expect that to work forever.
- By using an external script, we can immediately respond to whatever new means of
*ANNOYING* their legitimate users Microsoft will come up with next, as well as
make sure that, the minute a new retail version of Windows becomes available, it
also becomes available for download in Rufus.
* Note that if you are concerned about downloading a remote PS script that is being
run at the same level as an elevated application, you should understand that:
- Only scripts downloaded from GitHub, from an account that is protected with 2FA,
are allowed to run (i.e. someone would first have to steal a *physical* 2FA key
to be in a position to upload a malicious script).
- On top of this, only scripts that are signed with a separate private key (RSA +
AES-256), that is itself also protected with a strong unique password which only
a single person knows (and must manually enter each time they want to make a new
version of the script available for download), are allowed to run.
The above means that there's about as much chance for someone to manage to upload
a malicious script on the GitHub servers, that Rufus would allow to run, as there
is for someone to upload a malicious version of Rufus itself.
Still, if you are paranoid and have concerns that, even as you can validate from
its source that Rufus does not attempt to execute any remote script unless a user
actively selected and clicked the DOWNLOAD button, you can also completely disable
the remote script download feature, if you just set the update check to disabled
(which, by the way, Rufus *EXPLICITLY* asks you to choose whether you want to
enable or not, the very first time you run the application).
* Also remove _unlinkU() which duplicates what DeleteFileU() already does.
2019-03-02 23:28:56 +00:00
|
|
|
if (enable_fido) {
|
|
|
|
static_strcpy(download, lmprintf(MSG_040));
|
|
|
|
CharUpperBuffU(download, sizeof(download));
|
|
|
|
bw = max(bw, GetTextSize(GetDlgItem(hDlg, IDC_SELECT), download).cx + (3 * cbw) / 2);
|
|
|
|
style = GetWindowLong(GetDlgItem(hDlg, IDC_SELECT), GWL_STYLE);
|
|
|
|
style|= BS_SPLITBUTTON;
|
|
|
|
SetWindowLong(GetDlgItem(hDlg, IDC_SELECT), GWL_STYLE, style);
|
|
|
|
}
|
2018-07-06 04:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// The following goes over the data that gets populated into the half-width dropdowns
|
|
|
|
// (Partition scheme, Target System, Disk ID, File system, Cluster size, Nb passes)
|
|
|
|
// to figure out the minimum width we should allocate.
|
|
|
|
void GetHalfDropwdownWidth(HWND hDlg)
|
|
|
|
{
|
|
|
|
RECT rc;
|
|
|
|
unsigned int i, j, msg_id;
|
|
|
|
char tmp[256];
|
|
|
|
|
|
|
|
// Initialize half width to the UI's default size
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, IDC_PARTITION_TYPE), &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
hw = rc.right - rc.left - ddw;
|
|
|
|
|
|
|
|
// "Super Floppy Disk" is the longuest entry in the Partition Scheme dropdown
|
|
|
|
hw = max(hw, GetTextSize(GetDlgItem(hDlg, IDC_PARTITION_TYPE), (char*)sfd_name).cx);
|
|
|
|
|
|
|
|
// This is basically the same as SetClusterSizeLabels() except we're adding (Default) to each entry
|
|
|
|
for (i = 512, j = 1, msg_id = MSG_026; j<MAX_CLUSTER_SIZES; i <<= 1, j++) {
|
|
|
|
if (i > 8192) {
|
|
|
|
i /= 1024;
|
|
|
|
msg_id++;
|
|
|
|
}
|
|
|
|
safe_sprintf(tmp, 64, "%d %s", i, lmprintf(msg_id));
|
|
|
|
hw = max(hw, GetTextSize(GetDlgItem(hDlg, IDC_CLUSTER_SIZE), lmprintf(MSG_030, tmp)).cx);
|
|
|
|
}
|
|
|
|
// We don't go over file systems, because none of them will be longer than "Super Floppy Disk"
|
|
|
|
// We do however go over the BIOS vs UEFI entries, as some of these are translated
|
|
|
|
for (msg_id = MSG_031; msg_id <= MSG_033; msg_id++)
|
|
|
|
hw = max(hw, GetTextSize(GetDlgItem(hDlg, IDC_TARGET_SYSTEM), lmprintf(msg_id)).cx);
|
|
|
|
|
|
|
|
// Just in case, we also do the number of passes
|
|
|
|
for (i = 1; i <= 5; i++) {
|
|
|
|
char* msg = (i == 1) ? lmprintf(MSG_034, 1) : lmprintf(MSG_035, (i == 2) ? 2 : 4, (i == 2) ? "" : lmprintf(MSG_087, flash_type[i - 3]));
|
|
|
|
hw = max(hw, GetTextSize(GetDlgItem(hDlg, IDC_TARGET_SYSTEM), msg).cx);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, we must ensure that we'll have enough space for the 2 checkbox controls
|
|
|
|
// that end up with a half dropdown
|
|
|
|
hw = max(hw, GetTextWidth(hDlg, IDC_RUFUS_MBR) - sw);
|
|
|
|
hw = max(hw, GetTextWidth(hDlg, IDC_BAD_BLOCKS) - sw);
|
|
|
|
|
|
|
|
// Add the width of a blank dropdown
|
|
|
|
hw += ddw;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dbw = dialog border width
|
|
|
|
* mw = margin width
|
|
|
|
* fw = full dropdown width
|
|
|
|
* hd = half dropdown width
|
|
|
|
* bsw = boot selection dropdown width
|
|
|
|
* sw = separator width
|
|
|
|
* ssw = small separator width
|
|
|
|
* bw = button width
|
|
|
|
* sbw = small button width
|
|
|
|
*
|
|
|
|
* | fw |
|
|
|
|
* | bsw | ssw | sbw | ssw | bw |
|
|
|
|
* 8 ->|<- 96 ->|<- 24 ->|<- 96 ->|<- 8
|
|
|
|
* mw | hw | sw | hw | mw
|
|
|
|
* | bw | ssw | bw |
|
|
|
|
*/
|
|
|
|
void GetFullWidth(HWND hDlg)
|
|
|
|
{
|
|
|
|
RECT rc;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// Get the dialog border width
|
|
|
|
GetWindowRect(hDlg, &rc);
|
|
|
|
dbw = rc.right - rc.left;
|
|
|
|
GetClientRect(hDlg, &rc);
|
|
|
|
dbw -= rc.right - rc.left;
|
|
|
|
|
|
|
|
// Compute the minimum size needed for the Boot Selection dropdown
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, IDC_BOOT_SELECTION), &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
|
|
|
|
bsw = max(rc.right - rc.left, GetTextSize(hBootType, lmprintf(MSG_279)).cx + ddw);
|
|
|
|
bsw = max(bsw, GetTextSize(hBootType, lmprintf(MSG_281, lmprintf(MSG_280))).cx + ddw);
|
|
|
|
|
|
|
|
// Initialize full width to the UI's default size
|
2018-07-18 11:22:37 +00:00
|
|
|
GetWindowRect(GetDlgItem(hDlg, IDS_DEVICE_TXT), &rc);
|
2018-07-06 04:46:36 +00:00
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
fw = rc.right - rc.left - ddw;
|
|
|
|
|
|
|
|
// Go through the Image Options for Windows To Go
|
|
|
|
fw = max(fw, GetTextSize(GetDlgItem(hDlg, IDC_IMAGE_OPTION), lmprintf(MSG_117)).cx);
|
|
|
|
fw = max(fw, GetTextSize(GetDlgItem(hDlg, IDC_IMAGE_OPTION), lmprintf(MSG_118)).cx);
|
|
|
|
|
|
|
|
// Now deal with full length checkbox lines
|
|
|
|
for (i = 0; i<ARRAYSIZE(full_width_checkboxes); i++)
|
|
|
|
fw = max(fw, GetTextWidth(hDlg, full_width_checkboxes[i]));
|
|
|
|
|
|
|
|
// All of the above is for text only, so we need to add dd space
|
|
|
|
fw += ddw;
|
|
|
|
|
|
|
|
// Our min also needs to be longer than 2 half length dropdowns + spacer
|
|
|
|
fw = max(fw, 2 * hw + sw);
|
|
|
|
|
|
|
|
// Now that we have our minimum full width, adjust the button width if needed
|
|
|
|
// Adjust according to min full width
|
|
|
|
bw = max(bw, (fw - 2 * ssw - sw) / 4);
|
|
|
|
// Adjust according to min boot selection width
|
|
|
|
bw = max(bw, (bsw + sbw - sw) / 3);
|
|
|
|
|
|
|
|
// Adjust according to min half width
|
|
|
|
bw = max(bw, (hw / 2) - ssw);
|
|
|
|
|
|
|
|
// Now that our button width is set, we can adjust the rest
|
|
|
|
hw = max(hw, 2 * bw + ssw);
|
|
|
|
fw = max(fw, 2 * hw + sw);
|
|
|
|
|
|
|
|
bsw = max(bsw, fw - bw - 2 * ssw - sbw);
|
|
|
|
|
|
|
|
// TODO: Also pick a few choice messages from info/status
|
|
|
|
}
|
|
|
|
|
|
|
|
void PositionMainControls(HWND hDlg)
|
|
|
|
{
|
|
|
|
RECT rc;
|
|
|
|
HWND hCtrl, hPrevCtrl;
|
|
|
|
SIZE sz;
|
|
|
|
DWORD padding;
|
|
|
|
int i, x, button_fudge = 2;
|
|
|
|
|
|
|
|
// Start by resizing the whole dialog
|
|
|
|
GetWindowRect(hDlg, &rc);
|
|
|
|
// Don't forget to add the dialog border width, since we resize the whole dialog
|
|
|
|
SetWindowPos(hDlg, NULL, -1, -1, fw + 2 * mw + dbw, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER);
|
|
|
|
|
2018-07-06 10:23:57 +00:00
|
|
|
// Resize the height of the label, persistence size and progress bar to the height of standard dropdowns
|
2018-07-06 04:46:36 +00:00
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_DEVICE);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
ddh = rc.bottom - rc.top;
|
|
|
|
ddbh = ddh + button_fudge;
|
|
|
|
bh = max(bh, ddbh);
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_LABEL);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
SetWindowPos(hCtrl, hAdvancedFormatToolbar, rc.left, rc.top, rc.right - rc.left, ddh, SWP_NOZORDER);
|
2018-07-06 10:23:57 +00:00
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_PERSISTENCE_SIZE);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
SetWindowPos(hCtrl, GetDlgItem(hDlg, IDC_PERSISTENCE_SLIDER), rc.left, rc.top, rc.right - rc.left, ddh, SWP_NOZORDER);
|
2018-07-06 04:46:36 +00:00
|
|
|
GetWindowRect(hProgress, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
SetWindowPos(hProgress, hNBPasses, rc.left, rc.top, rc.right - rc.left, ddh, SWP_NOZORDER);
|
|
|
|
|
|
|
|
// Get the height of a typical row
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDS_BOOT_SELECTION_TXT);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
rh = rc.top;
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDS_DEVICE_TXT);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
rh -= rc.top;
|
|
|
|
|
|
|
|
// Get the height of the advanced options
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_LIST_USB_HDD);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
advanced_device_section_height = rc.top;
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_RUFUS_MBR);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
advanced_device_section_height = rc.bottom - advanced_device_section_height;
|
|
|
|
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_QUICK_FORMAT);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
advanced_format_section_height = rc.top;
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_BAD_BLOCKS);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
advanced_format_section_height = rc.bottom - advanced_format_section_height;
|
|
|
|
|
|
|
|
// Get the vertical position of the sections text
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDS_DRIVE_PROPERTIES_TXT);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
sz = GetTextSize(hCtrl, NULL);
|
|
|
|
section_vpos[0] = rc.top + 2 * sz.cy / 3;
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDS_FORMAT_OPTIONS_TXT);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
sz = GetTextSize(hCtrl, NULL);
|
|
|
|
section_vpos[1] = rc.top + 2 * sz.cy / 3;
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDS_STATUS_TXT);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
sz = GetTextSize(hCtrl, NULL);
|
|
|
|
section_vpos[2] = rc.top + 2 * sz.cy / 3;
|
|
|
|
|
|
|
|
// Seriously, who designed this bullshit API call where you pass a SIZE
|
|
|
|
// struct but can only retrieve one of cx or cy at a time?!?
|
|
|
|
SendMessage(hMultiToolbar, TB_GETIDEALSIZE, (WPARAM)FALSE, (LPARAM)&sz);
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, IDC_ABOUT), &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
SetWindowPos(hMultiToolbar, hProgress, rc.left, rc.top, sz.cx, ddbh, 0);
|
|
|
|
|
|
|
|
// Reposition the main buttons
|
|
|
|
for (i = 0; i < ARRAYSIZE(main_button_ids); i++) {
|
|
|
|
hCtrl = GetDlgItem(hDlg, main_button_ids[i]);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
x = mw + fw - bw;
|
|
|
|
if (i % 2 == 1)
|
|
|
|
x -= bw + ssw;
|
|
|
|
hPrevCtrl = GetNextWindow(hCtrl, GW_HWNDPREV);
|
|
|
|
SetWindowPos(hCtrl, hPrevCtrl, x, rc.top, bw, ddbh, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reposition the Save button
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_SAVE);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
SendMessage(hSaveToolbar, TB_GETIDEALSIZE, (WPARAM)FALSE, (LPARAM)&sz);
|
|
|
|
SendMessage(hSaveToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(sz.cx, ddbh));
|
|
|
|
// Microsoft, how I loathe thee!!!
|
|
|
|
padding = (DWORD)SendMessage(hSaveToolbar, TB_GETPADDING, 0, 0);
|
|
|
|
sz.cx = padding & 0xFFFF;
|
|
|
|
sz.cy = padding >> 16;
|
|
|
|
SendMessage(hSaveToolbar, TB_SETPADDING, 0, MAKELPARAM(sz.cx + 3, sz.cy + 2));
|
|
|
|
SetWindowPos(hSaveToolbar, hDeviceList, mw + fw - sbw, rc.top, sbw, ddbh, 0);
|
|
|
|
|
|
|
|
// Reposition the Hash button
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_HASH);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
SendMessage(hHashToolbar, TB_GETIDEALSIZE, (WPARAM)FALSE, (LPARAM)&sz);
|
|
|
|
SendMessage(hHashToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(sz.cx, ddbh));
|
|
|
|
padding = (DWORD)SendMessage(hHashToolbar, TB_GETPADDING, 0, 0);
|
|
|
|
sz.cx = padding & 0xFFFF;
|
|
|
|
sz.cy = padding >> 16;
|
|
|
|
SendMessage(hHashToolbar, TB_SETPADDING, 0, MAKELPARAM(sz.cx + 3, sz.cy + 2));
|
|
|
|
SetWindowPos(hHashToolbar, hBootType, mw + bsw + ssw, rc.top, sbw, ddbh, 0);
|
|
|
|
|
2018-07-06 10:23:57 +00:00
|
|
|
// Reposition the Persistence slider and resize it to the boot selection width
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_PERSISTENCE_SLIDER);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
2018-07-18 11:22:37 +00:00
|
|
|
SetWindowPos(hCtrl, GetDlgItem(hDlg, IDC_IMAGE_OPTION), mw, rc.top, bsw, rc.bottom - rc.top, 0);
|
2018-07-06 10:23:57 +00:00
|
|
|
|
|
|
|
// Reposition the Persistence Units dropdown (no need to resize)
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_PERSISTENCE_UNITS);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
sz.cx = fw - (rc.right - rc.left);
|
2018-07-18 11:22:37 +00:00
|
|
|
SetWindowPos(hCtrl, GetDlgItem(hDlg, IDC_PERSISTENCE_SIZE), mw + sz.cx, rc.top, rc.right - rc.left, rc.bottom - rc.top, 0);
|
|
|
|
ShowWindow(hCtrl, SW_HIDE);
|
2018-07-06 10:23:57 +00:00
|
|
|
|
|
|
|
// Reposition and resize the Persistence Size edit
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_PERSISTENCE_SIZE);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
2018-07-18 11:22:37 +00:00
|
|
|
SetWindowPos(hCtrl, GetDlgItem(hDlg, IDC_PERSISTENCE_SLIDER), mw + bsw + ssw, rc.top, fw - bsw - ssw, rc.bottom - rc.top, 0);
|
|
|
|
EnableWindow(hCtrl, FALSE);
|
2018-07-06 10:23:57 +00:00
|
|
|
|
2018-07-06 04:46:36 +00:00
|
|
|
// Reposition the CSM help tip
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDS_CSM_HELP_TXT);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
SetWindowPos(hCtrl, hTargetSystem, mw + fw + tw, rc.top, sbw, rc.bottom - rc.top, 0);
|
|
|
|
|
|
|
|
if (advanced_mode_device) {
|
|
|
|
// Still need to adjust the width of the device selection dropdown
|
|
|
|
GetWindowRect(hDeviceList, &rc);
|
|
|
|
MapWindowPoints(NULL, hMainDialog, (POINT*)&rc, 2);
|
|
|
|
SetWindowPos(hDeviceList, HWND_TOP, rc.left, rc.top, fw - ssw - sbw, rc.bottom - rc.top, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resize the full width controls
|
|
|
|
for (i = 0; i < ARRAYSIZE(full_width_controls); i++) {
|
|
|
|
hCtrl = GetDlgItem(hDlg, full_width_controls[i]);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
hPrevCtrl = GetNextWindow(hCtrl, GW_HWNDPREV);
|
|
|
|
SetWindowPos(hCtrl, hPrevCtrl, rc.left, rc.top, fw, rc.bottom - rc.top, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resize the half drowpdowns
|
|
|
|
for (i = 0; i < ARRAYSIZE(half_width_ids); i++) {
|
|
|
|
hCtrl = GetDlgItem(hDlg, half_width_ids[i]);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
// First 5 controls are on the left handside
|
|
|
|
// First 2 controls may overflow into separator
|
|
|
|
hPrevCtrl = GetNextWindow(hCtrl, GW_HWNDPREV);
|
|
|
|
SetWindowPos(hCtrl, hPrevCtrl, (i < 5) ? rc.left : mw + hw + sw, rc.top,
|
|
|
|
(i <2) ? hw + sw : hw, rc.bottom - rc.top, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resize the boot selection dropdown
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_BOOT_SELECTION);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
hPrevCtrl = GetNextWindow(hCtrl, GW_HWNDPREV);
|
|
|
|
SetWindowPos(hCtrl, hPrevCtrl, rc.left, rc.top, bsw, rc.bottom - rc.top, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ResizeDialogs(int shift)
|
|
|
|
{
|
|
|
|
RECT rc;
|
|
|
|
POINT point;
|
|
|
|
|
|
|
|
// Resize the main dialog
|
|
|
|
GetWindowRect(hMainDialog, &rc);
|
|
|
|
point.x = (rc.right - rc.left);
|
|
|
|
point.y = (rc.bottom - rc.top);
|
|
|
|
MoveWindow(hMainDialog, rc.left, rc.top, point.x, point.y + shift, TRUE);
|
|
|
|
|
|
|
|
// Resize the log
|
|
|
|
GetWindowRect(hLogDialog, &rc);
|
|
|
|
point.x = (rc.right - rc.left);
|
|
|
|
point.y = (rc.bottom - rc.top);
|
|
|
|
MoveWindow(hLogDialog, rc.left, rc.top, point.x, point.y + shift, TRUE);
|
|
|
|
MoveCtrlY(hLogDialog, IDC_LOG_CLEAR, shift);
|
|
|
|
MoveCtrlY(hLogDialog, IDC_LOG_SAVE, shift);
|
|
|
|
MoveCtrlY(hLogDialog, IDCANCEL, shift);
|
|
|
|
GetWindowRect(hLog, &rc);
|
|
|
|
point.x = (rc.right - rc.left);
|
|
|
|
point.y = (rc.bottom - rc.top) + shift;
|
|
|
|
SetWindowPos(hLog, NULL, 0, 0, point.x, point.y, SWP_NOZORDER);
|
|
|
|
// Don't forget to scroll the edit to the bottom after resize
|
|
|
|
Edit_Scroll(hLog, 0, Edit_GetLineCount(hLog));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Thanks to Microsoft atrocious DPI handling, we must adjust for low DPI
|
|
|
|
void AdjustForLowDPI(HWND hDlg)
|
|
|
|
{
|
|
|
|
static int ddy = 4;
|
|
|
|
int i, j;
|
|
|
|
RECT rc;
|
|
|
|
HWND hCtrl, hPrevCtrl;
|
|
|
|
int dy = 0;
|
|
|
|
|
|
|
|
if (fScale >= 1.3f)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAYSIZE(adjust_dpi_ids); i++) {
|
|
|
|
dy += ddy;
|
|
|
|
// "...and the other thing I really like about Microsoft's UI handling is how "
|
|
|
|
//."you never have to introduce weird hardcoded constants all over the place, "
|
|
|
|
// "just to make your UI look good...", said NO ONE ever.
|
|
|
|
if (adjust_dpi_ids[i][0] == IDC_QUICK_FORMAT)
|
|
|
|
dy += 1;
|
|
|
|
for (j = 0; j < 5; j++) {
|
|
|
|
if (adjust_dpi_ids[i][j] == 0)
|
|
|
|
break;
|
|
|
|
hCtrl = GetDlgItem(hDlg, adjust_dpi_ids[i][j]);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
hPrevCtrl = GetNextWindow(hCtrl, GW_HWNDPREV);
|
|
|
|
SetWindowPos(hCtrl, hPrevCtrl, rc.left, rc.top + dy,
|
|
|
|
rc.right - rc.left, rc.bottom - rc.top, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
section_vpos[1] += 9 * ddy;
|
|
|
|
section_vpos[2] += 16 * ddy + 1;
|
|
|
|
advanced_device_section_height += 3 * ddy;
|
|
|
|
advanced_format_section_height += 3 * ddy + 1;
|
|
|
|
|
|
|
|
ResizeDialogs(dy + 2 * ddy);
|
|
|
|
InvalidateRect(hDlg, NULL, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetSectionHeaders(HWND hDlg)
|
|
|
|
{
|
|
|
|
RECT rc;
|
|
|
|
HWND hCtrl;
|
|
|
|
SIZE sz;
|
|
|
|
HFONT hf;
|
|
|
|
wchar_t wtmp[128];
|
|
|
|
size_t wlen;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// Set the section header fonts and resize the static controls accordingly
|
|
|
|
hf = CreateFontA(-MulDiv(14, GetDeviceCaps(GetDC(hMainDialog), LOGPIXELSY), 72), 0, 0, 0,
|
|
|
|
FW_SEMIBOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, 0, 0, PROOF_QUALITY, 0, "Segoe UI");
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAYSIZE(section_control_ids); i++) {
|
|
|
|
SendDlgItemMessageA(hDlg, section_control_ids[i], WM_SETFONT, (WPARAM)hf, TRUE);
|
|
|
|
hCtrl = GetDlgItem(hDlg, section_control_ids[i]);
|
|
|
|
memset(wtmp, 0, sizeof(wtmp));
|
|
|
|
GetWindowTextW(hCtrl, wtmp, ARRAYSIZE(wtmp));
|
|
|
|
wlen = wcslen(wtmp);
|
|
|
|
wtmp[wlen++] = L' ';
|
|
|
|
wtmp[wlen++] = L' ';
|
|
|
|
SetWindowTextW(hCtrl, wtmp);
|
|
|
|
GetWindowRect(hCtrl, &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
sz = GetTextSize(hCtrl, NULL);
|
|
|
|
SetWindowPos(hCtrl, NULL, rc.left, rc.top, sz.cx, sz.cy, SWP_NOZORDER);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Toggle "advanced" options
|
|
|
|
void ToggleAdvancedDeviceOptions(BOOL enable)
|
|
|
|
{
|
|
|
|
RECT rc;
|
|
|
|
SIZE sz;
|
|
|
|
TBBUTTONINFO button_info;
|
|
|
|
int i, shift = advanced_device_section_height;
|
|
|
|
|
|
|
|
if (!enable)
|
|
|
|
shift = -shift;
|
|
|
|
section_vpos[1] += shift;
|
|
|
|
section_vpos[2] += shift;
|
|
|
|
|
|
|
|
// Toggle the Hide/Show toolbar text
|
|
|
|
utf8_to_wchar_no_alloc(lmprintf((enable) ? MSG_122 : MSG_121, lmprintf(MSG_119)), wtbtext[0], ARRAYSIZE(wtbtext[0]));
|
|
|
|
button_info.cbSize = sizeof(button_info);
|
|
|
|
button_info.dwMask = TBIF_TEXT;
|
|
|
|
button_info.pszText = wtbtext[0];
|
|
|
|
SendMessage(hAdvancedDeviceToolbar, TB_SETBUTTONINFO, (WPARAM)IDC_ADVANCED_DRIVE_PROPERTIES, (LPARAM)&button_info);
|
|
|
|
SendMessage(hAdvancedDeviceToolbar, TB_SETIMAGELIST, (WPARAM)0, (LPARAM)((enable) ? hUpImageList : hDownImageList));
|
|
|
|
GetWindowRect(hAdvancedDeviceToolbar, &rc);
|
|
|
|
MapWindowPoints(NULL, hMainDialog, (POINT*)&rc, 2);
|
|
|
|
SendMessage(hAdvancedDeviceToolbar, TB_GETIDEALSIZE, (WPARAM)FALSE, (LPARAM)&sz);
|
2019-07-05 11:24:50 +00:00
|
|
|
// TB_GETIDEALSIZE may act up and report negative values
|
|
|
|
if (sz.cx < 16)
|
|
|
|
sz.cx = fw;
|
2018-07-06 04:46:36 +00:00
|
|
|
SetWindowPos(hAdvancedDeviceToolbar, hTargetSystem, rc.left, rc.top, sz.cx, rc.bottom - rc.top, 0);
|
|
|
|
|
|
|
|
// Move the controls up or down
|
|
|
|
for (i = 0; i<ARRAYSIZE(advanced_device_move_ids); i++)
|
|
|
|
MoveCtrlY(hMainDialog, advanced_device_move_ids[i], shift);
|
|
|
|
|
|
|
|
// Hide or show the various advanced options
|
|
|
|
for (i = 0; i<ARRAYSIZE(advanced_device_toggle_ids); i++)
|
|
|
|
ShowWindow(GetDlgItem(hMainDialog, advanced_device_toggle_ids[i]), enable ? SW_SHOW : SW_HIDE);
|
|
|
|
|
|
|
|
GetWindowRect(hDeviceList, &rc);
|
|
|
|
MapWindowPoints(NULL, hMainDialog, (POINT*)&rc, 2);
|
|
|
|
SetWindowPos(hDeviceList, HWND_TOP, rc.left, rc.top, enable ? fw - ssw - sbw : fw, rc.bottom - rc.top, 0);
|
|
|
|
|
|
|
|
// Resize the main dialog and log window
|
|
|
|
ResizeDialogs(shift);
|
|
|
|
|
|
|
|
// Never hurts to force Windows' hand
|
|
|
|
InvalidateRect(hMainDialog, NULL, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ToggleAdvancedFormatOptions(BOOL enable)
|
|
|
|
{
|
|
|
|
RECT rc;
|
|
|
|
SIZE sz;
|
|
|
|
TBBUTTONINFO button_info;
|
|
|
|
int i, shift = advanced_format_section_height;
|
|
|
|
|
|
|
|
if (!enable)
|
|
|
|
shift = -shift;
|
|
|
|
section_vpos[2] += shift;
|
|
|
|
|
|
|
|
// Toggle the Hide/Show toolbar text
|
|
|
|
utf8_to_wchar_no_alloc(lmprintf((enable) ? MSG_122 : MSG_121, lmprintf(MSG_120)), wtbtext[1], ARRAYSIZE(wtbtext[0]));
|
|
|
|
button_info.cbSize = sizeof(button_info);
|
|
|
|
button_info.dwMask = TBIF_TEXT;
|
|
|
|
button_info.pszText = wtbtext[1];
|
|
|
|
SendMessage(hAdvancedFormatToolbar, TB_SETBUTTONINFO, (WPARAM)IDC_ADVANCED_FORMAT_OPTIONS, (LPARAM)&button_info);
|
|
|
|
SendMessage(hAdvancedFormatToolbar, TB_SETIMAGELIST, (WPARAM)0, (LPARAM)((enable) ? hUpImageList : hDownImageList));
|
|
|
|
GetWindowRect(hAdvancedFormatToolbar, &rc);
|
|
|
|
MapWindowPoints(NULL, hMainDialog, (POINT*)&rc, 2);
|
|
|
|
SendMessage(hAdvancedFormatToolbar, TB_GETIDEALSIZE, (WPARAM)FALSE, (LPARAM)&sz);
|
2019-07-05 11:24:50 +00:00
|
|
|
if (sz.cx < 16)
|
|
|
|
sz.cx = fw;
|
2018-07-06 04:46:36 +00:00
|
|
|
SetWindowPos(hAdvancedFormatToolbar, hClusterSize, rc.left, rc.top, sz.cx, rc.bottom - rc.top, 0);
|
|
|
|
|
|
|
|
// Move the controls up or down
|
|
|
|
for (i = 0; i<ARRAYSIZE(advanced_format_move_ids); i++)
|
|
|
|
MoveCtrlY(hMainDialog, advanced_format_move_ids[i], shift);
|
|
|
|
|
|
|
|
// Hide or show the various advanced options
|
|
|
|
for (i = 0; i<ARRAYSIZE(advanced_format_toggle_ids); i++)
|
|
|
|
ShowWindow(GetDlgItem(hMainDialog, advanced_format_toggle_ids[i]), enable ? SW_SHOW : SW_HIDE);
|
|
|
|
|
|
|
|
// Resize the main dialog and log window
|
|
|
|
ResizeDialogs(shift);
|
|
|
|
|
|
|
|
// Never hurts to force Windows' hand
|
|
|
|
InvalidateRect(hMainDialog, NULL, TRUE);
|
|
|
|
}
|
|
|
|
|
2018-07-18 11:22:37 +00:00
|
|
|
// Toggle the display of peristence unit dropdown and resize the size field
|
|
|
|
void TogglePersistenceControls(BOOL display)
|
|
|
|
{
|
|
|
|
RECT rc;
|
|
|
|
HWND hSize, hUnits;
|
2018-08-20 08:46:23 +00:00
|
|
|
LONG_PTR style;
|
|
|
|
LONG width = fw - bsw - ssw;
|
2018-07-18 11:22:37 +00:00
|
|
|
hSize = GetDlgItem(hMainDialog, IDC_PERSISTENCE_SIZE);
|
|
|
|
hUnits = GetDlgItem(hMainDialog, IDC_PERSISTENCE_UNITS);
|
|
|
|
|
2018-08-20 08:46:23 +00:00
|
|
|
style = GetWindowLongPtr(hSize, GWL_EXSTYLE);
|
2018-07-18 11:22:37 +00:00
|
|
|
if (display)
|
|
|
|
style |= WS_EX_RIGHT;
|
|
|
|
else
|
|
|
|
style &= ~WS_EX_RIGHT;
|
2018-08-20 08:46:23 +00:00
|
|
|
SetWindowLongPtr(hSize, GWL_EXSTYLE, style);
|
2018-07-18 11:22:37 +00:00
|
|
|
|
|
|
|
if (display) {
|
|
|
|
GetWindowRect(hUnits, &rc);
|
|
|
|
MapWindowPoints(NULL, hMainDialog, (POINT*)&rc, 2);
|
|
|
|
width -= (rc.right - rc.left) + ssw;
|
|
|
|
}
|
|
|
|
|
|
|
|
GetWindowRect(hSize, &rc);
|
|
|
|
MapWindowPoints(NULL, hMainDialog, (POINT*)&rc, 2);
|
|
|
|
SetWindowPos(hSize, GetDlgItem(hMainDialog, IDC_PERSISTENCE_SLIDER), mw + bsw + ssw, rc.top, width, rc.bottom - rc.top, 0);
|
|
|
|
|
|
|
|
EnableWindow(hSize, display ? TRUE : FALSE);
|
|
|
|
EnableWindow(hUnits, display ? TRUE : FALSE);
|
|
|
|
ShowWindow(hUnits, display ? SW_SHOW : SW_HIDE);
|
|
|
|
}
|
|
|
|
|
2019-06-05 16:00:21 +00:00
|
|
|
void SetPersistencePos(uint64_t pos)
|
2018-07-06 10:23:57 +00:00
|
|
|
{
|
2018-07-18 11:22:37 +00:00
|
|
|
char tmp[64];
|
2018-07-15 00:01:39 +00:00
|
|
|
|
2019-06-05 16:00:21 +00:00
|
|
|
if ((boot_type == BT_IMAGE) && (pos != 0)) {
|
2018-08-14 22:05:52 +00:00
|
|
|
TogglePersistenceControls(TRUE);
|
2018-07-18 11:22:37 +00:00
|
|
|
static_sprintf(tmp, "%ld", (LONG)pos);
|
|
|
|
} else {
|
2018-08-14 22:05:52 +00:00
|
|
|
TogglePersistenceControls(FALSE);
|
2018-07-18 11:22:37 +00:00
|
|
|
static_sprintf(tmp, "0 (%s)", lmprintf(MSG_124));
|
|
|
|
}
|
|
|
|
app_changed_size = TRUE;
|
|
|
|
SetWindowTextU(GetDlgItem(hMainDialog, IDC_PERSISTENCE_SIZE), tmp);
|
2018-07-06 10:23:57 +00:00
|
|
|
}
|
|
|
|
|
2018-08-14 22:05:52 +00:00
|
|
|
void SetPersistenceSize(void)
|
|
|
|
{
|
|
|
|
int i, proposed_unit_selection = 0;
|
|
|
|
LONGLONG base_unit = MB;
|
|
|
|
HWND hCtrl;
|
|
|
|
uint64_t max = 0, pos = 0;
|
|
|
|
|
|
|
|
if (ComboBox_GetCurSel(hDeviceList) >= 0) {
|
|
|
|
max = SelectedDrive.DiskSize - img_report.projected_size;
|
|
|
|
persistence_size = min(persistence_size, max);
|
|
|
|
pos = persistence_size;
|
|
|
|
|
|
|
|
// Reset the the Persistence Units dropdown
|
|
|
|
hCtrl = GetDlgItem(hMainDialog, IDC_PERSISTENCE_UNITS);
|
|
|
|
IGNORE_RETVAL(ComboBox_ResetContent(hCtrl));
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
IGNORE_RETVAL(ComboBox_SetItemData(hCtrl, ComboBox_AddStringU(hCtrl, lmprintf(MSG_022 + i)), i));
|
|
|
|
// If we have more than 7 discrete positions, set this unit as our base
|
|
|
|
if (SelectedDrive.DiskSize > 7 * base_unit)
|
|
|
|
proposed_unit_selection = i;
|
|
|
|
base_unit *= 1024;
|
|
|
|
// Don't allow a base unit unless the drive is at least twice the size of that unit
|
|
|
|
if (SelectedDrive.DiskSize < 2 * base_unit)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (persistence_unit_selection < 0)
|
|
|
|
persistence_unit_selection = proposed_unit_selection;
|
|
|
|
|
|
|
|
IGNORE_RETVAL(ComboBox_SetCurSel(hCtrl, persistence_unit_selection));
|
|
|
|
pos /= MB;
|
|
|
|
max /= MB;
|
|
|
|
for (i = 0; i < persistence_unit_selection; i++) {
|
|
|
|
pos /= 1024;
|
|
|
|
max /= 1024;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
hCtrl = GetDlgItem(hMainDialog, IDC_PERSISTENCE_SLIDER);
|
|
|
|
// Wow! Unless you set *all* these redraw WPARAMs to true, the one from
|
|
|
|
// TBM_SETPOS gets completely ignored if the value is zero!
|
|
|
|
SendMessage(hCtrl, TBM_SETRANGEMIN, (WPARAM)TRUE, (LPARAM)0);
|
|
|
|
SendMessage(hCtrl, TBM_SETRANGEMAX, (WPARAM)TRUE, (LPARAM)max);
|
|
|
|
SendMessage(hCtrl, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos);
|
|
|
|
|
2019-06-05 16:00:21 +00:00
|
|
|
SetPersistencePos(pos);
|
2018-08-14 22:05:52 +00:00
|
|
|
}
|
|
|
|
|
2018-07-06 04:46:36 +00:00
|
|
|
// Toggle the Image Option dropdown (Windows To Go or persistence settings)
|
2018-07-18 11:22:37 +00:00
|
|
|
void ToggleImageOptions(void)
|
2018-07-06 04:46:36 +00:00
|
|
|
{
|
2018-07-18 11:22:37 +00:00
|
|
|
BOOL has_wintogo, has_persistence;
|
|
|
|
uint8_t entry_image_options = image_options;
|
|
|
|
int i, shift = rh;
|
|
|
|
|
2019-04-13 14:29:27 +00:00
|
|
|
has_wintogo = ((boot_type == BT_IMAGE) && (image_path != NULL) && (img_report.is_iso) && (nWindowsVersion >= WINDOWS_8) && (HAS_WINTOGO(img_report)));
|
|
|
|
has_persistence = ((boot_type == BT_IMAGE) && (image_path != NULL) && (img_report.is_iso) && (HAS_PERSISTENCE(img_report)));
|
2018-07-18 11:22:37 +00:00
|
|
|
|
|
|
|
assert(popcnt8(image_options) <= 1);
|
2018-07-06 10:23:57 +00:00
|
|
|
|
2018-07-18 11:22:37 +00:00
|
|
|
// Keep a copy of the "Image Option" text (so that we don't have to duplicate its transation in the .loc)
|
|
|
|
if (image_option_txt[0] == 0)
|
|
|
|
GetWindowTextU(GetDlgItem(hMainDialog, IDS_IMAGE_OPTION_TXT), image_option_txt, sizeof(image_option_txt));
|
|
|
|
|
|
|
|
if ( ((has_wintogo) && !(image_options & IMOP_WINTOGO)) ||
|
|
|
|
((!has_wintogo) && (image_options & IMOP_WINTOGO)) ) {
|
2018-07-06 04:46:36 +00:00
|
|
|
image_options ^= IMOP_WINTOGO;
|
|
|
|
// Set the Windows To Go selection in the dropdown
|
|
|
|
IGNORE_RETVAL(ComboBox_SetCurSel(GetDlgItem(hMainDialog, IDC_IMAGE_OPTION), windows_to_go_selection));
|
2018-07-18 11:22:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (((has_persistence) && !(image_options & IMOP_PERSISTENCE)) ||
|
|
|
|
((!has_persistence) && (image_options & IMOP_PERSISTENCE))) {
|
2018-07-06 04:46:36 +00:00
|
|
|
image_options ^= IMOP_PERSISTENCE;
|
|
|
|
}
|
|
|
|
|
2018-07-18 11:22:37 +00:00
|
|
|
if ( ((entry_image_options != 0) && (has_wintogo || has_persistence)) ||
|
|
|
|
((entry_image_options == 0) && !(has_wintogo || has_persistence)) )
|
2018-07-06 04:46:36 +00:00
|
|
|
shift = 0;
|
|
|
|
|
|
|
|
if (shift != 0) {
|
2018-07-18 11:22:37 +00:00
|
|
|
if (entry_image_options != 0)
|
2018-07-06 04:46:36 +00:00
|
|
|
shift = -shift;
|
|
|
|
section_vpos[1] += shift;
|
|
|
|
section_vpos[2] += shift;
|
|
|
|
|
2018-07-18 11:22:37 +00:00
|
|
|
for (i = 0; i < ARRAYSIZE(image_option_move_ids); i++)
|
|
|
|
MoveCtrlY(hMainDialog, image_option_move_ids[i], shift);
|
2018-07-06 04:46:36 +00:00
|
|
|
|
2018-07-18 11:22:37 +00:00
|
|
|
// Resize the main dialog and log window
|
|
|
|
ResizeDialogs(shift);
|
2018-07-06 04:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Hide or show the boot options
|
|
|
|
for (i = 0; i < ARRAYSIZE(image_option_toggle_ids); i++) {
|
|
|
|
ShowWindow(GetDlgItem(hMainDialog, image_option_toggle_ids[i][0]),
|
|
|
|
(image_options & image_option_toggle_ids[i][1]) ? SW_SHOW : SW_HIDE);
|
|
|
|
}
|
2018-07-06 10:23:57 +00:00
|
|
|
// Set the dropdown default selection
|
|
|
|
if (image_options & IMOP_WINTOGO) {
|
|
|
|
SetWindowTextU(GetDlgItem(hMainDialog, IDS_IMAGE_OPTION_TXT), image_option_txt);
|
|
|
|
IGNORE_RETVAL(ComboBox_SetCurSel(GetDlgItem(hMainDialog, IDC_IMAGE_OPTION), windows_to_go_selection));
|
|
|
|
} else if (image_options & IMOP_PERSISTENCE) {
|
2018-07-18 11:22:37 +00:00
|
|
|
SetWindowTextU(GetDlgItem(hMainDialog, IDS_IMAGE_OPTION_TXT), lmprintf(MSG_123));
|
|
|
|
TogglePersistenceControls(persistence_size != 0);
|
2018-08-14 22:05:52 +00:00
|
|
|
SetPersistenceSize();
|
2018-07-06 10:23:57 +00:00
|
|
|
}
|
2018-07-06 04:46:36 +00:00
|
|
|
// If you don't force a redraw here, all kind of bad UI artifacts happen...
|
|
|
|
InvalidateRect(hMainDialog, NULL, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need to create the small toolbar buttons first so that we can compute their width
|
|
|
|
void CreateSmallButtons(HWND hDlg)
|
|
|
|
{
|
|
|
|
HIMAGELIST hImageList;
|
|
|
|
HICON hIconSave, hIconHash;
|
|
|
|
int icon_offset = 0, i16 = GetSystemMetrics(SM_CXSMICON);
|
|
|
|
TBBUTTON tbToolbarButtons[1];
|
|
|
|
unsigned char* buffer;
|
|
|
|
DWORD bufsize;
|
|
|
|
|
|
|
|
if (i16 >= 28)
|
|
|
|
icon_offset = 20;
|
|
|
|
else if (i16 >= 20)
|
|
|
|
icon_offset = 10;
|
|
|
|
|
|
|
|
hSaveToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, TOOLBAR_STYLE,
|
|
|
|
0, 0, 0, 0, hMainDialog, (HMENU)IDC_SAVE_TOOLBAR, hMainInstance, NULL);
|
|
|
|
hImageList = ImageList_Create(i16, i16, ILC_COLOR32 | ILC_HIGHQUALITYSCALE | ILC_MIRROR, 1, 0);
|
|
|
|
buffer = GetResource(hMainInstance, MAKEINTRESOURCEA(IDI_SAVE_16 + icon_offset), _RT_RCDATA, "save icon", &bufsize, FALSE);
|
|
|
|
hIconSave = CreateIconFromResourceEx(buffer, bufsize, TRUE, 0x30000, 0, 0, 0);
|
|
|
|
ImageList_AddIcon(hImageList, hIconSave);
|
|
|
|
DestroyIcon(hIconSave);
|
|
|
|
SendMessage(hSaveToolbar, TB_SETIMAGELIST, (WPARAM)0, (LPARAM)hImageList);
|
|
|
|
SendMessage(hSaveToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
|
|
|
|
memset(tbToolbarButtons, 0, sizeof(TBBUTTON));
|
|
|
|
tbToolbarButtons[0].idCommand = IDC_SAVE;
|
|
|
|
tbToolbarButtons[0].fsStyle = BTNS_AUTOSIZE;
|
|
|
|
tbToolbarButtons[0].fsState = TBSTATE_ENABLED;
|
|
|
|
tbToolbarButtons[0].iBitmap = 0;
|
|
|
|
SendMessage(hSaveToolbar, TB_ADDBUTTONS, (WPARAM)1, (LPARAM)&tbToolbarButtons);
|
|
|
|
|
|
|
|
hHashToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, TOOLBAR_STYLE,
|
|
|
|
0, 0, 0, 0, hMainDialog, (HMENU)IDC_HASH_TOOLBAR, hMainInstance, NULL);
|
|
|
|
hImageList = ImageList_Create(i16, i16, ILC_COLOR32 | ILC_HIGHQUALITYSCALE | ILC_MIRROR, 1, 0);
|
|
|
|
buffer = GetResource(hMainInstance, MAKEINTRESOURCEA(IDI_HASH_16 + icon_offset), _RT_RCDATA, "hash icon", &bufsize, FALSE);
|
|
|
|
hIconHash = CreateIconFromResourceEx(buffer, bufsize, TRUE, 0x30000, 0, 0, 0);
|
|
|
|
ImageList_AddIcon(hImageList, hIconHash);
|
|
|
|
DestroyIcon(hIconHash);
|
|
|
|
SendMessage(hHashToolbar, TB_SETIMAGELIST, (WPARAM)0, (LPARAM)hImageList);
|
|
|
|
SendMessage(hHashToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
|
|
|
|
memset(tbToolbarButtons, 0, sizeof(TBBUTTON));
|
|
|
|
tbToolbarButtons[0].idCommand = IDC_HASH;
|
|
|
|
tbToolbarButtons[0].fsStyle = BTNS_AUTOSIZE;
|
|
|
|
tbToolbarButtons[0].fsState = TBSTATE_ENABLED;
|
|
|
|
tbToolbarButtons[0].iBitmap = 0;
|
|
|
|
SendMessage(hHashToolbar, TB_ADDBUTTONS, (WPARAM)1, (LPARAM)&tbToolbarButtons);
|
|
|
|
}
|
|
|
|
|
|
|
|
static INT_PTR CALLBACK ProgressCallback(HWND hCtrl, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
HDC hDC;
|
|
|
|
RECT rc, rc2;
|
|
|
|
PAINTSTRUCT ps;
|
|
|
|
SIZE size;
|
|
|
|
LONG full_right;
|
|
|
|
wchar_t winfo[128];
|
|
|
|
static BOOL marquee_mode = FALSE;
|
|
|
|
static uint32_t pos = 0, min = 0, max = 0xFFFF;
|
|
|
|
static COLORREF color = PROGRESS_BAR_NORMAL_COLOR;
|
|
|
|
|
|
|
|
switch (message) {
|
|
|
|
|
|
|
|
case PBM_SETSTATE:
|
|
|
|
switch (wParam) {
|
|
|
|
case PBST_NORMAL:
|
|
|
|
color = PROGRESS_BAR_NORMAL_COLOR;
|
|
|
|
break;
|
|
|
|
case PBST_PAUSED:
|
|
|
|
color = PROGRESS_BAR_PAUSED_COLOR;
|
|
|
|
break;
|
|
|
|
case PBST_ERROR:
|
|
|
|
color = PROGRESS_BAR_ERROR_COLOR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
|
|
|
|
case PBM_SETRANGE:
|
2019-06-14 12:02:35 +00:00
|
|
|
CallWindowProc(progress_original_proc, hCtrl, message, wParam, lParam);
|
2018-07-06 04:46:36 +00:00
|
|
|
// Don't bother sanity checking min and max: If *you* want to
|
|
|
|
// be an ass about the progress bar range, it's *your* problem.
|
|
|
|
min = (uint32_t)(lParam & 0xFFFF);
|
|
|
|
max = (uint32_t)(lParam >> 16);
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
|
|
|
|
case PBM_SETPOS:
|
2019-06-14 12:02:35 +00:00
|
|
|
CallWindowProc(progress_original_proc, hCtrl, message, wParam, lParam);
|
2018-07-06 04:46:36 +00:00
|
|
|
pos = (WORD)wParam;
|
|
|
|
InvalidateRect(hProgress, NULL, TRUE);
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
|
|
|
|
case PBM_SETMARQUEE:
|
2019-06-14 12:02:35 +00:00
|
|
|
CallWindowProc(progress_original_proc, hCtrl, message, wParam, lParam);
|
2018-07-06 04:46:36 +00:00
|
|
|
if ((wParam == TRUE) && (!marquee_mode)) {
|
|
|
|
marquee_mode = TRUE;
|
|
|
|
pos = min;
|
|
|
|
color = PROGRESS_BAR_NORMAL_COLOR;
|
|
|
|
SetTimer(hCtrl, TID_MARQUEE_TIMER, MARQUEE_TIMER_REFRESH, NULL);
|
|
|
|
InvalidateRect(hProgress, NULL, TRUE);
|
|
|
|
} else if ((wParam == FALSE) && (marquee_mode)) {
|
|
|
|
marquee_mode = FALSE;
|
|
|
|
KillTimer(hCtrl, TID_MARQUEE_TIMER);
|
|
|
|
pos = min;
|
|
|
|
InvalidateRect(hProgress, NULL, TRUE);
|
|
|
|
}
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
|
|
|
|
case WM_TIMER:
|
|
|
|
if ((wParam == TID_MARQUEE_TIMER) && marquee_mode) {
|
|
|
|
pos += max((max - min) / (1000 / MARQUEE_TIMER_REFRESH), 1);
|
|
|
|
if ((pos > max) || (pos < min))
|
|
|
|
pos = min;
|
|
|
|
InvalidateRect(hProgress, NULL, TRUE);
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
|
|
|
return (INT_PTR)FALSE;
|
|
|
|
|
|
|
|
case WM_PAINT:
|
|
|
|
hDC = BeginPaint(hCtrl, &ps);
|
|
|
|
GetClientRect(hCtrl, &rc);
|
|
|
|
rc2 = rc;
|
|
|
|
InflateRect(&rc, -1, -1);
|
|
|
|
SelectObject(hDC, GetStockObject(DC_PEN));
|
|
|
|
SelectObject(hDC, GetStockObject(NULL_BRUSH));
|
|
|
|
// TODO: Handle SetText message so we can avoid this call
|
|
|
|
GetWindowTextW(hProgress, winfo, ARRAYSIZE(winfo));
|
|
|
|
SelectObject(hDC, hInfoFont);
|
|
|
|
GetTextExtentPoint32(hDC, winfo, (int)wcslen(winfo), &size);
|
|
|
|
if (size.cx > rc.right)
|
|
|
|
size.cx = rc.right;
|
|
|
|
if (size.cy > rc.bottom)
|
|
|
|
size.cy = rc.bottom;
|
|
|
|
full_right = rc.right;
|
|
|
|
if (marquee_mode) {
|
|
|
|
// Optional first segment
|
|
|
|
if (pos + ((max - min) / 5) > max) {
|
|
|
|
rc.right = MulDiv(pos + ((max - min) / 5) - max, rc.right, max - min);
|
|
|
|
SetTextColor(hDC, PROGRESS_BAR_INVERTED_TEXT_COLOR);
|
|
|
|
SetBkColor(hDC, color);
|
|
|
|
ExtTextOut(hDC, (full_right - size.cx) / 2, (rc.bottom - size.cy) / 2,
|
|
|
|
ETO_CLIPPED | ETO_OPAQUE | ETO_NUMERICSLOCAL, &rc, winfo, (int)wcslen(winfo), NULL);
|
|
|
|
rc.left = rc.right;
|
|
|
|
rc.right = full_right;
|
|
|
|
}
|
|
|
|
// Optional second segment
|
|
|
|
if (pos > min) {
|
|
|
|
rc.right = MulDiv(pos - min, rc.right, max - min);
|
|
|
|
SetTextColor(hDC, PROGRESS_BAR_NORMAL_TEXT_COLOR);
|
|
|
|
SetBkColor(hDC, PROGRESS_BAR_BACKGROUND_COLOR);
|
|
|
|
ExtTextOut(hDC, (full_right - size.cx) / 2, (rc.bottom - size.cy) / 2,
|
|
|
|
ETO_CLIPPED | ETO_OPAQUE | ETO_NUMERICSLOCAL, &rc, winfo, (int)wcslen(winfo), NULL);
|
|
|
|
rc.left = rc.right;
|
|
|
|
rc.right = full_right;
|
|
|
|
}
|
|
|
|
// Second to last segment
|
|
|
|
rc.right = MulDiv(pos - min + ((max - min) / 5), rc.right, max - min);
|
|
|
|
SetTextColor(hDC, PROGRESS_BAR_INVERTED_TEXT_COLOR);
|
|
|
|
SetBkColor(hDC, color);
|
|
|
|
ExtTextOut(hDC, (full_right - size.cx) / 2, (rc.bottom - size.cy) / 2,
|
|
|
|
ETO_CLIPPED | ETO_OPAQUE | ETO_NUMERICSLOCAL, &rc, winfo, (int)wcslen(winfo), NULL);
|
|
|
|
} else {
|
|
|
|
// First segment
|
|
|
|
rc.right = (pos > min) ? MulDiv(pos - min, rc.right, max - min) : rc.left;
|
|
|
|
SetTextColor(hDC, PROGRESS_BAR_INVERTED_TEXT_COLOR);
|
|
|
|
SetBkColor(hDC, color);
|
|
|
|
ExtTextOut(hDC, (full_right - size.cx) / 2, (rc.bottom - size.cy) / 2,
|
|
|
|
ETO_CLIPPED | ETO_OPAQUE | ETO_NUMERICSLOCAL, &rc, winfo, (int)wcslen(winfo), NULL);
|
|
|
|
}
|
|
|
|
// Last segment
|
|
|
|
rc.left = rc.right;
|
|
|
|
rc.right = full_right;
|
|
|
|
SetTextColor(hDC, PROGRESS_BAR_NORMAL_TEXT_COLOR);
|
|
|
|
SetBkColor(hDC, PROGRESS_BAR_BACKGROUND_COLOR);
|
|
|
|
ExtTextOut(hDC, (full_right - size.cx) / 2, (rc.bottom - size.cy) / 2,
|
|
|
|
ETO_CLIPPED | ETO_OPAQUE | ETO_NUMERICSLOCAL, &rc, winfo, (int)wcslen(winfo), NULL);
|
|
|
|
// Bounding rectangle
|
|
|
|
SetDCPenColor(hDC, PROGRESS_BAR_BOX_COLOR);
|
|
|
|
Rectangle(hDC, rc2.left, rc2.top, rc2.right, rc2.bottom);
|
|
|
|
EndPaint(hCtrl, &ps);
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CallWindowProc(progress_original_proc, hCtrl, message, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CreateAdditionalControls(HWND hDlg)
|
|
|
|
{
|
|
|
|
HINSTANCE hDll;
|
|
|
|
HIMAGELIST hToolbarImageList;
|
|
|
|
HICON hIcon, hIconUp, hIconDown;
|
|
|
|
RECT rc;
|
|
|
|
SIZE sz;
|
|
|
|
int icon_offset = 0, i, i16, s16, toolbar_dx = -4 - ((fScale > 1.49f) ? 1 : 0) - ((fScale > 1.99f) ? 1 : 0);
|
|
|
|
TBBUTTON tbToolbarButtons[7];
|
|
|
|
unsigned char* buffer;
|
|
|
|
DWORD bufsize;
|
|
|
|
|
|
|
|
s16 = i16 = GetSystemMetrics(SM_CXSMICON);
|
|
|
|
if (s16 >= 54)
|
|
|
|
s16 = 64;
|
|
|
|
else if (s16 >= 40)
|
|
|
|
s16 = 48;
|
|
|
|
else if (s16 >= 28)
|
|
|
|
s16 = 32;
|
|
|
|
else if (s16 >= 20)
|
|
|
|
s16 = 24;
|
|
|
|
if (i16 >= 28)
|
|
|
|
icon_offset = 20;
|
|
|
|
else if (i16 >= 20)
|
|
|
|
icon_offset = 10;
|
|
|
|
|
|
|
|
// Fetch the up and down expand icons for the advanced options toolbar
|
|
|
|
hDll = GetLibraryHandle("ComDlg32");
|
|
|
|
hIconDown = (HICON)LoadImage(hDll, MAKEINTRESOURCE(577), IMAGE_ICON, s16, s16, LR_DEFAULTCOLOR | LR_SHARED);
|
|
|
|
hIconUp = (HICON)LoadImage(hDll, MAKEINTRESOURCE(578), IMAGE_ICON, s16, s16, LR_DEFAULTCOLOR | LR_SHARED);
|
|
|
|
// Fallback to using Shell32 if we can't locate the icons we want in ComDlg32
|
|
|
|
hDll = GetLibraryHandle("Shell32");
|
|
|
|
if (hIconUp == NULL)
|
|
|
|
hIconUp = (HICON)LoadImage(hDll, MAKEINTRESOURCE(16749), IMAGE_ICON, s16, s16, LR_DEFAULTCOLOR | LR_SHARED);
|
|
|
|
if (hIconDown == NULL)
|
|
|
|
hIconDown = (HICON)LoadImage(hDll, MAKEINTRESOURCE(16750), IMAGE_ICON, s16, s16, LR_DEFAULTCOLOR | LR_SHARED);
|
|
|
|
hUpImageList = ImageList_Create(i16, i16, ILC_COLOR32 | ILC_HIGHQUALITYSCALE, 1, 0);
|
|
|
|
hDownImageList = ImageList_Create(i16, i16, ILC_COLOR32 | ILC_HIGHQUALITYSCALE, 1, 0);
|
|
|
|
ImageList_AddIcon(hUpImageList, hIconUp);
|
|
|
|
ImageList_AddIcon(hDownImageList, hIconDown);
|
|
|
|
|
|
|
|
// Create the advanced options toolbars
|
|
|
|
memset(wtbtext, 0, sizeof(wtbtext));
|
|
|
|
utf8_to_wchar_no_alloc(lmprintf((advanced_mode_device) ? MSG_122 : MSG_121, lmprintf(MSG_119)), wtbtext[0], ARRAYSIZE(wtbtext[0]));
|
|
|
|
hAdvancedDeviceToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, TOOLBAR_STYLE,
|
|
|
|
0, 0, 0, 0, hMainDialog, (HMENU)IDC_ADVANCED_DEVICE_TOOLBAR, hMainInstance, NULL);
|
|
|
|
SendMessage(hAdvancedDeviceToolbar, CCM_SETVERSION, (WPARAM)6, 0);
|
|
|
|
memset(tbToolbarButtons, 0, sizeof(TBBUTTON));
|
|
|
|
tbToolbarButtons[0].idCommand = IDC_ADVANCED_DRIVE_PROPERTIES;
|
|
|
|
tbToolbarButtons[0].fsStyle = BTNS_SHOWTEXT | BTNS_AUTOSIZE;
|
|
|
|
tbToolbarButtons[0].fsState = TBSTATE_ENABLED;
|
|
|
|
tbToolbarButtons[0].iString = (INT_PTR)wtbtext[0];
|
|
|
|
tbToolbarButtons[0].iBitmap = 0;
|
|
|
|
SendMessage(hAdvancedDeviceToolbar, TB_SETIMAGELIST, 0, (LPARAM)hUpImageList);
|
|
|
|
SendMessage(hAdvancedDeviceToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
|
|
|
|
SendMessage(hAdvancedDeviceToolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbToolbarButtons);
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, IDC_ADVANCED_DRIVE_PROPERTIES), &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
SendMessage(hAdvancedDeviceToolbar, TB_GETIDEALSIZE, (WPARAM)FALSE, (LPARAM)&sz);
|
|
|
|
// Yeah, so, like, TB_GETIDEALSIZE totally super doesn't work on Windows 7, for low zoom factor and when compiled with MSVC...
|
|
|
|
if (sz.cx < 16)
|
|
|
|
sz.cx = fw;
|
|
|
|
SetWindowPos(hAdvancedDeviceToolbar, hTargetSystem, rc.left + toolbar_dx, rc.top, sz.cx, rc.bottom - rc.top, 0);
|
|
|
|
|
|
|
|
utf8_to_wchar_no_alloc(lmprintf((advanced_mode_format) ? MSG_122 : MSG_121, lmprintf(MSG_120)), wtbtext[1], ARRAYSIZE(wtbtext[1]));
|
|
|
|
hAdvancedFormatToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, TOOLBAR_STYLE,
|
|
|
|
0, 0, 0, 0, hMainDialog, (HMENU)IDC_ADVANCED_FORMAT_TOOLBAR, hMainInstance, NULL);
|
|
|
|
SendMessage(hAdvancedFormatToolbar, CCM_SETVERSION, (WPARAM)6, 0);
|
|
|
|
memset(tbToolbarButtons, 0, sizeof(TBBUTTON));
|
|
|
|
tbToolbarButtons[0].idCommand = IDC_ADVANCED_FORMAT_OPTIONS;
|
|
|
|
tbToolbarButtons[0].fsStyle = BTNS_SHOWTEXT | BTNS_AUTOSIZE;
|
|
|
|
tbToolbarButtons[0].fsState = TBSTATE_ENABLED;
|
|
|
|
tbToolbarButtons[0].iString = (INT_PTR)wtbtext[1];
|
|
|
|
tbToolbarButtons[0].iBitmap = 0;
|
|
|
|
SendMessage(hAdvancedFormatToolbar, TB_SETIMAGELIST, (WPARAM)0, (LPARAM)hUpImageList);
|
|
|
|
SendMessage(hAdvancedFormatToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
|
|
|
|
SendMessage(hAdvancedFormatToolbar, TB_ADDBUTTONS, (WPARAM)1, (LPARAM)&tbToolbarButtons);
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, IDC_ADVANCED_FORMAT_OPTIONS), &rc);
|
|
|
|
MapWindowPoints(NULL, hDlg, (POINT*)&rc, 2);
|
|
|
|
SendMessage(hAdvancedFormatToolbar, TB_GETIDEALSIZE, (WPARAM)FALSE, (LPARAM)&sz);
|
|
|
|
if (sz.cx < 16)
|
|
|
|
sz.cx = fw;
|
|
|
|
SetWindowPos(hAdvancedFormatToolbar, hClusterSize, rc.left + toolbar_dx, rc.top, sz.cx, rc.bottom - rc.top, 0);
|
|
|
|
|
|
|
|
// Create the multi toolbar
|
|
|
|
hMultiToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, TOOLBAR_STYLE,
|
|
|
|
0, 0, 0, 0, hMainDialog, (HMENU)IDC_MULTI_TOOLBAR, hMainInstance, NULL);
|
|
|
|
hToolbarImageList = ImageList_Create(i16, i16, ILC_COLOR32 | ILC_HIGHQUALITYSCALE, 8, 0);
|
|
|
|
for (i = 0; i < ARRAYSIZE(multitoolbar_icons); i++) {
|
|
|
|
buffer = GetResource(hMainInstance, MAKEINTRESOURCEA(multitoolbar_icons[i] + icon_offset),
|
|
|
|
_RT_RCDATA, "toolbar icon", &bufsize, FALSE);
|
|
|
|
hIcon = CreateIconFromResourceEx(buffer, bufsize, TRUE, 0x30000, 0, 0, 0);
|
|
|
|
// Mirror the "world" icon on RTL since we can't use an ImageList mirroring flag for that...
|
|
|
|
if (right_to_left_mode && (i == 0))
|
|
|
|
hIcon = CreateMirroredIcon(hIcon);
|
|
|
|
ImageList_AddIcon(hToolbarImageList, hIcon);
|
|
|
|
DestroyIcon(hIcon);
|
|
|
|
}
|
|
|
|
SendMessage(hMultiToolbar, TB_SETIMAGELIST, (WPARAM)0, (LPARAM)hToolbarImageList);
|
|
|
|
SendMessage(hMultiToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
|
|
|
|
memset(tbToolbarButtons, 0, sizeof(TBBUTTON) * ARRAYSIZE(tbToolbarButtons));
|
|
|
|
tbToolbarButtons[0].idCommand = IDC_LANG;
|
|
|
|
tbToolbarButtons[0].fsStyle = BTNS_BUTTON;
|
|
|
|
tbToolbarButtons[0].fsState = TBSTATE_ENABLED;
|
|
|
|
tbToolbarButtons[0].iBitmap = 0;
|
|
|
|
tbToolbarButtons[1].fsStyle = BTNS_AUTOSIZE;
|
|
|
|
tbToolbarButtons[1].fsState = TBSTATE_INDETERMINATE;
|
|
|
|
tbToolbarButtons[1].iBitmap = I_IMAGENONE;
|
|
|
|
tbToolbarButtons[1].iString = (fScale < 1.5f) ? (INT_PTR)L"" : (INT_PTR)L" ";
|
|
|
|
tbToolbarButtons[2].idCommand = IDC_ABOUT;
|
|
|
|
tbToolbarButtons[2].fsStyle = BTNS_BUTTON;
|
|
|
|
tbToolbarButtons[2].fsState = TBSTATE_ENABLED;
|
|
|
|
tbToolbarButtons[2].iBitmap = 1;
|
|
|
|
tbToolbarButtons[3].fsStyle = BTNS_AUTOSIZE;
|
|
|
|
tbToolbarButtons[3].fsState = TBSTATE_INDETERMINATE;
|
|
|
|
tbToolbarButtons[3].iBitmap = I_IMAGENONE;
|
|
|
|
tbToolbarButtons[3].iString = (fScale < 1.5f) ? (INT_PTR)L"" : (INT_PTR)L" ";
|
|
|
|
tbToolbarButtons[4].idCommand = IDC_SETTINGS;
|
|
|
|
tbToolbarButtons[4].fsStyle = BTNS_BUTTON;
|
|
|
|
tbToolbarButtons[4].fsState = TBSTATE_ENABLED;
|
|
|
|
tbToolbarButtons[4].iBitmap = 2;
|
|
|
|
tbToolbarButtons[5].fsStyle = BTNS_AUTOSIZE;
|
|
|
|
tbToolbarButtons[5].fsState = TBSTATE_INDETERMINATE;
|
|
|
|
tbToolbarButtons[5].iBitmap = I_IMAGENONE;
|
|
|
|
tbToolbarButtons[5].iString = (fScale < 1.5f) ? (INT_PTR)L"" : (INT_PTR)L" ";
|
|
|
|
tbToolbarButtons[6].idCommand = IDC_LOG;
|
|
|
|
tbToolbarButtons[6].fsStyle = BTNS_BUTTON;
|
|
|
|
tbToolbarButtons[6].fsState = TBSTATE_ENABLED;
|
|
|
|
tbToolbarButtons[6].iBitmap = 3;
|
|
|
|
SendMessage(hMultiToolbar, TB_ADDBUTTONS, (WPARAM)7, (LPARAM)&tbToolbarButtons);
|
|
|
|
SendMessage(hMultiToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(i16, ddbh));
|
|
|
|
|
|
|
|
// Subclass the progress bar so that we can write on it
|
|
|
|
progress_original_proc = (WNDPROC)SetWindowLongPtr(hProgress, GWLP_WNDPROC, (LONG_PTR)ProgressCallback);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set up progress bar real estate allocation
|
|
|
|
void InitProgress(BOOL bOnlyFormat)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
float last_end = 0.0f, slots_discrete = 0.0f, slots_analog = 0.0f;
|
|
|
|
|
|
|
|
memset(nb_slots, 0, sizeof(nb_slots));
|
|
|
|
memset(slot_end, 0, sizeof(slot_end));
|
|
|
|
previous_end = 0.0f;
|
|
|
|
|
|
|
|
if (bOnlyFormat) {
|
|
|
|
nb_slots[OP_FORMAT] = -1;
|
|
|
|
} else {
|
|
|
|
nb_slots[OP_ANALYZE_MBR] = 1;
|
|
|
|
if (IsChecked(IDC_BAD_BLOCKS)) {
|
|
|
|
nb_slots[OP_BADBLOCKS] = -1;
|
|
|
|
}
|
2019-04-13 14:29:27 +00:00
|
|
|
if (boot_type != BT_NON_BOOTABLE) {
|
2018-07-06 04:46:36 +00:00
|
|
|
// 1 extra slot for PBR writing
|
|
|
|
switch (selection_default) {
|
|
|
|
case BT_MSDOS:
|
2019-08-20 17:06:07 +00:00
|
|
|
nb_slots[OP_FILE_COPY] = 3 + 1;
|
2018-07-06 04:46:36 +00:00
|
|
|
break;
|
|
|
|
case BT_FREEDOS:
|
2019-08-20 17:06:07 +00:00
|
|
|
nb_slots[OP_FILE_COPY] = 5 + 1;
|
2018-07-06 04:46:36 +00:00
|
|
|
break;
|
|
|
|
case BT_IMAGE:
|
2019-08-20 17:06:07 +00:00
|
|
|
nb_slots[OP_FILE_COPY] = img_report.is_iso ? -1 : 0;
|
2018-07-06 04:46:36 +00:00
|
|
|
break;
|
|
|
|
default:
|
2019-08-20 17:06:07 +00:00
|
|
|
nb_slots[OP_FILE_COPY] = 2 + 1;
|
2018-07-06 04:46:36 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (selection_default == BT_IMAGE && !img_report.is_iso) {
|
|
|
|
nb_slots[OP_FORMAT] = -1;
|
|
|
|
} else {
|
|
|
|
nb_slots[OP_ZERO_MBR] = 1;
|
|
|
|
nb_slots[OP_PARTITION] = 1;
|
|
|
|
nb_slots[OP_FIX_MBR] = 1;
|
2019-04-25 17:58:55 +00:00
|
|
|
nb_slots[OP_CREATE_FS] = (use_vds) ? 2 :
|
2018-07-06 04:46:36 +00:00
|
|
|
nb_steps[ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))];
|
2019-04-19 12:24:20 +00:00
|
|
|
// So, yeah, if you're doing slow format, or using Large FAT32, and have persistence, you'll see
|
|
|
|
// the progress bar revert during format on account that we reuse the same operation for both
|
|
|
|
// partitions. Maybe one day I'll be bothered to handle two separate OP_FORMAT ops...
|
2019-04-25 17:58:55 +00:00
|
|
|
if ((!IsChecked(IDC_QUICK_FORMAT)) || (persistence_size != 0) ||
|
|
|
|
((fs_type == FS_FAT32) && ((SelectedDrive.DiskSize >= LARGE_FAT32_SIZE) || (force_large_fat32)))) {
|
2018-07-06 04:46:36 +00:00
|
|
|
nb_slots[OP_FORMAT] = -1;
|
2019-04-25 17:58:55 +00:00
|
|
|
nb_slots[OP_CREATE_FS] = 0;
|
2018-07-06 04:46:36 +00:00
|
|
|
}
|
2019-04-13 14:29:27 +00:00
|
|
|
nb_slots[OP_FINALIZE] = ((selection_default == BT_IMAGE) && (fs_type == FS_NTFS)) ? 3 : 2;
|
2018-07-06 04:46:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-25 17:58:55 +00:00
|
|
|
for (i = 0; i < OP_MAX; i++) {
|
2018-07-06 04:46:36 +00:00
|
|
|
if (nb_slots[i] > 0) {
|
|
|
|
slots_discrete += nb_slots[i] * 1.0f;
|
|
|
|
}
|
|
|
|
if (nb_slots[i] < 0) {
|
|
|
|
slots_analog += nb_slots[i] * 1.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-25 17:58:55 +00:00
|
|
|
for (i = 0; i < OP_MAX; i++) {
|
2018-07-06 04:46:36 +00:00
|
|
|
if (nb_slots[i] == 0) {
|
|
|
|
slot_end[i + 1] = last_end;
|
|
|
|
} else if (nb_slots[i] > 0) {
|
|
|
|
slot_end[i + 1] = last_end + (1.0f * nb_slots[i]);
|
|
|
|
} else if (nb_slots[i] < 0) {
|
|
|
|
slot_end[i + 1] = last_end + (((100.0f - slots_discrete) * nb_slots[i]) / slots_analog);
|
|
|
|
}
|
|
|
|
last_end = slot_end[i + 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there's no analog, adjust our discrete ends to fill the whole bar
|
|
|
|
if (slots_analog == 0.0f) {
|
2019-04-25 17:58:55 +00:00
|
|
|
for (i = 0; i < OP_MAX; i++) {
|
2018-07-06 04:46:36 +00:00
|
|
|
slot_end[i + 1] *= 100.0f / slots_discrete;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Position the progress bar within each operation range
|
|
|
|
void UpdateProgress(int op, float percent)
|
|
|
|
{
|
|
|
|
int pos;
|
|
|
|
static uint64_t LastRefresh = 0;
|
|
|
|
|
|
|
|
if ((op < 0) || (op >= OP_MAX)) {
|
|
|
|
duprintf("UpdateProgress: invalid op %d\n", op);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (percent > 100.1f) {
|
2019-08-20 17:06:07 +00:00
|
|
|
// duprintf("UpdateProgress(%d): invalid percentage %0.2f\n", op, percent);
|
2018-07-06 04:46:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ((percent < 0.0f) && (nb_slots[op] <= 0)) {
|
|
|
|
duprintf("UpdateProgress(%d): error negative percentage sent for negative slot value\n", op);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (nb_slots[op] == 0)
|
|
|
|
return;
|
|
|
|
if (previous_end < slot_end[op]) {
|
|
|
|
previous_end = slot_end[op];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (percent < 0.0f) {
|
|
|
|
// Negative means advance one slot (1.0%) - requires a positive slot allocation
|
|
|
|
previous_end += (slot_end[op + 1] - slot_end[op]) / (1.0f * nb_slots[op]);
|
|
|
|
pos = (int)(previous_end / 100.0f * MAX_PROGRESS);
|
|
|
|
} else {
|
|
|
|
pos = (int)((previous_end + ((slot_end[op + 1] - previous_end) * (percent / 100.0f))) / 100.0f * MAX_PROGRESS);
|
|
|
|
}
|
|
|
|
if (pos > MAX_PROGRESS) {
|
|
|
|
duprintf("UpdateProgress(%d): rounding error - pos %d is greater than %d\n", op, pos, MAX_PROGRESS);
|
|
|
|
pos = MAX_PROGRESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reduce the refresh rate, to avoid weird effects on the sliding part of progress bar
|
|
|
|
if (GetTickCount64() > LastRefresh + (2 * MAX_REFRESH)) {
|
|
|
|
LastRefresh = GetTickCount64();
|
|
|
|
SendMessage(hProgress, PBM_SETPOS, (WPARAM)pos, 0);
|
|
|
|
SetTaskbarProgressValue(pos, MAX_PROGRESS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-20 17:06:07 +00:00
|
|
|
// This updates the progress bar as well as the data displayed on it so that we can
|
|
|
|
// display percentage completed, rate of transfer and estimated remaining duration.
|
|
|
|
// During init (op = OP_INIT) an optional HWND can be passed on which to look for
|
|
|
|
// a progress bar.
|
|
|
|
void UpdateProgressWithInfo(int op, int msg, uint64_t processed, uint64_t total)
|
|
|
|
{
|
|
|
|
HWND hProgressDialog = (HWND)(uintptr_t)processed;
|
|
|
|
static HWND hProgressBar = NULL;
|
|
|
|
static uint64_t start_time = 0, last_refresh = 0;
|
|
|
|
uint64_t rate = 0, current_time = GetTickCount64();
|
|
|
|
static float percent = 0.0f;
|
|
|
|
char msg_data[128];
|
|
|
|
static BOOL bNoAltMode = FALSE;
|
|
|
|
|
|
|
|
if (op == OP_INIT) {
|
|
|
|
start_time = current_time - 1;
|
|
|
|
last_refresh = 0;
|
|
|
|
percent = 0.0f;
|
|
|
|
rate = 0;
|
|
|
|
hProgressBar = NULL;
|
|
|
|
bNoAltMode = (BOOL)msg;
|
|
|
|
if (hProgressDialog != NULL) {
|
|
|
|
// Use the progress control provided, if any
|
|
|
|
hProgressBar = GetDlgItem(hProgressDialog, IDC_PROGRESS);
|
|
|
|
if (hProgressBar != NULL) {
|
|
|
|
SendMessage(hProgressBar, PBM_SETSTATE, (WPARAM)PBST_NORMAL, 0);
|
|
|
|
SendMessage(hProgressBar, PBM_SETMARQUEE, FALSE, 0);
|
|
|
|
SendMessage(hProgressBar, PBM_SETPOS, 0, 0);
|
|
|
|
}
|
|
|
|
SendMessage(hProgressDialog, UM_PROGRESS_INIT, 0, 0);
|
|
|
|
}
|
|
|
|
} else if ((hProgressBar != NULL) || (op > 0)) {
|
|
|
|
if (processed > total)
|
|
|
|
processed = total;
|
|
|
|
percent = (100.0f * processed) / (1.0f * total);
|
|
|
|
// TODO: Better transfer rate computation using a weighted algorithm such as one from
|
|
|
|
// https://stackoverflow.com/questions/2779600/how-to-estimate-download-time-remaining-accurately
|
|
|
|
rate = (current_time == start_time) ? 0 : (processed * 1000) / (current_time - start_time);
|
|
|
|
if ((processed == total) || (current_time > last_refresh + MAX_REFRESH)) {
|
|
|
|
if (bNoAltMode)
|
|
|
|
update_progress_type = 0;
|
|
|
|
if (update_progress_type == UPT_SPEED) {
|
|
|
|
static_sprintf(msg_data, "%s/s", SizeToHumanReadable(rate, FALSE, FALSE));
|
|
|
|
} else if (update_progress_type == UPT_TIME) {
|
|
|
|
uint64_t seconds = (rate == 0) ? 24 * 3600 : (total - processed) / rate + 1;
|
|
|
|
static_sprintf(msg_data, "%d:%02d:%02d", (uint32_t)(seconds / 3600), (uint16_t)((seconds % 3600) / 60), (uint16_t)(seconds % 60));
|
|
|
|
} else {
|
|
|
|
static_sprintf(msg_data, "%0.1f%%", percent);
|
|
|
|
}
|
|
|
|
last_refresh = current_time;
|
|
|
|
if (op < 0) {
|
|
|
|
SendMessage(hProgressBar, PBM_SETPOS, (WPARAM)(MAX_PROGRESS * percent / 100.0f), 0);
|
|
|
|
if (op == OP_NOOP_WITH_TASKBAR)
|
|
|
|
SetTaskbarProgressValue((ULONGLONG)(MAX_PROGRESS * percent / 100.0f), MAX_PROGRESS);
|
|
|
|
} else {
|
|
|
|
UpdateProgress(op, percent);
|
|
|
|
}
|
|
|
|
if (msg >= 0)
|
|
|
|
PrintInfo(0, msg, msg_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-06 04:46:36 +00:00
|
|
|
void ShowLanguageMenu(RECT rcExclude)
|
|
|
|
{
|
|
|
|
TPMPARAMS tpm;
|
|
|
|
HMENU menu;
|
2018-07-15 00:01:39 +00:00
|
|
|
RECT rc;
|
|
|
|
LONG nb_items = 1, adjust = 0;
|
2018-07-06 04:46:36 +00:00
|
|
|
loc_cmd* lcmd = NULL;
|
|
|
|
char lang[256];
|
|
|
|
char *search = "()";
|
|
|
|
char *l, *r, *str;
|
|
|
|
|
|
|
|
UM_LANGUAGE_MENU_MAX = UM_LANGUAGE_MENU;
|
|
|
|
menu = CreatePopupMenu();
|
|
|
|
list_for_each_entry(lcmd, &locale_list, loc_cmd, list) {
|
|
|
|
// The appearance of LTR languages must be fixed for RTL menus
|
|
|
|
if ((right_to_left_mode) && (!(lcmd->ctrl_id & LOC_RIGHT_TO_LEFT))) {
|
|
|
|
str = safe_strdup(lcmd->txt[1]);
|
|
|
|
l = strtok(str, search);
|
|
|
|
r = strtok(NULL, search);
|
|
|
|
static_sprintf(lang, LEFT_TO_RIGHT_EMBEDDING "(%s) " POP_DIRECTIONAL_FORMATTING "%s", r, l);
|
|
|
|
safe_free(str);
|
|
|
|
} else {
|
|
|
|
static_strcpy(lang, lcmd->txt[1]);
|
|
|
|
}
|
|
|
|
InsertMenuU(menu, -1, MF_BYPOSITION | ((selected_locale == lcmd) ? MF_CHECKED : 0), UM_LANGUAGE_MENU_MAX++, lang);
|
2018-07-15 00:01:39 +00:00
|
|
|
nb_items++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Empirical adjust if we have a small enough number of languages to select
|
|
|
|
if (nb_items < 20) {
|
|
|
|
GetWindowRect(hMultiToolbar, &rc);
|
|
|
|
MapWindowPoints(NULL, hMainDialog, (POINT*)&rc, 2);
|
|
|
|
adjust = rc.top - (nb_items * ddh) / 2;
|
2018-07-06 04:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Open the menu such that it doesn't overlap the specified rect
|
|
|
|
tpm.cbSize = sizeof(TPMPARAMS);
|
|
|
|
tpm.rcExclude = rcExclude;
|
|
|
|
TrackPopupMenuEx(menu, 0,
|
|
|
|
// In RTL languages, the menu should be placed at the bottom-right of the rect
|
|
|
|
right_to_left_mode ? rcExclude.right : rcExclude.left,
|
2018-07-15 00:01:39 +00:00
|
|
|
rcExclude.bottom + adjust, hMainDialog, &tpm);
|
2018-07-06 04:46:36 +00:00
|
|
|
DestroyMenu(menu);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetPassesTooltip(void)
|
|
|
|
{
|
|
|
|
const unsigned int pattern[BADLOCKS_PATTERN_TYPES][BADBLOCK_PATTERN_COUNT] =
|
|
|
|
{ BADBLOCK_PATTERN_SLC, BADCLOCK_PATTERN_MLC, BADBLOCK_PATTERN_TLC };
|
|
|
|
int sel = ComboBox_GetCurSel(hNBPasses);
|
|
|
|
int type = (sel < 2) ? 0 : sel - 2;
|
|
|
|
CreateTooltip(hNBPasses, lmprintf(MSG_153 + ((sel >= 2) ? 3 : sel),
|
|
|
|
pattern[type][0], pattern[type][1], pattern[type][2], pattern[type][3]), -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetBootTypeDropdownWidth(void)
|
|
|
|
{
|
|
|
|
HDC hDC;
|
|
|
|
HFONT hFont;
|
|
|
|
SIZE sz;
|
|
|
|
RECT rc;
|
|
|
|
|
|
|
|
if (image_path == NULL)
|
|
|
|
return;
|
|
|
|
// Set the maximum width of the dropdown according to the image selected
|
|
|
|
GetWindowRect(hBootType, &rc);
|
|
|
|
MapWindowPoints(NULL, hMainDialog, (POINT*)&rc, 2);
|
|
|
|
hDC = GetDC(hBootType);
|
|
|
|
hFont = (HFONT)SendMessageA(hBootType, WM_GETFONT, 0, 0);
|
|
|
|
SelectObject(hDC, hFont);
|
|
|
|
GetTextExtentPointU(hDC, short_image_path, &sz);
|
|
|
|
safe_release_dc(hBootType, hDC);
|
|
|
|
SendMessage(hBootType, CB_SETDROPPEDWIDTH, (WPARAM)max(sz.cx + 10, rc.right - rc.left), (LPARAM)0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the horizontal section lines
|
|
|
|
void OnPaint(HDC hdc)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
HPEN hp = CreatePen(0, (fScale < 1.5f) ? 2 : 3, RGB(0, 0, 0));
|
|
|
|
SelectObject(hdc, hp);
|
|
|
|
for (i = 0; i < ARRAYSIZE(section_vpos); i++) {
|
|
|
|
MoveToEx(hdc, mw + 10, section_vpos[i], NULL);
|
|
|
|
LineTo(hdc, mw + fw, section_vpos[i]);
|
|
|
|
}
|
|
|
|
}
|