Add dpi support for panel tab and caption

- use recommended subclassing for docking panel tab and caption
- remove unused function

ref #14959

Close #15394
This commit is contained in:
ozone10 2024-07-02 18:54:43 +02:00 committed by Don Ho
parent 3bca7bf278
commit 8866d4b7fe
6 changed files with 152 additions and 147 deletions

View File

@ -58,28 +58,19 @@ static LRESULT CALLBACK hookProcMouse(int nCode, WPARAM wParam, LPARAM lParam)
DockingCont::DockingCont()
{
_captionHeightDynamic = NppParameters::getInstance()._dpiManager.scaleY(_captionHeightDynamic);
_captionGapDynamic = NppParameters::getInstance()._dpiManager.scaleY(_captionGapDynamic);
_closeButtonPosLeftDynamic = NppParameters::getInstance()._dpiManager.scaleX(_closeButtonPosLeftDynamic);
_closeButtonPosTopDynamic = NppParameters::getInstance()._dpiManager.scaleY(_closeButtonPosTopDynamic);
setDpi();
_captionHeightDynamic = _dpiManager.scale(HIGH_CAPTION);
_captionGapDynamic = _dpiManager.scale(CAPTION_GAP);
_closeButtonPosLeftDynamic = _dpiManager.scale(CLOSEBTN_POS_LEFT);
_closeButtonPosTopDynamic = _dpiManager.scale(CLOSEBTN_POS_TOP);
_closeButtonWidth = NppParameters::getInstance()._dpiManager.scaleX(12); // bitmap image is 12x12
_closeButtonHeight = NppParameters::getInstance()._dpiManager.scaleY(12);
_closeButtonWidth = _dpiManager.scale(g_dockingContCloseBtnSize);
_closeButtonHeight = _dpiManager.scale(g_dockingContCloseBtnSize);
}
DockingCont::~DockingCont()
{
if (_hFont != nullptr)
{
::DeleteObject(_hFont);
_hFont = nullptr;
}
if (_hFontCaption != nullptr)
{
::DeleteObject(_hFontCaption);
_hFontCaption = nullptr;
}
destroyFonts();
}
@ -267,12 +258,27 @@ bool DockingCont::isTbVis(tTbData* data)
}
void DockingCont::destroyFonts()
{
if (_hFont != nullptr)
{
::DeleteObject(_hFont);
_hFont = nullptr;
}
if (_hFontCaption != nullptr)
{
::DeleteObject(_hFontCaption);
_hFontCaption = nullptr;
}
}
//
// Process function of caption bar
//
LRESULT DockingCont::runProcCaption(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
static ToolTip toolTip;
static ToolTip toolTip;
switch (Message)
{
@ -314,7 +320,7 @@ LRESULT DockingCont::runProcCaption(HWND hwnd, UINT Message, WPARAM wParam, LPAR
}
focusClient();
return TRUE;
return 0;
}
case WM_LBUTTONUP:
{
@ -333,7 +339,7 @@ LRESULT DockingCont::runProcCaption(HWND hwnd, UINT Message, WPARAM wParam, LPAR
}
focusClient();
return TRUE;
return 0;
}
case WM_LBUTTONDBLCLK:
{
@ -341,7 +347,7 @@ LRESULT DockingCont::runProcCaption(HWND hwnd, UINT Message, WPARAM wParam, LPAR
::SendMessage(_hParent, DMM_FLOATALL, 0, reinterpret_cast<LPARAM>(this));
focusClient();
return TRUE;
return 0;
}
case WM_MOUSEMOVE:
{
@ -400,7 +406,7 @@ LRESULT DockingCont::runProcCaption(HWND hwnd, UINT Message, WPARAM wParam, LPAR
toolTip.destroy();
_bCapTTHover = FALSE;
}
return TRUE;
return 0;
}
case WM_MOUSEHOVER:
{
@ -422,13 +428,13 @@ LRESULT DockingCont::runProcCaption(HWND hwnd, UINT Message, WPARAM wParam, LPAR
generic_string tip = pNativeSpeaker->getLocalizedStrFromID("close-panel-tip", TEXT("Close"));
toolTip.Show(rc, tip.c_str(), pt.x, pt.y + 20);
}
return TRUE;
return 0;
}
case WM_MOUSELEAVE:
{
toolTip.destroy();
_bCapTTHover = FALSE;
return TRUE;
return 0;
}
case WM_SIZE:
{
@ -445,7 +451,23 @@ LRESULT DockingCont::runProcCaption(HWND hwnd, UINT Message, WPARAM wParam, LPAR
break;
}
return ::CallWindowProc(_hDefaultCaptionProc, hwnd, Message, wParam, lParam);
return ::DefSubclassProc(hwnd, Message, wParam, lParam);
}
LRESULT DockingCont::DockingCaptionSubclass(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
case WM_NCDESTROY:
{
::RemoveWindowSubclass(hWnd, DockingCaptionSubclass, uIdSubclass);
break;
}
default:
break;
}
return reinterpret_cast<DockingCont*>(dwRefData)->runProcCaption(hWnd, uMsg, wParam, lParam);
}
void DockingCont::drawCaptionItem(DRAWITEMSTRUCT *pDrawItemStruct)
@ -815,7 +837,7 @@ LRESULT DockingCont::runProcTab(HWND hwnd, UINT Message, WPARAM wParam, LPARAM l
case WM_LBUTTONDOWN:
{
_beginDrag = TRUE;
return TRUE;
return 0;
}
case WM_LBUTTONUP:
{
@ -829,12 +851,12 @@ LRESULT DockingCont::runProcTab(HWND hwnd, UINT Message, WPARAM wParam, LPARAM l
selectTab(iItem);
_beginDrag = FALSE;
return TRUE;
return 0;
}
case WM_LBUTTONDBLCLK:
{
NotifyParent((_isFloating == true)?DMM_DOCK:DMM_FLOAT);
return TRUE;
return 0;
}
case WM_MBUTTONUP:
{
@ -861,7 +883,7 @@ LRESULT DockingCont::runProcTab(HWND hwnd, UINT Message, WPARAM wParam, LPARAM l
{
hideToolbar((tTbData*)tcItem.lParam);
}
return TRUE;
return 0;
}
case WM_MOUSEMOVE:
@ -908,9 +930,6 @@ LRESULT DockingCont::runProcTab(HWND hwnd, UINT Message, WPARAM wParam, LPARAM l
TCITEM tcItem {};
RECT rc {};
// destroy old tooltip
toolTip.destroy();
// recalc mouse position
::ClientToScreen(hwnd, &info.pt);
@ -918,7 +937,10 @@ LRESULT DockingCont::runProcTab(HWND hwnd, UINT Message, WPARAM wParam, LPARAM l
tcItem.mask = TCIF_PARAM;
::SendMessage(hwnd, TCM_GETITEM, iItem, reinterpret_cast<LPARAM>(&tcItem));
if (!tcItem.lParam)
return FALSE;
break;
// destroy old tooltip
toolTip.destroy();
toolTip.init(_hInst, hwnd);
toolTip.Show(rc, (reinterpret_cast<tTbData*>(tcItem.lParam))->pszName, info.pt.x, info.pt.y + 20);
@ -930,7 +952,7 @@ LRESULT DockingCont::runProcTab(HWND hwnd, UINT Message, WPARAM wParam, LPARAM l
_beginDrag = FALSE;
}
return TRUE;
return 0;
}
case WM_MOUSEHOVER:
@ -952,23 +974,23 @@ LRESULT DockingCont::runProcTab(HWND hwnd, UINT Message, WPARAM wParam, LPARAM l
tcItem.mask = TCIF_PARAM;
::SendMessage(hwnd, TCM_GETITEM, iItem, reinterpret_cast<LPARAM>(&tcItem));
if (!tcItem.lParam)
return FALSE;
break;
toolTip.init(_hInst, hwnd);
toolTip.Show(rc, ((tTbData*)tcItem.lParam)->pszName, info.pt.x, info.pt.y + 20);
return TRUE;
toolTip.Show(rc, reinterpret_cast<tTbData*>(tcItem.lParam)->pszName, info.pt.x, info.pt.y + 20);
return 0;
}
case WM_MOUSELEAVE:
{
toolTip.destroy();
_bTabTTHover = FALSE;
return TRUE;
return 0;
}
case WM_NOTIFY:
{
LPNMHDR lpnmhdr = (LPNMHDR)lParam;
LPNMHDR lpnmhdr = reinterpret_cast<LPNMHDR>(lParam);
if ((lpnmhdr->hwndFrom == _hContTab) && (lpnmhdr->code == TCN_GETOBJECT))
{
@ -981,6 +1003,7 @@ LRESULT DockingCont::runProcTab(HWND hwnd, UINT Message, WPARAM wParam, LPARAM l
iItem = static_cast<int32_t>(::SendMessage(hwnd, TCM_HITTEST, 0, reinterpret_cast<LPARAM>(&info)));
selectTab(iItem);
return 0;
}
break;
}
@ -1000,14 +1023,30 @@ LRESULT DockingCont::runProcTab(HWND hwnd, UINT Message, WPARAM wParam, LPARAM l
break;
}
}
return 0;
break;
}
default:
break;
}
return ::CallWindowProc(_hDefaultTabProc, hwnd, Message, wParam, lParam);
return ::DefSubclassProc(hwnd, Message, wParam, lParam);
}
LRESULT DockingCont::DockingTabSubclass(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
case WM_NCDESTROY:
{
::RemoveWindowSubclass(hWnd, DockingTabSubclass, uIdSubclass);
break;
}
default:
break;
}
return reinterpret_cast<DockingCont*>(dwRefData)->runProcTab(hWnd, uMsg, wParam, lParam);
}
void DockingCont::drawTabItem(DRAWITEMSTRUCT* pDrawItemStruct)
@ -1062,7 +1101,7 @@ void DockingCont::drawTabItem(DRAWITEMSTRUCT* pDrawItemStruct)
const int iconDpiDynamicalX = rc.left + (isSelected ? wPadding : (rc.right - rc.left - iconSize + 1) / 2);
const int iconDpiDynamicalY = rc.top + (rc.bottom - rc.top - iconSize - onePadding) / 2;
::DrawIconEx(hDc, iconDpiDynamicalX, iconDpiDynamicalY, tbData->hIconTab, 0, 0, 0, nullptr, DI_NORMAL);
::DrawIconEx(hDc, iconDpiDynamicalX, iconDpiDynamicalY, tbData->hIconTab, iconSize, iconSize, 0, nullptr, DI_NORMAL);
if (isSelected)
{
@ -1112,12 +1151,12 @@ intptr_t CALLBACK DockingCont::run_dlgProc(UINT Message, WPARAM wParam, LPARAM l
_hCaption = ::GetDlgItem(_hSelf, IDC_BTN_CAPTION);
// intial subclassing of caption
::SetWindowLongPtr(_hCaption, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
_hDefaultCaptionProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(_hCaption, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(wndCaptionProc)));
constexpr UINT_PTR idSubclassCaption = 1;
::SetWindowSubclass(_hCaption, DockingCaptionSubclass, idSubclassCaption, reinterpret_cast<DWORD_PTR>(this));
// intial subclassing of tab
::SetWindowLongPtr(_hContTab, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
_hDefaultTabProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(_hContTab, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(wndTabProc)));
constexpr UINT_PTR idSubclassTab = 2;
::SetWindowSubclass(_hContTab, DockingTabSubclass, idSubclassTab, reinterpret_cast<DWORD_PTR>(this));
// set min tab width
const int tabDpiPadding = _dpiManager.scale(g_dockingContTabIconSize + g_dockingContTabIconPadding * 2);
@ -1227,7 +1266,52 @@ intptr_t CALLBACK DockingCont::run_dlgProc(UINT Message, WPARAM wParam, LPARAM l
}
return FALSE;
}
case WM_COMMAND :
case WM_DPICHANGED:
{
_dpiManager.setDpiWP(wParam);
[[fallthrough]];
}
case WM_DPICHANGED_AFTERPARENT:
{
if (Message != WM_DPICHANGED)
{
_dpiManager.setDpi(_hParent);
}
_captionHeightDynamic = _dpiManager.scale(HIGH_CAPTION);
_captionGapDynamic = _dpiManager.scale(CAPTION_GAP);
_closeButtonPosLeftDynamic = _dpiManager.scale(CLOSEBTN_POS_LEFT);
_closeButtonPosTopDynamic = _dpiManager.scale(CLOSEBTN_POS_TOP);
_closeButtonWidth = _dpiManager.scale(g_dockingContCloseBtnSize);
_closeButtonHeight = _dpiManager.scale(g_dockingContCloseBtnSize);
const int tabDpiPadding = _dpiManager.scale(g_dockingContTabIconSize + g_dockingContTabIconPadding * 2);
::SendMessage(_hContTab, TCM_SETMINTABWIDTH, 0, tabDpiPadding);
TabCtrl_SetPadding(_hContTab, tabDpiPadding / 2, 0);
TabCtrl_SetItemSize(_hContTab, 2 * tabDpiPadding, tabDpiPadding);
destroyFonts();
LOGFONT lfTab{ _dpiManager.getDefaultGUIFontForDpi() };
_hFont = ::CreateFontIndirect(&lfTab);
LOGFONT lfCaption{ _dpiManager.getDefaultGUIFontForDpi(DPIManagerV2::FontType::smcaption) };
_hFontCaption = ::CreateFontIndirect(&lfCaption);
if (Message == WM_DPICHANGED)
{
_dpiManager.setPositionDpi(lParam, _hSelf);
}
else
{
onSize();
}
return TRUE;
}
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
@ -1702,7 +1786,7 @@ bool DockingCont::updateCaption()
void DockingCont::focusClient()
{
TCITEM tcItem {};
int iItem = getActiveTb();
int iItem = getActiveTb();
if (iItem != -1)
{

View File

@ -42,6 +42,8 @@ enum eMousePos {
#define CLOSEBTN_POS_LEFT 3
#define CLOSEBTN_POS_TOP 3
constexpr int g_dockingContCloseBtnSize = 12;
constexpr int g_dockingContTabIconSize = 16;
constexpr int g_dockingContTabIconPadding = 3;
@ -132,19 +134,17 @@ public:
::DestroyWindow(_hSelf);
};
void destroyFonts();
protected :
// Subclassing caption
LRESULT runProcCaption(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK wndCaptionProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
return (((DockingCont *)(::GetWindowLongPtr(hwnd, GWLP_USERDATA)))->runProcCaption(hwnd, Message, wParam, lParam));
};
static LRESULT CALLBACK DockingCaptionSubclass(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
// Subclassing tab
LRESULT runProcTab(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK wndTabProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
return (((DockingCont *)(::GetWindowLongPtr(hwnd, GWLP_USERDATA)))->runProcTab(hwnd, Message, wParam, lParam));
};
static LRESULT CALLBACK DockingTabSubclass(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
intptr_t CALLBACK run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) override;
@ -196,12 +196,6 @@ private:
// Important value for DlgMoving class
BOOL _dragFromTab = FALSE;
// subclassing handle for caption
WNDPROC _hDefaultCaptionProc = nullptr;
// subclassing handle for tab
WNDPROC _hDefaultTabProc = nullptr;
// for moving and reordering
UINT _prevItem = 0;
BOOL _beginDrag = FALSE;
@ -218,8 +212,8 @@ private:
int _captionGapDynamic = CAPTION_GAP;
int _closeButtonPosLeftDynamic = CLOSEBTN_POS_LEFT;
int _closeButtonPosTopDynamic = CLOSEBTN_POS_TOP;
int _closeButtonWidth = 12;
int _closeButtonHeight = 12;
int _closeButtonWidth = g_dockingContCloseBtnSize;
int _closeButtonHeight = g_dockingContCloseBtnSize;
// data of added windows
std::vector<tTbData *> _vTbData;

View File

@ -80,10 +80,6 @@ public :
DPIManagerV2::setPositionDpi(lParam, _hSelf, flags);
}
void sendDpiMsgToChildCtrls(WPARAM wParam = 0, LPARAM lParam = 0) {
DPIManagerV2::sendMessageToChildControls(_hSelf, WM_DPICHANGED, wParam, lParam);
}
void destroy() override;
DPIManagerV2& dpiManager() { return _dpiManager; }

View File

@ -26,12 +26,15 @@ class ToolTip : public Window
public:
ToolTip() = default;
void destroy() {
::DestroyWindow(_hSelf);
_hSelf = NULL;
void destroy() override {
if (_hSelf != nullptr)
{
::DestroyWindow(_hSelf);
_hSelf = nullptr;
}
};
virtual void init(HINSTANCE hInst, HWND hParent);
void init(HINSTANCE hInst, HWND hParent) override;
void Show(RECT rectTitle, const TCHAR* pszTitleText, int iXOff = 0, int iWidthOff = 0);
protected:

View File

@ -209,77 +209,6 @@ LOGFONT DPIManagerV2::getDefaultGUIFontForDpi(UINT dpi, FontType type)
return lf;
}
// currently send message only to selected buttons; listbox and edit controls with scrollbars
void DPIManagerV2::sendMessageToChildControls(HWND hwndParent, UINT msg, WPARAM wParam, LPARAM lParam)
{
struct WMessage
{
UINT _msg = 0;
WPARAM _wParam = 0;
LPARAM _lParam = 0;
};
struct WMessage p { msg, wParam, lParam };
::EnumChildWindows(hwndParent, [](HWND hwnd, LPARAM childLParam) WINAPI_LAMBDA_RETURN(BOOL) {
auto & p = *reinterpret_cast<WMessage*>(childLParam);
constexpr size_t classNameLen = 32;
TCHAR className[classNameLen]{};
::GetClassName(hwnd, className, classNameLen);
auto style = ::GetWindowLongPtr(hwnd, GWL_STYLE);
if (wcscmp(className, WC_BUTTON) == 0)
{
switch (style & BS_TYPEMASK)
{
case BS_CHECKBOX:
case BS_AUTOCHECKBOX:
case BS_3STATE:
case BS_AUTO3STATE:
case BS_RADIOBUTTON:
case BS_AUTORADIOBUTTON:
{
if ((style & BS_PUSHLIKE) != BS_PUSHLIKE)
{
::SendMessage(hwnd, p._msg, p._wParam, p._lParam);
}
break;
}
default:
{
break;
}
}
return TRUE;
}
if (wcscmp(className, WC_EDIT) == 0)
{
bool hasScrollBar = ((style & WS_HSCROLL) == WS_HSCROLL) || ((style & WS_VSCROLL) == WS_VSCROLL);
if (hasScrollBar)
{
::SendMessage(hwnd, p._msg, p._wParam, p._lParam);
}
return TRUE;
}
if (wcscmp(className, WC_LISTBOX) == 0)
{
if ((style & LBS_COMBOBOX) != LBS_COMBOBOX)
{
bool hasScrollBar = ((style & WS_HSCROLL) == WS_HSCROLL) || ((style & WS_VSCROLL) == WS_VSCROLL);
if (hasScrollBar)
{
::SendMessage(hwnd, p._msg, p._wParam, p._lParam);
}
}
return TRUE;
}
return TRUE;
}, reinterpret_cast<LPARAM>(&p));
}
void DPIManagerV2::loadIcon(HINSTANCE hinst, const wchar_t* pszName, int cx, int cy, HICON* phico, UINT fuLoad)
{
if (::LoadIconWithScaleDown(hinst, pszName, cx, cy, phico) != S_OK)

View File

@ -47,7 +47,7 @@ public:
static void initDpiAPI();
static int getSystemMetricsForDpi(int nIndex, UINT dpi);
int getSystemMetricsForDpi(int nIndex) {
int getSystemMetricsForDpi(int nIndex) const {
return getSystemMetricsForDpi(nIndex, _dpi);
}
static DPI_AWARENESS_CONTEXT setThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT dpiContext);
@ -107,11 +107,11 @@ public:
return scale(x, USER_DEFAULT_SCREEN_DPI, getDpiForWindow(hWnd));
}
int scale(int x) {
int scale(int x) const {
return scale(x, _dpi);
}
int unscale(int x) {
int unscale(int x) const {
return unscale(x, _dpi);
}
@ -123,7 +123,7 @@ public:
return -(scale(pt, getDpiForWindow(hWnd), 72));
}
int scaleFont(int pt) {
int scaleFont(int pt) const {
return scaleFont(pt, _dpi);
}
@ -131,11 +131,10 @@ public:
static LOGFONT getDefaultGUIFontForDpi(HWND hWnd, FontType type = FontType::message) {
return getDefaultGUIFontForDpi(getDpiForWindow(hWnd), type);
}
LOGFONT getDefaultGUIFontForDpi(FontType type = FontType::message) {
LOGFONT getDefaultGUIFontForDpi(FontType type = FontType::message) const {
return getDefaultGUIFontForDpi(_dpi, type);
}
static void sendMessageToChildControls(HWND hwndParent, UINT msg, WPARAM wParam, LPARAM lParam);
static void loadIcon(HINSTANCE hinst, const wchar_t* pszName, int cx, int cy, HICON* phico, UINT fuLoad = LR_DEFAULTCOLOR);
private: