From fb82d7904202500867c561d04831eb53a1f82c46 Mon Sep 17 00:00:00 2001 From: ozone10 Date: Sat, 14 Jun 2025 17:46:40 +0200 Subject: [PATCH] Enhance NPPM_DARKMODESUBCLASSANDTHEME: Enable darkmode progress bar for plugins Fix #16675, close #16687 --- PowerEditor/src/NppDarkMode.cpp | 234 ++++++++++++++++++ .../src/ScintillaComponent/FindReplaceDlg.cpp | 11 - 2 files changed, 234 insertions(+), 11 deletions(-) diff --git a/PowerEditor/src/NppDarkMode.cpp b/PowerEditor/src/NppDarkMode.cpp index 7f6a7dfcd..eb6ebcc8f 100644 --- a/PowerEditor/src/NppDarkMode.cpp +++ b/PowerEditor/src/NppDarkMode.cpp @@ -2572,6 +2572,234 @@ namespace NppDarkMode SetWindowSubclass(hwnd, ListViewSubclass, g_listViewSubclassID, 0); } + struct ProgressBarData + { + ThemeData _themeData{ VSCLASS_PROGRESS }; + BufferData _bufferData; + + int _iStateID = PBFS_NORMAL; // PBFS_PARTIAL for cyan color + }; + + static void getProgressBarRects(HWND hWnd, RECT* rcEmpty, RECT* rcFilled) + { + const auto pos = static_cast(::SendMessage(hWnd, PBM_GETPOS, 0, 0)); + + PBRANGE range{}; + ::SendMessage(hWnd, PBM_GETRANGE, TRUE, reinterpret_cast(&range)); + const int iMin = range.iLow; + + const int currPos = pos - iMin; + if (currPos != 0) + { + const int totalWidth = rcEmpty->right - rcEmpty->left; + rcFilled->left = rcEmpty->left; + rcFilled->top = rcEmpty->top; + rcFilled->bottom = rcEmpty->bottom; + rcFilled->right = rcEmpty->left + static_cast(static_cast(currPos) / (range.iHigh - iMin) * totalWidth); + + rcEmpty->left = rcFilled->right; // to avoid painting under filled part + } + } + + static void paintProgressBar(HWND hWnd, HDC hdc, const ProgressBarData& progressBarData) + { + const auto& hTheme = progressBarData._themeData._hTheme; + + RECT rcClient{}; + ::GetClientRect(hWnd, &rcClient); + + NppDarkMode::paintRoundFrameRect(hdc, rcClient, NppDarkMode::getEdgePen(), 0, 0); + + ::InflateRect(&rcClient, -1, -1); + rcClient.left = 1; + + RECT rcFill{}; + NppDarkMode::getProgressBarRects(hWnd, &rcClient, &rcFill); + ::DrawThemeBackground(hTheme, hdc, PP_FILL, progressBarData._iStateID, &rcFill, nullptr); + ::FillRect(hdc, &rcClient, NppDarkMode::getCtrlBackgroundBrush()); + } + + static constexpr UINT_PTR g_progressBarSubclassID = 42; + + static LRESULT CALLBACK ProgressBarSubclass( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam, + UINT_PTR uIdSubclass, + DWORD_PTR dwRefData + ) + { + auto* pProgressBarData = reinterpret_cast(dwRefData); + auto& themeData = pProgressBarData->_themeData; + auto& bufferData = pProgressBarData->_bufferData; + const auto& hMemDC = bufferData._hMemDC; + + switch (uMsg) + { + case WM_NCDESTROY: + { + ::RemoveWindowSubclass(hWnd, ProgressBarSubclass, uIdSubclass); + delete pProgressBarData; + break; + } + + case WM_ERASEBKGND: + { + if (!NppDarkMode::isEnabled() || !themeData.ensureTheme(hWnd)) + { + break; + } + + const auto* hdc = reinterpret_cast(wParam); + if (hdc != hMemDC) + { + return FALSE; + } + return TRUE; + } + + 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; + } + + RECT rcClient{}; + ::GetClientRect(hWnd, &rcClient); + + if (bufferData.ensureBuffer(hdc, rcClient)) + { + const int savedState = ::SaveDC(hMemDC); + ::IntersectClipRect( + hMemDC, + ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom + ); + + NppDarkMode::paintProgressBar(hWnd, hMemDC, *pProgressBarData); + + ::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: + { + themeData.closeTheme(); + return 0; + } + + case WM_THEMECHANGED: + { + themeData.closeTheme(); + break; + } + + case PBM_SETSTATE: + { + switch (wParam) + { + case PBST_NORMAL: + { + pProgressBarData->_iStateID = PBFS_NORMAL; // green + break; + } + + case PBST_ERROR: + { + pProgressBarData->_iStateID = PBFS_ERROR; // red + break; + } + + case PBST_PAUSED: + { + pProgressBarData->_iStateID = PBFS_PAUSED; // yellow + break; + } + + default: + { + break; + } + } + break; + } + + default: + { + break; + } + } + return ::DefSubclassProc(hWnd, uMsg, wParam, lParam); + } + + static void subclassProgressBar(HWND hWnd) + { + if (::GetWindowSubclass(hWnd, ProgressBarSubclass, g_progressBarSubclassID, nullptr) == FALSE) + { + auto pProgressBarData = reinterpret_cast(new ProgressBarData()); + ::SetWindowSubclass(hWnd, ProgressBarSubclass, g_progressBarSubclassID, pProgressBarData); + } + } + + static void setProgressBarClassicTheme(HWND hWnd) + { + auto nStyle = ::GetWindowLongPtr(hWnd, GWL_STYLE); + const bool hasFlag = (nStyle & WS_DLGFRAME) == WS_DLGFRAME; + + if (NppDarkMode::isEnabled() != hasFlag) + { + nStyle ^= WS_DLGFRAME; + ::SetWindowLongPtr(hWnd, GWL_STYLE, nStyle); + } + + NppDarkMode::disableVisualStyle(hWnd, NppDarkMode::isEnabled()); + if (NppDarkMode::isEnabled()) + { + ::SendMessage(hWnd, PBM_SETBKCOLOR, 0, static_cast(NppDarkMode::getBackgroundColor())); + static constexpr COLORREF greenFill = HEXRGB(0x06B025); + ::SendMessage(hWnd, PBM_SETBARCOLOR, 0, static_cast(greenFill)); + } + } + + static void subclassAndThemeProgressBar(HWND hWnd, NppDarkModeParams p) + { + if (p._theme) + { + if (p._subclass) + { + NppDarkMode::subclassProgressBar(hWnd); + } + } + else + { + NppDarkMode::setProgressBarClassicTheme(hWnd); + } + } + struct UpDownData { BufferData _bufferData; @@ -2938,6 +3166,12 @@ namespace NppDarkMode return TRUE; } + if (wcscmp(className, PROGRESS_CLASS) == 0) + { + NppDarkMode::subclassAndThemeProgressBar(hwnd, p); + return TRUE; + } + // Plugin might use rich edit control version 2.0 and later if (wcscmp(className, L"RichEdit20W") == 0 || wcscmp(className, L"RICHEDIT50W") == 0) { diff --git a/PowerEditor/src/ScintillaComponent/FindReplaceDlg.cpp b/PowerEditor/src/ScintillaComponent/FindReplaceDlg.cpp index 2f49c83e1..212625432 100644 --- a/PowerEditor/src/ScintillaComponent/FindReplaceDlg.cpp +++ b/PowerEditor/src/ScintillaComponent/FindReplaceDlg.cpp @@ -6447,17 +6447,6 @@ int Progress::createProgressWindow() ::SendMessage(_hPBar, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); - // Set border so user can distinguish easier progress bar, - // especially, when getBackgroundColor is very similar or same - // as getDlgBackgroundColor - NppDarkMode::setBorder(_hPBar, NppDarkMode::isEnabled()); - NppDarkMode::disableVisualStyle(_hPBar, NppDarkMode::isEnabled()); - if (NppDarkMode::isEnabled()) - { - ::SendMessage(_hPBar, PBM_SETBKCOLOR, 0, static_cast(NppDarkMode::getBackgroundColor())); - ::SendMessage(_hPBar, PBM_SETBARCOLOR, 0, static_cast(NppDarkMode::getDarkerTextColor())); - } - wstring cancel = pNativeSpeaker->getLocalizedStrFromID("common-cancel", L"Cancel"); _hBtn = ::CreateWindowEx(0, WC_BUTTON, cancel.c_str(), WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,