mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-23 13:54:54 +02:00
Improve dark mode updown control appearance in dark mode
Fix #16560, close #16568
This commit is contained in:
parent
2de6260610
commit
9232226d3f
@ -80,10 +80,15 @@ static std::wstring getWndClassName(HWND hWnd)
|
||||
{
|
||||
constexpr int strLen = 32;
|
||||
std::wstring className(strLen, 0);
|
||||
className.resize(::GetClassName(hWnd, &className[0], strLen));
|
||||
className.resize(::GetClassName(hWnd, className.data(), strLen));
|
||||
return className;
|
||||
}
|
||||
|
||||
static bool cmpWndClassName(HWND hWnd, const wchar_t* classNameToCmp)
|
||||
{
|
||||
return (getWndClassName(hWnd) == classNameToCmp);
|
||||
}
|
||||
|
||||
namespace NppDarkMode
|
||||
{
|
||||
struct Brushes
|
||||
@ -1153,19 +1158,19 @@ namespace NppDarkMode
|
||||
NppDarkMode::paintRoundRect(hdc, rect, hpen, static_cast<HBRUSH>(::GetStockObject(NULL_BRUSH)), width, height);
|
||||
}
|
||||
|
||||
constexpr int g_win11CornerRoundness = 4;
|
||||
|
||||
struct ThemeData
|
||||
{
|
||||
HTHEME _hTheme = nullptr;
|
||||
const wchar_t* _themeClass;
|
||||
const wchar_t* _themeClass = nullptr;
|
||||
|
||||
ThemeData() = default;
|
||||
|
||||
ThemeData(const wchar_t* themeClass)
|
||||
: _themeClass(themeClass)
|
||||
{}
|
||||
|
||||
ThemeData()
|
||||
: _themeClass(nullptr)
|
||||
{}
|
||||
|
||||
~ThemeData()
|
||||
{
|
||||
closeTheme();
|
||||
@ -2265,7 +2270,7 @@ namespace NppDarkMode
|
||||
::FillRect(hdc, &rcInner, isDisabled ? NppDarkMode::getDlgBackgroundBrush() : NppDarkMode::getCtrlBackgroundBrush());
|
||||
}
|
||||
|
||||
const int roundCornerValue = NppDarkMode::isWindows11() ? 4 : 0;
|
||||
const int roundCornerValue = NppDarkMode::isWindows11() ? g_win11CornerRoundness : 0;
|
||||
|
||||
NppDarkMode::paintRoundFrameRect(hdc, rcClient, hSelectedPen, roundCornerValue, roundCornerValue);
|
||||
|
||||
@ -2464,6 +2469,129 @@ namespace NppDarkMode
|
||||
SetWindowSubclass(hwnd, ListViewSubclass, g_listViewSubclassID, 0);
|
||||
}
|
||||
|
||||
struct UpDownData
|
||||
{
|
||||
BufferData _bufferData;
|
||||
|
||||
RECT _rcClient{};
|
||||
RECT _rcPrev{};
|
||||
RECT _rcNext{};
|
||||
int _cornerRoundness = 0;
|
||||
bool _isHorizontal = false;
|
||||
bool _isAligned = false;
|
||||
bool _wasHotNext = false;
|
||||
|
||||
UpDownData() = delete;
|
||||
|
||||
explicit UpDownData(HWND hWnd)
|
||||
: _isHorizontal((::GetWindowLongPtr(hWnd, GWL_STYLE) & UDS_HORZ) == UDS_HORZ)
|
||||
, _isAligned((::GetWindowLongPtr(hWnd, GWL_STYLE) & UDS_ALIGNRIGHT) == UDS_ALIGNRIGHT)
|
||||
{
|
||||
_cornerRoundness = (NppDarkMode::isWindows11() && cmpWndClassName(::GetParent(hWnd), WC_TABCONTROL)) ? (g_win11CornerRoundness + 1) : 0;
|
||||
updateRect(hWnd);
|
||||
}
|
||||
|
||||
~UpDownData() = default;
|
||||
|
||||
void updateRectUpDown()
|
||||
{
|
||||
if (_isHorizontal)
|
||||
{
|
||||
RECT rcArrowLeft{
|
||||
_rcClient.left, _rcClient.top,
|
||||
_rcClient.right - ((_rcClient.right - _rcClient.left) / 2) - 1, _rcClient.bottom
|
||||
};
|
||||
|
||||
RECT rcArrowRight{
|
||||
rcArrowLeft.right + 1, _rcClient.top,
|
||||
_rcClient.right, _rcClient.bottom
|
||||
};
|
||||
|
||||
_rcPrev = rcArrowLeft;
|
||||
_rcNext = rcArrowRight;
|
||||
}
|
||||
else
|
||||
{
|
||||
static const LONG offset = _isAligned ? 2 : 0;
|
||||
|
||||
RECT rcArrowTop{
|
||||
_rcClient.left + offset, _rcClient.top,
|
||||
_rcClient.right, _rcClient.bottom - ((_rcClient.bottom - _rcClient.top) / 2)
|
||||
};
|
||||
|
||||
RECT rcArrowBottom{
|
||||
_rcClient.left + offset, rcArrowTop.bottom,
|
||||
_rcClient.right, _rcClient.bottom
|
||||
};
|
||||
|
||||
_rcPrev = rcArrowTop;
|
||||
_rcNext = rcArrowBottom;
|
||||
}
|
||||
}
|
||||
|
||||
void updateRect(HWND hWnd)
|
||||
{
|
||||
::GetClientRect(hWnd, &_rcClient);
|
||||
updateRectUpDown();
|
||||
}
|
||||
|
||||
bool updateRect(RECT rcClientNew)
|
||||
{
|
||||
if (::EqualRect(&_rcClient, &rcClientNew) == FALSE)
|
||||
{
|
||||
_rcClient = rcClientNew;
|
||||
updateRectUpDown();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static void paintUpDown(HWND hWnd, HDC hdc, UpDownData& upDownData)
|
||||
{
|
||||
const bool isDisabled = ::IsWindowEnabled(hWnd) == FALSE;
|
||||
const int roundness = upDownData._cornerRoundness;
|
||||
|
||||
::FillRect(hdc, &upDownData._rcClient, NppDarkMode::getDlgBackgroundBrush());
|
||||
::SetBkMode(hdc, TRANSPARENT);
|
||||
|
||||
POINT ptCursor{};
|
||||
::GetCursorPos(&ptCursor);
|
||||
::ScreenToClient(hWnd, &ptCursor);
|
||||
|
||||
const bool isHotPrev = ::PtInRect(&upDownData._rcPrev, ptCursor) == TRUE;
|
||||
const bool isHotNext = ::PtInRect(&upDownData._rcNext, ptCursor) == TRUE;
|
||||
|
||||
upDownData._wasHotNext = !isHotPrev && (::PtInRect(&upDownData._rcClient, ptCursor) == TRUE);
|
||||
|
||||
auto paintUpDownBtn = [&](const RECT& rect, bool isHot) -> void {
|
||||
HBRUSH hBrush = isDisabled ? NppDarkMode::getDlgBackgroundBrush() : (isHot ? NppDarkMode::getHotBackgroundBrush() : NppDarkMode::getCtrlBackgroundBrush());
|
||||
HPEN hPen = isDisabled ? NppDarkMode::getDisabledEdgePen() : (isHot ? NppDarkMode::getHotEdgePen() : NppDarkMode::getEdgePen());
|
||||
|
||||
NppDarkMode::paintRoundRect(hdc, rect, hPen, hBrush, roundness, roundness);
|
||||
};
|
||||
|
||||
paintUpDownBtn(upDownData._rcPrev, isHotPrev);
|
||||
paintUpDownBtn(upDownData._rcNext, isHotNext);
|
||||
|
||||
auto hFont = reinterpret_cast<HFONT>(::SendMessage(hWnd, WM_GETFONT, 0, 0));
|
||||
auto holdFont = static_cast<HFONT>(::SelectObject(hdc, hFont));
|
||||
|
||||
constexpr UINT dtFlags = DT_NOPREFIX | DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOCLIP;
|
||||
const COLORREF clrText = isDisabled ? NppDarkMode::getDisabledTextColor() : NppDarkMode::getDarkerTextColor();
|
||||
|
||||
const LONG offset = upDownData._isHorizontal ? DPIManagerV2::scale(1, ::GetParent(hWnd)) : 0;
|
||||
RECT rcTectPrev{ upDownData._rcPrev.left, upDownData._rcPrev.top, upDownData._rcPrev.right, upDownData._rcPrev.bottom - offset };
|
||||
::SetTextColor(hdc, isHotPrev ? NppDarkMode::getTextColor() : clrText);
|
||||
::DrawText(hdc, upDownData._isHorizontal ? L"<" : L"˄", -1, &rcTectPrev, dtFlags);
|
||||
|
||||
RECT rcTectNext{ upDownData._rcNext.left + offset, upDownData._rcNext.top, upDownData._rcNext.right, upDownData._rcNext.bottom - offset };
|
||||
::SetTextColor(hdc, isHotNext ? NppDarkMode::getTextColor() : clrText);
|
||||
::DrawText(hdc, upDownData._isHorizontal ? L">" : L"˅", -1, &rcTectNext, dtFlags);
|
||||
|
||||
::SelectObject(hdc, holdFont);
|
||||
}
|
||||
|
||||
constexpr UINT_PTR g_upDownSubclassID = 42;
|
||||
|
||||
static LRESULT CALLBACK UpDownSubclass(
|
||||
@ -2475,120 +2603,16 @@ namespace NppDarkMode
|
||||
DWORD_PTR dwRefData
|
||||
)
|
||||
{
|
||||
auto pButtonData = reinterpret_cast<ButtonData*>(dwRefData);
|
||||
auto* pUpDownData = reinterpret_cast<UpDownData*>(dwRefData);
|
||||
auto& bufferData = pUpDownData->_bufferData;
|
||||
auto& hMemDC = bufferData._hMemDC;
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_PRINTCLIENT:
|
||||
case WM_PAINT:
|
||||
{
|
||||
if (!NppDarkMode::isEnabled())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
const auto style = ::GetWindowLongPtr(hWnd, GWL_STYLE);
|
||||
const bool isHorizontal = ((style & UDS_HORZ) == UDS_HORZ);
|
||||
|
||||
bool hasTheme = pButtonData->ensureTheme(hWnd);
|
||||
|
||||
RECT rcClient{};
|
||||
::GetClientRect(hWnd, &rcClient);
|
||||
|
||||
PAINTSTRUCT ps{};
|
||||
auto hdc = ::BeginPaint(hWnd, &ps);
|
||||
|
||||
::FillRect(hdc, &rcClient, NppDarkMode::getDlgBackgroundBrush());
|
||||
|
||||
RECT rcArrowPrev{};
|
||||
RECT rcArrowNext{};
|
||||
|
||||
if (isHorizontal)
|
||||
{
|
||||
RECT rcArrowLeft{
|
||||
rcClient.left, rcClient.top,
|
||||
rcClient.right - ((rcClient.right - rcClient.left) / 2), rcClient.bottom
|
||||
};
|
||||
|
||||
RECT rcArrowRight{
|
||||
rcArrowLeft.right - 1, rcClient.top,
|
||||
rcClient.right, rcClient.bottom
|
||||
};
|
||||
|
||||
rcArrowPrev = rcArrowLeft;
|
||||
rcArrowNext = rcArrowRight;
|
||||
}
|
||||
else
|
||||
{
|
||||
RECT rcArrowTop{
|
||||
rcClient.left, rcClient.top,
|
||||
rcClient.right, rcClient.bottom - ((rcClient.bottom - rcClient.top) / 2)
|
||||
};
|
||||
|
||||
RECT rcArrowBottom{
|
||||
rcClient.left, rcArrowTop.bottom - 1,
|
||||
rcClient.right, rcClient.bottom
|
||||
};
|
||||
|
||||
rcArrowPrev = rcArrowTop;
|
||||
rcArrowNext = rcArrowBottom;
|
||||
}
|
||||
|
||||
POINT ptCursor{};
|
||||
::GetCursorPos(&ptCursor);
|
||||
::ScreenToClient(hWnd, &ptCursor);
|
||||
|
||||
bool isHotPrev = ::PtInRect(&rcArrowPrev, ptCursor);
|
||||
bool isHotNext = ::PtInRect(&rcArrowNext, ptCursor);
|
||||
|
||||
::SetBkMode(hdc, TRANSPARENT);
|
||||
|
||||
if (hasTheme)
|
||||
{
|
||||
::DrawThemeBackground(pButtonData->hTheme, hdc, BP_PUSHBUTTON, isHotPrev ? PBS_HOT : PBS_NORMAL, &rcArrowPrev, nullptr);
|
||||
::DrawThemeBackground(pButtonData->hTheme, hdc, BP_PUSHBUTTON, isHotNext ? PBS_HOT : PBS_NORMAL, &rcArrowNext, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
::FillRect(hdc, &rcArrowPrev, isHotPrev ? NppDarkMode::getHotBackgroundBrush() : NppDarkMode::getBackgroundBrush());
|
||||
::FillRect(hdc, &rcArrowNext, isHotNext ? NppDarkMode::getHotBackgroundBrush() : NppDarkMode::getBackgroundBrush());
|
||||
}
|
||||
|
||||
const auto arrowTextFlags = DT_NOPREFIX | DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOCLIP;
|
||||
|
||||
::SetTextColor(hdc, isHotPrev ? NppDarkMode::getTextColor() : NppDarkMode::getDarkerTextColor());
|
||||
::DrawText(hdc, isHorizontal ? L"<" : L"˄", -1, &rcArrowPrev, arrowTextFlags);
|
||||
|
||||
::SetTextColor(hdc, isHotNext ? NppDarkMode::getTextColor() : NppDarkMode::getDarkerTextColor());
|
||||
::DrawText(hdc, isHorizontal ? L">" : L"˅", -1, &rcArrowNext, arrowTextFlags);
|
||||
|
||||
if (!hasTheme)
|
||||
{
|
||||
NppDarkMode::paintRoundFrameRect(hdc, rcArrowPrev, NppDarkMode::getEdgePen());
|
||||
NppDarkMode::paintRoundFrameRect(hdc, rcArrowNext, NppDarkMode::getEdgePen());
|
||||
}
|
||||
|
||||
::EndPaint(hWnd, &ps);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
case WM_DPICHANGED:
|
||||
case WM_DPICHANGED_AFTERPARENT:
|
||||
{
|
||||
pButtonData->closeTheme();
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_THEMECHANGED:
|
||||
{
|
||||
pButtonData->closeTheme();
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_NCDESTROY:
|
||||
{
|
||||
::RemoveWindowSubclass(hWnd, UpDownSubclass, uIdSubclass);
|
||||
delete pButtonData;
|
||||
delete pUpDownData;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2596,47 +2620,138 @@ namespace NppDarkMode
|
||||
{
|
||||
if (NppDarkMode::isEnabled())
|
||||
{
|
||||
RECT rcClient{};
|
||||
::GetClientRect(hWnd, &rcClient);
|
||||
::FillRect(reinterpret_cast<HDC>(wParam), &rcClient, NppDarkMode::getDlgBackgroundBrush());
|
||||
auto hdc = reinterpret_cast<HDC>(wParam);
|
||||
if (hdc != hMemDC)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_PAINT:
|
||||
{
|
||||
if (!NppDarkMode::isEnabled())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
PAINTSTRUCT ps{};
|
||||
HDC hdc = ::BeginPaint(hWnd, &ps);
|
||||
|
||||
if (ps.rcPaint.right <= ps.rcPaint.left || ps.rcPaint.bottom <= ps.rcPaint.top)
|
||||
{
|
||||
::EndPaint(hWnd, &ps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pUpDownData->_isHorizontal && pUpDownData->_isAligned)
|
||||
{
|
||||
::OffsetRect(&ps.rcPaint, 2, 0);
|
||||
}
|
||||
|
||||
RECT rcClient{};
|
||||
::GetClientRect(hWnd, &rcClient);
|
||||
pUpDownData->updateRect(rcClient);
|
||||
if (!pUpDownData->_isHorizontal && pUpDownData->_isAligned)
|
||||
{
|
||||
::OffsetRect(&rcClient, 2, 0);
|
||||
}
|
||||
|
||||
if (bufferData.ensureBuffer(hdc, rcClient))
|
||||
{
|
||||
int savedState = ::SaveDC(hMemDC);
|
||||
::IntersectClipRect(
|
||||
hMemDC,
|
||||
ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom
|
||||
);
|
||||
|
||||
NppDarkMode::paintUpDown(hWnd, hMemDC, *pUpDownData);
|
||||
|
||||
::RestoreDC(hMemDC, savedState);
|
||||
|
||||
::BitBlt(
|
||||
hdc,
|
||||
ps.rcPaint.left, ps.rcPaint.top,
|
||||
ps.rcPaint.right - ps.rcPaint.left,
|
||||
ps.rcPaint.bottom - ps.rcPaint.top,
|
||||
hMemDC,
|
||||
ps.rcPaint.left, ps.rcPaint.top,
|
||||
SRCCOPY
|
||||
);
|
||||
}
|
||||
|
||||
::EndPaint(hWnd, &ps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_DPICHANGED:
|
||||
case WM_DPICHANGED_AFTERPARENT:
|
||||
{
|
||||
pUpDownData->updateRect(hWnd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_MOUSEMOVE:
|
||||
{
|
||||
if (!NppDarkMode::isEnabled())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (pUpDownData->_wasHotNext)
|
||||
{
|
||||
pUpDownData->_wasHotNext = false;
|
||||
::RedrawWindow(hWnd, nullptr, nullptr, RDW_INVALIDATE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_MOUSELEAVE:
|
||||
{
|
||||
if (!NppDarkMode::isEnabled())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
pUpDownData->_wasHotNext = false;
|
||||
::RedrawWindow(hWnd, nullptr, nullptr, RDW_INVALIDATE);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
|
||||
return ::DefSubclassProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static void subclassAndThemeUpDownControl(HWND hwnd, NppDarkModeParams p)
|
||||
bool subclassTabUpDownControl(HWND hWnd)
|
||||
{
|
||||
if (cmpWndClassName(hWnd, UPDOWN_CLASS))
|
||||
{
|
||||
if (::GetWindowSubclass(hWnd, UpDownSubclass, g_upDownSubclassID, nullptr) == FALSE)
|
||||
{
|
||||
auto pUpdownData = reinterpret_cast<DWORD_PTR>(new UpDownData(hWnd));
|
||||
::SetWindowSubclass(hWnd, UpDownSubclass, g_upDownSubclassID, pUpdownData);
|
||||
NppDarkMode::setDarkExplorerTheme(hWnd);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void subclassAndThemeUpDownControl(HWND hWnd, NppDarkModeParams p)
|
||||
{
|
||||
if (p._subclass)
|
||||
{
|
||||
auto pButtonData = reinterpret_cast<DWORD_PTR>(new ButtonData());
|
||||
SetWindowSubclass(hwnd, UpDownSubclass, g_upDownSubclassID, pButtonData);
|
||||
NppDarkMode::subclassTabUpDownControl(hWnd);
|
||||
}
|
||||
|
||||
if (p._theme)
|
||||
else if (p._theme)
|
||||
{
|
||||
SetWindowTheme(hwnd, p._themeClassName, nullptr);
|
||||
::SetWindowTheme(hWnd, p._themeClassName, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool subclassTabUpDownControl(HWND hwnd)
|
||||
{
|
||||
constexpr size_t classNameLen = 16;
|
||||
wchar_t className[classNameLen]{};
|
||||
GetClassName(hwnd, className, classNameLen);
|
||||
if (wcscmp(className, UPDOWN_CLASS) == 0)
|
||||
{
|
||||
auto pButtonData = reinterpret_cast<DWORD_PTR>(new ButtonData());
|
||||
SetWindowSubclass(hwnd, UpDownSubclass, g_upDownSubclassID, pButtonData);
|
||||
NppDarkMode::setDarkExplorerTheme(hwnd);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void setUrlLinkControlColor(HWND hWnd, NppDarkModeParams p)
|
||||
{
|
||||
if (p._theme)
|
||||
@ -2972,7 +3087,7 @@ namespace NppDarkMode
|
||||
{
|
||||
if (NppDarkMode::isWindows11())
|
||||
{
|
||||
roundCornerValue = 5;
|
||||
roundCornerValue = g_win11CornerRoundness + 1;
|
||||
}
|
||||
|
||||
::FillRect(nmtbcd->nmcd.hdc, &nmtbcd->nmcd.rc, NppDarkMode::getDlgBackgroundBrush());
|
||||
@ -3285,7 +3400,7 @@ namespace NppDarkMode
|
||||
static int roundCornerValue = 0;
|
||||
if (NppDarkMode::isWindows11())
|
||||
{
|
||||
roundCornerValue = 5;
|
||||
roundCornerValue = g_win11CornerRoundness + 1;
|
||||
}
|
||||
|
||||
const bool isHot = (rbBand.uChevronState & STATE_SYSTEM_HOTTRACKED) == STATE_SYSTEM_HOTTRACKED;
|
||||
|
Loading…
x
Reference in New Issue
Block a user