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