1+ // Copyright 2021 Osman Tunçelli. All rights reserved.
2+ // Use of this source code is governed by a LGPL license that can be
3+ // found in the COPYING file.
4+
5+ using PaintDotNet . VisualStyling ;
6+ using System ;
7+ using System . Drawing ;
8+ using System . Runtime . InteropServices ;
9+ using System . Security ;
10+ using System . Windows . Forms ;
11+
12+ namespace SvgFileTypePlugin
13+ {
14+ internal class PdnPluginForm : Form
15+ {
16+ public PdnPluginForm ( )
17+ {
18+ StartPosition = FormStartPosition . CenterParent ;
19+ MaximizeBox = MinimizeBox = false ;
20+ ShowIcon = false ;
21+ }
22+
23+ public bool UseNativeDarkMode { get ; set ; }
24+
25+ protected override void OnHandleCreated ( EventArgs e )
26+ {
27+ base . OnHandleCreated ( e ) ;
28+ InitTheme ( ) ;
29+ }
30+
31+ public void InitTheme ( )
32+ {
33+ bool isDark = false ;
34+ void Apply ( Control . ControlCollection controls )
35+ {
36+ foreach ( Control control in controls )
37+ {
38+ if ( control is TransparentLabel )
39+ {
40+ continue ;
41+ }
42+
43+ if ( control is Label label )
44+ {
45+ label . FlatStyle = FlatStyle . System ;
46+ if ( control is LinkLabel link )
47+ {
48+ if ( ForeColor != DefaultForeColor )
49+ {
50+ link . LinkColor = ForeColor ;
51+ link . VisitedLinkColor = ForeColor ;
52+ }
53+ else
54+ {
55+ link . LinkColor = Color . Empty ;
56+ link . VisitedLinkColor = Color . Empty ;
57+ }
58+ }
59+ }
60+ else if ( control is ButtonBase buttonBase )
61+ {
62+ if ( control is CheckBox || control is RadioButton )
63+ {
64+ buttonBase . FlatStyle = FlatStyle . Standard ;
65+ }
66+ else
67+ {
68+ buttonBase . FlatStyle = FlatStyle . System ;
69+ }
70+ }
71+
72+ if ( isDark && UseNativeDarkMode )
73+ {
74+ Native . SetWindowTheme ( control . Handle , "DarkMode_Explorer" , null ) ;
75+ }
76+
77+ control . ForeColor = ForeColor ;
78+ control . BackColor = BackColor ;
79+ if ( control . HasChildren )
80+ {
81+ Apply ( control . Controls ) ;
82+ }
83+ }
84+ }
85+
86+ if ( ThemeConfig . EffectiveTheme == PdnTheme . Aero )
87+ {
88+ if ( AeroColors . IsDark )
89+ {
90+ BackColor = AeroColors . CanvasBackFillColor ;
91+ if ( UseNativeDarkMode )
92+ {
93+ Native . UseImmersiveDarkModeColors ( Handle , true ) ;
94+ }
95+ isDark = true ;
96+ }
97+ else
98+ {
99+ BackColor = AeroColors . FormBackColor ;
100+ }
101+ ForeColor = AeroColors . FormTextColor ;
102+ }
103+ else if ( SystemInformation . HighContrast )
104+ {
105+ BackColor = DefaultBackColor ;
106+ ForeColor = DefaultForeColor ;
107+ }
108+ else
109+ {
110+ BackColor = ClassicColors . FormBackColor ;
111+ ForeColor = ClassicColors . FormForeColor ;
112+ }
113+ Apply ( Controls ) ;
114+ }
115+
116+ public DialogResult ShowDialog ( Form owner )
117+ {
118+ Func < DialogResult > action = ( ) => base . ShowDialog ( owner ) ;
119+ return owner ? . InvokeRequired == true ? ( DialogResult ) owner . Invoke ( action ) : action ( ) ;
120+ }
121+
122+ public new DialogResult ShowDialog ( )
123+ {
124+ return ShowDialog ( Utils . GetMainForm ( ) ) ;
125+ }
126+
127+ protected void ModifyControl ( Control control , Action action )
128+ {
129+ if ( control . InvokeRequired )
130+ {
131+ control . Invoke ( ( MethodInvoker ) ( ( ) => ModifyControl ( control , action ) ) ) ;
132+ return ;
133+ }
134+ action ( ) ;
135+ }
136+
137+ #region Dark Mode
138+ [ SuppressUnmanagedCodeSecurity ]
139+ internal static class Native
140+ {
141+ const string uxtheme = "uxtheme" ;
142+ const string user32 = "user32" ;
143+
144+ [ DllImport ( uxtheme , SetLastError = true , ExactSpelling = true , CharSet = CharSet . Unicode ) ]
145+ public static extern int SetWindowTheme ( IntPtr hWnd , string pszSubAppName , string pszSubIdList ) ;
146+
147+ [ DllImport ( uxtheme , SetLastError = true , EntryPoint = "#133" ) ]
148+ public static extern bool AllowDarkModeForWindow ( IntPtr hWnd , bool allow ) ;
149+
150+ [ DllImport ( uxtheme , SetLastError = true , EntryPoint = "#135" ) ]
151+ static extern int SetPreferredAppMode ( int i ) ;
152+
153+ [ DllImport ( user32 , SetLastError = true ) ]
154+ static extern bool SetWindowCompositionAttribute ( IntPtr hwnd , ref WindowCompositionAttributeData data ) ;
155+
156+ [ DllImport ( user32 , SetLastError = true , CharSet = CharSet . Auto ) ]
157+ public static extern bool DestroyIcon ( IntPtr handle ) ;
158+
159+ [ DllImport ( "dwmapi" , SetLastError = true ) ]
160+ static extern int DwmSetWindowAttribute ( IntPtr hwnd , int attr , ref int attrValue , int attrSize ) ;
161+
162+ [ DllImport ( "gdi32" , SetLastError = true ) ]
163+ static extern int GetDeviceCaps ( IntPtr hdc , int nIndex ) ;
164+
165+ const int DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19 ;
166+ const int DWMWA_USE_IMMERSIVE_DARK_MODE = 20 ;
167+ const int PREFFERED_APP_MODE__ALLOW_DARK = 1 ;
168+ const int PREFFERED_APP_MODE__DEFAULT = 0 ;
169+
170+ public enum DeviceCap
171+ {
172+ VERTRES = 10 ,
173+ DESKTOPVERTRES = 117
174+ }
175+
176+ [ StructLayout ( LayoutKind . Sequential ) ]
177+ struct WindowCompositionAttributeData
178+ {
179+ public WindowCompositionAttribute Attribute ;
180+ public IntPtr Data ;
181+ public int SizeOfData ;
182+ }
183+
184+ public static void ControlSetDarkMode ( IntPtr handle , bool v )
185+ {
186+ SetWindowTheme ( handle , v ? "DarkMode_Explorer" : "Explorer" , null ) ;
187+ }
188+
189+ enum WindowCompositionAttribute
190+ {
191+ WCA_ACCENT_POLICY = 19 ,
192+ WCA_USEDARKMODECOLORS = 26
193+ }
194+
195+ internal static bool UseImmersiveDarkModeColors ( IntPtr handle , bool dark )
196+ {
197+ int size = Marshal . SizeOf ( typeof ( int ) ) ;
198+ IntPtr pBool = Marshal . AllocHGlobal ( size ) ;
199+ try
200+ {
201+ Marshal . WriteInt32 ( pBool , 0 , dark ? 1 : 0 ) ;
202+ var data = new WindowCompositionAttributeData ( )
203+ {
204+ Attribute = WindowCompositionAttribute . WCA_USEDARKMODECOLORS ,
205+ Data = pBool ,
206+ SizeOfData = size
207+ } ;
208+ return SetWindowCompositionAttribute ( handle , ref data ) ;
209+ }
210+ finally
211+ {
212+ if ( pBool != IntPtr . Zero )
213+ {
214+ Marshal . FreeHGlobal ( pBool ) ;
215+ }
216+ }
217+ }
218+
219+ public static void SetPrefferDarkMode ( bool dark )
220+ {
221+ SetPreferredAppMode ( dark ? PREFFERED_APP_MODE__ALLOW_DARK : PREFFERED_APP_MODE__DEFAULT ) ;
222+ }
223+
224+ public static bool UseImmersiveDarkMode ( IntPtr handle , bool enabled )
225+ {
226+ if ( IsWindows10OrGreater ( 17763 ) )
227+ {
228+
229+ var attribute = DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 ;
230+ if ( IsWindows10OrGreater ( 18985 ) )
231+ {
232+ attribute = DWMWA_USE_IMMERSIVE_DARK_MODE ;
233+ }
234+
235+ int useImmersiveDarkMode = enabled ? 1 : 0 ;
236+ return DwmSetWindowAttribute ( handle , attribute , ref useImmersiveDarkMode , sizeof ( int ) ) == 0 ;
237+ }
238+
239+ return false ;
240+ }
241+
242+ public static bool IsWindows10OrGreater ( int build = - 1 )
243+ {
244+ return Environment . OSVersion . Version . Major >= 10 && Environment . OSVersion . Version . Build >= build ;
245+ }
246+
247+ public static float GetScalingFactor ( )
248+ {
249+ float ScreenScalingFactor ;
250+
251+ using ( var g = Graphics . FromHwnd ( IntPtr . Zero ) )
252+ {
253+ var desktop = g . GetHdc ( ) ;
254+ var LogicalScreenHeight = GetDeviceCaps ( desktop , ( int ) DeviceCap . VERTRES ) ;
255+ var PhysicalScreenHeight = GetDeviceCaps ( desktop , ( int ) DeviceCap . DESKTOPVERTRES ) ;
256+
257+ ScreenScalingFactor = PhysicalScreenHeight / ( float ) LogicalScreenHeight ;
258+ }
259+
260+ return ScreenScalingFactor ; // 1.25 = 125%
261+ }
262+ }
263+ #endregion
264+ }
265+ }
0 commit comments