diff --git a/NppDarkMode.cpp b/NppDarkMode.cpp deleted file mode 100644 index 07e0490..0000000 --- a/NppDarkMode.cpp +++ /dev/null @@ -1,3241 +0,0 @@ -// This file is part of Notepad++ project -// Copyright (C)2021 adzm / Adam D. Walling - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// at your option any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - - -#include "NppDarkMode.h" - -#include "DarkMode/DarkMode.h" -#include "DarkMode/UAHMenuBar.h" - -#include -#include -#include - -#include "Parameters.h" -#include "resource.h" - -#include - -#include - -#ifdef __GNUC__ -#include -#define WINAPI_LAMBDA WINAPI -#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE -#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 -#endif -#else -#define WINAPI_LAMBDA -#endif - -// already added in project files -// keep for plugin authors -//#ifdef _MSC_VER -//#pragma comment(lib, "dwmapi.lib") -//#pragma comment(lib, "uxtheme.lib") -//#endif - -constexpr COLORREF HEXRGB(DWORD rrggbb) { - // from 0xRRGGBB like natural #RRGGBB - // to the little-endian 0xBBGGRR - return - ((rrggbb & 0xFF0000) >> 16) | - ((rrggbb & 0x00FF00)) | - ((rrggbb & 0x0000FF) << 16); -} - -namespace NppDarkMode -{ - struct Brushes//结构体用于管理颜色和画笔 - { - HBRUSH background = nullptr; - HBRUSH softerBackground = nullptr; - HBRUSH hotBackground = nullptr; - HBRUSH pureBackground = nullptr; - HBRUSH errorBackground = nullptr; - //HBRUSH 类型的成员变量,用于存储不同背景颜色的画刷对象 - HBRUSH edgeBrush = nullptr; - HBRUSH hotEdgeBrush = nullptr; - HBRUSH disabledEdgeBrush = nullptr; - - Brushes(const Colors& colors) - //构造函数:接受一个 Colors 对象作为参数,使用 CreateSolidBrush 函数创建相应颜色的画刷对象。 - : background(::CreateSolidBrush(colors.background)) - , softerBackground(::CreateSolidBrush(colors.softerBackground)) - , hotBackground(::CreateSolidBrush(colors.hotBackground)) - , pureBackground(::CreateSolidBrush(colors.pureBackground)) - , errorBackground(::CreateSolidBrush(colors.errorBackground)) - - , edgeBrush(::CreateSolidBrush(colors.edge)) - , hotEdgeBrush(::CreateSolidBrush(colors.hotEdge)) - , disabledEdgeBrush(::CreateSolidBrush(colors.disabledEdge)) - {} - - ~Brushes()//析构函数 释放所有画刷对象,使用 DeleteObject 函数 - { - ::DeleteObject(background); background = nullptr; - ::DeleteObject(softerBackground); softerBackground = nullptr; - ::DeleteObject(hotBackground); hotBackground = nullptr; - ::DeleteObject(pureBackground); pureBackground = nullptr; - ::DeleteObject(errorBackground); errorBackground = nullptr; - - ::DeleteObject(edgeBrush); edgeBrush = nullptr; - ::DeleteObject(hotEdgeBrush); hotEdgeBrush = nullptr; - ::DeleteObject(disabledEdgeBrush); disabledEdgeBrush = nullptr; - } - - void change(const Colors& colors)//change 函数:用于更改颜色,首先释放当前的画刷对象,然后创建新的画刷对象 - { - ::DeleteObject(background); - ::DeleteObject(softerBackground); - ::DeleteObject(hotBackground); - ::DeleteObject(pureBackground); - ::DeleteObject(errorBackground); - - ::DeleteObject(edgeBrush); - ::DeleteObject(hotEdgeBrush); - ::DeleteObject(disabledEdgeBrush); - - background = ::CreateSolidBrush(colors.background); - softerBackground = ::CreateSolidBrush(colors.softerBackground); - hotBackground = ::CreateSolidBrush(colors.hotBackground); - pureBackground = ::CreateSolidBrush(colors.pureBackground); - errorBackground = ::CreateSolidBrush(colors.errorBackground); - - edgeBrush = ::CreateSolidBrush(colors.edge); - hotEdgeBrush = ::CreateSolidBrush(colors.hotEdge); - disabledEdgeBrush = ::CreateSolidBrush(colors.disabledEdge); - } - }; - - struct Pens - { - HPEN darkerTextPen = nullptr; - HPEN edgePen = nullptr; - HPEN hotEdgePen = nullptr; - HPEN disabledEdgePen = nullptr; - //HPEN 类型的成员变量,用于存储不同颜色的画笔对象 - Pens(const Colors& colors) - //构造函数 接受一个 Colors 对象作为参数,使用 CreatePen 函数创建相应颜色的画笔对象 - : darkerTextPen(::CreatePen(PS_SOLID, 1, colors.darkerText)) - , edgePen(::CreatePen(PS_SOLID, 1, colors.edge)) - , hotEdgePen(::CreatePen(PS_SOLID, 1, colors.hotEdge)) - , disabledEdgePen(::CreatePen(PS_SOLID, 1, colors.disabledEdge)) - {} - - ~Pens() - {//析构函数:释放所有画笔对象,使用 DeleteObject 函数 - ::DeleteObject(darkerTextPen); darkerTextPen = nullptr; - ::DeleteObject(edgePen); edgePen = nullptr; - ::DeleteObject(hotEdgePen); hotEdgePen = nullptr; - ::DeleteObject(disabledEdgePen); disabledEdgePen = nullptr; - } - - void change(const Colors& colors) - {//change 函数:用于更改颜色,首先释放当前的画笔对象,然后创建新的画笔对象 - ::DeleteObject(darkerTextPen); - ::DeleteObject(edgePen); - ::DeleteObject(hotEdgePen); - ::DeleteObject(disabledEdgePen); - - darkerTextPen = ::CreatePen(PS_SOLID, 1, colors.darkerText); - edgePen = ::CreatePen(PS_SOLID, 1, colors.edge); - hotEdgePen = ::CreatePen(PS_SOLID, 1, colors.hotEdge); - disabledEdgePen = ::CreatePen(PS_SOLID, 1, colors.disabledEdge); - } - - }; - - // black (default) - static const Colors darkColors{ - HEXRGB(0x202020), // background - HEXRGB(0x404040), // softerBackground - HEXRGB(0x404040), // hotBackground - HEXRGB(0x202020), // pureBackground - HEXRGB(0xB00000), // errorBackground - HEXRGB(0xE0E0E0), // textColor - HEXRGB(0xC0C0C0), // darkerTextColor - HEXRGB(0x808080), // disabledTextColor - HEXRGB(0xFFFF00), // linkTextColor - HEXRGB(0x646464), // edgeColor - HEXRGB(0x9B9B9B), // hotEdgeColor - HEXRGB(0x484848) // disabledEdgeColor - }; - - // red tone - static const Colors darkRedColors{ - HEXRGB(0x302020), // background - HEXRGB(0x504040), // softerBackground - HEXRGB(0x504040), // hotBackground - HEXRGB(0x302020), // pureBackground - HEXRGB(0xC00000), // errorBackground - HEXRGB(0xE0E0E0), // textColor - HEXRGB(0xC0C0C0), // darkerTextColor - HEXRGB(0x808080), // disabledTextColor - HEXRGB(0xFFFF00), // linkTextColor - HEXRGB(0x908080), // edgeColor - HEXRGB(0xBBABAB), // hotEdgeColor - HEXRGB(0x584848) // disabledEdgeColor - }; - - // green tone - static const Colors darkGreenColors{ - HEXRGB(0x203020), // background - HEXRGB(0x405040), // softerBackground - HEXRGB(0x405040), // hotBackground - HEXRGB(0x203020), // pureBackground - HEXRGB(0xB01000), // errorBackground - HEXRGB(0xE0E0E0), // textColor - HEXRGB(0xC0C0C0), // darkerTextColor - HEXRGB(0x808080), // disabledTextColor - HEXRGB(0xFFFF00), // linkTextColor - HEXRGB(0x809080), // edgeColor - HEXRGB(0xABBBAB), // hotEdgeColor - HEXRGB(0x485848) // disabledEdgeColor - }; - - // blue tone - static const Colors darkBlueColors{ - HEXRGB(0x202040), // background - HEXRGB(0x404060), // softerBackground - HEXRGB(0x404060), // hotBackground - HEXRGB(0x202040), // pureBackground - HEXRGB(0xB00020), // errorBackground - HEXRGB(0xE0E0E0), // textColor - HEXRGB(0xC0C0C0), // darkerTextColor - HEXRGB(0x808080), // disabledTextColor - HEXRGB(0xFFFF00), // linkTextColor - HEXRGB(0x8080A0), // edgeColor - HEXRGB(0xABABCB), // hotEdgeColor - HEXRGB(0x484868) // disabledEdgeColor - }; - - // purple tone - static const Colors darkPurpleColors{ - HEXRGB(0x302040), // background - HEXRGB(0x504060), // softerBackground - HEXRGB(0x504060), // hotBackground - HEXRGB(0x302040), // pureBackground - HEXRGB(0xC00020), // errorBackground - HEXRGB(0xE0E0E0), // textColor - HEXRGB(0xC0C0C0), // darkerTextColor - HEXRGB(0x808080), // disabledTextColor - HEXRGB(0xFFFF00), // linkTextColor - HEXRGB(0x9080A0), // edgeColor - HEXRGB(0xBBABCB), // hotEdgeColor - HEXRGB(0x584868) // disabledEdgeColor - }; - - // cyan tone - static const Colors darkCyanColors{ - HEXRGB(0x203040), // background - HEXRGB(0x405060), // softerBackground - HEXRGB(0x405060), // hotBackground - HEXRGB(0x203040), // pureBackground - HEXRGB(0xB01020), // errorBackground - HEXRGB(0xE0E0E0), // textColor - HEXRGB(0xC0C0C0), // darkerTextColor - HEXRGB(0x808080), // disabledTextColor - HEXRGB(0xFFFF00), // linkTextColor - HEXRGB(0x8090A0), // edgeColor - HEXRGB(0xBBBBCB), // hotEdgeColor - HEXRGB(0x485868) // disabledEdgeColor - }; - - // olive tone - static const Colors darkOliveColors{ - HEXRGB(0x303020), // background - HEXRGB(0x505040), // softerBackground - HEXRGB(0x505040), // hotBackground - HEXRGB(0x303020), // pureBackground - HEXRGB(0xC01000), // errorBackground - HEXRGB(0xE0E0E0), // textColor - HEXRGB(0xC0C0C0), // darkerTextColor - HEXRGB(0x808080), // disabledTextColor - HEXRGB(0xFFFF00), // linkTextColor - HEXRGB(0x909080), // edgeColor - HEXRGB(0xBBBBAB), // hotEdgeColor - HEXRGB(0x585848) // disabledEdgeColor - }; - - // customized - Colors darkCustomizedColors{ - HEXRGB(0x202020), // background - HEXRGB(0x404040), // softerBackground - HEXRGB(0x404040), // hotBackground - HEXRGB(0x202020), // pureBackground - HEXRGB(0xB00000), // errorBackground - HEXRGB(0xE0E0E0), // textColor - HEXRGB(0xC0C0C0), // darkerTextColor - HEXRGB(0x808080), // disabledTextColor - HEXRGB(0xFFFF00), // linkTextColor - HEXRGB(0x646464), // edgeColor - HEXRGB(0x9B9B9B), // hotEdgeColor - HEXRGB(0x484848) // disabledEdgeColor - }; - - ColorTone g_colorToneChoice = blackTone; - - void setDarkTone(ColorTone colorToneChoice) - { - g_colorToneChoice = colorToneChoice; - } - // 定义主题结构体,包含颜色、画刷和画笔 - struct Theme - { - Colors _colors; // 存储颜色 - Brushes _brushes; // 管理画刷 - Pens _pens; // 管理画笔 - - // 构造函数,初始化颜色、画刷和画笔 - Theme(const Colors& colors) - : _colors(colors), _brushes(colors), _pens(colors) - {} - - // 更改主题颜色 - void change(const Colors& colors) - { - _colors = colors; // 更新颜色 - _brushes.change(colors); // 更改画刷颜色 - _pens.change(colors); // 更改画笔颜色 - } - }; - - // 定义不同主题的实例 - Theme tDefault(darkColors); // 默认主题 - Theme tR(darkRedColors); // 红色主题 - Theme tG(darkGreenColors); // 绿色主题 - Theme tB(darkBlueColors); // 蓝色主题 - Theme tP(darkPurpleColors); // 紫色主题 - Theme tC(darkCyanColors); // 青色主题 - Theme tO(darkOliveColors); // 橄榄色主题 - Theme tCustom(darkCustomizedColors); // 自定义主题 - - // 获取当前主题 - Theme& getTheme() - { - switch (g_colorToneChoice) - { - case redTone: - return tR; // 返回红色主题 - - case greenTone: - return tG; // 返回绿色主题 - - case blueTone: - return tB; // 返回蓝色主题 - - case purpleTone: - return tP; // 返回紫色主题 - - case cyanTone: - return tC; // 返回青色主题 - - case oliveTone: - return tO; // 返回橄榄色主题 - - case customizedTone: - return tCustom; // 返回自定义主题 - - default: - return tDefault; // 返回默认主题 - } - } - - // 获取已配置的选项 - Options configuredOptions() - { - NppGUI nppGui = NppParameters::getInstance().getNppGUI(); - Options opt; - opt.enable = nppGui._darkmode._isEnabled; // 设置是否启用暗模式 - opt.enableMenubar = opt.enable; // 设置是否启用菜单栏 - opt.enablePlugin = nppGui._darkmode._isEnabledPlugin; // 设置是否启用插件 - - g_colorToneChoice = nppGui._darkmode._colorTone; // 设置颜色调色板选择 - tCustom.change(nppGui._darkmode._customColors); // 更改自定义主题的颜色 - - return opt; // 返回选项 - } - - // 初始化暗模式 - void initDarkMode() - { - _options = configuredOptions(); // 设置选项 - - initExperimentalDarkMode(); // 初始化实验性暗模式 - initAdvancedOptions(); // 初始化高级选项 - - g_isAtLeastWindows10 = NppDarkMode::isWindows10(); // 判断是否至少为 Windows 10 - - if (!g_isAtLeastWindows10) - { - g_advOptions._enableWindowsMode = false; // 如果不是 Windows 10,则禁用 Windows 模式 - } - else if (NppDarkMode::isWindowsModeEnabled()) - { - NppParameters& nppParam = NppParameters::getInstance(); - NppGUI& nppGUI = nppParam.getNppGUI(); - nppGUI._darkmode._isEnabled = NppDarkMode::isDarkModeReg() && !IsHighContrast(); // 检查并设置暗模式状态 - _options.enable = nppGUI._darkmode._isEnabled; // 更新选项中的暗模式状态 - _options.enableMenubar = _options.enable; // 更新选项中的菜单栏状态 - } - } - - setDarkMode(_options.enable, true); - - using PWINEGETVERSION = const CHAR* (__cdecl *)(void); - - PWINEGETVERSION pWGV = nullptr; - auto hNtdllModule = GetModuleHandle(L"ntdll.dll"); - if (hNtdllModule) - { - pWGV = reinterpret_cast(GetProcAddress(hNtdllModule, "wine_get_version")); - } - - g_isWine = pWGV != nullptr; - } - - // attempts to apply new options from NppParameters, sends NPPM_INTERNAL_REFRESHDARKMODE to hwnd's top level parent - void refreshDarkMode(HWND hwnd, bool forceRefresh) - { - bool supportedChanged = false; - - auto config = configuredOptions(); - - if (_options.enable != config.enable) - { - supportedChanged = true; - _options.enable = config.enable; - setDarkMode(_options.enable, _options.enable); - } - - if (_options.enableMenubar != config.enableMenubar) - { - supportedChanged = true; - _options.enableMenubar = config.enableMenubar; - } - - // other options not supported to change at runtime currently - - if (!supportedChanged && !forceRefresh) - { - // nothing to refresh, changes were not supported. - return; - } - - HWND hwndRoot = GetAncestor(hwnd, GA_ROOTOWNER); - - // wParam == true, will reset style and toolbar icon - ::SendMessage(hwndRoot, NPPM_INTERNAL_REFRESHDARKMODE, static_cast(!forceRefresh), 0); - } - - void initAdvancedOptions() - { - NppGUI& nppGui = NppParameters::getInstance().getNppGUI(); - g_advOptions = nppGui._darkmode._advOptions; - } - - bool isEnabled() - { - return _options.enable; - } - - bool isEnabledForPlugins() - { - return _options.enablePlugin; - } - - bool isDarkMenuEnabled() - { - return _options.enableMenubar; - } - - bool isExperimentalActive() - { - return g_darkModeEnabled; - } - - bool isExperimentalSupported() - { - return g_darkModeSupported; - } - - bool isWindowsModeEnabled() - { - return g_advOptions._enableWindowsMode; - } - - void setWindowsMode(bool enable) - { - g_advOptions._enableWindowsMode = enable; - } - - void setThemeName(const generic_string& newThemeName) - { - if (NppDarkMode::isEnabled()) - g_advOptions._darkDefaults._xmlFileName = newThemeName; - else - g_advOptions._lightDefaults._xmlFileName = newThemeName; - } - - generic_string getThemeName() - { - auto& theme = NppDarkMode::isEnabled() ? g_advOptions._darkDefaults._xmlFileName : g_advOptions._lightDefaults._xmlFileName; - return (lstrcmp(theme.c_str(), L"stylers.xml") == 0) ? L"" : theme; - } - - static bool g_isCustomToolIconUsed = NppParameters::getInstance().getCustomizedToolIcons() != nullptr; - - void setToolBarIconSet(int state2Set, bool useDark) - { - if (useDark) - g_advOptions._darkDefaults._toolBarIconSet = state2Set; - else - g_advOptions._lightDefaults._toolBarIconSet = state2Set; - } - - int getToolBarIconSet(bool useDark) - { - if (g_isCustomToolIconUsed) - { - return -1; - } - return useDark ? g_advOptions._darkDefaults._toolBarIconSet : g_advOptions._lightDefaults._toolBarIconSet; - } - - void setTabIconSet(bool useAltIcons, bool useDark) - { - if (useDark) - g_advOptions._darkDefaults._tabIconSet = useAltIcons ? 1 : 2; - else - g_advOptions._lightDefaults._tabIconSet = useAltIcons ? 1 : 0; - } - - int getTabIconSet(bool useDark) - { - return useDark ? g_advOptions._darkDefaults._tabIconSet : g_advOptions._lightDefaults._tabIconSet; - } - - bool useTabTheme() - { - return NppDarkMode::isEnabled() ? g_advOptions._darkDefaults._tabUseTheme : g_advOptions._lightDefaults._tabUseTheme; - } - - void setAdvancedOptions() - { - NppGUI& nppGui = NppParameters::getInstance().getNppGUI(); - auto& advOpt = nppGui._darkmode._advOptions; - - advOpt = g_advOptions; - } - - bool isWindows10() - { - return IsWindows10(); - } - - bool isWindows11() - { - return IsWindows11(); - } - - DWORD getWindowsBuildNumber() - { - return GetWindowsBuildNumber(); - } - - COLORREF invertLightness(COLORREF c) - { - WORD h = 0; - WORD s = 0; - WORD l = 0; - ColorRGBToHLS(c, &h, &l, &s); - - l = 240 - l; - - COLORREF invert_c = ColorHLSToRGB(h, l, s); - - return invert_c; - } - - COLORREF invertLightnessSofter(COLORREF c) - { - WORD h = 0; - WORD s = 0; - WORD l = 0; - ColorRGBToHLS(c, &h, &l, &s); - - l = std::min(240U - l, 211U); - - COLORREF invert_c = ColorHLSToRGB(h, l, s); - - return invert_c; - } - - static TreeViewStyle g_treeViewStyle = TreeViewStyle::classic; - static COLORREF g_treeViewBg = NppParameters::getInstance().getCurrentDefaultBgColor(); - static double g_lighnessTreeView = 50.0; - - // adapted from https://stackoverflow.com/a/56678483 - double calculatePerceivedLighness(COLORREF c) - { - auto linearValue = [](double colorChannel) -> double - { - colorChannel /= 255.0; - if (colorChannel <= 0.04045) - return colorChannel / 12.92; - return std::pow(((colorChannel + 0.055) / 1.055), 2.4); - }; - - double r = linearValue(static_cast(GetRValue(c))); - double g = linearValue(static_cast(GetGValue(c))); - double b = linearValue(static_cast(GetBValue(c))); - - double luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b; - - double lighness = (luminance <= 216.0 / 24389.0) ? (luminance * 24389.0 / 27.0) : (std::pow(luminance, (1.0 / 3.0)) * 116.0 - 16.0); - return lighness; - } - - COLORREF getBackgroundColor() { return getTheme()._colors.background; } - COLORREF getSofterBackgroundColor() { return getTheme()._colors.softerBackground; } - COLORREF getHotBackgroundColor() { return getTheme()._colors.hotBackground; } - COLORREF getDarkerBackgroundColor() { return getTheme()._colors.pureBackground; } - COLORREF getErrorBackgroundColor() { return getTheme()._colors.errorBackground; } - COLORREF getTextColor() { return getTheme()._colors.text; } - COLORREF getDarkerTextColor() { return getTheme()._colors.darkerText; } - COLORREF getDisabledTextColor() { return getTheme()._colors.disabledText; } - COLORREF getLinkTextColor() { return getTheme()._colors.linkText; } - COLORREF getEdgeColor() { return getTheme()._colors.edge; } - COLORREF getHotEdgeColor() { return getTheme()._colors.hotEdge; } - COLORREF getDisabledEdgeColor() { return getTheme()._colors.disabledEdge; } - - HBRUSH getBackgroundBrush() { return getTheme()._brushes.background; } - HBRUSH getSofterBackgroundBrush() { return getTheme()._brushes.softerBackground; } - HBRUSH getHotBackgroundBrush() { return getTheme()._brushes.hotBackground; } - HBRUSH getDarkerBackgroundBrush() { return getTheme()._brushes.pureBackground; } - HBRUSH getErrorBackgroundBrush() { return getTheme()._brushes.errorBackground; } - - HBRUSH getEdgeBrush() { return getTheme()._brushes.edgeBrush; } - HBRUSH getHotEdgeBrush() { return getTheme()._brushes.hotEdgeBrush; } - HBRUSH getDisabledEdgeBrush() { return getTheme()._brushes.disabledEdgeBrush; } - - HPEN getDarkerTextPen() { return getTheme()._pens.darkerTextPen; } - HPEN getEdgePen() { return getTheme()._pens.edgePen; } - HPEN getHotEdgePen() { return getTheme()._pens.hotEdgePen; } - HPEN getDisabledEdgePen() { return getTheme()._pens.disabledEdgePen; } - - void setBackgroundColor(COLORREF c) - { - Colors clrs = getTheme()._colors; - clrs.background = c; - getTheme().change(clrs); - } - - void setSofterBackgroundColor(COLORREF c) - { - Colors clrs = getTheme()._colors; - clrs.softerBackground = c; - getTheme().change(clrs); - } - - void setHotBackgroundColor(COLORREF c) - { - Colors clrs = getTheme()._colors; - clrs.hotBackground = c; - getTheme().change(clrs); - } - - void setDarkerBackgroundColor(COLORREF c) - { - Colors clrs = getTheme()._colors; - clrs.pureBackground = c; - getTheme().change(clrs); - } - - void setErrorBackgroundColor(COLORREF c) - { - Colors clrs = getTheme()._colors; - clrs.errorBackground = c; - getTheme().change(clrs); - } - - void setTextColor(COLORREF c) - { - Colors clrs = getTheme()._colors; - clrs.text = c; - getTheme().change(clrs); - } - - void setDarkerTextColor(COLORREF c) - { - Colors clrs = getTheme()._colors; - clrs.darkerText = c; - getTheme().change(clrs); - } - - void setDisabledTextColor(COLORREF c) - { - Colors clrs = getTheme()._colors; - clrs.disabledText = c; - getTheme().change(clrs); - } - - void setLinkTextColor(COLORREF c) - { - Colors clrs = getTheme()._colors; - clrs.linkText = c; - getTheme().change(clrs); - } - - void setEdgeColor(COLORREF c) - { - Colors clrs = getTheme()._colors; - clrs.edge = c; - getTheme().change(clrs); - } - - void setHotEdgeColor(COLORREF c) - { - Colors clrs = getTheme()._colors; - clrs.hotEdge = c; - getTheme().change(clrs); - } - - void setDisabledEdgeColor(COLORREF c) - { - Colors clrs = getTheme()._colors; - clrs.disabledEdge = c; - getTheme().change(clrs); - } - - Colors getDarkModeDefaultColors() - { - return darkColors; - } - - void changeCustomTheme(const Colors& colors) - { - tCustom.change(colors); - } - - // handle events - - void handleSettingChange(HWND hwnd, LPARAM lParam, bool isFromBtn) - { - UNREFERENCED_PARAMETER(hwnd); - - if (!isExperimentalSupported()) - { - return; - } - - if (IsColorSchemeChangeMessage(lParam) || isFromBtn) - { - // ShouldAppsUseDarkMode() is not reliable from 1903+, use NppDarkMode::isDarkModeReg() instead - g_darkModeEnabled = NppDarkMode::isDarkModeReg() && !IsHighContrast(); - } - } - - bool isDarkModeReg() - { - DWORD data{}; - DWORD dwBufSize = sizeof(data); - LPCTSTR lpSubKey = L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; - LPCTSTR lpValue = L"AppsUseLightTheme"; - - auto result = RegGetValue(HKEY_CURRENT_USER, lpSubKey, lpValue, RRF_RT_REG_DWORD, nullptr, &data, &dwBufSize); - if (result != ERROR_SUCCESS) - { - return false; - } - - // dark mode is 0, light mode is 1 - return data == 0UL; - } - - // processes messages related to UAH / custom menubar drawing. - // return true if handled, false to continue with normal processing in your wndproc - bool runUAHWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* lr) - { - static HTHEME g_menuTheme = nullptr; - - UNREFERENCED_PARAMETER(wParam); - switch (message) - { - case WM_UAHDRAWMENU: - { - UAHMENU* pUDM = (UAHMENU*)lParam; - RECT rc{}; - - // get the menubar rect - { - MENUBARINFO mbi{}; - mbi.cbSize = sizeof(MENUBARINFO); - GetMenuBarInfo(hWnd, OBJID_MENU, 0, &mbi); - - RECT rcWindow{}; - GetWindowRect(hWnd, &rcWindow); - - // the rcBar is offset by the window rect - rc = mbi.rcBar; - OffsetRect(&rc, -rcWindow.left, -rcWindow.top); - - rc.top -= 1; - } - - FillRect(pUDM->hdc, &rc, NppDarkMode::getDarkerBackgroundBrush()); - - *lr = 0; - - return true; - } - case WM_UAHDRAWMENUITEM: - { - UAHDRAWMENUITEM* pUDMI = (UAHDRAWMENUITEM*)lParam; - - // get the menu item string - wchar_t menuString[256] = { '\0' }; - MENUITEMINFO mii{}; - { - mii.cbSize = sizeof(MENUITEMINFO); - mii.fMask = MIIM_STRING; - mii.dwTypeData = menuString; - mii.cch = (sizeof(menuString) / 2) - 1; - - GetMenuItemInfo(pUDMI->um.hmenu, pUDMI->umi.iPosition, TRUE, &mii); - } - - // get the item state for drawing - - DWORD dwFlags = DT_CENTER | DT_SINGLELINE | DT_VCENTER; - - int iTextStateID = MPI_NORMAL; - int iBackgroundStateID = MPI_NORMAL; - { - if ((pUDMI->dis.itemState & ODS_INACTIVE) | (pUDMI->dis.itemState & ODS_DEFAULT)) - { - // normal display - iTextStateID = MPI_NORMAL; - iBackgroundStateID = MPI_NORMAL; - } - if (pUDMI->dis.itemState & ODS_HOTLIGHT) - { - // hot tracking - iTextStateID = MPI_HOT; - iBackgroundStateID = MPI_HOT; - } - if (pUDMI->dis.itemState & ODS_SELECTED) - { - // clicked -- MENU_POPUPITEM has no state for this, though MENU_BARITEM does - iTextStateID = MPI_HOT; - iBackgroundStateID = MPI_HOT; - } - if ((pUDMI->dis.itemState & ODS_GRAYED) || (pUDMI->dis.itemState & ODS_DISABLED)) - { - // disabled / grey text - iTextStateID = MPI_DISABLED; - iBackgroundStateID = MPI_DISABLED; - } - if (pUDMI->dis.itemState & ODS_NOACCEL) - { - dwFlags |= DT_HIDEPREFIX; - } - } - - if (!g_menuTheme) - { - g_menuTheme = OpenThemeData(hWnd, L"Menu"); - } - - if (iBackgroundStateID == MPI_NORMAL || iBackgroundStateID == MPI_DISABLED) - { - FillRect(pUDMI->um.hdc, &pUDMI->dis.rcItem, NppDarkMode::getDarkerBackgroundBrush()); - } - else if (iBackgroundStateID == MPI_HOT || iBackgroundStateID == MPI_DISABLEDHOT) - { - FillRect(pUDMI->um.hdc, &pUDMI->dis.rcItem, NppDarkMode::getHotBackgroundBrush()); - } - else - { - DrawThemeBackground(g_menuTheme, pUDMI->um.hdc, MENU_POPUPITEM, iBackgroundStateID, &pUDMI->dis.rcItem, nullptr); - } - DTTOPTS dttopts{}; - dttopts.dwSize = sizeof(DTTOPTS); - if (iTextStateID == MPI_NORMAL || iTextStateID == MPI_HOT) - { - dttopts.dwFlags |= DTT_TEXTCOLOR; - dttopts.crText = NppDarkMode::getTextColor(); - } - DrawThemeTextEx(g_menuTheme, pUDMI->um.hdc, MENU_POPUPITEM, iTextStateID, menuString, mii.cch, dwFlags, &pUDMI->dis.rcItem, &dttopts); - - *lr = 0; - - return true; - } - case WM_THEMECHANGED: - { - if (g_menuTheme) - { - CloseThemeData(g_menuTheme); - g_menuTheme = nullptr; - } - // continue processing in main wndproc - return false; - } - default: - return false; - } - } - - void drawUAHMenuNCBottomLine(HWND hWnd) - { - MENUBARINFO mbi{}; - mbi.cbSize = sizeof(MENUBARINFO); - if (!GetMenuBarInfo(hWnd, OBJID_MENU, 0, &mbi)) - { - return; - } - - RECT rcClient{}; - GetClientRect(hWnd, &rcClient); - MapWindowPoints(hWnd, nullptr, (POINT*)&rcClient, 2); - - RECT rcWindow{}; - GetWindowRect(hWnd, &rcWindow); - - OffsetRect(&rcClient, -rcWindow.left, -rcWindow.top); - - // the rcBar is offset by the window rect - RECT rcAnnoyingLine = rcClient; - rcAnnoyingLine.bottom = rcAnnoyingLine.top; - rcAnnoyingLine.top--; - - - HDC hdc = GetWindowDC(hWnd); - FillRect(hdc, &rcAnnoyingLine, NppDarkMode::getDarkerBackgroundBrush()); - ReleaseDC(hWnd, hdc); - } - - // from DarkMode.h - - void initExperimentalDarkMode() - { - ::InitDarkMode(); - } - - void setDarkMode(bool useDark, bool fixDarkScrollbar) - { - ::SetDarkMode(useDark, fixDarkScrollbar); - } - - void allowDarkModeForApp(bool allow) - { - ::AllowDarkModeForApp(allow); - } - - bool allowDarkModeForWindow(HWND hWnd, bool allow) - { - return ::AllowDarkModeForWindow(hWnd, allow); - } - - void setTitleBarThemeColor(HWND hWnd) - { - ::RefreshTitleBarThemeColor(hWnd); - } - - void enableDarkScrollBarForWindowAndChildren(HWND hwnd) - { - ::EnableDarkScrollBarForWindowAndChildren(hwnd); - } - - void paintRoundFrameRect(HDC hdc, const RECT rect, const HPEN hpen, int width, int height) - { - auto holdBrush = ::SelectObject(hdc, ::GetStockObject(NULL_BRUSH)); - auto holdPen = ::SelectObject(hdc, hpen); - ::RoundRect(hdc, rect.left, rect.top, rect.right, rect.bottom, width, height); - ::SelectObject(hdc, holdBrush); - ::SelectObject(hdc, holdPen); - } - - struct ButtonData - { - HTHEME hTheme = nullptr; - int iStateID = 0; - - ~ButtonData() - { - closeTheme(); - } - - bool ensureTheme(HWND hwnd) - { - if (!hTheme) - { - hTheme = OpenThemeData(hwnd, WC_BUTTON); - } - return hTheme != nullptr; - } - - void closeTheme() - { - if (hTheme) - { - CloseThemeData(hTheme); - hTheme = nullptr; - } - } - }; - - void renderButton(HWND hwnd, HDC hdc, HTHEME hTheme, int iPartID, int iStateID) - {//提供按钮 - RECT rcClient{}; - WCHAR szText[256] = { '\0' }; - DWORD nState = static_cast(SendMessage(hwnd, BM_GETSTATE, 0, 0)); - DWORD uiState = static_cast(SendMessage(hwnd, WM_QUERYUISTATE, 0, 0)); - auto nStyle = ::GetWindowLongPtr(hwnd, GWL_STYLE); - - HFONT hFont = nullptr; - HFONT hOldFont = nullptr; - HFONT hCreatedFont = nullptr; - LOGFONT lf{}; - if (SUCCEEDED(GetThemeFont(hTheme, hdc, iPartID, iStateID, TMT_FONT, &lf))) - { - hCreatedFont = CreateFontIndirect(&lf); - hFont = hCreatedFont; - } - - if (!hFont) { - hFont = reinterpret_cast(SendMessage(hwnd, WM_GETFONT, 0, 0)); - } - - hOldFont = static_cast(SelectObject(hdc, hFont)); - - DWORD dtFlags = DT_LEFT; // DT_LEFT is 0 - dtFlags |= (nStyle & BS_MULTILINE) ? DT_WORDBREAK : DT_SINGLELINE; - dtFlags |= ((nStyle & BS_CENTER) == BS_CENTER) ? DT_CENTER : (nStyle & BS_RIGHT) ? DT_RIGHT : 0; - dtFlags |= ((nStyle & BS_VCENTER) == BS_VCENTER) ? DT_VCENTER : (nStyle & BS_BOTTOM) ? DT_BOTTOM : 0; - dtFlags |= (uiState & UISF_HIDEACCEL) ? DT_HIDEPREFIX : 0; - - if (!(nStyle & BS_MULTILINE) && !(nStyle & BS_BOTTOM) && !(nStyle & BS_TOP)) - { - dtFlags |= DT_VCENTER; - } - - GetClientRect(hwnd, &rcClient); - GetWindowText(hwnd, szText, _countof(szText)); - - SIZE szBox = { 13, 13 }; - GetThemePartSize(hTheme, hdc, iPartID, iStateID, NULL, TS_DRAW, &szBox); - - RECT rcText = rcClient; - GetThemeBackgroundContentRect(hTheme, hdc, iPartID, iStateID, &rcClient, &rcText); - - RECT rcBackground = rcClient; - if (dtFlags & DT_SINGLELINE) - { - rcBackground.top += (rcText.bottom - rcText.top - szBox.cy) / 2; - } - rcBackground.bottom = rcBackground.top + szBox.cy; - rcBackground.right = rcBackground.left + szBox.cx; - rcText.left = rcBackground.right + 3; - - DrawThemeParentBackground(hwnd, hdc, &rcClient); - DrawThemeBackground(hTheme, hdc, iPartID, iStateID, &rcBackground, nullptr); - - DTTOPTS dtto{}; - dtto.dwSize = sizeof(DTTOPTS); - dtto.dwFlags = DTT_TEXTCOLOR; - dtto.crText = NppDarkMode::getTextColor(); - - if (nStyle & WS_DISABLED) - { - dtto.crText = NppDarkMode::getDisabledTextColor(); - } - - DrawThemeTextEx(hTheme, hdc, iPartID, iStateID, szText, -1, dtFlags, &rcText, &dtto); - - if ((nState & BST_FOCUS) && !(uiState & UISF_HIDEFOCUS)) - { - RECT rcTextOut = rcText; - dtto.dwFlags |= DTT_CALCRECT; - DrawThemeTextEx(hTheme, hdc, iPartID, iStateID, szText, -1, dtFlags | DT_CALCRECT, &rcTextOut, &dtto); - RECT rcFocus = rcTextOut; - rcFocus.bottom++; - rcFocus.left--; - rcFocus.right++; - DrawFocusRect(hdc, &rcFocus); - } - - if (hCreatedFont) DeleteObject(hCreatedFont); - SelectObject(hdc, hOldFont); - } - - void paintButton(HWND hwnd, HDC hdc, ButtonData& buttonData) - { - DWORD nState = static_cast(SendMessage(hwnd, BM_GETSTATE, 0, 0)); - const auto nStyle = GetWindowLongPtr(hwnd, GWL_STYLE); - const auto nButtonStyle = nStyle & BS_TYPEMASK; - - int iPartID = BP_CHECKBOX; - - // Plugin might use BS_3STATE and BS_AUTO3STATE button style - if (nButtonStyle == BS_CHECKBOX || nButtonStyle == BS_AUTOCHECKBOX || nButtonStyle == BS_3STATE || nButtonStyle == BS_AUTO3STATE) - { - iPartID = BP_CHECKBOX; - } - else if (nButtonStyle == BS_RADIOBUTTON || nButtonStyle == BS_AUTORADIOBUTTON) - { - iPartID = BP_RADIOBUTTON; - } - else - { - assert(false); - } - - // states of BP_CHECKBOX and BP_RADIOBUTTON are the same - int iStateID = RBS_UNCHECKEDNORMAL; - - if (nStyle & WS_DISABLED) iStateID = RBS_UNCHECKEDDISABLED; - else if (nState & BST_PUSHED) iStateID = RBS_UNCHECKEDPRESSED; - else if (nState & BST_HOT) iStateID = RBS_UNCHECKEDHOT; - - if (nState & BST_CHECKED) iStateID += 4; - - if (BufferedPaintRenderAnimation(hwnd, hdc)) - { - return; - } - - BP_ANIMATIONPARAMS animParams{}; - animParams.cbSize = sizeof(BP_ANIMATIONPARAMS); - animParams.style = BPAS_LINEAR; - if (iStateID != buttonData.iStateID) - { - GetThemeTransitionDuration(buttonData.hTheme, iPartID, buttonData.iStateID, iStateID, TMT_TRANSITIONDURATIONS, &animParams.dwDuration); - } - - RECT rcClient{}; - GetClientRect(hwnd, &rcClient); - - HDC hdcFrom = nullptr; - HDC hdcTo = nullptr; - HANIMATIONBUFFER hbpAnimation = BeginBufferedAnimation(hwnd, hdc, &rcClient, BPBF_COMPATIBLEBITMAP, nullptr, &animParams, &hdcFrom, &hdcTo); - if (hbpAnimation) - { - if (hdcFrom) - { - renderButton(hwnd, hdcFrom, buttonData.hTheme, iPartID, buttonData.iStateID); - } - if (hdcTo) - { - renderButton(hwnd, hdcTo, buttonData.hTheme, iPartID, iStateID); - } - - buttonData.iStateID = iStateID; - - EndBufferedAnimation(hbpAnimation, TRUE); - } - else - { - renderButton(hwnd, hdc, buttonData.hTheme, iPartID, iStateID); - - buttonData.iStateID = iStateID; - } - } - - constexpr UINT_PTR g_buttonSubclassID = 42; - - LRESULT CALLBACK ButtonSubclass( - HWND hWnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam, - UINT_PTR uIdSubclass, - DWORD_PTR dwRefData - ) - { - UNREFERENCED_PARAMETER(uIdSubclass); - - auto pButtonData = reinterpret_cast(dwRefData); - - switch (uMsg) - { - case WM_UPDATEUISTATE: - if (HIWORD(wParam) & (UISF_HIDEACCEL | UISF_HIDEFOCUS)) - { - InvalidateRect(hWnd, nullptr, FALSE); - } - break; - case WM_NCDESTROY: - RemoveWindowSubclass(hWnd, ButtonSubclass, g_buttonSubclassID); - delete pButtonData; - break; - case WM_ERASEBKGND: - if (NppDarkMode::isEnabled() && pButtonData->ensureTheme(hWnd)) - { - return TRUE; - } - else - { - break; - } - case WM_THEMECHANGED: - pButtonData->closeTheme(); - break; - case WM_PRINTCLIENT: - case WM_PAINT: - if (NppDarkMode::isEnabled() && pButtonData->ensureTheme(hWnd)) - { - PAINTSTRUCT ps{}; - HDC hdc = reinterpret_cast(wParam); - if (!hdc) - { - hdc = BeginPaint(hWnd, &ps); - } - - paintButton(hWnd, hdc, *pButtonData); - - if (ps.hdc) - { - EndPaint(hWnd, &ps); - } - - return 0; - } - else - { - break; - } - case WM_SIZE: - case WM_DESTROY: - BufferedPaintStopAllAnimations(hWnd); - break; - case WM_ENABLE: - if (NppDarkMode::isEnabled()) - { - // skip the button's normal wndproc so it won't redraw out of wm_paint - LRESULT lr = DefWindowProc(hWnd, uMsg, wParam, lParam); - InvalidateRect(hWnd, nullptr, FALSE); - return lr; - } - break; - } - return DefSubclassProc(hWnd, uMsg, wParam, lParam); - } - - void subclassButtonControl(HWND hwnd) - { - DWORD_PTR pButtonData = reinterpret_cast(new ButtonData()); - SetWindowSubclass(hwnd, ButtonSubclass, g_buttonSubclassID, pButtonData); - } - - void paintGroupbox(HWND hwnd, HDC hdc, ButtonData& buttonData) - { - auto nStyle = ::GetWindowLongPtr(hwnd, GWL_STYLE); - bool isDisabled = (nStyle & WS_DISABLED) == WS_DISABLED; - int iPartID = BP_GROUPBOX; - int iStateID = isDisabled ? GBS_DISABLED : GBS_NORMAL; - - RECT rcClient{}; - GetClientRect(hwnd, &rcClient); - - RECT rcText = rcClient; - RECT rcBackground = rcClient; - - HFONT hFont = nullptr; - HFONT hOldFont = nullptr; - HFONT hCreatedFont = nullptr; - LOGFONT lf{}; - if (SUCCEEDED(GetThemeFont(buttonData.hTheme, hdc, iPartID, iStateID, TMT_FONT, &lf))) - { - hCreatedFont = CreateFontIndirect(&lf); - hFont = hCreatedFont; - } - - if (!hFont) - { - hFont = reinterpret_cast(SendMessage(hwnd, WM_GETFONT, 0, 0)); - } - - hOldFont = static_cast(::SelectObject(hdc, hFont)); - - WCHAR szText[256] = { '\0' }; - GetWindowText(hwnd, szText, _countof(szText)); - - auto style = static_cast(::GetWindowLongPtr(hwnd, GWL_STYLE)); - bool isCenter = (style & BS_CENTER) == BS_CENTER; - - if (szText[0]) - { - SIZE textSize{}; - GetTextExtentPoint32(hdc, szText, static_cast(wcslen(szText)), &textSize); - - int centerPosX = isCenter ? ((rcClient.right - rcClient.left - textSize.cx) / 2) : 7; - - rcBackground.top += textSize.cy / 2; - rcText.left += centerPosX; - rcText.bottom = rcText.top + textSize.cy; - rcText.right = rcText.left + textSize.cx + 4; - - ExcludeClipRect(hdc, rcText.left, rcText.top, rcText.right, rcText.bottom); - } - else - { - SIZE textSize{}; - GetTextExtentPoint32(hdc, L"M", 1, &textSize); - rcBackground.top += textSize.cy / 2; - } - - RECT rcContent = rcBackground; - GetThemeBackgroundContentRect(buttonData.hTheme, hdc, BP_GROUPBOX, iStateID, &rcBackground, &rcContent); - ExcludeClipRect(hdc, rcContent.left, rcContent.top, rcContent.right, rcContent.bottom); - - //DrawThemeParentBackground(hwnd, hdc, &rcClient); - //DrawThemeBackground(buttonData.hTheme, hdc, BP_GROUPBOX, iStateID, &rcBackground, nullptr); - NppDarkMode::paintRoundFrameRect(hdc, rcBackground, NppDarkMode::getEdgePen()); - - SelectClipRgn(hdc, nullptr); - - if (szText[0]) - { - rcText.right -= 2; - rcText.left += 2; - - DTTOPTS dtto{}; - dtto.dwSize = sizeof(DTTOPTS); - dtto.dwFlags = DTT_TEXTCOLOR; - dtto.crText = isDisabled ? NppDarkMode::getDisabledTextColor() : NppDarkMode::getTextColor(); - - DWORD textFlags = isCenter ? DT_CENTER : DT_LEFT; - - if(::SendMessage(hwnd, WM_QUERYUISTATE, 0, 0) != static_cast(NULL)) - { - textFlags |= DT_HIDEPREFIX; - } - - DrawThemeTextEx(buttonData.hTheme, hdc, BP_GROUPBOX, iStateID, szText, -1, textFlags | DT_SINGLELINE, &rcText, &dtto); - } - - if (hCreatedFont) DeleteObject(hCreatedFont); - SelectObject(hdc, hOldFont); - } - - constexpr UINT_PTR g_groupboxSubclassID = 42; - - LRESULT CALLBACK GroupboxSubclass( - HWND hWnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam, - UINT_PTR uIdSubclass, - DWORD_PTR dwRefData - ) - { - UNREFERENCED_PARAMETER(uIdSubclass); - - auto pButtonData = reinterpret_cast(dwRefData); - - switch (uMsg) - { - case WM_NCDESTROY: - RemoveWindowSubclass(hWnd, GroupboxSubclass, g_groupboxSubclassID); - delete pButtonData; - break; - case WM_ERASEBKGND: - if (NppDarkMode::isEnabled() && pButtonData->ensureTheme(hWnd)) - { - return TRUE; - } - else - { - break; - } - case WM_THEMECHANGED: - pButtonData->closeTheme(); - break; - case WM_PRINTCLIENT: - case WM_PAINT: - if (NppDarkMode::isEnabled() && pButtonData->ensureTheme(hWnd)) - { - PAINTSTRUCT ps{}; - HDC hdc = reinterpret_cast(wParam); - if (!hdc) - { - hdc = BeginPaint(hWnd, &ps); - } - - paintGroupbox(hWnd, hdc, *pButtonData); - - if (ps.hdc) - { - EndPaint(hWnd, &ps); - } - - return 0; - } - else - { - break; - } - break; - } - return DefSubclassProc(hWnd, uMsg, wParam, lParam); - } - - void subclassGroupboxControl(HWND hwnd) - { - DWORD_PTR pButtonData = reinterpret_cast(new ButtonData()); - SetWindowSubclass(hwnd, GroupboxSubclass, g_groupboxSubclassID, pButtonData); - } - - constexpr UINT_PTR g_tabSubclassID = 42; - - LRESULT CALLBACK TabSubclass( - HWND hWnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam, - UINT_PTR uIdSubclass, - DWORD_PTR dwRefData - ) - { - UNREFERENCED_PARAMETER(uIdSubclass); - UNREFERENCED_PARAMETER(dwRefData); - - switch (uMsg) - { - case WM_PAINT: - { - if (!NppDarkMode::isEnabled()) - { - break; - } - - LONG_PTR dwStyle = GetWindowLongPtr(hWnd, GWL_STYLE); - if ((dwStyle & TCS_BUTTONS) || (dwStyle & TCS_VERTICAL)) - { - break; - } - - PAINTSTRUCT ps{}; - HDC hdc = ::BeginPaint(hWnd, &ps); - ::FillRect(hdc, &ps.rcPaint, NppDarkMode::getDarkerBackgroundBrush()); - - auto holdPen = static_cast(::SelectObject(hdc, NppDarkMode::getEdgePen())); - - HRGN holdClip = CreateRectRgn(0, 0, 0, 0); - if (1 != GetClipRgn(hdc, holdClip)) - { - DeleteObject(holdClip); - holdClip = nullptr; - } - - HFONT hFont = reinterpret_cast(SendMessage(hWnd, WM_GETFONT, 0, 0)); - auto hOldFont = SelectObject(hdc, hFont); - - POINT ptCursor{}; - ::GetCursorPos(&ptCursor); - ScreenToClient(hWnd, &ptCursor); - - int nTabs = TabCtrl_GetItemCount(hWnd); - - int nSelTab = TabCtrl_GetCurSel(hWnd); - for (int i = 0; i < nTabs; ++i) - { - RECT rcItem{}; - TabCtrl_GetItemRect(hWnd, i, &rcItem); - RECT rcFrame = rcItem; - - RECT rcIntersect{}; - if (IntersectRect(&rcIntersect, &ps.rcPaint, &rcItem)) - { - bool bHot = PtInRect(&rcItem, ptCursor); - bool isSelectedTab = (i == nSelTab); - - HRGN hClip = CreateRectRgnIndirect(&rcItem); - - SelectClipRgn(hdc, hClip); - - SetTextColor(hdc, (bHot || isSelectedTab ) ? NppDarkMode::getTextColor() : NppDarkMode::getDarkerTextColor()); - - ::InflateRect(&rcItem, -1, -1); - rcItem.right += 1; - - // for consistency getBackgroundBrush() - // would be better, than getSofterBackgroundBrush(), - // however default getBackgroundBrush() has same color - // as getDarkerBackgroundBrush() - ::FillRect(hdc, &rcItem, isSelectedTab ? NppDarkMode::getDarkerBackgroundBrush() : bHot ? NppDarkMode::getHotBackgroundBrush() : NppDarkMode::getSofterBackgroundBrush()); - - SetBkMode(hdc, TRANSPARENT); - - TCHAR label[MAX_PATH]{}; - TCITEM tci{}; - tci.mask = TCIF_TEXT; - tci.pszText = label; - tci.cchTextMax = MAX_PATH - 1; - - ::SendMessage(hWnd, TCM_GETITEM, i, reinterpret_cast(&tci)); - - auto dpiManager = NppParameters::getInstance()._dpiManager; - - RECT rcText = rcItem; - rcText.left += dpiManager.scaleX(5); - rcText.right -= dpiManager.scaleX(3); - - if (isSelectedTab) - { - rcText.bottom -= dpiManager.scaleY(4); - ::InflateRect(&rcFrame, 0, 1); - } - if (i != nTabs - 1) - { - rcFrame.right += 1; - } - - ::FrameRect(hdc, &rcFrame, NppDarkMode::getEdgeBrush()); - - DrawText(hdc, label, -1, &rcText, DT_LEFT | DT_VCENTER | DT_SINGLELINE); - - DeleteObject(hClip); - - SelectClipRgn(hdc, holdClip); - } - } - - SelectObject(hdc, hOldFont); - - SelectClipRgn(hdc, holdClip); - if (holdClip) - { - DeleteObject(holdClip); - holdClip = nullptr; - } - - SelectObject(hdc, holdPen); - - EndPaint(hWnd, &ps); - return 0; - } - - case WM_NCDESTROY: - { - RemoveWindowSubclass(hWnd, TabSubclass, g_tabSubclassID); - break; - } - - case WM_PARENTNOTIFY: - { - switch (LOWORD(wParam)) - { - case WM_CREATE: - { - auto hwndUpdown = reinterpret_cast(lParam); - if (NppDarkMode::subclassTabUpDownControl(hwndUpdown)) - { - return 0; - } - break; - } - } - return 0; - } - - } - return DefSubclassProc(hWnd, uMsg, wParam, lParam); - } - - void subclassTabControl(HWND hwnd) - { - SetWindowSubclass(hwnd, TabSubclass, g_tabSubclassID, 0); - } - - constexpr UINT_PTR g_customBorderSubclassID = 42; - - LRESULT CALLBACK CustomBorderSubclass( - HWND hWnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam, - UINT_PTR uIdSubclass, - DWORD_PTR dwRefData - ) - { - UNREFERENCED_PARAMETER(dwRefData); - - static bool isHotStatic = false; - - switch (uMsg) - { - case WM_NCPAINT: - { - if (!NppDarkMode::isEnabled()) - { - break; - } - - DefSubclassProc(hWnd, uMsg, wParam, lParam); - - HDC hdc = ::GetWindowDC(hWnd); - RECT rcClient{}; - ::GetClientRect(hWnd, &rcClient); - rcClient.right += (2 * ::GetSystemMetrics(SM_CXEDGE)); - - auto style = ::GetWindowLongPtr(hWnd, GWL_STYLE); - bool hasVerScrollbar = (style & WS_VSCROLL) == WS_VSCROLL; - if (hasVerScrollbar) - { - rcClient.right += ::GetSystemMetrics(SM_CXVSCROLL); - } - - rcClient.bottom += (2 * ::GetSystemMetrics(SM_CYEDGE)); - - bool hasHorScrollbar = (style & WS_HSCROLL) == WS_HSCROLL; - if (hasHorScrollbar) - { - rcClient.bottom += ::GetSystemMetrics(SM_CYHSCROLL); - } - - HPEN hPen = ::CreatePen(PS_SOLID, 1, NppDarkMode::getBackgroundColor()); - RECT rcInner = rcClient; - ::InflateRect(&rcInner, -1, -1); - NppDarkMode::paintRoundFrameRect(hdc, rcInner, hPen); - ::DeleteObject(hPen); - - bool hasFocus = ::GetFocus() == hWnd; - - POINT ptCursor{}; - ::GetCursorPos(&ptCursor); - ::ScreenToClient(hWnd, &ptCursor); - - bool isHot = ::PtInRect(&rcClient, ptCursor); - - bool isWindowEnabled = ::IsWindowEnabled(hWnd) == TRUE; - HPEN hEnabledPen = ((isHotStatic && isHot) || hasFocus ? NppDarkMode::getHotEdgePen() : NppDarkMode::getEdgePen()); - - NppDarkMode::paintRoundFrameRect(hdc, rcClient, isWindowEnabled ? hEnabledPen : NppDarkMode::getDisabledEdgePen()); - - ::ReleaseDC(hWnd, hdc); - - return 0; - } - break; - - case WM_NCCALCSIZE: - { - if (!NppDarkMode::isEnabled()) - { - break; - } - - auto lpRect = reinterpret_cast(lParam); - ::InflateRect(lpRect, -(::GetSystemMetrics(SM_CXEDGE)), -(::GetSystemMetrics(SM_CYEDGE))); - - auto style = ::GetWindowLongPtr(hWnd, GWL_STYLE); - bool hasVerScrollbar = (style & WS_VSCROLL) == WS_VSCROLL; - if (hasVerScrollbar) - { - lpRect->right -= ::GetSystemMetrics(SM_CXVSCROLL); - } - - bool hasHorScrollbar = (style & WS_HSCROLL) == WS_HSCROLL; - if (hasHorScrollbar) - { - lpRect->bottom -= ::GetSystemMetrics(SM_CYHSCROLL); - } - - return 0; - } - break; - - case WM_MOUSEMOVE: - { - if (!NppDarkMode::isEnabled()) - { - break; - } - - if (::GetFocus() == hWnd) - { - break; - } - - TRACKMOUSEEVENT tme{}; - tme.cbSize = sizeof(TRACKMOUSEEVENT); - tme.dwFlags = TME_LEAVE; - tme.hwndTrack = hWnd; - tme.dwHoverTime = HOVER_DEFAULT; - TrackMouseEvent(&tme); - - if (!isHotStatic) - { - isHotStatic = true; - ::SetWindowPos(hWnd, nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); - } - } - break; - - case WM_MOUSELEAVE: - { - if (!NppDarkMode::isEnabled()) - { - break; - } - - if (isHotStatic) - { - isHotStatic = false; - ::SetWindowPos(hWnd, nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); - } - - TRACKMOUSEEVENT tme{}; - tme.cbSize = sizeof(TRACKMOUSEEVENT); - tme.dwFlags = TME_LEAVE | TME_CANCEL; - tme.hwndTrack = hWnd; - tme.dwHoverTime = HOVER_DEFAULT; - TrackMouseEvent(&tme); - } - break; - - case WM_NCDESTROY: - { - RemoveWindowSubclass(hWnd, CustomBorderSubclass, uIdSubclass); - } - break; - } - return DefSubclassProc(hWnd, uMsg, wParam, lParam); - } - - void subclassCustomBorderForListBoxAndEditControls(HWND hwnd) - { - SetWindowSubclass(hwnd, CustomBorderSubclass, g_customBorderSubclassID, 0); - } - - constexpr UINT_PTR g_comboBoxSubclassID = 42; - - LRESULT CALLBACK ComboBoxSubclass( - HWND hWnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam, - UINT_PTR uIdSubclass, - DWORD_PTR dwRefData - ) - { - auto hwndEdit = reinterpret_cast(dwRefData); - - switch (uMsg) - { - case WM_PAINT: - { - if (!NppDarkMode::isEnabled()) - { - break; - } - - RECT rc{}; - ::GetClientRect(hWnd, &rc); - - PAINTSTRUCT ps{}; - auto hdc = ::BeginPaint(hWnd, &ps); - - ::SelectObject(hdc, reinterpret_cast(::SendMessage(hWnd, WM_GETFONT, 0, 0))); - ::SetBkColor(hdc, NppDarkMode::getBackgroundColor()); - - auto holdBrush = ::SelectObject(hdc, NppDarkMode::getDarkerBackgroundBrush()); - - auto& dpiManager = NppParameters::getInstance()._dpiManager; - - RECT rcArrow{}; - - COMBOBOXINFO cbi{}; - cbi.cbSize = sizeof(COMBOBOXINFO); - const bool resultCbi = ::GetComboBoxInfo(hWnd, &cbi) != FALSE; - if (resultCbi) - { - rcArrow = cbi.rcButton; - rcArrow.left -= 1; - } - else - { - rcArrow = { - rc.right - dpiManager.scaleX(17), rc.top + 1, - rc.right - 1, rc.bottom - 1 - }; - } - - bool hasFocus = false; - - const bool isWindowEnabled = ::IsWindowEnabled(hWnd) == TRUE; - - // CBS_DROPDOWN text is handled by parent by WM_CTLCOLOREDIT - auto style = ::GetWindowLongPtr(hWnd, GWL_STYLE); - if ((style & CBS_DROPDOWNLIST) == CBS_DROPDOWNLIST) - { - hasFocus = ::GetFocus() == hWnd; - - RECT rcTextBg{}; - if (resultCbi) - { - rcTextBg = cbi.rcItem; - } - else - { - rcTextBg = rc; - - rcTextBg.left += 1; - rcTextBg.top += 1; - rcTextBg.right = rcArrow.left - 1; - rcTextBg.bottom -= 1; - } - - ::FillRect(hdc, &rcTextBg, NppDarkMode::getBackgroundBrush()); // erase background on item change - - auto index = static_cast(::SendMessage(hWnd, CB_GETCURSEL, 0, 0)); - if (index != CB_ERR) - { - ::SetTextColor(hdc, isWindowEnabled ? NppDarkMode::getTextColor() : NppDarkMode::getDisabledTextColor()); - ::SetBkColor(hdc, NppDarkMode::getBackgroundColor()); - auto bufferLen = static_cast(::SendMessage(hWnd, CB_GETLBTEXTLEN, index, 0)); - TCHAR* buffer = new TCHAR[(bufferLen + 1)]; - ::SendMessage(hWnd, CB_GETLBTEXT, index, reinterpret_cast(buffer)); - - RECT rcText = rcTextBg; - rcText.left += 4; - rcText.right -= 4; - - ::DrawText(hdc, buffer, -1, &rcText, DT_NOPREFIX | DT_LEFT | DT_VCENTER | DT_SINGLELINE); - delete[] buffer; - } - - if (hasFocus && ::SendMessage(hWnd, CB_GETDROPPEDSTATE, 0, 0) == FALSE) - { - ::DrawFocusRect(hdc, &rcTextBg); - } - } - else if ((style & CBS_DROPDOWN) == CBS_DROPDOWN && hwndEdit != nullptr) - { - hasFocus = ::GetFocus() == hwndEdit; - } - - POINT ptCursor{}; - ::GetCursorPos(&ptCursor); - ::ScreenToClient(hWnd, &ptCursor); - - bool isHot = ::PtInRect(&rc, ptCursor); - - auto colorEnabledText = isHot ? NppDarkMode::getTextColor() : NppDarkMode::getDarkerTextColor(); - ::SetTextColor(hdc, isWindowEnabled ? colorEnabledText : NppDarkMode::getDisabledTextColor()); - ::SetBkColor(hdc, isHot ? NppDarkMode::getHotBackgroundColor() : NppDarkMode::getBackgroundColor()); - ::FillRect(hdc, &rcArrow, isHot ? NppDarkMode::getHotBackgroundBrush() : NppDarkMode::getBackgroundBrush()); - TCHAR arrow[] = L"˅"; - ::DrawText(hdc, arrow, -1, &rcArrow, DT_NOPREFIX | DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOCLIP); - ::SetBkColor(hdc, NppDarkMode::getBackgroundColor()); - - auto hEnabledPen = (isHot || hasFocus) ? NppDarkMode::getHotEdgePen() : NppDarkMode::getEdgePen(); - auto hSelectedPen = isWindowEnabled ? hEnabledPen : NppDarkMode::getDisabledEdgePen(); - auto holdPen = static_cast(::SelectObject(hdc, hSelectedPen)); - - POINT edge[] = { - {rcArrow.left - 1, rcArrow.top}, - {rcArrow.left - 1, rcArrow.bottom} - }; - ::Polyline(hdc, edge, _countof(edge)); - - int roundCornerValue = NppDarkMode::isWindows11() ? dpiManager.scaleX(4) : 0; - NppDarkMode::paintRoundFrameRect(hdc, rc, hSelectedPen, roundCornerValue, roundCornerValue); - - ::SelectObject(hdc, holdPen); - ::SelectObject(hdc, holdBrush); - - ::EndPaint(hWnd, &ps); - return 0; - } - - case WM_NCDESTROY: - { - ::RemoveWindowSubclass(hWnd, ComboBoxSubclass, uIdSubclass); - break; - } - } - return DefSubclassProc(hWnd, uMsg, wParam, lParam); - } - - void subclassComboBoxControl(HWND hwnd) - { - DWORD_PTR hwndEditData = 0; - auto style = ::GetWindowLongPtr(hwnd, GWL_STYLE); - if ((style & CBS_DROPDOWN) == CBS_DROPDOWN) - { - POINT pt = { 5, 5 }; - hwndEditData = reinterpret_cast(::ChildWindowFromPoint(hwnd, pt)); - } - SetWindowSubclass(hwnd, ComboBoxSubclass, g_comboBoxSubclassID, hwndEditData); - } - - constexpr UINT_PTR g_listViewSubclassID = 42; - - LRESULT CALLBACK ListViewSubclass( - HWND hWnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam, - UINT_PTR uIdSubclass, - DWORD_PTR dwRefData - ) - { - UNREFERENCED_PARAMETER(dwRefData); - - switch (uMsg) - { - case WM_NCDESTROY: - { - ::RemoveWindowSubclass(hWnd, ListViewSubclass, uIdSubclass); - break; - } - - case WM_NOTIFY: - { - switch (reinterpret_cast(lParam)->code) - { - case NM_CUSTOMDRAW: - { - auto lpnmcd = reinterpret_cast(lParam); - switch (lpnmcd->dwDrawStage) - { - case CDDS_PREPAINT: - { - if (NppDarkMode::isExperimentalSupported() && NppDarkMode::isEnabled()) - { - return CDRF_NOTIFYITEMDRAW; - } - return CDRF_DODEFAULT; - } - - case CDDS_ITEMPREPAINT: - { - SetTextColor(lpnmcd->hdc, NppDarkMode::getDarkerTextColor()); - - return CDRF_NEWFONT; - } - - default: - return CDRF_DODEFAULT; - } - } - break; - } - break; - } - break;, - } - return DefSubclassProc(hWnd, uMsg, wParam, lParam); - } - - void subclassListViewControl(HWND hwnd) - { - SetWindowSubclass(hwnd, ListViewSubclass, g_listViewSubclassID, 0); - } - - constexpr UINT_PTR g_upDownSubclassID = 42; - - LRESULT CALLBACK UpDownSubclass( - HWND hWnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam, - UINT_PTR uIdSubclass, - DWORD_PTR dwRefData - ) - { - auto pButtonData = reinterpret_cast(dwRefData); // 获取与子类化控件相关的数据结构 - - 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::getDarkerBackgroundBrush()); // 填充客户区背景色 - - // 计算前后箭头的位置 - 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_THEMECHANGED: - { - pButtonData->closeTheme(); - break; - } - - case WM_NCDESTROY: - { - ::RemoveWindowSubclass(hWnd, UpDownSubclass, uIdSubclass); - delete pButtonData; - break; - } - - case WM_ERASEBKGND: - { - if (NppDarkMode::isEnabled()) - { - RECT rcClient{}; - ::GetClientRect(hWnd, &rcClient); - ::FillRect(reinterpret_cast(wParam), &rcClient, NppDarkMode::getDarkerBackgroundBrush()); - return TRUE; - } - break; - } - } - return DefSubclassProc(hWnd, uMsg, wParam, lParam); - } - - void subclassAndThemeUpDownControl(HWND hwnd, NppDarkModeParams p) - { - if (p._subclass) - { - auto pButtonData = reinterpret_cast(new ButtonData()); - SetWindowSubclass(hwnd, UpDownSubclass, g_upDownSubclassID, pButtonData); - } - - if (p._theme) - { - SetWindowTheme(hwnd, p._themeClassName, nullptr); - } - } - - bool subclassTabUpDownControl(HWND hwnd) - { - constexpr size_t classNameLen = 16; - TCHAR className[classNameLen]{}; - GetClassName(hwnd, className, classNameLen); - if (wcscmp(className, UPDOWN_CLASS) == 0) - { - auto pButtonData = reinterpret_cast(new ButtonData()); - SetWindowSubclass(hwnd, UpDownSubclass, g_upDownSubclassID, pButtonData); - NppDarkMode::setDarkExplorerTheme(hwnd); - return true; - } - - return false; - } - - void autoSubclassAndThemeChildControls(HWND hwndParent, bool subclass, bool theme) - { - NppDarkModeParams p{ - g_isAtLeastWindows10 && NppDarkMode::isEnabled() ? L"DarkMode_Explorer" : nullptr - , subclass - , theme - }; - - ::EnableThemeDialogTexture(hwndParent, theme && !NppDarkMode::isEnabled() ? ETDT_ENABLETAB : ETDT_DISABLE); - - EnumChildWindows(hwndParent, [](HWND hwnd, LPARAM lParam) WINAPI_LAMBDA { - auto& p = *reinterpret_cast(lParam); - constexpr size_t classNameLen = 32; - TCHAR className[classNameLen]{}; - GetClassName(hwnd, className, classNameLen); - - if (wcscmp(className, WC_BUTTON) == 0) - { - NppDarkMode::subclassAndThemeButton(hwnd, p); - return TRUE; - } - - if (wcscmp(className, WC_COMBOBOX) == 0) - { - NppDarkMode::subclassAndThemeComboBox(hwnd, p); - return TRUE; - } - - if (wcscmp(className, WC_EDIT) == 0) - { - if (!g_isWine) - { - NppDarkMode::subclassAndThemeListBoxOrEditControl(hwnd, p, false); - } - return TRUE; - } - - if (wcscmp(className, WC_LISTBOX) == 0) - { - if (!g_isWine) - { - NppDarkMode::subclassAndThemeListBoxOrEditControl(hwnd, p, true); - } - return TRUE; - } - - if (wcscmp(className, WC_LISTVIEW) == 0) - { - NppDarkMode::subclassAndThemeListView(hwnd, p); - return TRUE; - } - - if (wcscmp(className, WC_TREEVIEW) == 0) - { - NppDarkMode::themeTreeView(hwnd, p); - return TRUE; - } - - if (wcscmp(className, TOOLBARCLASSNAME) == 0) - { - NppDarkMode::themeToolbar(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) - { - NppDarkMode::themeRichEdit(hwnd, p); - return TRUE; - } - - // For plugins - if (wcscmp(className, UPDOWN_CLASS) == 0) - { - NppDarkMode::subclassAndThemeUpDownControl(hwnd, p); - return TRUE; - } - - /* - // for debugging - if (wcscmp(className, L"#32770") == 0) - { - return TRUE; - } - - if (wcscmp(className, L"Static") == 0) - { - return TRUE; - } - - if (wcscmp(className, L"msctls_trackbar32") == 0) - { - return TRUE; - } - */ - - return TRUE; - }, reinterpret_cast(&p)); - } - - void autoThemeChildControls(HWND hwndParent) - { - autoSubclassAndThemeChildControls(hwndParent, false, g_isAtLeastWindows10); - } - - void subclassAndThemeButton(HWND hwnd, NppDarkModeParams p) - { - auto nButtonStyle = ::GetWindowLongPtr(hwnd, GWL_STYLE); - switch (nButtonStyle & BS_TYPEMASK) - { - // Plugin might use BS_3STATE and BS_AUTO3STATE button style - case BS_CHECKBOX: - case BS_AUTOCHECKBOX: - case BS_3STATE: - case BS_AUTO3STATE: - case BS_RADIOBUTTON: - case BS_AUTORADIOBUTTON: - { - if ((nButtonStyle & BS_PUSHLIKE) == BS_PUSHLIKE) - { - if (p._theme) - { - SetWindowTheme(hwnd, p._themeClassName, nullptr); - } - break; - } - if (p._subclass) - { - NppDarkMode::subclassButtonControl(hwnd); - } - break; - } - - case BS_GROUPBOX: - { - if (p._subclass) - { - NppDarkMode::subclassGroupboxControl(hwnd); - } - break; - } - - case BS_PUSHBUTTON: - case BS_DEFPUSHBUTTON: - case BS_SPLITBUTTON: - case BS_DEFSPLITBUTTON: - { - if (p._theme) - { - SetWindowTheme(hwnd, p._themeClassName, nullptr); - } - break; - } - - default: - { - break; - } - } - } - - void subclassAndThemeComboBox(HWND hwnd, NppDarkModeParams p) - { - auto style = ::GetWindowLongPtr(hwnd, GWL_STYLE); - - if ((style & CBS_DROPDOWNLIST) == CBS_DROPDOWNLIST || (style & CBS_DROPDOWN) == CBS_DROPDOWN) - { - COMBOBOXINFO cbi{}; - cbi.cbSize = sizeof(COMBOBOXINFO); - BOOL result = ::GetComboBoxInfo(hwnd, &cbi); - if (result == TRUE) - { - if (p._theme && cbi.hwndList) - { - //dark scrollbar for listbox of combobox - ::SetWindowTheme(cbi.hwndList, p._themeClassName, nullptr); - } - } - - if (p._subclass) - { - NppDarkMode::subclassComboBoxControl(hwnd); - } - } - } - - void subclassAndThemeListBoxOrEditControl(HWND hwnd, NppDarkModeParams p, bool isListBox) - { - const auto style = ::GetWindowLongPtr(hwnd, GWL_STYLE); - bool hasScrollBar = ((style & WS_HSCROLL) == WS_HSCROLL) || ((style & WS_VSCROLL) == WS_VSCROLL); - if (p._theme && (isListBox || hasScrollBar)) - { - //dark scrollbar for listbox or edit control - SetWindowTheme(hwnd, p._themeClassName, nullptr); - } - - const auto exStyle = ::GetWindowLongPtr(hwnd, GWL_EXSTYLE); - bool hasClientEdge = (exStyle & WS_EX_CLIENTEDGE) == WS_EX_CLIENTEDGE; - bool isCBoxListBox = isListBox && (style & LBS_COMBOBOX) == LBS_COMBOBOX; - - if (p._subclass && hasClientEdge && !isCBoxListBox) - { - NppDarkMode::subclassCustomBorderForListBoxAndEditControls(hwnd); - } - -#ifndef __MINGW64__ // mingw build for 64 bit has issue with GetWindowSubclass, it is undefined - - bool changed = false; - if (::GetWindowSubclass(hwnd, CustomBorderSubclass, g_customBorderSubclassID, nullptr) == TRUE) - { - if (NppDarkMode::isEnabled()) - { - if (hasClientEdge) - { - ::SetWindowLongPtr(hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_CLIENTEDGE); - changed = true; - } - } - else if (!hasClientEdge) - { - ::SetWindowLongPtr(hwnd, GWL_EXSTYLE, exStyle | WS_EX_CLIENTEDGE); - changed = true; - } - } - - if (changed) - { - ::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); - } - -#endif // !__MINGW64__ - } - - void subclassAndThemeListView(HWND hwnd, NppDarkModeParams p) - { - if (p._theme) - { - NppDarkMode::setDarkListView(hwnd); - NppDarkMode::setDarkTooltips(hwnd, NppDarkMode::ToolTipsType::listview); - } - - ListView_SetTextColor(hwnd, NppParameters::getInstance().getCurrentDefaultFgColor()); - ListView_SetTextBkColor(hwnd, NppParameters::getInstance().getCurrentDefaultBgColor()); - ListView_SetBkColor(hwnd, NppParameters::getInstance().getCurrentDefaultBgColor()); - - if (p._subclass) - { - auto exStyle = ListView_GetExtendedListViewStyle(hwnd); - ListView_SetExtendedListViewStyle(hwnd, exStyle | LVS_EX_DOUBLEBUFFER); - NppDarkMode::subclassListViewControl(hwnd); - } - } - - void themeTreeView(HWND hwnd, NppDarkModeParams p) - { - TreeView_SetTextColor(hwnd, NppParameters::getInstance().getCurrentDefaultFgColor()); - TreeView_SetBkColor(hwnd, NppParameters::getInstance().getCurrentDefaultBgColor()); - - NppDarkMode::calculateTreeViewStyle(); - NppDarkMode::setTreeViewStyle(hwnd); - - if (p._theme) - { - NppDarkMode::setDarkTooltips(hwnd, NppDarkMode::ToolTipsType::treeview); - } - } - - void themeToolbar(HWND hwnd, NppDarkModeParams p) - { - NppDarkMode::setDarkLineAbovePanelToolbar(hwnd); - - if (p._theme) - { - NppDarkMode::setDarkTooltips(hwnd, NppDarkMode::ToolTipsType::toolbar); - } - } - - void themeRichEdit(HWND hwnd, NppDarkModeParams p) - { - if (p._theme) - { - //dark scrollbar for rich edit control - SetWindowTheme(hwnd, p._themeClassName, nullptr); - } - } - - LRESULT darkToolBarNotifyCustomDraw(LPARAM lParam) - { - auto nmtbcd = reinterpret_cast(lParam); - static int roundCornerValue = 0; - - switch (nmtbcd->nmcd.dwDrawStage) - { - case CDDS_PREPAINT: - { - if (NppDarkMode::isEnabled()) - { - auto dpiManager = NppParameters::getInstance()._dpiManager; - roundCornerValue = NppDarkMode::isWindows11() ? dpiManager.scaleX(5) : 0; - - ::FillRect(nmtbcd->nmcd.hdc, &nmtbcd->nmcd.rc, NppDarkMode::getDarkerBackgroundBrush()); - return CDRF_NOTIFYITEMDRAW; - } - return CDRF_DODEFAULT; - } - - case CDDS_ITEMPREPAINT: - { - nmtbcd->hbrLines = NppDarkMode::getEdgeBrush(); - nmtbcd->clrText = NppDarkMode::getTextColor(); - nmtbcd->clrTextHighlight = NppDarkMode::getTextColor(); - nmtbcd->clrBtnFace = NppDarkMode::getBackgroundColor(); - nmtbcd->clrBtnHighlight = NppDarkMode::getSofterBackgroundColor(); - nmtbcd->clrHighlightHotTrack = NppDarkMode::getHotBackgroundColor(); - nmtbcd->nStringBkMode = TRANSPARENT; - nmtbcd->nHLStringBkMode = TRANSPARENT; - - if ((nmtbcd->nmcd.uItemState & CDIS_CHECKED) == CDIS_CHECKED) - { - auto holdBrush = ::SelectObject(nmtbcd->nmcd.hdc, NppDarkMode::getSofterBackgroundBrush()); - auto holdPen = ::SelectObject(nmtbcd->nmcd.hdc, NppDarkMode::getEdgePen()); - ::RoundRect(nmtbcd->nmcd.hdc, nmtbcd->nmcd.rc.left, nmtbcd->nmcd.rc.top, nmtbcd->nmcd.rc.right, nmtbcd->nmcd.rc.bottom, roundCornerValue, roundCornerValue); - ::SelectObject(nmtbcd->nmcd.hdc, holdBrush); - ::SelectObject(nmtbcd->nmcd.hdc, holdPen); - - nmtbcd->nmcd.uItemState &= ~CDIS_CHECKED; - } - - return TBCDRF_HILITEHOTTRACK | TBCDRF_USECDCOLORS | CDRF_NOTIFYPOSTPAINT; - } - - case CDDS_ITEMPOSTPAINT: - { - bool isDropDown = false; - - auto exStyle = ::SendMessage(nmtbcd->nmcd.hdr.hwndFrom, TB_GETEXTENDEDSTYLE, 0, 0); - if ((exStyle & TBSTYLE_EX_DRAWDDARROWS) == TBSTYLE_EX_DRAWDDARROWS) - { - TBBUTTONINFO tbButtonInfo{}; - tbButtonInfo.cbSize = sizeof(TBBUTTONINFO); - tbButtonInfo.dwMask = TBIF_STYLE; - ::SendMessage(nmtbcd->nmcd.hdr.hwndFrom, TB_GETBUTTONINFO, nmtbcd->nmcd.dwItemSpec, reinterpret_cast(&tbButtonInfo)); - - isDropDown = (tbButtonInfo.fsStyle & BTNS_DROPDOWN) == BTNS_DROPDOWN; - } - - if ( !isDropDown && (nmtbcd->nmcd.uItemState & CDIS_HOT) == CDIS_HOT) - { - NppDarkMode::paintRoundFrameRect(nmtbcd->nmcd.hdc, nmtbcd->nmcd.rc, NppDarkMode::getHotEdgePen(), roundCornerValue, roundCornerValue); - } - - return CDRF_DODEFAULT; - } - - default: - return CDRF_DODEFAULT; - } - } - - LRESULT darkListViewNotifyCustomDraw(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool isPlugin) - { - auto lplvcd = reinterpret_cast(lParam); - - switch (lplvcd->nmcd.dwDrawStage) - { - case CDDS_PREPAINT: - { - return CDRF_NOTIFYITEMDRAW; - } - - case CDDS_ITEMPREPAINT: - { - auto isSelected = ListView_GetItemState(lplvcd->nmcd.hdr.hwndFrom, lplvcd->nmcd.dwItemSpec, LVIS_SELECTED) == LVIS_SELECTED; - - if (NppDarkMode::isEnabled()) - { - if (isSelected) - { - lplvcd->clrText = NppDarkMode::getTextColor(); - lplvcd->clrTextBk = NppDarkMode::getSofterBackgroundColor(); - - ::FillRect(lplvcd->nmcd.hdc, &lplvcd->nmcd.rc, NppDarkMode::getSofterBackgroundBrush()); - } - else if ((lplvcd->nmcd.uItemState & CDIS_HOT) == CDIS_HOT) - { - lplvcd->clrText = NppDarkMode::getTextColor(); - lplvcd->clrTextBk = NppDarkMode::getHotBackgroundColor(); - - ::FillRect(lplvcd->nmcd.hdc, &lplvcd->nmcd.rc, NppDarkMode::getHotBackgroundBrush()); - } - } - - if (isSelected) - { - ::DrawFocusRect(lplvcd->nmcd.hdc, &lplvcd->nmcd.rc); - } - - LRESULT lr = CDRF_DODEFAULT; - - if (isPlugin) - { - lr = ::DefSubclassProc(hWnd, uMsg, wParam, lParam); - } - - return lr | CDRF_NEWFONT; - } - - default: - break; - } - return ::DefSubclassProc(hWnd, uMsg, wParam, lParam); - } - - LRESULT darkTreeViewNotifyCustomDraw(LPARAM lParam) - { - auto lptvcd = reinterpret_cast(lParam); - - switch (lptvcd->nmcd.dwDrawStage) - { - case CDDS_PREPAINT: - { - if (NppDarkMode::isEnabled()) - { - return CDRF_NOTIFYITEMDRAW; - } - return CDRF_DODEFAULT; - } - - case CDDS_ITEMPREPAINT: - { - if ((lptvcd->nmcd.uItemState & CDIS_SELECTED) == CDIS_SELECTED) - { - lptvcd->clrText = NppDarkMode::getTextColor(); - lptvcd->clrTextBk = NppDarkMode::getSofterBackgroundColor(); - ::FillRect(lptvcd->nmcd.hdc, &lptvcd->nmcd.rc, NppDarkMode::getSofterBackgroundBrush()); - - return CDRF_NEWFONT | CDRF_NOTIFYPOSTPAINT; - } - - if ((lptvcd->nmcd.uItemState & CDIS_HOT) == CDIS_HOT) - { - lptvcd->clrText = NppDarkMode::getTextColor(); - lptvcd->clrTextBk = NppDarkMode::getHotBackgroundColor(); - - auto notifyResult = CDRF_DODEFAULT; - if (g_isAtLeastWindows10 || g_treeViewStyle == TreeViewStyle::light) - { - ::FillRect(lptvcd->nmcd.hdc, &lptvcd->nmcd.rc, NppDarkMode::getHotBackgroundBrush()); - notifyResult = CDRF_NOTIFYPOSTPAINT; - } - - return CDRF_NEWFONT | notifyResult; - } - - return CDRF_DODEFAULT; - } - - case CDDS_ITEMPOSTPAINT: - { - RECT rcFrame = lptvcd->nmcd.rc; - rcFrame.left -= 1; - rcFrame.right += 1; - - if ((lptvcd->nmcd.uItemState & CDIS_HOT) == CDIS_HOT) - { - NppDarkMode::paintRoundFrameRect(lptvcd->nmcd.hdc, rcFrame, NppDarkMode::getHotEdgePen(), 0, 0); - } - else if ((lptvcd->nmcd.uItemState & CDIS_SELECTED) == CDIS_SELECTED) - { - NppDarkMode::paintRoundFrameRect(lptvcd->nmcd.hdc, rcFrame, NppDarkMode::getEdgePen(), 0, 0); - } - - return CDRF_DODEFAULT; - - } - - default: - return CDRF_DODEFAULT; - } - } - - constexpr UINT_PTR g_pluginDockWindowSubclassID = 42; - - LRESULT CALLBACK PluginDockWindowSubclass( - HWND hWnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam, - UINT_PTR uIdSubclass, - DWORD_PTR dwRefData - ) - { - UNREFERENCED_PARAMETER(dwRefData); - - switch (uMsg) - { - case WM_ERASEBKGND: - { - if (NppDarkMode::isEnabled()) - { - RECT rect{}; - GetClientRect(hWnd, &rect); - ::FillRect(reinterpret_cast(wParam), &rect, NppDarkMode::getDarkerBackgroundBrush()); - return TRUE; - } - break; - } - - case WM_NCDESTROY: - { - ::RemoveWindowSubclass(hWnd, PluginDockWindowSubclass, uIdSubclass); - break; - } - - case NPPM_INTERNAL_REFRESHDARKMODE: - { - NppDarkMode::autoThemeChildControls(hWnd); - return TRUE; - } - - case WM_CTLCOLOREDIT: - { - if (NppDarkMode::isEnabled()) - { - return NppDarkMode::onCtlColorSofter(reinterpret_cast(wParam)); - } - break; - } - - case WM_CTLCOLORLISTBOX: - { - if (NppDarkMode::isEnabled()) - { - return NppDarkMode::onCtlColorListbox(wParam, lParam); - } - break; - } - - case WM_CTLCOLORDLG: - { - - if (NppDarkMode::isEnabled()) - { - return NppDarkMode::onCtlColorDarker(reinterpret_cast(wParam)); - } - break; - } - - case WM_CTLCOLORSTATIC: - { - if (NppDarkMode::isEnabled()) - { - constexpr size_t classNameLen = 16; - TCHAR className[classNameLen]{}; - auto hwndEdit = reinterpret_cast(lParam); - GetClassName(hwndEdit, className, classNameLen); - if (wcscmp(className, WC_EDIT) == 0) - { - return NppDarkMode::onCtlColor(reinterpret_cast(wParam)); - } - return NppDarkMode::onCtlColorDarker(reinterpret_cast(wParam)); - } - break; - } - - case WM_PRINTCLIENT: - { - if (NppDarkMode::isEnabled()) - { - return TRUE; - } - break; - } - - case WM_NOTIFY: - { - const auto nmhdr = reinterpret_cast(lParam); - switch (nmhdr->code) - { - case NM_CUSTOMDRAW: - { - constexpr size_t classNameLen = 16; - TCHAR className[classNameLen]{}; - GetClassName(nmhdr->hwndFrom, className, classNameLen); - - if (wcscmp(className, TOOLBARCLASSNAME) == 0) - { - return NppDarkMode::darkToolBarNotifyCustomDraw(lParam); - } - - if (wcscmp(className, WC_LISTVIEW) == 0) - { - return NppDarkMode::darkListViewNotifyCustomDraw(hWnd, uMsg, wParam, lParam, true); - } - - if (wcscmp(className, WC_TREEVIEW) == 0) - { - return NppDarkMode::darkTreeViewNotifyCustomDraw(lParam); - } - } - break; - } - break; - } - } - return DefSubclassProc(hWnd, uMsg, wParam, lParam); - } - - void autoSubclassAndThemePluginDockWindow(HWND hwnd) - { - SetWindowSubclass(hwnd, PluginDockWindowSubclass, g_pluginDockWindowSubclassID, 0); - NppDarkMode::autoSubclassAndThemeChildControls(hwnd, true, g_isAtLeastWindows10); - } - - ULONG autoSubclassAndThemePlugin(HWND hwnd, ULONG dmFlags) - { - // Used on parent of edit, listbox, static text, treeview, listview and toolbar controls. - // Should be used only one time on parent control after its creation - // even when starting in light mode. - // e.g. in WM_INITDIALOG, in WM_CREATE or after CreateWindow. - constexpr ULONG dmfSubclassParent = 0x00000001UL; - // Should be used only one time on main control/window after initializations of all its children controls - // even when starting in light mode. - // Will also use dmfSetThemeChildren flag. - // e.g. in WM_INITDIALOG, in WM_CREATE or after CreateWindow. - constexpr ULONG dmfSubclassChildren = 0x00000002UL; - // Will apply theme on buttons with style: - // BS_PUSHLIKE, BS_PUSHBUTTON, BS_DEFPUSHBUTTON, BS_SPLITBUTTON or BS_DEFSPLITBUTTON. - // Will apply theme for scrollbars on edit, listbox and rich edit controls. - // Will apply theme for tooltips on listview, treeview and toolbar buttons. - // Should be handled after controls initializations and in NPPN_DARKMODECHANGED. - // Requires at least Windows 10 to work properly. - constexpr ULONG dmfSetThemeChildren = 0x00000004UL; - // Set dark title bar. - // Should be handled after controls initializations and in NPPN_DARKMODECHANGED. - // Requires at least Windows 10 and WS_CAPTION style to work properly. - constexpr ULONG dmfSetTitleBar = 0x00000008UL; - // Will apply dark explorer theme. - // Used mainly for scrollbars and tooltips not handled with dmfSetThemeChildren. - // Might also change style for other elements. - // Should be handled after controls initializations and in NPPN_DARKMODECHANGED. - // Requires at least Windows 10 to work properly. - constexpr ULONG dmfSetThemeDirectly = 0x00000010UL; - - // defined in Notepad_plus_msgs.h - //constexpr ULONG dmfInit = dmfSubclassParent | dmfSubclassChildren | dmfSetTitleBar; // 0x000000BUL - //constexpr ULONG dmfHandleChange = dmfSetThemeChildren | dmfSetTitleBar; // 0x000000CUL - - constexpr ULONG dmfRequiredMask = dmfSubclassParent | dmfSubclassChildren | dmfSetThemeChildren | dmfSetTitleBar | dmfSetThemeDirectly; - //constexpr ULONG dmfAllMask = dmfSubclassParent | dmfSubclassChildren | dmfSetThemeChildren | dmfSetTitleBar | dmfSetThemeDirectly; - - if (hwnd == nullptr || (dmFlags & dmfRequiredMask) == 0) - { - return 0; - } - - auto dmfBitwiseCheck = [dmFlags](ULONG flag) -> bool { - return (dmFlags & flag) == flag; - }; - - ULONG result = 0UL; - - if (dmfBitwiseCheck(dmfSubclassParent)) - { - const bool success = ::SetWindowSubclass(hwnd, PluginDockWindowSubclass, g_pluginDockWindowSubclassID, 0) == TRUE; - if (success) - { - result |= dmfSubclassParent; - } - } - - const bool subclassChildren = dmfBitwiseCheck(dmfSubclassChildren); - if (dmfBitwiseCheck(dmfSetThemeChildren) || subclassChildren) - { - NppDarkMode::autoSubclassAndThemeChildControls(hwnd, subclassChildren, g_isAtLeastWindows10); - result |= dmfSetThemeChildren; - - if (subclassChildren) - { - result |= dmfSubclassChildren; - } - } - - if (dmfBitwiseCheck(dmfSetTitleBar)) - { - const auto style = ::GetWindowLongPtr(hwnd, GWL_STYLE); - if (NppDarkMode::isExperimentalSupported() && ((style & WS_CAPTION) == WS_CAPTION)) - { - NppDarkMode::setDarkTitleBar(hwnd); - result |= dmfSetTitleBar; - } - } - - if (dmfBitwiseCheck(dmfSetThemeDirectly)) - { - if (NppDarkMode::isWindows10()) - { - NppDarkMode::setDarkExplorerTheme(hwnd); - result |= dmfSetThemeDirectly; - } - } - - return result; - } - - constexpr UINT_PTR g_windowNotifySubclassID = 42; - - LRESULT CALLBACK WindowNotifySubclass( - HWND hWnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam, - UINT_PTR uIdSubclass, - DWORD_PTR dwRefData - ) - { - UNREFERENCED_PARAMETER(dwRefData); - - switch (uMsg) - { - case WM_NCDESTROY: - { - ::RemoveWindowSubclass(hWnd, WindowNotifySubclass, uIdSubclass); - break; - } - - case WM_NOTIFY: - { - auto nmhdr = reinterpret_cast(lParam); - - constexpr size_t classNameLen = 16; - TCHAR className[classNameLen]{}; - GetClassName(nmhdr->hwndFrom, className, classNameLen); - - switch (nmhdr->code) - { - case NM_CUSTOMDRAW: - { - if (wcscmp(className, TOOLBARCLASSNAME) == 0) - { - return NppDarkMode::darkToolBarNotifyCustomDraw(lParam); - } - - if (wcscmp(className, WC_LISTVIEW) == 0) - { - return NppDarkMode::darkListViewNotifyCustomDraw(hWnd, uMsg, wParam, lParam, false); - } - - if (wcscmp(className, WC_TREEVIEW) == 0) - { - return NppDarkMode::darkTreeViewNotifyCustomDraw(lParam); - } - } - break; - } - break; - } - } - return DefSubclassProc(hWnd, uMsg, wParam, lParam); - } - - void autoSubclassAndThemeWindowNotify(HWND hwnd) - { - SetWindowSubclass(hwnd, WindowNotifySubclass, g_windowNotifySubclassID, 0); - } - - void setDarkTitleBar(HWND hwnd) - { - constexpr DWORD win10Build2004 = 19041; - if (NppDarkMode::getWindowsBuildNumber() >= win10Build2004) - { - BOOL value = NppDarkMode::isEnabled() ? TRUE : FALSE; - ::DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value)); - } - else - { - NppDarkMode::allowDarkModeForWindow(hwnd, NppDarkMode::isEnabled()); - NppDarkMode::setTitleBarThemeColor(hwnd); - } - } - - void setDarkExplorerTheme(HWND hwnd) - { - SetWindowTheme(hwnd, g_isAtLeastWindows10 && NppDarkMode::isEnabled() ? L"DarkMode_Explorer" : nullptr, nullptr); - } - - void setDarkScrollBar(HWND hwnd) - { - NppDarkMode::setDarkExplorerTheme(hwnd); - } - - void setDarkTooltips(HWND hwnd, ToolTipsType type) - { - UINT msg = 0; - switch (type) - { - case NppDarkMode::ToolTipsType::toolbar: - msg = TB_GETTOOLTIPS; - break; - case NppDarkMode::ToolTipsType::listview: - msg = LVM_GETTOOLTIPS; - break; - case NppDarkMode::ToolTipsType::treeview: - msg = TVM_GETTOOLTIPS; - break; - case NppDarkMode::ToolTipsType::tabbar: - msg = TCM_GETTOOLTIPS; - break; - default: - msg = 0; - break; - } - - if (msg == 0) - { - NppDarkMode::setDarkExplorerTheme(hwnd); - } - else - { - auto hTips = reinterpret_cast(::SendMessage(hwnd, msg, 0, 0)); - if (hTips != nullptr) - { - NppDarkMode::setDarkExplorerTheme(hTips); - } - } - } - - void setDarkLineAbovePanelToolbar(HWND hwnd) - { - COLORSCHEME scheme{}; - scheme.dwSize = sizeof(COLORSCHEME); - - if (NppDarkMode::isEnabled()) - { - scheme.clrBtnHighlight = NppDarkMode::getDarkerBackgroundColor(); - scheme.clrBtnShadow = NppDarkMode::getDarkerBackgroundColor(); - } - else - { - scheme.clrBtnHighlight = CLR_DEFAULT; - scheme.clrBtnShadow = CLR_DEFAULT; - } - - ::SendMessage(hwnd, TB_SETCOLORSCHEME, 0, reinterpret_cast(&scheme)); - } - - void setDarkListView(HWND hwnd) - { - if (NppDarkMode::isExperimentalSupported()) - { - bool useDark = NppDarkMode::isEnabled(); - - HWND hHeader = ListView_GetHeader(hwnd); - NppDarkMode::allowDarkModeForWindow(hHeader, useDark); - SetWindowTheme(hHeader, useDark ? L"ItemsView" : nullptr, nullptr); - - NppDarkMode::allowDarkModeForWindow(hwnd, useDark); - SetWindowTheme(hwnd, L"Explorer", nullptr); - } - } - - void disableVisualStyle(HWND hwnd, bool doDisable) - { - if (doDisable) - { - SetWindowTheme(hwnd, L"", L""); - } - else - { - SetWindowTheme(hwnd, nullptr, nullptr); - } - } - - // range to determine when it should be better to use classic style - constexpr double g_middleGrayRange = 2.0; - - void calculateTreeViewStyle() - { - COLORREF bgColor = NppParameters::getInstance().getCurrentDefaultBgColor(); - - if (g_treeViewBg != bgColor || g_lighnessTreeView == 50.0) - { - g_lighnessTreeView = calculatePerceivedLighness(bgColor); - g_treeViewBg = bgColor; - } - - if (g_lighnessTreeView < (50.0 - g_middleGrayRange)) - { - g_treeViewStyle = TreeViewStyle::dark; - } - else if (g_lighnessTreeView > (50.0 + g_middleGrayRange)) - { - g_treeViewStyle = TreeViewStyle::light; - } - else - { - g_treeViewStyle = TreeViewStyle::classic; - } - } - - void setTreeViewStyle(HWND hwnd) - { - auto style = static_cast(::GetWindowLongPtr(hwnd, GWL_STYLE)); - bool hasHotStyle = (style & TVS_TRACKSELECT) == TVS_TRACKSELECT; - bool change = false; - switch (g_treeViewStyle) - { - case TreeViewStyle::light: - { - if (!hasHotStyle) - { - style |= TVS_TRACKSELECT; - change = true; - } - SetWindowTheme(hwnd, L"Explorer", nullptr); - break; - } - case TreeViewStyle::dark: - { - if (!hasHotStyle) - { - style |= TVS_TRACKSELECT; - change = true; - } - SetWindowTheme(hwnd, g_isAtLeastWindows10 ? L"DarkMode_Explorer" : nullptr, nullptr); - break; - } - default: - { - if (hasHotStyle) - { - style &= ~TVS_TRACKSELECT; - change = true; - } - SetWindowTheme(hwnd, nullptr, nullptr); - break; - } - } - - if (change) - { - ::SetWindowLongPtr(hwnd, GWL_STYLE, style); - } - } - - bool isThemeDark() - { - return g_treeViewStyle == TreeViewStyle::dark; - } - - void setBorder(HWND hwnd, bool border) - { - auto style = static_cast(::GetWindowLongPtr(hwnd, GWL_STYLE)); - bool hasBorder = (style & WS_BORDER) == WS_BORDER; - bool change = false; - - if (!hasBorder && border) - { - style |= WS_BORDER; - change = true; - } - else if (hasBorder && !border) - { - style &= ~WS_BORDER; - change = true; - } - - if (change) - { - ::SetWindowLongPtr(hwnd, GWL_STYLE, style); - ::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); - } - } - - BOOL CALLBACK enumAutocompleteProc(HWND hwnd, LPARAM /*lParam*/) - { - constexpr size_t classNameLen = 16; - TCHAR className[classNameLen]{}; - GetClassName(hwnd, className, classNameLen); - if ((wcscmp(className, L"ListBoxX") == 0)) - { - NppDarkMode::setDarkTitleBar(hwnd); - NppDarkMode::autoThemeChildControls(hwnd); - - return FALSE; - } - - return TRUE; - } - - // set dark scrollbar for autocomplete list - void setDarkAutoCompletion() - { - ::EnumThreadWindows(::GetCurrentThreadId(), (WNDENUMPROC)enumAutocompleteProc, 0); - } - - LRESULT onCtlColor(HDC hdc) - { - if (!NppDarkMode::isEnabled()) - { - return FALSE; - } - - ::SetTextColor(hdc, NppDarkMode::getTextColor()); - ::SetBkColor(hdc, NppDarkMode::getBackgroundColor()); - return reinterpret_cast(NppDarkMode::getBackgroundBrush()); - } - - LRESULT onCtlColorSofter(HDC hdc) - { - if (!NppDarkMode::isEnabled()) - { - return FALSE; - } - - ::SetTextColor(hdc, NppDarkMode::getTextColor()); - ::SetBkColor(hdc, NppDarkMode::getSofterBackgroundColor()); - return reinterpret_cast(NppDarkMode::getSofterBackgroundBrush()); - } - - LRESULT onCtlColorDarker(HDC hdc) - { - if (!NppDarkMode::isEnabled()) - { - return FALSE; - } - - ::SetTextColor(hdc, NppDarkMode::getTextColor()); - ::SetBkColor(hdc, NppDarkMode::getDarkerBackgroundColor()); - return reinterpret_cast(NppDarkMode::getDarkerBackgroundBrush()); - } - - LRESULT onCtlColorError(HDC hdc) - { - if (!NppDarkMode::isEnabled()) - { - return FALSE; - } - - ::SetTextColor(hdc, NppDarkMode::getTextColor()); - ::SetBkColor(hdc, NppDarkMode::getErrorBackgroundColor()); - return reinterpret_cast(NppDarkMode::getErrorBackgroundBrush()); - } - - LRESULT onCtlColorDarkerBGStaticText(HDC hdc, bool isTextEnabled) - { - if (!NppDarkMode::isEnabled()) - { - ::SetTextColor(hdc, ::GetSysColor(isTextEnabled ? COLOR_WINDOWTEXT : COLOR_GRAYTEXT)); - return FALSE; - } - - ::SetTextColor(hdc, isTextEnabled ? NppDarkMode::getTextColor() : NppDarkMode::getDisabledTextColor()); - ::SetBkColor(hdc, NppDarkMode::getDarkerBackgroundColor()); - return reinterpret_cast(NppDarkMode::getDarkerBackgroundBrush()); - } - - INT_PTR onCtlColorListbox(WPARAM wParam, LPARAM lParam) - { - auto hdc = reinterpret_cast(wParam); - auto hwnd = reinterpret_cast(lParam); - - auto style = ::GetWindowLongPtr(hwnd, GWL_STYLE); - bool isComboBox = (style & LBS_COMBOBOX) == LBS_COMBOBOX; - if (!isComboBox && ::IsWindowEnabled(hwnd)) - { - return static_cast(NppDarkMode::onCtlColorSofter(hdc)); - } - return static_cast(NppDarkMode::onCtlColor(hdc)); - } - - struct HLSColour - { - WORD _hue; - WORD _lightness; - WORD _saturation; - - COLORREF toRGB() const { return ColorHLSToRGB(_hue, _lightness, _saturation); } - }; - - using IndividualTabColours = std::array; - - static constexpr IndividualTabColours individualTabHuesFor_Dark { { HLSColour{37, 60, 60}, HLSColour{70, 60, 60}, HLSColour{144, 70, 60}, HLSColour{255, 60, 60}, HLSColour{195, 60, 60} } }; - static constexpr IndividualTabColours individualTabHues { { HLSColour{37, 210, 150}, HLSColour{70, 210, 150}, HLSColour{144, 210, 150}, HLSColour{255, 210, 150}, HLSColour{195, 210, 150}}}; - - - COLORREF getIndividualTabColour(int colourIndex, bool themeDependant, bool saturated) - { - if (colourIndex < 0 || colourIndex > 4) return {}; - - HLSColour result; - if (themeDependant) - { - result = individualTabHuesFor_Dark[colourIndex]; - - if (saturated) - { - result._lightness = 146U; - result._saturation = std::min(240U, result._saturation + 100U); - } - } - else - { - result = individualTabHues[colourIndex]; - - if (saturated) - { - result._lightness = 140U; - result._saturation = std::min(240U, result._saturation + 30U); - } - } - - return result.toRGB(); - } -} diff --git a/NppDarkMode.h b/NppDarkMode.h deleted file mode 100644 index e47c80d..0000000 --- a/NppDarkMode.h +++ /dev/null @@ -1,251 +0,0 @@ -// This file is part of Notepad++ project -// Copyright (c) 2021 adzm / Adam D. Walling - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// at your option any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#pragma once - -#include - -#include "Common.h" // for generic_string -//δ붨һΪNppDarkModeռ䣬аһЩṹͺ -namespace NppDarkMode -{ - struct Colors - { - // ɫṹColorsɫͱɫȵ㱳ɫɫ󱳾ɫıɫɫıɫıɫıɫԵɫȵԵɫñԵɫ - COLORREF background = 0; - COLORREF softerBackground = 0; - COLORREF hotBackground = 0; - COLORREF pureBackground = 0; - COLORREF errorBackground = 0; - COLORREF text = 0; - COLORREF darkerText = 0; - COLORREF disabledText = 0; - COLORREF linkText = 0; - COLORREF edge = 0; - COLORREF hotEdge = 0; - COLORREF disabledEdge = 0; - }; - - struct Options - { - // Optionsṹ壬ڴ洢ģʽѡ - bool enable = false; - bool enableMenubar = false; - bool enablePlugin = false; - }; - - struct NppDarkModeParams - { - // NppDarkModeParamsṹ壬ڴ洢ģʽIJ - const wchar_t* _themeClassName = nullptr; - bool _subclass = false; - bool _theme = false; - }; - - enum class ToolTipsType - { - // ToolTipsTypeö٣ڱʶͬ͵Ĺʾ - tooltip, - toolbar, - listview, - treeview, - tabbar - }; - - enum ColorTone { - // ColorToneö٣ڱʶͬɫ - blackTone = 0, - redTone = 1, - greenTone = 2, - blueTone = 3, - purpleTone = 4, - cyanTone = 5, - oliveTone = 6, - customizedTone = 32 - }; - - enum class TreeViewStyle - { - // TreeViewStyleö٣ڱʶͬͼʽ - classic = 0, - light = 1, - dark = 2 - }; - - struct AdvOptDefaults - { - // AdvOptDefaultsṹ壬ڴ洢߼ѡĬֵ - generic_string _xmlFileName; - int _toolBarIconSet = -1; - int _tabIconSet = -1; - bool _tabUseTheme = false; - }; - - struct AdvancedOptions - { - // AdvancedOptionsṹ壬ڴ洢߼ѡ - bool _enableWindowsMode = false; - - NppDarkMode::AdvOptDefaults _darkDefaults{ L"DarkModeDefault.xml", 0, 2, false }; - NppDarkMode::AdvOptDefaults _lightDefaults{ L"", 4, 0, true }; - }; - - void initDarkMode(); // ʼģʽNppParametersлȡѡ - void refreshDarkMode(HWND hwnd, bool forceRefresh = false); // ӦµѡNPPM_INTERNAL_REFRESHDARKMODEϢhwndĶ - - void initAdvancedOptions(); // ʼ߼ѡ - - bool isEnabled(); // ȡģʽǷõ״̬ - bool isDarkMenuEnabled(); // ȡ˵Ƿʹðģʽ״̬ - bool isEnabledForPlugins(); // ȡǷʹðģʽ״̬ - bool isExperimentalActive(); // ȡʵ԰ģʽǷõ״̬ - bool isExperimentalSupported(); // ȡʵ԰ģʽǷֵ֧״̬ - - bool isWindowsModeEnabled(); // ȡWindowsģʽǷõ״̬ - void setWindowsMode(bool enable); // WindowsģʽǷ - generic_string getThemeName(); // ȡ - void setThemeName(const generic_string& newThemeName); // - int getToolBarIconSet(bool useDark); // ȡͼ꼯 - void setToolBarIconSet(int state2Set, bool useDark); // ùͼ꼯 - int getTabIconSet(bool useDark); // ȡѡͼ꼯 - void setTabIconSet(bool useAltIcons, bool useDark); // ѡͼ꼯 - bool useTabTheme(); // ȡѡǷ - void setAdvancedOptions(); // ø߼ѡ - - bool isWindows10(); // ȡWindowsǷΪ10汾 - bool isWindows11(); // ȡWindowsǷΪ11汾 - DWORD getWindowsBuildNumber(); // ȡWindowsĹ汾 - - COLORREF invertLightness(COLORREF c); // תɫ - COLORREF invertLightnessSofter(COLORREF c); // תɫ - double calculatePerceivedLighness(COLORREF c); // ɫ - - void setDarkTone(ColorTone colorToneChoice); // ðģʽɫ - - COLORREF getBackgroundColor(); // ȡɫ - COLORREF getSofterBackgroundColor(); // ȡͱɫ - COLORREF getHotBackgroundColor(); // ȡȵ㱳ɫ - COLORREF getDarkerBackgroundColor(); // ȡɫɫ - COLORREF getErrorBackgroundColor(); // ȡ󱳾ɫ - - COLORREF getTextColor(); // ȡıɫ - COLORREF getDarkerTextColor(); // ȡɫıɫ - COLORREF getDisabledTextColor(); // ȡıɫ - COLORREF getLinkTextColor(); // ȡıɫ - - COLORREF getEdgeColor(); // ȡԵɫ - COLORREF getHotEdgeColor(); // ȡȵԵɫ - COLORREF getDisabledEdgeColor(); // ȡñԵɫ - - HBRUSH getBackgroundBrush(); // ȡˢ - HBRUSH getDarkerBackgroundBrush(); // ȡɫˢ - HBRUSH getSofterBackgroundBrush(); // ȡͱˢ - HBRUSH getHotBackgroundBrush(); // ȡȵ㱳ˢ - HBRUSH getErrorBackgroundBrush(); // ȡ󱳾ˢ - - HBRUSH getEdgeBrush(); // ȡԵˢ - HBRUSH getHotEdgeBrush(); // ȡȵԵˢ - HBRUSH getDisabledEdgeBrush(); // ȡñԵˢ - - COLORREF getIndividualTabColour(int colourIndex, bool themeDependant, bool saturated); - - void setBackgroundColor(COLORREF c); - void setSofterBackgroundColor(COLORREF c); - void setHotBackgroundColor(COLORREF c); - void setDarkerBackgroundColor(COLORREF c); - void setErrorBackgroundColor(COLORREF c); - void setTextColor(COLORREF c); - void setDarkerTextColor(COLORREF c); - void setDisabledTextColor(COLORREF c); - void setLinkTextColor(COLORREF c); - void setEdgeColor(COLORREF c); - void setHotEdgeColor(COLORREF c); - void setDisabledEdgeColor(COLORREF c); - - Colors getDarkModeDefaultColors(); - void changeCustomTheme(const Colors& colors); - - // handle events - void handleSettingChange(HWND hwnd, LPARAM lParam, bool isFromBtn = false); - bool isDarkModeReg(); - - // processes messages related to UAH / custom menubar drawing. - // return true if handled, false to continue with normal processing in your wndproc - bool runUAHWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* lr); - void drawUAHMenuNCBottomLine(HWND hWnd); - - // from DarkMode.h - void initExperimentalDarkMode(); - void setDarkMode(bool useDark, bool fixDarkScrollbar); - void allowDarkModeForApp(bool allow); - bool allowDarkModeForWindow(HWND hWnd, bool allow); - void setTitleBarThemeColor(HWND hWnd); - - // enhancements to DarkMode.h - void enableDarkScrollBarForWindowAndChildren(HWND hwnd); - - inline void paintRoundFrameRect(HDC hdc, const RECT rect, const HPEN hpen, int width = 0, int height = 0); - - void subclassButtonControl(HWND hwnd); - void subclassGroupboxControl(HWND hwnd); - void subclassTabControl(HWND hwnd); - void subclassComboBoxControl(HWND hwnd); - - bool subclassTabUpDownControl(HWND hwnd); - - void subclassAndThemeButton(HWND hwnd, NppDarkModeParams p); - void subclassAndThemeComboBox(HWND hwnd, NppDarkModeParams p); - void subclassAndThemeListBoxOrEditControl(HWND hwnd, NppDarkModeParams p, bool isListBox); - void subclassAndThemeListView(HWND hwnd, NppDarkModeParams p); - void themeTreeView(HWND hwnd, NppDarkModeParams p); - void themeToolbar(HWND hwnd, NppDarkModeParams p); - void themeRichEdit(HWND hwnd, NppDarkModeParams p); - - void autoSubclassAndThemeChildControls(HWND hwndParent, bool subclass = true, bool theme = true); - void autoThemeChildControls(HWND hwndParent); - - LRESULT darkToolBarNotifyCustomDraw(LPARAM lParam); - LRESULT darkListViewNotifyCustomDraw(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool isPlugin); - LRESULT darkTreeViewNotifyCustomDraw(LPARAM lParam); - - void autoSubclassAndThemePluginDockWindow(HWND hwnd); - ULONG autoSubclassAndThemePlugin(HWND hwnd, ULONG dmFlags); - void autoSubclassAndThemeWindowNotify(HWND hwnd); - - void setDarkTitleBar(HWND hwnd); - void setDarkExplorerTheme(HWND hwnd); - void setDarkScrollBar(HWND hwnd); - void setDarkTooltips(HWND hwnd, ToolTipsType type); - void setDarkLineAbovePanelToolbar(HWND hwnd); - void setDarkListView(HWND hwnd); - - void disableVisualStyle(HWND hwnd, bool doDisable); - void calculateTreeViewStyle(); - void setTreeViewStyle(HWND hwnd); - bool isThemeDark(); - void setBorder(HWND hwnd, bool border = true); - - BOOL CALLBACK enumAutocompleteProc(HWND hwnd, LPARAM lParam); - void setDarkAutoCompletion(); - - LRESULT onCtlColor(HDC hdc); - LRESULT onCtlColorSofter(HDC hdc); - LRESULT onCtlColorDarker(HDC hdc); - LRESULT onCtlColorError(HDC hdc); - LRESULT onCtlColorDarkerBGStaticText(HDC hdc, bool isTextEnabled); - INT_PTR onCtlColorListbox(WPARAM wParam, LPARAM lParam); -} -//ЩҪڳʼ͹Notepad++İģʽɫáʽڿؼ⻯ȹܡ \ No newline at end of file diff --git a/doc/Notepad_plus_plus.docx b/doc/Notepad_plus_plus.docx new file mode 100644 index 0000000..5cee372 Binary files /dev/null and b/doc/Notepad_plus_plus.docx differ