mirror of
https://github.com/GerbilSoft/rom-properties.git
synced 2025-06-18 11:35:38 -04:00
[win32] RP_ShellPropSheetExt: Initial scrolling for data widgets.
Currently only works if multiple tabs are displayed. The child dialog control has WS_VSCROLL and the scroll information is set after all the tabs are set up. SubtabDlgProc: - WM_VSCROLL: Scroll the window as necessary, using the description label height as the line height and one visible page worth as the page height. - Call DefSubclassProc() instead of simply returning FALSE. This partially fixes issue #204: Windows UI has no scroll bar Reported by @InternalLoss.
This commit is contained in:
parent
43f27f0964
commit
cff90b5309
@ -58,7 +58,7 @@
|
|||||||
#define NOMINMAX 1
|
#define NOMINMAX 1
|
||||||
//#define NOMSG 1
|
//#define NOMSG 1
|
||||||
#define NOOPENFILE 1
|
#define NOOPENFILE 1
|
||||||
#define NOSCROLL 1
|
//#define NOSCROLL 1
|
||||||
#define NOSERVICE 1
|
#define NOSERVICE 1
|
||||||
//#define NOSOUND 1
|
//#define NOSOUND 1
|
||||||
//#define NOTEXTMETRIC 1
|
//#define NOTEXTMETRIC 1
|
||||||
|
@ -106,9 +106,13 @@ class RP_ShellPropSheetExt_Private
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Property for "D pointer".
|
// Property for "D pointer".
|
||||||
// This points to the ConfigDialogPrivate object.
|
// This points to the RP_ShellPropSheetExt_Private object.
|
||||||
static const TCHAR D_PTR_PROP[];
|
static const TCHAR D_PTR_PROP[];
|
||||||
|
|
||||||
|
// Property for "tab pointer".
|
||||||
|
// This points to the RP_ShellPropSheetExt_Private::tab object.
|
||||||
|
static const TCHAR TAB_PTR_PROP[];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// ROM filename.
|
// ROM filename.
|
||||||
string filename;
|
string filename;
|
||||||
@ -198,14 +202,19 @@ class RP_ShellPropSheetExt_Private
|
|||||||
HWND hDlg; // Tab child dialog.
|
HWND hDlg; // Tab child dialog.
|
||||||
HWND lblCredits; // Credits label.
|
HWND lblCredits; // Credits label.
|
||||||
POINT curPt; // Current point.
|
POINT curPt; // Current point.
|
||||||
|
int scrollPos; // Scrolling position.
|
||||||
|
|
||||||
tab() : hDlg(nullptr), lblCredits(nullptr) {
|
tab() : hDlg(nullptr), lblCredits(nullptr), scrollPos(0) {
|
||||||
curPt.x = 0; curPt.y = 0;
|
curPt.x = 0; curPt.y = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
vector<tab> tabs;
|
vector<tab> tabs;
|
||||||
int curTabIndex;
|
int curTabIndex;
|
||||||
|
|
||||||
|
// Sizes.
|
||||||
|
int lblDescHeight; // Description label height.
|
||||||
|
SIZE dlgSize; // Visible dialog size.
|
||||||
|
|
||||||
// MessageWidget for ROM operation notifications.
|
// MessageWidget for ROM operation notifications.
|
||||||
HWND hMessageWidget;
|
HWND hMessageWidget;
|
||||||
int iTabHeightOrig;
|
int iTabHeightOrig;
|
||||||
@ -252,6 +261,21 @@ class RP_ShellPropSheetExt_Private
|
|||||||
void loadImages(void);
|
void loadImages(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* Check if we need to use WS_EX_LAYOUTRTL.
|
||||||
|
* TODO: Cache this value?
|
||||||
|
* @return WS_EX_LAYOUTRTL if process is RTL; otherwise 0.
|
||||||
|
*/
|
||||||
|
static inline DWORD checkLayoutRTL(void)
|
||||||
|
{
|
||||||
|
// Set WS_EX_LAYOUTRTL if the process is RTL.
|
||||||
|
DWORD dwDefaultLayout;
|
||||||
|
const BOOL bRet = GetProcessDefaultLayout(&dwDefaultLayout);
|
||||||
|
return (unlikely(bRet && dwDefaultLayout == LAYOUT_RTL))
|
||||||
|
? WS_EX_LAYOUTRTL
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rescale an image to be as close to the required size as possible.
|
* Rescale an image to be as close to the required size as possible.
|
||||||
* @param req_sz [in] Required size.
|
* @param req_sz [in] Required size.
|
||||||
@ -446,7 +470,7 @@ class RP_ShellPropSheetExt_Private
|
|||||||
* @param uIdSubclass
|
* @param uIdSubclass
|
||||||
* @param dWRefData RP_ShellPropSheetExt_Private
|
* @param dWRefData RP_ShellPropSheetExt_Private
|
||||||
*/
|
*/
|
||||||
static LRESULT CALLBACK DialogSubclassProc(
|
static LRESULT CALLBACK MainDialogSubclassProc(
|
||||||
HWND hWnd, UINT uMsg,
|
HWND hWnd, UINT uMsg,
|
||||||
WPARAM wParam, LPARAM lParam,
|
WPARAM wParam, LPARAM lParam,
|
||||||
UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
|
UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
|
||||||
@ -484,6 +508,10 @@ class RP_ShellPropSheetExt_Private
|
|||||||
// This points to the ConfigDialogPrivate object.
|
// This points to the ConfigDialogPrivate object.
|
||||||
const TCHAR RP_ShellPropSheetExt_Private::D_PTR_PROP[] = _T("RP_ShellPropSheetExt_Private");
|
const TCHAR RP_ShellPropSheetExt_Private::D_PTR_PROP[] = _T("RP_ShellPropSheetExt_Private");
|
||||||
|
|
||||||
|
// Property for "tab pointer".
|
||||||
|
// This points to the RP_ShellPropSheetExt_Private::tab object.
|
||||||
|
const TCHAR RP_ShellPropSheetExt_Private::TAB_PTR_PROP[] = _T("RP_ShellPropSheetExt_Private::tab");
|
||||||
|
|
||||||
RP_ShellPropSheetExt_Private::RP_ShellPropSheetExt_Private(RP_ShellPropSheetExt *q, string &&filename)
|
RP_ShellPropSheetExt_Private::RP_ShellPropSheetExt_Private(RP_ShellPropSheetExt *q, string &&filename)
|
||||||
: q_ptr(q)
|
: q_ptr(q)
|
||||||
, filename(std::move(filename))
|
, filename(std::move(filename))
|
||||||
@ -502,6 +530,7 @@ RP_ShellPropSheetExt_Private::RP_ShellPropSheetExt_Private(RP_ShellPropSheetExt
|
|||||||
, dwExStyleRTL(0)
|
, dwExStyleRTL(0)
|
||||||
, tabWidget(nullptr)
|
, tabWidget(nullptr)
|
||||||
, curTabIndex(0)
|
, curTabIndex(0)
|
||||||
|
, lblDescHeight(0)
|
||||||
, hMessageWidget(nullptr)
|
, hMessageWidget(nullptr)
|
||||||
, iTabHeightOrig(0)
|
, iTabHeightOrig(0)
|
||||||
, def_lc(0)
|
, def_lc(0)
|
||||||
@ -511,6 +540,10 @@ RP_ShellPropSheetExt_Private::RP_ShellPropSheetExt_Private(RP_ShellPropSheetExt
|
|||||||
// Initialize the alternate row color.
|
// Initialize the alternate row color.
|
||||||
colorAltRow = LibWin32Common::getAltRowColor();
|
colorAltRow = LibWin32Common::getAltRowColor();
|
||||||
|
|
||||||
|
// Initialize other structs.
|
||||||
|
dlgSize.cx = 0;
|
||||||
|
dlgSize.cy = 0;
|
||||||
|
|
||||||
// Check for RTL.
|
// Check for RTL.
|
||||||
// NOTE: Windows Explorer on Windows 7 seems to return 0 from GetProcessDefaultLayout(),
|
// NOTE: Windows Explorer on Windows 7 seems to return 0 from GetProcessDefaultLayout(),
|
||||||
// even if an RTL language is in use. We'll check the taskbar layout instead.
|
// even if an RTL language is in use. We'll check the taskbar layout instead.
|
||||||
@ -1131,6 +1164,9 @@ int RP_ShellPropSheetExt_Private::initBitfield(HWND hDlg, HWND hWndTab,
|
|||||||
}
|
}
|
||||||
pt.y -= rect_subtract.bottom;
|
pt.y -= rect_subtract.bottom;
|
||||||
|
|
||||||
|
// WS_EX_LAYOUTRTL
|
||||||
|
const DWORD dwExStyleRTL = checkLayoutRTL();
|
||||||
|
|
||||||
row = 0; col = 0;
|
row = 0; col = 0;
|
||||||
auto iter = tnames.cbegin();
|
auto iter = tnames.cbegin();
|
||||||
uint32_t bitfield = field.data.bitfield;
|
uint32_t bitfield = field.data.bitfield;
|
||||||
@ -2580,7 +2616,8 @@ void RP_ShellPropSheetExt_Private::initDialog(void)
|
|||||||
// and 8 DLUs tall, plus 4 vertical DLUs for spacing.
|
// and 8 DLUs tall, plus 4 vertical DLUs for spacing.
|
||||||
RECT tmpRect = {0, 0, 0, 8+4};
|
RECT tmpRect = {0, 0, 0, 8+4};
|
||||||
MapDialogRect(hDlgSheet, &tmpRect);
|
MapDialogRect(hDlgSheet, &tmpRect);
|
||||||
SIZE descSize = {max_text_width, tmpRect.bottom};
|
const SIZE descSize = {max_text_width, tmpRect.bottom};
|
||||||
|
this->lblDescHeight = descSize.cy;
|
||||||
|
|
||||||
// Get the dialog margin.
|
// Get the dialog margin.
|
||||||
// 7x7 DLU margin is recommended by the Windows UX guidelines.
|
// 7x7 DLU margin is recommended by the Windows UX guidelines.
|
||||||
@ -2599,10 +2636,8 @@ void RP_ShellPropSheetExt_Private::initDialog(void)
|
|||||||
// Adjust the rectangle for margins.
|
// Adjust the rectangle for margins.
|
||||||
InflateRect(&dlgRect, -dlgMargin.left, -dlgMargin.top);
|
InflateRect(&dlgRect, -dlgMargin.left, -dlgMargin.top);
|
||||||
// Calculate the size for convenience purposes.
|
// Calculate the size for convenience purposes.
|
||||||
SIZE dlgSize = {
|
dlgSize.cx = dlgRect.right - dlgRect.left;
|
||||||
dlgRect.right - dlgRect.left,
|
dlgSize.cy = dlgRect.bottom - dlgRect.top;
|
||||||
dlgRect.bottom - dlgRect.top
|
|
||||||
};
|
|
||||||
|
|
||||||
// Current position.
|
// Current position.
|
||||||
POINT headerPt = {dlgRect.left, dlgRect.top};
|
POINT headerPt = {dlgRect.left, dlgRect.top};
|
||||||
@ -2693,6 +2728,11 @@ void RP_ShellPropSheetExt_Private::initDialog(void)
|
|||||||
// Hide subsequent tabs.
|
// Hide subsequent tabs.
|
||||||
swpFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_HIDEWINDOW;
|
swpFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_HIDEWINDOW;
|
||||||
|
|
||||||
|
// Store the D object pointer with this particular tab dialog.
|
||||||
|
SetProp(tab.hDlg, D_PTR_PROP, static_cast<HANDLE>(this));
|
||||||
|
// Store the D object pointer with this particular tab dialog.
|
||||||
|
SetProp(tab.hDlg, TAB_PTR_PROP, static_cast<HANDLE>(&tab));
|
||||||
|
|
||||||
// Current point should be equal to the margins.
|
// Current point should be equal to the margins.
|
||||||
// FIXME: On both WinXP and Win7, ths ends up with an
|
// FIXME: On both WinXP and Win7, ths ends up with an
|
||||||
// 8px left margin, and 6px top/right margins.
|
// 8px left margin, and 6px top/right margins.
|
||||||
@ -2857,6 +2897,26 @@ void RP_ShellPropSheetExt_Private::initDialog(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update scrollbar settings.
|
||||||
|
// TODO: If a VScroll bar is added, adjust widths of RFT_LISTDATA.
|
||||||
|
// TODO: HScroll bar?
|
||||||
|
const auto tabs_cend = tabs.cend();
|
||||||
|
for (auto iter = tabs.cbegin(); iter != tabs_cend; ++iter) {
|
||||||
|
// Set scroll info.
|
||||||
|
// FIXME: Separate child dialog for no tabs.
|
||||||
|
const auto &tab = *iter;
|
||||||
|
|
||||||
|
// VScroll bar
|
||||||
|
SCROLLINFO si;
|
||||||
|
si.cbSize = sizeof(SCROLLINFO);
|
||||||
|
si.fMask = SIF_ALL;
|
||||||
|
si.nMin = 0;
|
||||||
|
si.nMax = tab.curPt.y - 2; // max is exclusive
|
||||||
|
si.nPage = dlgSize.cy;
|
||||||
|
si.nPos = 0;
|
||||||
|
SetScrollInfo(tab.hDlg, SB_VERT, &si, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
// Initial update of RFT_MULTI_STRING fields.
|
// Initial update of RFT_MULTI_STRING fields.
|
||||||
if (!vecStringMulti.empty()) {
|
if (!vecStringMulti.empty()) {
|
||||||
def_lc = pFields->defaultLanguageCode();
|
def_lc = pFields->defaultLanguageCode();
|
||||||
@ -3203,7 +3263,7 @@ void RP_ShellPropSheetExt_Private::menuOptions_action_triggered(int menuId)
|
|||||||
* @param uIdSubclass
|
* @param uIdSubclass
|
||||||
* @param dWRefData RP_ShellPropSheetExt_Private
|
* @param dWRefData RP_ShellPropSheetExt_Private
|
||||||
*/
|
*/
|
||||||
LRESULT CALLBACK RP_ShellPropSheetExt_Private::DialogSubclassProc(
|
LRESULT CALLBACK RP_ShellPropSheetExt_Private::MainDialogSubclassProc(
|
||||||
HWND hWnd, UINT uMsg,
|
HWND hWnd, UINT uMsg,
|
||||||
WPARAM wParam, LPARAM lParam,
|
WPARAM wParam, LPARAM lParam,
|
||||||
UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
|
UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
|
||||||
@ -3212,13 +3272,13 @@ LRESULT CALLBACK RP_ShellPropSheetExt_Private::DialogSubclassProc(
|
|||||||
case WM_NCDESTROY:
|
case WM_NCDESTROY:
|
||||||
// Remove the window subclass.
|
// Remove the window subclass.
|
||||||
// Reference: https://blogs.msdn.microsoft.com/oldnewthing/20031111-00/?p=41883
|
// Reference: https://blogs.msdn.microsoft.com/oldnewthing/20031111-00/?p=41883
|
||||||
RemoveWindowSubclass(hWnd, DialogSubclassProc, uIdSubclass);
|
RemoveWindowSubclass(hWnd, MainDialogSubclassProc, uIdSubclass);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_COMMAND:
|
case WM_COMMAND:
|
||||||
if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_RP_OPTIONS) {
|
if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_RP_OPTIONS) {
|
||||||
// Pop up the menu.
|
// Pop up the menu.
|
||||||
RP_ShellPropSheetExt_Private *const d = reinterpret_cast<RP_ShellPropSheetExt_Private*>(dwRefData);
|
auto *const d = reinterpret_cast<RP_ShellPropSheetExt_Private*>(dwRefData);
|
||||||
assert(d->hBtnOptions != nullptr);
|
assert(d->hBtnOptions != nullptr);
|
||||||
assert(d->hMenuOptions != nullptr);
|
assert(d->hMenuOptions != nullptr);
|
||||||
if (!d->hBtnOptions || !d->hMenuOptions)
|
if (!d->hBtnOptions || !d->hMenuOptions)
|
||||||
@ -3331,7 +3391,7 @@ void RP_ShellPropSheetExt_Private::createOptionsButton(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Subclass the parent dialog so we can intercept WM_COMMAND.
|
// Subclass the parent dialog so we can intercept WM_COMMAND.
|
||||||
SetWindowSubclass(hWndParent, DialogSubclassProc,
|
SetWindowSubclass(hWndParent, MainDialogSubclassProc,
|
||||||
static_cast<UINT_PTR>(IDC_RP_OPTIONS),
|
static_cast<UINT_PTR>(IDC_RP_OPTIONS),
|
||||||
reinterpret_cast<DWORD_PTR>(this));
|
reinterpret_cast<DWORD_PTR>(this));
|
||||||
|
|
||||||
@ -3921,8 +3981,7 @@ INT_PTR CALLBACK RP_ShellPropSheetExt_Private::DlgProc(HWND hDlg, UINT uMsg, WPA
|
|||||||
// FIXME: FBI's age rating is cut off on Windows
|
// FIXME: FBI's age rating is cut off on Windows
|
||||||
// if we don't adjust for WM_SHOWWINDOW.
|
// if we don't adjust for WM_SHOWWINDOW.
|
||||||
case WM_SHOWWINDOW: {
|
case WM_SHOWWINDOW: {
|
||||||
RP_ShellPropSheetExt_Private *const d = static_cast<RP_ShellPropSheetExt_Private*>(
|
auto *const d = static_cast<RP_ShellPropSheetExt_Private*>(GetProp(hDlg, D_PTR_PROP));
|
||||||
GetProp(hDlg, D_PTR_PROP));
|
|
||||||
if (!d) {
|
if (!d) {
|
||||||
// No RP_ShellPropSheetExt_Private. Can't do anything...
|
// No RP_ShellPropSheetExt_Private. Can't do anything...
|
||||||
return false;
|
return false;
|
||||||
@ -3972,8 +4031,7 @@ INT_PTR CALLBACK RP_ShellPropSheetExt_Private::DlgProc(HWND hDlg, UINT uMsg, WPA
|
|||||||
}
|
}
|
||||||
|
|
||||||
case WM_DESTROY: {
|
case WM_DESTROY: {
|
||||||
RP_ShellPropSheetExt_Private *const d = static_cast<RP_ShellPropSheetExt_Private*>(
|
auto *const d = static_cast<RP_ShellPropSheetExt_Private*>(GetProp(hDlg, D_PTR_PROP));
|
||||||
GetProp(hDlg, D_PTR_PROP));
|
|
||||||
if (d && d->lblIcon) {
|
if (d && d->lblIcon) {
|
||||||
// Stop the animation timer.
|
// Stop the animation timer.
|
||||||
d->lblIcon->stopAnimTimer();
|
d->lblIcon->stopAnimTimer();
|
||||||
@ -3991,8 +4049,7 @@ INT_PTR CALLBACK RP_ShellPropSheetExt_Private::DlgProc(HWND hDlg, UINT uMsg, WPA
|
|||||||
}
|
}
|
||||||
|
|
||||||
case WM_NOTIFY: {
|
case WM_NOTIFY: {
|
||||||
RP_ShellPropSheetExt_Private *const d = static_cast<RP_ShellPropSheetExt_Private*>(
|
auto *const d = static_cast<RP_ShellPropSheetExt_Private*>(GetProp(hDlg, D_PTR_PROP));
|
||||||
GetProp(hDlg, D_PTR_PROP));
|
|
||||||
if (!d) {
|
if (!d) {
|
||||||
// No RP_ShellPropSheetExt_Private. Can't do anything...
|
// No RP_ShellPropSheetExt_Private. Can't do anything...
|
||||||
return false;
|
return false;
|
||||||
@ -4002,8 +4059,7 @@ INT_PTR CALLBACK RP_ShellPropSheetExt_Private::DlgProc(HWND hDlg, UINT uMsg, WPA
|
|||||||
}
|
}
|
||||||
|
|
||||||
case WM_COMMAND: {
|
case WM_COMMAND: {
|
||||||
RP_ShellPropSheetExt_Private *const d = static_cast<RP_ShellPropSheetExt_Private*>(
|
auto *const d = static_cast<RP_ShellPropSheetExt_Private*>(GetProp(hDlg, D_PTR_PROP));
|
||||||
GetProp(hDlg, D_PTR_PROP));
|
|
||||||
if (!d) {
|
if (!d) {
|
||||||
// No RP_ShellPropSheetExt_Private. Can't do anything...
|
// No RP_ShellPropSheetExt_Private. Can't do anything...
|
||||||
return false;
|
return false;
|
||||||
@ -4013,8 +4069,7 @@ INT_PTR CALLBACK RP_ShellPropSheetExt_Private::DlgProc(HWND hDlg, UINT uMsg, WPA
|
|||||||
}
|
}
|
||||||
|
|
||||||
case WM_PAINT: {
|
case WM_PAINT: {
|
||||||
RP_ShellPropSheetExt_Private *const d = static_cast<RP_ShellPropSheetExt_Private*>(
|
auto *const d = static_cast<RP_ShellPropSheetExt_Private*>(GetProp(hDlg, D_PTR_PROP));
|
||||||
GetProp(hDlg, D_PTR_PROP));
|
|
||||||
if (!d) {
|
if (!d) {
|
||||||
// No RP_ShellPropSheetExt_Private. Can't do anything...
|
// No RP_ShellPropSheetExt_Private. Can't do anything...
|
||||||
return false;
|
return false;
|
||||||
@ -4025,8 +4080,7 @@ INT_PTR CALLBACK RP_ShellPropSheetExt_Private::DlgProc(HWND hDlg, UINT uMsg, WPA
|
|||||||
case WM_SYSCOLORCHANGE:
|
case WM_SYSCOLORCHANGE:
|
||||||
case WM_THEMECHANGED: {
|
case WM_THEMECHANGED: {
|
||||||
// Reload the images.
|
// Reload the images.
|
||||||
RP_ShellPropSheetExt_Private *const d = static_cast<RP_ShellPropSheetExt_Private*>(
|
auto *const d = static_cast<RP_ShellPropSheetExt_Private*>(GetProp(hDlg, D_PTR_PROP));
|
||||||
GetProp(hDlg, D_PTR_PROP));
|
|
||||||
if (!d) {
|
if (!d) {
|
||||||
// No RP_ShellPropSheetExt_Private. Can't do anything...
|
// No RP_ShellPropSheetExt_Private. Can't do anything...
|
||||||
return false;
|
return false;
|
||||||
@ -4068,8 +4122,7 @@ INT_PTR CALLBACK RP_ShellPropSheetExt_Private::DlgProc(HWND hDlg, UINT uMsg, WPA
|
|||||||
// SPI_GETFONTSMOOTHING or SPI_GETFONTSMOOTHINGTYPE,
|
// SPI_GETFONTSMOOTHING or SPI_GETFONTSMOOTHINGTYPE,
|
||||||
// but that message isn't sent when previewing changes
|
// but that message isn't sent when previewing changes
|
||||||
// for ClearType. (It's sent when applying the changes.)
|
// for ClearType. (It's sent when applying the changes.)
|
||||||
RP_ShellPropSheetExt_Private *const d = static_cast<RP_ShellPropSheetExt_Private*>(
|
auto *const d = static_cast<RP_ShellPropSheetExt_Private*>(GetProp(hDlg, D_PTR_PROP));
|
||||||
GetProp(hDlg, D_PTR_PROP));
|
|
||||||
if (d) {
|
if (d) {
|
||||||
// Update the fonts.
|
// Update the fonts.
|
||||||
d->fontHandler.updateFonts();
|
d->fontHandler.updateFonts();
|
||||||
@ -4078,8 +4131,7 @@ INT_PTR CALLBACK RP_ShellPropSheetExt_Private::DlgProc(HWND hDlg, UINT uMsg, WPA
|
|||||||
}
|
}
|
||||||
|
|
||||||
case WM_CTLCOLORSTATIC: {
|
case WM_CTLCOLORSTATIC: {
|
||||||
RP_ShellPropSheetExt_Private *const d = static_cast<RP_ShellPropSheetExt_Private*>(
|
auto *const d = static_cast<RP_ShellPropSheetExt_Private*>(GetProp(hDlg, D_PTR_PROP));
|
||||||
GetProp(hDlg, D_PTR_PROP));
|
|
||||||
if (!d) {
|
if (!d) {
|
||||||
// No RP_ShellPropSheetExt_Private. Can't do anything...
|
// No RP_ShellPropSheetExt_Private. Can't do anything...
|
||||||
return false;
|
return false;
|
||||||
@ -4095,8 +4147,7 @@ INT_PTR CALLBACK RP_ShellPropSheetExt_Private::DlgProc(HWND hDlg, UINT uMsg, WPA
|
|||||||
}
|
}
|
||||||
|
|
||||||
case WM_WTSSESSION_CHANGE: {
|
case WM_WTSSESSION_CHANGE: {
|
||||||
RP_ShellPropSheetExt_Private *const d = static_cast<RP_ShellPropSheetExt_Private*>(
|
auto *const d = static_cast<RP_ShellPropSheetExt_Private*>(GetProp(hDlg, D_PTR_PROP));
|
||||||
GetProp(hDlg, D_PTR_PROP));
|
|
||||||
if (!d) {
|
if (!d) {
|
||||||
// No RP_ShellPropSheetExt_Private. Can't do anything...
|
// No RP_ShellPropSheetExt_Private. Can't do anything...
|
||||||
return false;
|
return false;
|
||||||
@ -4187,28 +4238,94 @@ UINT CALLBACK RP_ShellPropSheetExt_Private::CallbackProc(HWND hWnd, UINT uMsg, L
|
|||||||
*/
|
*/
|
||||||
INT_PTR CALLBACK RP_ShellPropSheetExt_Private::SubtabDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
INT_PTR CALLBACK RP_ShellPropSheetExt_Private::SubtabDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
// Propagate NM_CUSTOMDRAW to the parent dialog.
|
switch (uMsg) {
|
||||||
if (uMsg == WM_NOTIFY) {
|
case WM_DESTROY: {
|
||||||
const NMHDR *const pHdr = reinterpret_cast<const NMHDR*>(lParam);
|
// Remove the D_PTR_PROP and TAB_PTR_PROP properties from the page.
|
||||||
switch (pHdr->code) {
|
// The D_PTR_PROP property stored the pointer to the
|
||||||
case LVN_GETDISPINFO:
|
// RP_ShellPropSheetExt_Private object.
|
||||||
case NM_CUSTOMDRAW:
|
// The TAB_PTR_PROP property stored the pointer to the
|
||||||
case LVN_ITEMCHANGING: {
|
// RP_ShellPropSheetExt_Private::tab object.
|
||||||
// NOTE: Since this is a DlgProc, we can't simply return
|
RemoveProp(hDlg, RP_ShellPropSheetExtPrivate::D_PTR_PROP);
|
||||||
// the CDRF code. It has to be set as DWLP_MSGRESULT.
|
RemoveProp(hDlg, RP_ShellPropSheetExtPrivate::TAB_PTR_PROP);
|
||||||
// References:
|
return TRUE;
|
||||||
// - https://stackoverflow.com/questions/40549962/c-winapi-listview-nm-customdraw-not-getting-cdds-itemprepaint
|
}
|
||||||
// - https://stackoverflow.com/a/40552426
|
|
||||||
INT_PTR result = SendMessage(GetParent(hDlg), uMsg, wParam, lParam);
|
case WM_NOTIFY: {
|
||||||
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, result);
|
// Propagate NM_CUSTOMDRAW to the parent dialog.
|
||||||
return true;
|
const NMHDR *const pHdr = reinterpret_cast<const NMHDR*>(lParam);
|
||||||
|
switch (pHdr->code) {
|
||||||
|
case LVN_GETDISPINFO:
|
||||||
|
case NM_CUSTOMDRAW:
|
||||||
|
case LVN_ITEMCHANGING: {
|
||||||
|
// NOTE: Since this is a DlgProc, we can't simply return
|
||||||
|
// the CDRF code. It has to be set as DWLP_MSGRESULT.
|
||||||
|
// References:
|
||||||
|
// - https://stackoverflow.com/questions/40549962/c-winapi-listview-nm-customdraw-not-getting-cdds-itemprepaint
|
||||||
|
// - https://stackoverflow.com/a/40552426
|
||||||
|
INT_PTR result = SendMessage(GetParent(hDlg), uMsg, wParam, lParam);
|
||||||
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, result);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WM_VSCROLL: {
|
||||||
|
auto *const d = static_cast<RP_ShellPropSheetExt_Private*>(GetProp(hDlg, D_PTR_PROP));
|
||||||
|
auto *const tab = static_cast<RP_ShellPropSheetExt_Private::tab*>(GetProp(hDlg, TAB_PTR_PROP));
|
||||||
|
if (!d || !tab) {
|
||||||
|
// No RP_ShellPropSheetExt_Private or tab. Can't do anything...
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
// Check the operation and scroll there.
|
||||||
break;
|
int deltaY = 0;
|
||||||
|
switch (LOWORD(wParam)) {
|
||||||
|
case SB_TOP:
|
||||||
|
deltaY = -tab->scrollPos;
|
||||||
|
break;
|
||||||
|
case SB_BOTTOM:
|
||||||
|
deltaY = tab->curPt.y - tab->scrollPos;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SB_LINEUP:
|
||||||
|
deltaY = -d->lblDescHeight;
|
||||||
|
break;
|
||||||
|
case SB_LINEDOWN:
|
||||||
|
deltaY = d->lblDescHeight;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SB_PAGEUP:
|
||||||
|
deltaY = -d->dlgSize.cy;
|
||||||
|
break;
|
||||||
|
case SB_PAGEDOWN:
|
||||||
|
deltaY = d->dlgSize.cy;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SB_THUMBTRACK:
|
||||||
|
case SB_THUMBPOSITION:
|
||||||
|
deltaY = HIWORD(wParam) - tab->scrollPos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure this doesn't go out of range.
|
||||||
|
int scrollPos = tab->scrollPos + deltaY;
|
||||||
|
if (scrollPos < 0) {
|
||||||
|
deltaY -= scrollPos;
|
||||||
|
} else if (scrollPos + d->dlgSize.cy > tab->curPt.y) {
|
||||||
|
deltaY -= (scrollPos + 1) - (tab->curPt.y - d->dlgSize.cy);
|
||||||
|
}
|
||||||
|
|
||||||
|
tab->scrollPos += deltaY;
|
||||||
|
SetScrollPos(hDlg, SB_VERT, tab->scrollPos, TRUE);
|
||||||
|
ScrollWindow(hDlg, 0, -deltaY, nullptr, nullptr);
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dummy callback procedure that does nothing.
|
// Dummy callback procedure that does nothing.
|
||||||
return false; // Let system deal with other messages
|
return DefSubclassProc(hDlg, uMsg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ END
|
|||||||
*/
|
*/
|
||||||
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||||
IDD_SUBTAB_CHILD_DIALOG DIALOGEX 0, 0, 16, 16
|
IDD_SUBTAB_CHILD_DIALOG DIALOGEX 0, 0, 16, 16
|
||||||
STYLE DS_3DLOOK | DS_CONTROL | DS_SHELLFONT | WS_VISIBLE | WS_CHILDWINDOW | WS_TABSTOP
|
STYLE DS_3DLOOK | DS_CONTROL | DS_SHELLFONT | WS_VISIBLE | WS_CHILDWINDOW | WS_TABSTOP | WS_VSCROLL
|
||||||
EXSTYLE WS_EX_NOPARENTNOTIFY | WS_EX_TRANSPARENT | WS_EX_CONTROLPARENT
|
EXSTYLE WS_EX_NOPARENTNOTIFY | WS_EX_TRANSPARENT | WS_EX_CONTROLPARENT
|
||||||
FONT 8, "MS Shell Dlg", FW_NORMAL, 0, 0
|
FONT 8, "MS Shell Dlg", FW_NORMAL, 0, 0
|
||||||
BEGIN
|
BEGIN
|
||||||
|
Loading…
Reference in New Issue
Block a user