1
// TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2023 - TortoiseGit
4 // Copyright (C) 2020-2021 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include <unordered_map>
26 #pragma warning(disable : 4458) // declaration of 'xxx' hides class member
30 using ThemeChangeCallback
= std::function
<void()>;
33 * Singleton to handle Theme related methods.
34 * provides callbacks to allow different parts of the app
35 * to receive notifications when the theme changes.
44 static CTheme
& Instance();
46 // cf. src/TortoiseUDiff/UDiffColors.h, src/SshAskPass/SshAskPass.cpp and src/TortoiseGitBlame/BlameIndexColors.h
47 static const COLORREF darkBkColor
= 0x202020;
48 static const COLORREF darkBkHotColor
= 0x404040;
49 static const COLORREF darkTextColor
= 0xDDDDDD;
50 static const COLORREF darkDisabledTextColor
= 0x808080;
52 /// call this on every WM_SYSCOLORCHANGED message
53 void OnSysColorChanged();
54 /// returns true if dark mode is even allowed. We only allow dark mode on Win10 1809 or later.
55 bool IsDarkModeAllowed();
56 /// sets the theme and calls all registered callbacks.
57 /// if \force is true, all Callback functions are called whether the mode changed or not
58 void SetDarkTheme(bool b
= true, bool force
= false);
59 /// returns true if dark theme is enabled. If false, then the normal theme is active.
60 bool IsDarkTheme() const;
61 /// returns true if high contrast mode is on
62 bool IsHighContrastMode() const;
63 /// returns true if high contrast mode is on, and the color scheme is dark
64 bool IsHighContrastModeDark() const;
65 /// converts a color to the theme color. For normal theme the \b clr is returned unchanged.
66 /// for dark theme, the color is adjusted in brightness.
67 COLORREF
GetThemeColor(COLORREF clr
, bool fixed
= false) const;
68 Gdiplus::Color
GetThemeColor(Gdiplus::Color clr
, bool fixed
= false) const;
69 /// registers a callback function that's called for every theme change.
70 /// returns an id that can be used to unregister the callback function.
71 int RegisterThemeChangeCallback(ThemeChangeCallback
&& cb
);
72 /// unregisters a callback function.
73 bool RemoveRegisteredCallback(int id
);
75 /// sets the theme for a whole dialog. For dark mode, the
76 /// windows are subclassed if necessary. For normal mode,
77 /// subclassing is removed to ensure the behavior is
78 /// identical to the original.
79 bool SetThemeForDialog(HWND hWnd
, bool bDark
);
81 static void RGBToHSB(COLORREF rgb
, BYTE
& hue
, BYTE
& saturation
, BYTE
& brightness
);
82 static void RGBtoHSL(COLORREF color
, float& h
, float& s
, float& l
);
83 static COLORREF
HSLtoRGB(float h
, float s
, float l
);
85 static std::optional
<LRESULT
> HandleMenuBar(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
89 static BOOL CALLBACK
AdjustThemeForChildrenProc(HWND hwnd
, LPARAM lParam
);
90 static LRESULT CALLBACK
ListViewSubclassProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, UINT_PTR uIdSubclass
, DWORD_PTR dwRefData
);
91 static LRESULT CALLBACK
ComboBoxSubclassProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, UINT_PTR uIdSubclass
, DWORD_PTR dwRefData
);
92 static LRESULT CALLBACK
MainSubclassProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, UINT_PTR uIdSubclass
, DWORD_PTR dwRefData
);
93 static LRESULT CALLBACK
ButtonSubclassProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, UINT_PTR uIdSubclass
, DWORD_PTR dwRefData
);
94 static LRESULT CALLBACK
AutoSuggestSubclassProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, UINT_PTR uIdSubclass
, DWORD_PTR dwRefData
);
97 bool m_bLoaded
= false;
99 bool m_isHighContrastMode
= false;
100 bool m_isHighContrastModeDark
= false;
101 bool m_bDarkModeIsAllowed
= false;
102 std::unordered_map
<int, ThemeChangeCallback
> m_themeChangeCallbacks
;
103 int m_lastThemeChangeCallbackId
= 0;
104 CRegStdDWORD m_regDarkTheme
;
105 static HBRUSH s_backBrush
;
106 static HBRUSH s_backHotBrush
;