From 9f8f220ec6d1ab7f7d2ee1a9e6a599d2e1c1f5fd Mon Sep 17 00:00:00 2001
From: pipi <1779595642@qq.com>
Date: Mon, 22 Jan 2024 16:19:43 +0800
Subject: [PATCH] =?UTF-8?q?=E6=96=B0=5F=E6=B3=9B=E8=AF=BB=E6=8A=A5?=
=?UTF-8?q?=E5=91=8A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
NppDarkMode.cpp | 3241 ------------------------------------
NppDarkMode.h | 251 ---
doc/Notepad_plus_plus.docx | Bin 0 -> 533900 bytes
3 files changed, 3492 deletions(-)
delete mode 100644 NppDarkMode.cpp
delete mode 100644 NppDarkMode.h
create mode 100644 doc/Notepad_plus_plus.docx
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 0000000000000000000000000000000000000000..5cee372c8adc2bea2bc60a0e8247884200fa6720
GIT binary patch
literal 533900
zcmeFYQy@@tXx-C
zmK6Sif}sIH06_r(0TBZo-o9-X0s{fk
zf`L%w1A+Xv{{OZAizU#UBKsGV2`Th8@YircwX=div{)PQAD*hhfOY0{>wr&!%*u~9
z<&GP&WtUY~T8J#bcaIV^J-U{^=FcuM#kKB;+!QfQzf@gwmfF?HyPd;8Wboi0!|tF+
zI--WE`}>76Ph=wWVz&w-mSKkp&qS7bk`#XbqMS_$n)rW5$&kc*!)R|C4j!{5?obGj
z>3r)RE}$*xxU_ZxmL0^lwBw$4)f}5wea^L$n)#=ho
z^wx_qVJ^bp+9(gRFa9Yv0h!n>frpBs-I%GBZ((tfGz_Py$tQMM@Y%h!Ex~GeJHk&W
zN`=~ur8e%>^L8_R5hAmwUY}O*YfvvtAMtXpqn5HwgrdvyFAmlW+uL$PDBlNJ3tH~N
zWI9-qVU!j=T}QwPV7@@r**wVn1`o@)BOH%%@tfW*1fT6OtDUGI*%uLp*I!Zm3We!d
zXGMrKmvT_W#0WF)zvuPM8|YFgQ$nI~!e3(zYb?A~kO%6h<+5a#J#&!no(lOtnL9Ew
zpzwR}2R`roaee=x^7j`MNa25@c82Od@Sp!?4*p{0?kOcQUncW}yF{{{K<>|6(5h
z|Bhar`2SIwc)EvYi<)F{M^E%j*5n&lg!wZd3o)^x^>>#ll76`*jDW@Sbb>`>HLC}I
zg=UP^Lw%r;N~mFJ7p}Hyzr#~wJ5XA9cK!@s-C-Xr>*K-bdze(pPWl@uaS|OuChhmm`6sOq-`hTJevaSCEhbRybwH`1K
z@_#aNw|6pOFtImwwf#>W{*NBK@-9Uy1os;1q^49{k{P~8#6
z0t(_x#~xO%i%bMV5As<$^XS3*ra*{ncSCF^8O9o6w2uc^~0y~B)2
z-JUIFO&v0_;p5i+>-P8ga#yQC^^7&Sv;#ztHKrw3&BM3FD04G&$r6oPn$$eoz8t*A
zv{@SPE?jkBlOk;;bOq+$569#pK=rkrPenOwMM!ig>JOy$Nt8et9j%sk_pZX
zoT!-Dgk}VBpCMwsJ8U4HpB1kvU%o#?lfHajiQU!7+V-<^6A<;C>GgXscMDU}x6@$6
zyHxow+hHtwy_lMx?bXf3!ichx)2#sIZp{=ITQOTLa8$C`H!_7O_C^EljQMERmlsJ>
zX&I8qvS>2I+-E+M_gE|6N+*Oz7E9fy0AuPh#zw;!%QjjBLh0tYi;!fI&~cGEVgdKR
z1{Fk4CdZ8W17`*@q`AIg2PL7aR8#6;Q!B`ML2tM~Zo98%0sz7iYtrDtK(monr|jl1
z2T*evQ=B0cI`I~dW48+#$BJvcyF~6UYUA5tW_od3nfe9nHuM^;WKSJ)g6gxXmbMw-zK>&e<_G>j01Qx96(&4+4`B
zjO;J3I*}7`HR-#eS5nH&{1fF-;BmrlGL2&{C}PTv6_pEKz=DZ?bGB8koQpUPK+}p1
z8^c{n{0cgG@#MsFPyfcLueRtej{wET@%^#zxx8H9$+Q1`nLufbjpC(W;_RWi#DWpU
zmlzh))JMBKo%;Af*Isou_e-v>lBJpY_R2x1
zgXQ<_;&Q+F;>Q;}XNIu>4&w~$?WxI@pPh|pS5H7
zbfT@jwg+Lw?{x||>#5@L`}TM`n=A6pi>3Dy==>l)Yjr(2cpFszZNCGY?b?rV+{D%W
zm_418Y3u8P#t(S${2bn&-E)KW{@a59_mBIzqX+u$^7(B1-o8D)KLATvS#i4%g^&d$UI=Y}6VPOK
zLOpE0&(>L>`WtfT|+Gn|^HH1_bV_0y>9PEpn+aGImIueF@DuHY1AlWBKCaXbXYP
zwqD=ct%W4SRBU}Kj5!Y%!GhOb>^%<{%hn%){MWZhzu2D_;NqFIJh?0Xk%k)k+Vxhv
zddJTV%B(oMO#zNPUR=KKvk@r3z(xJT;IrZBV3sz=jUE5T&e?}HDpSuVJ=scjyS<%F
z^lk@yG3w-ZS{^8Hh|}*-&J1PSD51{o#}2uJ<>URB0U?)tKk=i;AYlVTixa)D0du(oxR^L{ygD42>OJYSbz2y
zrub!Fn>|<0N*Ji_&o^Lnt;l|@jeU2s!@>0H#t+04R~M}OA4}&Gc>g@0HD-5q3^RZf
z4$LrOB;eR1AXTINHeDOfB6xsH2B2Sa*+qn)z1F~@u~xt-;Op-4c#eWMgbhbYhVh~E
z_$eU{^rSnBnzg4r?HoPE6q{kofq1ZvP1~2`xSujHfb~`h+&XkUEUm~k-QMysWdC)Q
z<@W+VYrC>(R(FyaBK@~bN0A@_Dl-T*2s63R>UPuv$JlhgO-lsGXn+b5P7;YTFrKra
zQwhtTkTobkKQ%r;uOv~4k-V#}#aAofNmDmqy{`7StTr6th{DhpoPZ6PHpU1|x~Pg~
zMh8?9$^fvM@|R|n9rlS9tc#wnOm#UB4g&^!k-SYU*ZRH7{z|?`@OSr!m04FxJ-W;o5n_TKeow-)&G
zTuCbi{SBN5(xF}>o`D6n^8B}U%}a&s`X%B1FY--!zJ(B2pOg10Kt6CMV1J!a~%n8+g#>%<8o@T
zjB*M8`3649dR0+7Jt(czj0R43G9;t`q1sBt5(8cLPpGqL$Xbfdj4(uGo7gZHC>1nH
zsMP$T>l&O#AT+-6-`U@yIR81n^!_{00LzxA!U6>JcHc6j6R?VaB8E&R)uJpScM`s8CZS?(Q{J!#I6qkTtqR<|f8O9tj@eo9z|rg)yEY1aTInZXDFZ8Ih6f#2V6v;(thxyijjrTiC#5TI7#^jna?e?-K&gRr(S{~vzl);
z*w=D$dCkK6r>tUOlr2C)>t=EFWec77^g;g5kui+03p?)6MzMKi2;HUH<%B-^y{4Hp
zquVvgB)Oo8r3eF^c~yB$BA&XYGZafkeYJ&IR))QpWUowRmae=O=~AyfX`QDwxmqv{
z5EO_bB{~;FP?MKc&=W|W{Db$VvqJ%Klq3cx1vt*B199=gLBB`!d?8?6?`F*iKPibf
zUJO|X7~eCI8Ly*-31D;(9(q3leHYGk4U#SMG@eSkU}6&OPC1ir@mM6y+w{E{x1V2{
z>Uq&!)H~GJgF2G5nJ}%Pa+#KH>v{$HNuad`8CLEjwgTuUwEp2jW>l(_T@>1wiuQ4s
zd_4;Nm(JEVou$gvbt*3Eklz|2>c%D0^9kW>$_H>WuF^vCwP!^ji5&ChT(T~$qOb<#
z1Z&z}-V99J`3v35my#!&Rccc<^IY{nUNOx|cWnu+q~uEQ5b^ph+}^-;0!^HQ*v>qP
zYJDN^vAk>?&n^+Wl>B!6#!EHJ&CaMiO)bH3O
z6l*6My;-7Kbi$LcDFs#X$r|d->0^@a{o^W|t_7zgmz{kxfEAmXJeZ2>XmF$`y6sI9%Lnn(^$Ge@_rZZZIhjb1Rw`GUkL#Neg3Pp=96gjc67U4EZJaKba
zA|m!fCPn4?O)TgO$nJDk@34QgOyi^rc4mSo@5}v?`A(SFP6IymwfW%ncyXvYv9%EIIu?=$QM+=Sy8X`0dJEnswM2;}3QW_Dw6lkxB}=fO5dQKp
zhKzq9nrVyPoqjx!>EIu!f==lCTdeX`91T&@Shi-}GR_Opv=>oBni;tALGVaaaD1fA
z0=+1;(R`X2@|jt2n6h2+h_U^YN5jv52Oz}7>_Iq&D0E%C
zlX^l~@?^m>Z8%oU-uf9=`>k(m`kAKP>s9_*t0NIcu1sjqO^beTVceVHVe~tY=%}bN
z9okI)|C%@pWmRt8xKk8`X=#(X)x3W%@E;M%(}ktDt}g
zYDafyN}XHateiYOhE{V0}`+-0FeF4%mE@N{kF&>it+PAVo6
zRZSxPxe6#s=WN({?8NrLcW0yVOZR?4Q7|k@exN=rLfHK)%&+lMC>iEN*#t?Pm_%@O
zr}S8%rIom0uf+X02k6)-2aqcoNgb+am24Y`A4!JGOBbYc&k1MTk59nUn&q6$P-X!MUr&zSruH^qsD`D|4^l`xGGNcE1Ej
z31Apv>wMmVUJshQy+%xl+zwrB9wYn}jahDSmlR=EWdhl_x_zzBD{a3%U*~!X-m@zJ
zBoF#8f^~=$ZKS}KoMh8>*A2|qhC;G2d{^lH-&gSdW>PMOEYYG*#I{>M2vPgF{?9>{
z(9-2giQ%wWJeGIxc`O@7SFx&7m`Du<2DT$9(Tn{fEEHqWK(p83C&h?-tju-i7e5?T
z-rUZZI-eHb&x@CkD8Zwv_31$wL@rHXvt0<1;2^;Cd6LjbS)OKPuubJgX
zK_Q#$LGSN5YA>PLB)TMea8svV2h)^rU30gHG*|*HTY>-&aV;
z#8TUtI|+Z({z9@;|ICsHVuwL6q_R=l^W*7muIu%&b-oO|MY(#PbB5ysaH}9W2_Gjgi$hH2`(WWJ}xiC_9@*@YBf
z;h{?z%D3+IH7*O88^%TpUc@>`*`ygB(rT!?=fn#1z3U*FZWQD0gN1t^<^L}7cD?}D
z!%@!9%s}4S@wWr{BpvN|KTpnjzox3GVheyFOh0~H=;ETL3%s9ljQO>LpG-QTQ}Umm
z*uTQ8pUBHG?}2ixn{&-Xh&d73CeX6R8YfspU^<8f<4&qC+C{&+wX3sxb;8;!yPXCc*>dd9OhgMKgaRv$~Ni>v*et^D(5cUtskrVQU^2;8|m&zJoJ
zVEicx_LPT?zrF(OkI#e24^Cp@{nG>rO0@d|9Noi!`yVo&Jbb@4a_*a8kA64TeH?6E
zzAwO*uLS~Twd3~wL%h4eaOx2Q@qKVVvbT?ca5DKmJ_8^l$3?%x#Su1=h!f0dw8GFl
zjWg2ehzNFSfRr|DM$=RA
zW!3aXo)LgHq#n)?d+J*zYc9V9MR6r?rYOj=d;L58y|r3QgedplP&QypOXbTCYls*s
z>i!fA1$h=3iZ16!BamN$6h)Q@EC{Cj?)P9v@Qeo{xll)UdHK)ZG+(U2ZDX$Z2&(H$
z=dzIbr@D~BrQF~YvT96zC>`b;G_9MYmNRo|>S9$aq<}Cn0b>VY3>eU4bbt58o&7pdh#{8~Eq*bdHVEWN8Da$@b9PQI%*>f9aSl21PUQ%eVO*Wa86)!M3A=U2RC`B7-7iU2$O(4oQ3m+nce@ej6+ZK(-M}R<
z?)B?UQq4Ig%vvNboXm;q_rTIT)`*n;heHO}#wd}wKhuWt5*q%V;R(h}nFTNW)?r5E
z0cO=H?%1wB_q4CcS}(6b2z3bMdZLbr{Y+q;jgKpS&LRJvHZVVOL@FNNa#cnBR6cvFUcNq7Jr7aau~0kj6CV)hyPksR>>ar;=w>>M%_zW%{PFMH
zzI7Y?r=uur^G7xHh>eg-(sUVT0d8bbc%Wpp-UQllzN8Smo=I|fNR^3TKe5(?bCTwU
zy()R0U60jRgpjf@A(96<95qx=auHgeA!{blqXXN;iHQ`c601jrE~Nda`Nj>~jT}Fh
zImS!meu;qm8U_uPIKuTpvLPdOWFtSrXi%6hPl8vGD}m}srY7Ag9ZUmc{sqZGHI#r%
zW5$7pFTqNo35Z!}4+$N~FNF{-8|5O3%R-Q>=)g@v=UpQ#I%2}99?Puop7mxH)N#tg
zTNk;8S(jbMo*7~L%B8BtV+0?2(`YHlI58rv9Ys%(MX1RB3HGfXKo33Q)1eRN`Be~m
zE}_u|xg?Fyf?_Ns(SbPyPYR|E`%zSICOG90z>|j<-spE7e?zyD4QlclBG?UhDWD?_I?%HWUD
ze}7DM9ZQ)BEg)#FIJGLWL>92Na@V1u!mGdF$fcX^FHI#7DaME0c$F{^Wi$rp_Bd9ZH-RG0zu2S_}#|YChSea9cq#8zW~sl}QZb
z)!fo$NyuCoug=JE6Znm>TQV8i)31JSK48W?V(N{`$s56mfJ<<+42=G38ro*yNYzzk
zr&5EzJIrCD{PjNs7HJzo>??#Hkj2lhQ2ty}LVS+vfB;voY}K|lsCqcF(?|pu&{hJA
zdL;r_yzmoI1jM9)5qW-;43L_Wd!w>>NuyMI(6dPigNUQxP+nRPxFHhhT#)9_yrbnG
zI?l7z-qZ0zf$T&^t-uBV3tv(u>&y!QL&2N<#`Ouan2m(J$Emm$NV@afby;1owvmE7
zstrUxg?0H;|7iJ&HcS|)^^$`Q23bB0gO*Y(CH$xL($D+b!+8j;A=Sru!Pnz`3ONEM
zk`@|Mq(9GF9+DwqZ8DDs1Xx&MdVj8`j%gk;mo5Ct*~84jC@IgzHP8xwut4LmL2|c@
z<-*_Nx%8OvS1PVP@bdu{Bi5^J|{yB)B~aD6_os{&df@!GdO
z0=;)xhVe4PV?Z&Ux^7`*CLUDNkoV`vE!VE9Tl3C)h
zY&&^IjMKnCm;EKC8p-*PMQcXR#gg+hXy)heO`c#@3H^qwu3*ojw-U}*Xzs;%g0g?PV@Sh
zrJ?^%te+b(3o`=K8erBWyYF~rW4?Z#Us<2pxOve8JN|#eTGH1MeIc`k$fpiXaw(+V
zp!U*^h;MqWhx8;;OQ-OJ%CN4Y+~o6n_NBoyWROyC<>4pZXkR~UYM7IWMea)_8ySQG7|fN(#16qam;W66r|`j~Bj9F#7b!-N@S^BZ
zUIDZj6o@aF6{46WGlRIPn
z#CXA)vy}aNhL;P#2NEMl;FaqRZX4cjekMql0&vFWg#B4t8g|U&og4gt%{ZdEQWGn%07y~
zOVFfdglkcKKJ&J{t5&CWY%R%_Wtjxcgo|j>Dc)qKk_aqI@ukX}7|G)}=Fc>QP8Rdv
zL=y#R659qu@$rv58yQ>6di-8vEj&w-+=%&Fl!~IR~zRg2|%Rwu!eumk1aU;L4tpW0um$EX_Vpkw9`FYOxj{cIj4NnswcaA1!vK@gCM?`0X5n2D710(fGX;?
zZ!`9#5m8*?p?UjRHNdDSlFVIJ_93}=p0<&$gU_73c@Z}4kB5wGPMvivx`fd$iBpjh
zV2HUDp~Pxjj8(7>SC%v*1P$wsTDVQMGIbq(Ls(48Wuq}gViR-!BD~|k6e7M5$x%Qt
zD9ey)6(9KBnj|@{U$T{=6Db<*P{WDT0LHS)GK&Qm#2Hyu+$&icX34q8aPR(0Jzr
z&rBGvL(BZP)pbs<)=`1Eh861dicO?2fm*p#c_Q}8seU-lkh3!IBMkW%PrrNDkil%tct0zL0Y)xO2Wz~$LyBp8|N_r^O0+C}U
ziLxn5L3#wE7omXBpPz*GFl0r^0)>P=v6c{Z5)F#~fzlWe9L=w7dI*DJD5A(r)l<++wys`3@03MKYhD7O^2+@cv$JMx72a5uf--Em6xyp{Z%yx*)v|AgwArkrwz
zJ>qpa|G?mGsmb8Z1@P7de49@(&{P1prg|W1i&t#n35ssHT6fzBMWxgP!P?!qmSk^y
z3L8U)H%@)x1imfIk6w?u+9cxE+HU!FyqxTT--yQ;c!ik9l_HSJGH>qzPq5=U6i`aT
zjPKL(MDh~r#-{YBRI_wxsNUSFoUVX}9s!&0n=Q|KeKWW4aF{#QErCBjcmmEDNJyE2
z=PUwf{Lb`j*JI*2dcUK4UzRSHH!p<0Rsxh>*fXA__Oiv$C_
z=_*z$^0WhDi9(vWJFjQdSab=rV;5XHXo_0(g};4J^tpUvH+(zRQi#QQJGiyE5{<4d
z2lvdGe>i0cp@D#?388NMHyw$IJX3oNRilPLf`|34p
znA}~iU(Nu^`@1*WKA)T)QH8Wp5pTH$bc2allMJX=A8RMi)7f$vjqe7=r*VW^Jd5O1
zanNw`4bAP6o=T|}`^z^Fs``pQ@5y-_UW|mllY3)`7<&Y+jIb8D#~vsD?pWZZy{)gS?P**a&`iNbM+4L5Bg%YH!4+MAfRk%iL&NiPjOi+aiZGYX_EC~T
z;CLa{gVi^8)3bGR@9ndlM7{m#p#7Cr^umcfhw16LMZ=TUntZvc0z?H71
zJMLP-4~;Vb{S>N)!86_23vzxPhvzP|WC7OyX0(@gBG;mUP9j5!mNM4Y#HEYn{og**TUw65m{;#quy$s&=zS(}CyMqA8^zV&j*8#
zg((c2=BSkBLMVtdsEx9YKt0gSOg
zP^alD@B2Wepbt<|p8bVIK15hB1IPb9_(BV2H`C;S4Te|{wBi*8Uld{A~*w(
zlVh?xo5ePC{u^v*rvaOSc1owT)n~H(5oUxFMe^{|Ir6_=2OxHbtYnKLAKJTZ1L2N)
z+Jp54dUuPP#pFoHyX9^-tGjp2{cCz%*?Q4B93iy3;`8ZzoVwNXaURnn?5&0DB1F_E#yjor_32!
za7ThkAlZ*L&^?^2Un6b^7NIm2DeKQ0?sO-detN+Qvk#nkbQU5`%qyL*r(9S3o&Ysc
zbUYY9Cis99!3Fz8vq6PqCPpu4q`<%>zs>aH~{uZ{P7%S3Y#CRS8-~EQ_P?`8djUAL4CU
z4-lRU!NC#_QvKmK7p`p-n!#cg7}if=)I^CI4EW%tYa6HSeM+_*`!clj)D*X+NYyS3
zb=n3J;O80&t2em9>Z%TKGQ@J9n9Ke1pn0dUAjy(9L>V1p@`WE
ziKa+L;VQ<7QLkY!$vws1p!mDo%<$h3p>?Cn5flEpW{rw7MNLUER-926PaRmQp5SE3
zP^C(~GkBt8dF%XPK<30K(6kH@`|5<1fyV7}^r``h3dlw=%<{cs1TMm~jkF-!0=gtw
zl#_oQxu#)oN^~T|MNHxL$rP=?;b;yOzJ)7efvw;SNrB7-T8=&Z*nB-kYH+b4Dj5N8
z*-$44k$BMoa7UzZC64fA5*g|^i+_Zmt%@B4>QOfpI!^(DT7y3szf4B9xPMD#Zqa}7
zhU|Tvm^Gnf4A(Giu-VqEn192d#IlVDZBQW!Ed)r|#g`7EO5{K|cL9Oykqgfbd>~*c
z&03X<6*?@1uq9eX+gQ#OB$?&GkE8|bSE)jO8I7%WM2^AylNBW4wPjnW#VLVM#8?{m
z;r)A5kTQqi5)k3ng~hJ5y-+f!#47?xG-)fv*f{Obo5*{l0&M>1UTgSHprmE(cIA
zN~$+%Hbs|Af?|~RJH%g;ptsKhQ9L)}1-4lEAjzf-*P_p@R&I!fjY{O$;n#J7h?s^~
ztVBuf$l#hZieac=O{q{ELRBDeo0M`<7du$tt-O&{fE{ubsjWtta>Y}H6jA8s6w@#b
zs5D2+N|MHHhRv5KaOmS>E}j(+nAZ@YFjB69C@?pB(Q#*g-glvE(>MrMiBqyl%S
z$)Ek5kdB>Y`2^XS0E|ZwUrB}6s%v-Hxyo?v589#YP~4R>>|ma8FBgFz1NwuR6NIFR
zo>$~2#6#)YgCrqkZ@85Ur-q!4$sG^~>@##Xy=Gu`(`*LNcpQJK;F=g*J>Z-H)r<0A
zF$Y8=@o?P^Xs~xkQY_nCu`vi`lbwi;n&H9-QJYw`#?WTA9#2m>poW>`e7@D>UN5V8
zWqEymqE8RDbp8)S18>5%IaQQvK3`RcVW3=@$DUqCkQArNSKJPqa72dDMPCZK+4k}J
zIQc8PLARxSKKt0)vq!IZHk%TC{~U*e%D?yK+|6DIZh5_XAJ2L=^l!XXFU$#l&V(9E
z5een-kjI_H1(Bov$x{cg&5clJ@BPGm>GhYp=X0JA6e#kjm6RtG%}_8sa9g-a
zd+)`5o&xSO2UOzVI{a$D@-^f1;Dz8{*X#51hPeRY@>{)tD~9pS*)v}3x2gHlu5bI}
zQxsRgWYKF`U(Zp0;C9}vaSH&G&l2Hd|Gw;{4sh3rt1sW@p3cWBnf8jGSB=jKIuF$v
z9%gzqrPn*Yst`-boI9Zaz<+=0a})5Mx?h?j*g`E_yN`wKe3!T-EsGQQa`gI+YufW+
z>-jz!7{Mgu&EtPxEJ*gc+w*Sg&G>ohS=zfPYZCZo^nGPvfL~xL#TD4tHG1iKy>3~4
znrgci>+`(_WAVK|;X|xuZky$~z1n@7{7K={oI9|pE$UwG!NLhM
zW{Y-<+JFT!!o7+ZgCqi77|}YwamO|QNx_9kL4{#f$h?Tz3t^}On;g8XngVGG)+)Us
z!)eEd$j5_2AR~1kHVO(ZyG3iqkKjT!3hE8;eFf0YdShzqFU<+~nvSIt&BVX>>#Y+B
zQOOK-D<7REt4>($Hj`H+9(7wrMN+$0Wu`Xx#w*h)vP>hi)v-uKB`@f{8@6m|KQ}3_
z(M+j=Ho*x$?1OmY4Jxz78r*!~%(sMwP{D1{TGl`ks^v#GqLZP5(@?Wa
za&cy))=G$2A#kqHt7ET>2iqP{P$$~N4~?wIO0BI((r9rC&L^GK)!I&I;qd>@=*9VQZCK$6QE_|%RISK&biQnJjw
zvT}qyS@jyX4CF)$aqJ@t9_q`BD;s7kPK{T#6s}f@EzM`r4jrtPpfJuY23zxjRhSJn
zDB7GW|ENJTV~U0(r2);LZo6E9GeMn5D3YKOWL-joT@~vF+hIaWQ}E1LEyqamml;*l
zhG@f#jm6;E%3#=xlS@E~G-*{qP1_bMn$frW8fLkPcenusexL$u6hfh36O)zBVx4Cw
zS&0~%)euRBOG}|KCDE1=Cwvu!6c*aL$Phk}mM)#-|g5>5+WJzvwpqM4eEv%k7n
zdIfCY1r7!%MiD=7N9#ERkWU9+DAt1~Ht&c*4JU#8ho^pPOXg%*GIf>$9tWpcVRNb!
zmXefPiP|`S`v56_t8qR#q=Li}{<;A~L=6lUEs^VMSnHXDHQb8XJ>HzWR=tWJlm55m*SrZlS@79t#wzTPZh~wj?0xn=_FBfQue!
z?hLY##L64H{BGzLj^Lc2AuY>tpU+8~1`4Y9?6fjWtrF;M=`RDi5T1>af)hir;M5YA
z!u%e)il*dAfZ0r6XS|}<7rz>v4vl~+b%Tu9pUlkOm)c~NDTFCt%ewZ
zm3zRBhG}>|U#%7wzc>mGro$^7N_JT2k7RJ@wIZXnv_)X3F^<|&xt&H7pi!l=0MT=|
z7)pJ=SiL|)tmOkf8bl(*04Y3i`Az{6Zz@-t-=46&?weybs#X$dqYk>`UkqiFQ-GbC
zkU^it=e^NewOr`sK=)&*6#kRbYq`uPy6d92r<2ZP9K{0D#g8sEqscx~4>70xMnN;f
z{DiL#(ix}rTySOs#)NAA`bC+ER}Pa=`7EwFQPCA;1A#9({*jJZTC1Mr#Gfg9n(>PN
z3MH(5mVC8mAh~(`^8MeYR$v>#4W*
zT(
zc#q1|*ZTNgXN$R?F@5#Yvyl`+P@7Z!nU`me5vd2KmY!4vIbVnrJ0q4L6-QX#t(ETlFN@JJhM>#cFGHX*uN2k83-=%oi?
zjyEbzpPocpT9B>=Q=pKr7E8=%YS}lf$aeBvnDVVutL178)M&}Y9@E8;6WZZu3`&T_
zM?*-AQ&@
zk9-1eKT?}IGqh`o4pyfdf_7`6*g%NbFPSFd_0ps(;;lsA2|BjwiMgBzJV?eKT(
zQZt`%@@_&yPRQC3D@Y<7iV<7WCPM_ya-sl5h*8*DGF{xccnqBtXU^gpk1z$Ywx3`@
zE+j$&45bOx8OcUtav0^_jSICL`w0jc_vC|&S;Y%2Fa|fL6@$_`qTyU+sz1jH+iF~;
z%cu-Ll|*^L`yJ(7WH5M&RjY~jCXtFIm=)&pr+&kikC-|ruX;S@lIO>K2xtoU`7ru^6=7m-cse~w+RU1cY<_?A
zoTCb~+ye&!VVxb~4_`u06XT6Mpt&Tlv9dc;%h3y|pH-ZO7{zUmmdBgBs2M_r7_E
zY{9Pa@YZwK%MkLuaIV?lK8F782AwkS`$R;)#HQejhsyJ3@AS4ke*Ik4gfZOwUXM`v
zy+EskFhLDvOc5%3nev_NM-%!qKdu9Jc~5{)|1hmB#(}
zetf%r=5eiTw%tzO@U?ypj@17i$FYGz;>SVi7WZ`-@iCtc{v1?X591ju_X6ArdM;nYd@LqzNfcTYO`Y0ad}yYV9an4
zUcQ^vH5*b9)5K+c8IwNO=Hii|OWskB^1%ykHBDJ_Aq|ts%jcA;kW9jv=vHMxKcPrc
zPcW7QNQV@oeT1mLX5rw3iiFXDQ(|HF!t;bX_LwS>GcY?(>nibtPOH_N8#8P@mEI-`
zs6*D@hi`>{QjvxJz48SZA~9ZWYEN~~boYAJ>SevaR#p<1Rqdsx
z6jQXVjdiXRi&?hBFG^-sk@+@nOTtBc9wHvPC!M4JBe4qxj@ORSTH;gJeo8Q5kZ=uS
z^n0a7)P=u?cf9z5M2a=+!BLt)mYbO=DSu~Lq55TO#}g3L3ssFBQU69VF1ex-j0^KA
z?|sj;tdEYDcFSN9TsP;WD||4r5i}hx(FEhxl{*9kC%*lz4jf#0i6
zwQ}Y_A3>k=FquGaYSnI(saNT;M0f)7D7bRU^j({A_=s)
zldwz@6m%#i)pI8Y(6kIiZmPklCfuzJm7!3hJ~ClifBP*VCLPnn(8@*V&XExfCQwXd
z0G6k`rWjH5S08eBk0@=-sId*6-0Eyey`r!?f6oJ(RNsM`Se3X4$^r{jOz=v$^MC{^
zXvJR?iUD2vuZGG9aR5vX_Sx@giCoG|GS4RmKFzP;k)}Vy4TU>;nAZwiG_*4V4(DY@
zm<44Fskf|YOklxET_^K$R7U*!`FqL1$+N9hYGaiM!Qq&R=w`xEm3j4;-9kvWu<<#&bezN&eD?;K?Iwbj^$jg~dogb(N&tmx35EkkM4MkV?lKet`*yF0NdZfm#yhpr7`<=tO`SA13dP+$3mFf`HE~QU*bJokg*{1uyk>2
zVL2F6_lrM$H75;(3>i!y&cMKuphT6_z?!o7bxiwFX->L@BO%Qo*DO$a(COE(u~2ZQ
zd7XZhW+6N*SDfc>$O_k5q?IEog4%UUeC@(vGI+XDpI@*N4Ptuf<=0j1implep*0g}
zdN0$@o(o#W&0e*M=OheC>x7Z#i91!}Mwugu3@bB^9-`ZS@iW?@cv|dyG?ccevDH(4
zB7+fUnChUql+SwVk?3JJ%`)y(eu%i1fQ5;FA46RE*zc%Ru1zk0+AV=9e8$u*Lu-wL
zFVo9q&@$@l$?0=b`TTH*KYr?P-)tmoR9)Z}ukZrLV=lg3Frj
zFGrbNUq}@RB0;h^=<~8+N}fW(nTqJacg?hmwKIh3sBL9a@)TzRdjUB|7)E9Y0g1R>
zS_Qw%l(8m4kvk^Sj9m`YP+bqjt_2U{95qP4W8vzLoPV5}r5^X;<-&5fd%!Ba_nj=R
zcFVK51JhWvyHIWG5;-ke_eV@Lv^E!Ejb)qhpYAsn)?}AH&%n^7PMMW|MkA$IQG3et
zLnL;k$nf>$ZrwI6^{U&!yu4iBYz@mEI$6C8Z$n(XAIUq^#pHY#lx^EroM|gH+7$a-sq{G8s0BZ(T`r~OrY!@%
z0!R9S_lYV*0OPOq=O?r5Ti2}TonVWR!|y?<<9d}H%wovMZ8|YH4FWeU_TSTd%+Vk@
z-jVJx4F%a9a2j%P+*@}M<~9FHDy!`Yad=1cj!y)#j@C;gyXp40i^q%J#uKlHoIagY
z{2i>GhxOXTb$5yR2$pS{;TP}t4ba!AJ^Qa0wtfq%P0sC9bw;L5-TZ9xB`!-`e;v6c
zI~ED;lL+k#jY>U^168ctXVnYq+b=?sg=}B;(lg2BxJA`K=~S^b8B}K5?_3?5bUu_t
zwC!qyZ|8*I;tu7p4>-^%2*(g53DUb`kS>+b_Z{u-&H4z?uel7Hje9n!HkM#UK6!{#
zq~p#@+}n?1ZF|a{;IvpZ{rZ5x<(_!JHK0UGcV!@SD0>YGZc-=Ph2O+j`C;`_b4gq1
z`N*x+ixURz#;B_=+hBPy1N~3inkwxX=(9^H5Hh@J^R@#0scD71@nP3T-m!>u?4S&T
zMeg2U4$&V;@-BenouAE8_1yXpKt-cQDV@mue$98}EO`cM-aI~;O?pzNaX|_%dSz01
zuS7_K%gB81mt>s(;gO2j3EA46x80YjYT_z0O+@2Wqb&P%$!jeL`&G|(1h66I>O_*gJEea$~%ZdM~Tu$y1zQ15BXcAorz8Y2IDQJ!jFd1zyx-qtoyZwm+P
z9r#<7k$;tW{?}R~|E9DI3`6LGAYyn(
zme@^HN9+ZE3Bpuhk@-=puC6iimD|bLhdhg}UHPMrzstm4bb&)B(OBb`{0heFCf}w;
zqj;eo2;&$ZFc$-i279iiA2G24ocpJ%T~J)cX^mJ6A37Qbt>im<3ZZ56B#plFQ`+=s
z#kWVn-%?1JE?s;5>X8^VS1}%{fKO{*sXfhJDWo<*j3ry89CJ5?N{%#D5;CCbi2g#6
zKNn@ObP#!V@qVA3MA(A4qNi{_z*$jxnN|TR#J<65kCH3U=NQ`$+mU-u5c>!c2Mu44
z6N~J%(n%nt=S=JKHM&Ah*)fs#JVHNOrGPSsdB2dpII
zwwfPtX`E#6RSYG>zcYv*j@^jZw(chX|a0zFU+
zjOq$EcPVJoJ_cQNQAF8G&1DhxlrvNq8{Zfk!fw@}Kfsm(UgJALVl-3s3uY|2hdcNA
z5Es3T;+G^|JeamVsP7Jxu2L^ImBaccUcIO&iPG?OmvTe5v89!Ic<1I+1)nAuH^GHc
zDAb(y$!AL55ej|mjlewrW@)iCgIK&JZd?Dwgd&+!)WAPzL()PbmEqSK6AG;1BdS>J
zvUwF52Rqjq#(1##V9W=|)eosT&}sDo21v-l7#pmX&TN*E871iEO9)UUn)woZ6W`Yg
zpTrH)nGeOVY9%gw^Hn*{Tmz(fprmaJcDg&uR|sV%&aK3n`wh
z2%)%7L-9s}$cB)U83siiMB=6VDn*ptRWgecH080*B2~8Qq3=6HC|&45Hc=j_+J9ySD%{j->O9+>F?~6>YvA
z6sTlM#W*$K1o<-XGRX!z8M4UL%tnE8Tz`rcRBe`URUnFoLzP0|O%$19?3Gt6@+fN1
zXC6eivgUqujtlW=T8e{@;IWG^6ZcjL4R){znVJXe=#068y(7Zeq_uQpq7>Ctfn~;p
zf>6Pou*TRIv_GStXpm~c7fo}PxG=~caX?*$tYA*0Z&VOPhV>gphcjGp^Mulu!SUPV
za1+xPb@)oC-G(F&rTalZdLkX}M!e|TcH-~CB9jIt#^Oh@ukFcM8IPq>n}5!I2Rj`R
zx)EvXE3R399A`&ARcAm+G?|Gr;Mh`-NOxFvhGqB$lc@1wUQen+ck9Y2q?bqPSg-u}
z?)L|pU$KvtAYorc-^}nlyyktBuVVOcew7+jDE5JiA+QBI)Qt^h7scS4hy;aYyMwu=
zLsT%iHZER>APrTP-QQGMU5nitSv;qCDNOz{I%&(on6n-tE6MB$D2q7Ga>n%$X)FzS
z?1S+uz7@!A*tL^1U;SdPC+fO8{W6w1O5hJ#`j2ZPRdlb8Vju05PnWJe9ylcH^=jQ%`my|CD}5=Ep16;4K>jVm<@FoH4R-
zN78#5bEfKU#$nf5>AUi&?Q|l05E(*mbVg3@>wcw0)Ad1sFvMF@rkuy?T7TA9dcrZtlU!p-GU|`VT
z?_hvCmrVDGz#niYMKM9JiV>WB;0KhMfQ$ebSXC^-qX9JV8_r%_!wHc6&aWTv6;ph7
z;HHU%vbwX9t%bdeiL-&RfwKW{4-CwU$jI8lUf#~a*4c@OQ_G9Uorsg3n#cqA_Mv|J
z#lXPA^nbp=z{t+yxq|8Svh8w1UQ*lLRdiAUH51i+Fe-;8+r{g7rMN(s213HFEQPvY2%uajBgR{?*h>iLW7#?g@>NmsUX<{SD8
znUt6J1VlvD44@^j8@DDQVceDD9?_JSNR{Qp`D3;)1@1YZ1h<;utW-}3le&_Vml
za}W?*;@lflU*T&D6Gn@p@1B96VtStQ`N<_LY+Q4)+#dC(>tTKQ!Oh;q
zMI<{5GVY5Ix(^L>Z}DW`+3wnkcm@R=9*=J@X5tQ^;}*reCK3FH-0tzOl^vM>mib4=
zU6k2)u8z=qtcB0V&CGq%R>@Z^go~wWbX8U$#G|>|Pi7-o!RhJgZJ`i{>v^#3PA6!r
zwi;m%NGF|LT|#<7!dqYekw$^Ses{#?Q|^!sy%03G+ezb|l^`z=cRD!l^21+4BMh{h
zOpd_esJ2Bxx$FK15W%u~&`L=VK>Rkuf3${=Hyz4~?j1h-AvBAgLT~aLkCccgm+sGh
z+T+X*m@keDv%7Bm(wuQVtgC4YeeDeOpUw{4eD0mc+X%~$M8ftHGyrt&QU76!qT9i6
z4Ztp1{y*H!bIgZ67=o_F7s^xY{YRpO65oHc^H^!sP;=WhB0ZQTy9
zWm??NxW_>8EqIN3`h0l;0xQHGzTiGd?bkIs>DylDDL1DpPtCoft0peZ9lS^$xB^cZ
z5ftVj48ADd&8v<83kYmwrl0lga4i$&(h>Q=&}uV&j!Js|+8vRwF{`IZ{i`QsS4qv9%9qez#05UUttNqOs^gxGugW
zvCPGj#SB)8w;o+Pe(Tp0A4b?J4;2V3r;5arfuuH(s8Bc13ZY=|yS-VfU+tqk=S%q9
zExT7P#O$K{mwOBfmDew?IAhsatY}?i@V?~lj=)9IU^Ek(MdVQl|K;36q}}F;LZ_Ww
zx;S9e6Pt`2;!7Qw8zNa$<=^i`J!&%goY~-V7#h1vOsQ5BgWB_#K)b=dJ2CNl&q;)y^8yTf?tL$-JlGslP?
zchpt-^VJ3CWWjJaMe(zW5&%pE5>-=&@R4scJ^BFx^YCQ(oP+QKF=Gc;NanPnUE7tlXf|g5a2cNu0
zx6R7?V|yT;=E-v9qEN-y+8|y5UM&G&xh*TBe^6o%AZ@X4?O(oP0)q?($99WDPd_uE
zt&vouc9;FlU8v=>p|)EiekAP%cf`>wzUe$(QrT}%?QVxaG+aS252pP&AD+)ovO7Hf
zm-jj+K4HR;CI*i$#WnuY*RWW;1BL9ZLse$k{KdMXEwj}5bCsy^i&)wc8xLP4)9Ai}
z!OsAATe0fV>1?^T{>FcXe8$+>71ms7o-~uypSY}Q@ZQdK=seD?Jd+44hc_uLxw$kl
z2+A;bJ6b`l*RkCkPM`Ih(wh6V)BTKu&s!vgq75E51aGl$@29&;ez(*el?-;sS_XgW
zQYfAU|KX5L;Hl~BWq5rD6hG<+3sYNR+$^U{=MtEnRyLoP{y_Cz$uY(X%0pfD>BUn#
zrYU6TC1V>~@@2RlGywY{uni1{Z0E
z2^FJKo=abEuhH=t%JZ!+H%H^qay!@khx=tJ^8^BMQz59!+7NAWaQ?ECs7X&H;I*8gYM6RYP2(X&xwlza962LKQF^qX9@JoHj`ZTR+@wG&d8Wb
zJ#RpTuJm4~V_xXr?QCsr)oW~_d!;cd#2yn)f%lV9mYvc)qMYMthVlK82u!V00h_b&kdHyZ46d(g}+^_uOiYA5GY3I
zXY3QZB?e_*T_o+ccpf|AaJY)cB9Gtn{uA+N9CzRR$#a#2A1hZXQ`kLWc80Y>+uD&7
znE(&Eu!`mRE!hwG?B`{l4E1Cx9fe`xcnu8TRKI-emzwZkDB(l4^4`d4DP_HAJXXvw
zx9px0Kh}Me#HHQKc&h`4Yg?|E+QIrebwy@_zZ5Q=w8pMNH?pl&Ru?EP55!(0#k+A#
zUU)9887YX^JQQQ(6JLETDptZW(-BJtL$A{B-yw`-@|Bx@Qy)zDlCB1p#A$+ch4iFu3|B^{XSNni7Ggl6BS~hnqbwKVYPX_K@>4HSeNI%w1BR9NjT}aKjDj&*=Y6*jh&L2Y{&GW
z>AESLI7w050$H`PSW;TQBaO$V6*+(=hHB
zoSDG_Ucu%o0fHwg;6J{)|q998P(ed*G8a+!uTDT;UB~d_s*B=fPSvPW@^E
z6Hi?nzb2j)yIqx^6+eZdY3lvKqir=PnBu%OiB#mAbKA@0P8SK6y;tlV2~)0d@#GB=
z=%Q!vvolifgE|gN>9oS?$GeRFn>la3S)=ug@8C00@Rq1Be{WpxyFCsL2QT6)b!s$q
z-XDONpfoQ>wf(v}?L-3c53!Wbakjl|?mQAft&fl8T8+3yVRCSFoRY$qcmH&Xc%m9S
z(V`$-Z9oq!hAV-=B*@!r+qB|W=q+uFcHyX@%YYb4!=WjqlQEMF7SD7fkvURbe>MS8RkquK6hti>Oarg8N3LBk9i~>
z{lacJ4Hb&!elpfn%6WGq6Bw=MXHnrr_BmOr>FPKH0ehtHMyT_>2I@}wk|=N2s^o>9
zRw=05ucw6ch)VZ&^vS^J0@dclGyhE+k4KDR^y0?(cLewAA-i%qsar{5LfC)!Qe-sg
z$6AXH6GtH?H0%y<+MOL<9I@P`MM(X$rgv*ZNSH|a7zZ);7D=`FZ<3mxFG$01~u)xImGOP4ku(o2Vv|WnxVo4xp}3dzVk|~uHG3)D3?dYG3>Hu4Y*pi@k`hd>
zzr#-|*UtAH38&aH{AbTZy0C9(L6MW^i<{1rosEV>nYA8F^$)m27#65J7@>CGAgZ76
z-Bu^s!MRY^`gP~}J@@+m@foW%<8t1cndloY_M)<$YY|;VZSdVJi9K#F*Z7=*7;YV9
zNBCoMP;CV~g#|8EHj}pk-n!m=R-T8=Vle5r8fv6d5p7OT_MC<(-B36-B6`)FV`BGS
z`4sJoB1w1n`qMn8*U7h7qKQ?_Dxv~;K)=)_jPthLrA-MiwZSR^MS(nJ{~Q|$6pOSp
zoVg4x?H}*Zm@PkCZ{0mF{DO`|r(OR9q0{7u0w_3Ll{9{;&0p`>N+ZMD`2HDXXcP*0
zqLVc3w7TcIZ6pEw-}-mXD`Mj{31^Hk=XX7C`*#tw7}Le!A0;Wa9^&TllK4f8hvG2T
zaUrrA&%ez42}4Wry_|cfqRHn~*hIe?tMZ~!IlbR1-fZwZMzw8be<(WKz&}j%hEpg@
z&X`B_h%I;f-sEuzv!Z^?ds99@owM5X91!3Wc1K}L+cRkLaJzc%Ec`$_JRRdoDB>{FXb*hyx?~oTNExeeN*&4_U$GL4L?HX*g&=ioSa>Zly2_;_dpH;Az$j!s;
zJm@!5%gfCTS>Mvf*%CibCo2n1$AAzHnkQH6D;kmeFeR&l&t<&(^WFukBzIEpuO}N7
zoRi^gngA&iVQ9?bN3mGk&Pg-5cv>0J%|q8ezauVwSq$SHExT^y5yo9@4nAD8Cdv5F
zxFNaW*Q8gQj#Rj&J!EY?(Do#;m91>o9wvuSZzr0_*l@D`3G8vY+`HL+er}E3jvPoV
zye%2Em5bC0j{JrHiFBhkB5Z4*B?z@xgvhut8cGrzH@l?yycml`k=}i@Ewjn2
zdMJ>w-dQgS*xEJ#8+7cq0#$8SqPNZ}@3qSYM&&SSi9~r$>w{~ttGE%5(g0t2eT7;!
zTvQ5!(Shn3hv;d=z-2N0deY$TY+t;IfntjHM2g1V#UdDwB`v~Yjos@!iuW(RSh1B&
z&`i#r$X{3aizOv#d?rVthPxV~w}C8Cd6tNUXuh_7sSqiR=*RviAnz@!m)-uNt-PGK
z+r6B`&d6i3Sp)+K{PTn*&Jm6!HiTLuTG<%w?q|~V-U(x*QaeYwHLQSHoDWayR}PB=
zD%NCqjt9yFCp7B*2=zWr=xM3nPg-sPLe+A=3a-Ce-<;qV#~SJ+_SfTRI1yT+fl?W(
zNxk`5RE$0503E>vw3uMi0SRwHLa|uqRCAIlwSB(xEO7G(Pw`$NgFYfQl@u`fCup*b
z2a={V?lIuXAkwCZ33cE$y)1O>_UD~m_`C%6hvpNTwr2tR@9WK+SDnVlkw+Y}1mp6>
z;gi=(GQ8<%LYEaAYke}E!^W1vbRF5c+$bOC=JKK(Y!3MGEvbNf&$)`r=wlYI$Gz}P
z_@38)q^iKHZR?rIF17r59!pbJx7=#BUn1}5_is?nO&zG(C_H4KMwKTYH9Bs@`~(-s5?u$94NI7KaV0W=D3M7}d9c
zzZ~nzSuW|5$85dF%}IF)xe;z$(XU>2->>PjPv+}ZaP@zai*vmkCr%YNhs?&`L@=JVXd_(r7y+2KCsQ`C#pQr4=dV<6u>1Lv%(<46M|P|0R^^sifr
z54?;B^|UN$WwLlxhg;yoz3IeaFw5HN!EK&so4@hY!{dA;d*`02E1$~bhXqjgh*&v(
zG}>Es%j2&jb5zpsf{!yyI(Mia^neLDgGLMmz}a6l{Nyg~vj!fB_^{8P7Jj?5QWoMN
zH;%5YKTXBxp*GyzU|!>n`5bx43a`pyY<@=gY>bK$KkTtjSn#N`kRe|eSQpdspm#pJYoljqe#+QVN0NC-^JmemD#O!QIX4O*!eDbuYbpnbANBR)8ZE%0zBq&e-)b&CR8|r*eGf&%$xCWe
z?}u}*yx1gbSt2}%^%~vrT4eKD;6LnMxci2I_)J
zvC2Z<1beCknSkkru*9_4Qv0Yx=VmOvLDZvu>TKa&ugMA(GyH5Rk0-@%
z^QiqAw&Z+Dpq18(i>K0fvk2c`dIX6!NY~Xry><|R067-&(^wQZZ3>_u{=#GZBTFJcq
zSv1LbfTN3O*y$D*ST!{j
zg1JV5-+FAwQ1q>nJqTXxBo?&nVb>-M`-)m%d_zi-I
z>yGxVIKiP5%4LA;#>lf%$;uDBeCmQ*3iBT5Zs)dT1QYMSTEVb)iJA5o4}AO3=(wfA
zB@cH9CN6$EXD2TQ=+P=ye4?F$zO6714^K~;ZIA>WC)GO7eWokow@j|x%6?`qw}|i|
zF7`%*e8f7wR;6CN67pZb6TCBx2NXR+Y})X}OkG`$R{r*t<@<|Muv-jCfAU2gpM{GA
z3zzD6bwVF~%dpo336i?lL2T?{2+$B#x!;a?A-GwcS3aV?f8sGJPQxT1Uqj9BhifgM
z34;<>>K#U;e?(zCG~C!rJ#g6Kb@Uq~BrhFd^O@O;|9It>Y$H-|K0S4nRB7VF$3b{J
zUtXCOe_AEj#CT!!*l$6hRNXSW*>CkrThhJOeB>`!7dTv@=zF|MyuN!5b-YrSix^9)
z+gC-sSA;*rjkG)dR2cqH^Th7SoiWI0slT}7wt}0@z+=cx03vAQ*jEWu4%#J?f*@7b
zKEFu=TeZ6za<*L5SzdM2gZr(mZM(0PLL#hA@71_aEY;RNqbGK{3kKY$}c|pBnDM?FTNa^G)UTR$5v0zYia$_=iu7ZiUbs?P1;^I|4=ok9A&oCl-UNSQB7ObrU;`
zQPpO%vIIR9NsseS%}D(Mck9vjs^J
zXZ{{a>!82?Mhs6X64Q@*>t3>2vKp7jYxjIa$Or({8!O#Ab
z>OP`lSBqM;P*aOV)D2CPMun!o(E;vcYp533)uBNQAw&?PV;}?=j1r=^@G31m_Sg-
z6P_i`9tGU}(U`0vH1jpzftUt>9ykm@;L!jA4{b`&3XJ4R_x$s~{WxwRgiz!?;;m7U
z4h(b+uQy@IyzwHB1qy$e?DS!D&_mnqP^0=xGnpTUhv21@5;6
zMwFXFM!xNJeJo$Yz0oJ<|MyeLp;bRyafH*=0_pTfDlrmZZ|5$cu~)a=XSH%osa`QM
z6tv!>jt$*sc`k~Tbq}|34bHlj@H`1QfDK_>e4l%q8
zGOxkH|90O$MdI>n1b`UYx6ZE^ZkzGLAIjPNL%K;%TkzDap@#|883NlW#!QPFa8nsQ
zdWh{Kf*g)9{627_kcDnL97jt};uRHdk+@e$u;;|nY5~K8M4N6fDzteX^s|i-%%C%c
zFlMODftj{TjCCPCy3U~(vGg$Cu2J^nn{qMkZ0u(KiqrQ&AIV`DOUUZ7v#CI@!MLlw2(*@X#%mqyr{ptrKcMBhtT*l
zw)m|#8AXYhhTz~xz&xMcyL&^rdm^|SYV$JC@_7?sB+UNkB*1+?V1i)_E(l=U>D3~R
zUk2=nw$=s&?FDFUh8Q`T?MUQduDyr?x`L6I@^}pyxh;C#N+_XG+e0b{h48oV^$|KG0VM18IwtMZ;7WVy-t4I?Jd*_Og?AqcmmO>ZuD!AXNP2d
z$_kT@A?ak$rHXMf16-gj4)jU(Y>=uU32RV}w28kt+$8}pX&^$P8EN7P%m`+v`f7?BPeV*4?^q;o~|EsL}F_>p%dg^3T
zi8qF7OfLlFx!@4(3EZ3F>D(X&ZJCV-ni_1E!Wx(6!U7yaq5fZ?P2ueRgu`Bq%w8*s
zWL|s@sX+;@u(=O@e^PM-Gg1b*g0adJ2GIXI+G-!M&yZoCA@D#~
z{)7Ue1X9ohzMMS#gpp{Gyv-}`1Iq?R4DJpwSL@$<0#Z3V5bf2Fe`OKt*$^7j(~FHP
zJbGcdcgE%KNJdLxDTKYQ=H3TZoJ>Nd1-mg4Q&?)h%}^llO&14dShqXlz;xT_rHX`M
zTP8+2*Jze{r26pWk&LrM`aHZG`GKz6#&5`b
zOQJmbaRvH4i;$^<`>zXmPyOG8gm0`khOUc+U1_0zP~0V#!zGvo%2FH!9YU^MVyzXb
zyrTfukGOtIA_;g4_`Cuw&f*2f$;%Bv-_
z+Ev*kbcs?g3+7db_2Eg)JQS5b^~4lN;Rt_xb9Ml47`t&X<@sflae~444a#wL1~->K
zu8AKNqSedfT4@WM@)8CoV~7{vE06ze*j
zQr?CDnJ{vm92k(2JQTmd6)DhjoIG>&i0N@aDRv#nr!hq$AR*I#?#u9VP*lggz}sj7
z0Xg@|4Brl6{mb*5`v|UlCq7T&=F*{kA(Joph)h>L-|ho3M?Yr`kU(L~;LZJ=?R=9l
znu^(Il`4`Q5f~^0l_T#&;7L^DXY%=%Q^GtMu#P$ZayED+4}M!?KzX0iKWI>bVM?aj
ztF!siU*Kv%`{u>AQ0t=@5hIL)yHq7~xbzMZDREslzJbIJSoQ*dOzV;06>!S_d
z9^J2JHUs{-KJ{3AU^o?1cvUbVV+YX*y$tr1S*~7zj}nj1cxaY9E#bD()Fg2EwI9)G
z;3CCl9?uu#T=T|=p|6aHa#!UCkGA1!B3a_Rqp%GN7EPv5}zupNs0UkDP_HQD(c)HLr)U1mrL=W6|
zWcPR^!9)2%{mHQbPfkOuz&m~L-dylo+eL_e!NGh<+ib$CN+W6fW%;HLOE7?f@HW7J
ze~DM$wE6-{y@p)_->*QsM+gQ=Z@YBa8%Njz?^DQm!z$5s(X>SE)c~u4cpNud96{cE
zTixddkD)gjuf1&_MA|FR4H=A!1CHQuOer?GaU@O}%k()UQl3+6m~$;o;s>&jUmA
zd}x9L?+FGcgp(&b3Nqh7#ru{M6rb7bfb8zwW&QKZ`)*0ox(Gp{L;v$fvgOxD$h~oa
z@heAtjbVqYqYBkTX;mN(+jb!lqid&N(
zx_XYA1b`O!ugZFOe~d;pw^p|D#}MOc;uIz28lQ+)N-5;L&7|5WXb+wk@5x&(s@H;4Ro~#;rCSdzhDW@v%{H=eX57)oj-)u41
zAHu9<%C`73luaLY7%mckH$%Khv3}X*<|6FS1`C&<{?P6j@UisI9W`42nEj0;K!bLD
z-CkKlcJ?%245(}&wisoQGQbGVqh3cEkL&3R>;5!kt(7!BhnnogcDCyGvcHn-1$vg{
zQRUyV(r$Nwvs-N)C(hovKj%2%a~|hO3=39BAaloIsLn(b`xXCmLw*8hqh`SJtj=+)?3?9!T8%4^(V7PN*7YPq$?Y%-oT)$!g_qyG}^F*?Uu-wMV
z5ggF8l!nNu)%tAY+leSvbANc9?z|`c|~oST@$MgHT1`Emf~G~F-wBzPp&CC
z0jJYz#Oy;@MrgTp`1s&KCs^G&8IUeE?0Qk)4?qQAY_v3}o>j|N<5So;j2hZ0Gk0G1
zmNhvpk7|t=QpvXmD_w23T0wC-IKri?HdkA2rFboAVcaB{Y5IT(eVG
zm8&h?O9h+p#7eyR5~&hjaoL+7FOp>5+c%~JbD%aUv$feq?^RuycNoJYa{CR={_fA<
zWh?o1he_&N7Hz-Yx!K(aNfFoFfR!ke!R;mwttoPztYQR2rh)819kccI{g{;TO?@DL
zBY=~W<>jN@N*k+g_Glm6K2AArm)(-{Yj)tH{_Cz|9JX@sar+(XZ|zab8Hk6z!
zhm|q9$6`cM_uApOR6tUI25NLL!Y=N$I(zU%+wjN}Hoeh0MT_qfYM(5quVp)t-eE+K
z-Qy>A8DesKM(6y(Fo;@;=wL)|65?wSCF%9m!zN4lQ=96&oFqP@1(Tvp&=3uf5w=
zyQl4G+;2Zls&4AH0Yh0*&W1?=QZ6nLQRP!7%V-7qd!N^EX_s4$o(dzMqWeKHi
zX8W1tx`ioFsQzkcTB-kK&_$@&O_9y5+wNNcGSDg$l9u}QYH<0!N#tswI(A5LlJI0<
zXfj84ch8NZg3a4vLnEJZiGvjqIm=p}ZvuhXR=8=`J!`8!i8ZG%Fxc!FdXcnqO~<>#
z(WPjHHCsHf(xwiB-5pSi7YAu|WARqIkQycRuL?sN9@grx>Qk!pp{{Y3qC1pF;+up}
zPsJOIb!x;iTHU3G;S)SXYbjYoE3fmAsXTF_GZwH*Sv_ZwB@^g5n(Ae=pyrv>w>ghebV+T*fFPcDl`xnAcUB>nA+Ca%h$$0%)ee{$YC
z_+6@?zXbqT)Gx;_ZDraErUPY*KzoC(eXG`i
z_vFPYQ+CQ;wbI8ORhgEszqscS3>H`Xs%G7n8BIBiBj%<&x|C@M4m$?3)RP!IA8&v<
z^E5160J66JWn^%z?e9lqHrE@h#qr4>`-w0dNjtKKL-6tMwHSCM7yhqP!OY)DXNsb|u3e_%ox*w+6^u?q67GI!egLR|W
zlP85<5`2_;UQBAHILD#+4a4$oI%l=8cw?;ED`krKepSw9N|ENJf0oy8o8%gACDL_jY^r~Jticv`s&qvg_k(4fVAP9?T1^a)j9Lsb$tDsG
zJo5olWoP>{R#3}eZm#F^0oaH%-n1+<$z#3-*e=lz!r!wciESssi?nOdLSu0JyU1OM
zWqwZ_u!3x?XG!K6tS*1^O*v8)*E_Avxz-v>nvT4iO&&eFKF02zt@WZ_;^9VCNPv(L
zBq=`pNL$81wRb-(WeFpHlyau57s)K;uv|4#9u!Ujyg~Mm_RK-IaM_F4hTn