Enhance NPPM_DARKMODESUBCLASSANDTHEME: Enable darkmode progress bar for plugins

Fix #16675, close #16687
This commit is contained in:
ozone10 2025-06-14 17:46:40 +02:00 committed by Don Ho
parent 2214d10ce2
commit fb82d79042
2 changed files with 234 additions and 11 deletions

View File

@ -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<int>(::SendMessage(hWnd, PBM_GETPOS, 0, 0));
PBRANGE range{};
::SendMessage(hWnd, PBM_GETRANGE, TRUE, reinterpret_cast<LPARAM>(&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<int>(static_cast<double>(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<ProgressBarData*>(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<HDC>(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<DWORD_PTR>(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<LPARAM>(NppDarkMode::getBackgroundColor()));
static constexpr COLORREF greenFill = HEXRGB(0x06B025);
::SendMessage(hWnd, PBM_SETBARCOLOR, 0, static_cast<LPARAM>(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)
{

View File

@ -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<LPARAM>(NppDarkMode::getBackgroundColor()));
::SendMessage(_hPBar, PBM_SETBARCOLOR, 0, static_cast<LPARAM>(NppDarkMode::getDarkerTextColor()));
}
wstring cancel = pNativeSpeaker->getLocalizedStrFromID("common-cancel", L"Cancel");
_hBtn = ::CreateWindowEx(0, WC_BUTTON, cancel.c_str(),
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,