1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.IO;
  8 using System.Text;
  9 using System.XPath;
 10 
 11 namespace System.Windows
 12 {
 13     public enum SystemMetricsId : int
 14     {
 15         SM_ARRANGE = 56
 16         SM_CLEANBOOT = 67
 17         SM_CMONITORS = 80
 18         SM_CMOUSEBUTTONS = 43
 19         SM_CONVERTIBLESLATEMODE = 0x2003
 20         SM_CXBORDER = 5
 21         SM_CXCURSOR = 13
 22         SM_CXDLGFRAME = 7
 23         SM_CXDOUBLECLK = 36
 24         SM_CXDRAG = 68
 25         SM_CXEDGE = 45
 26         SM_CXFIXEDFRAME = 7
 27         SM_CXFOCUSBORDER = 83
 28         SM_CXFRAME = 32
 29         SM_CXFULLSCREEN = 16
 30         SM_CXHSCROLL = 21
 31         SM_CXHTHUMB = 10
 32         SM_CXICON = 11
 33         SM_CXICONSPACING = 38
 34         SM_CXMAXIMIZED = 61
 35         SM_CXMAXTRACK = 59
 36         SM_CXMENUCHECK = 71
 37         SM_CXMENUSIZE = 54
 38         SM_CXMIN = 28
 39         SM_CXMINIMIZED = 57
 40         SM_CXMINSPACING = 47
 41         SM_CXMINTRACK = 34
 42         SM_CXPADDEDBORDER = 92
 43         SM_CXSCREEN = 0
 44         SM_CXSIZE = 30
 45         SM_CXSIZEFRAME = 32
 46         SM_CXSMICON = 49
 47         SM_CXSMSIZE = 52
 48         SM_CXVIRTUALSCREEN = 78
 49         SM_CXVSCROLL = 2
 50         SM_CYBORDER = 6
 51         SM_CYCAPTION = 4
 52         SM_CYCURSOR = 14
 53         SM_CYDLGFRAME = 8
 54         SM_CYDOUBLECLK = 37
 55         SM_CYDRAG = 69
 56         SM_CYEDGE = 46
 57         SM_CYFIXEDFRAME = 8
 58         SM_CYFOCUSBORDER = 84
 59         SM_CYFRAME = 33
 60         SM_CYFULLSCREEN = 17
 61         SM_CYHSCROLL = 3
 62         SM_CYICON = 12
 63         SM_CYICONSPACING = 39
 64         SM_CYKANJIWINDOW = 18
 65         SM_CYMAXIMIZED = 62
 66         SM_CYMAXTRACK = 60
 67         SM_CYMENU = 15
 68         SM_CYMENUCHECK = 72
 69         SM_CYMENUSIZE = 55
 70         SM_CYMIN = 29
 71         SM_CYMINIMIZED = 58
 72         SM_CYMINSPACING = 48
 73         SM_CYMINTRACK = 35
 74         SM_CYSCREEN = 1
 75         SM_CYSIZE = 31
 76         SM_CYSIZEFRAME = 33
 77         SM_CYSMCAPTION = 51
 78         SM_CYSMICON = 50
 79         SM_CYSMSIZE = 53
 80         SM_CYVIRTUALSCREEN = 79
 81         SM_CYVSCROLL = 20
 82         SM_CYVTHUMB = 9
 83         SM_DBCSENABLED = 42
 84         SM_DEBUG = 22
 85         SM_DIGITIZER = 94
 86         SM_IMMENABLED = 82
 87         SM_MAXIMUMTOUCHES = 95
 88         SM_MEDIACENTER = 87
 89         SM_MENUDROPALIGNMENT = 40
 90         SM_MIDEASTENABLED = 74
 91         SM_MOUSEPRESENT = 19
 92         SM_MOUSEHORIZONTALWHEELPRESENT = 91
 93         SM_MOUSEWHEELPRESENT = 75
 94         SM_NETWORK = 63
 95         SM_PENWINDOWS = 41
 96         SM_REMOTECONTROL = 0x2001
 97         SM_REMOTESESSION = 0x1000
 98         SM_SAMEDISPLAYFORMAT = 81
 99         SM_SERVERR2 = 89
100         SM_SHOWSOUNDS = 70
101         SM_SHUTTINGDOWN = 0x2000
102         SM_SLOWMACHINE = 73
103         SM_STARTER = 88
104         SM_SWAPBUTTON = 23
105         SM_SYSTEMDOCKED = 0x2004
106         SM_TABLETPC = 86
107         SM_XVIRTUALSCREEN = 76
108         SM_YVIRTUALSCREEN = 77
109     }
110 
111     int GetSystemMetrics(SystemMetricsId id)
112     {
113         return WinGetSystemMetrics(cast<int>(id));
114     }
115 
116     public const float inchMM = 25.4f;
117     public const float pointMM = 0.351450f;
118 
119     public inline nothrow float InchToMM(float inches)
120     {
121         return inches * inchMM;
122     }
123 
124     public inline nothrow float MMToInch(float mm)
125     {
126         return mm / inchMM;
127     }
128 
129     public inline nothrow float PointToMM(float points)
130     {
131         return points * pointMM;
132     }
133 
134     public inline nothrow float MMToPoint(float mm)
135     {
136         return mm / pointMM;
137     }
138 
139     public inline nothrow int MMToPixels(float mmfloat dpi)
140     {
141         return cast<int>(mm * dpi / inchMM);
142     }
143 
144     public inline nothrow float PixelsToMM(int pixelsfloat dpi)
145     {
146         return pixels * inchMM / dpi;
147     }
148 
149     public inline nothrow double GoldenRatio()
150     {
151         return 1 + Sqrt(5) / 2;
152     }
153 
154     public string GetDefaultMetricsFilePath()
155     {
156         string metricsFilePath;
157         string cmajorRootDir = RtGetEnvironmentVariable("CMAJOR_ROOT");
158         if (!cmajorRootDir.IsEmpty())
159         {
160             metricsFilePath = Path.Combine(Path.Combine(cmajorRootDir"config")"metrics.xml");
161         }
162         return metricsFilePath;
163     }
164 
165     public class SizeElement
166     {
167         public SizeElement(const string& name_) : name(name_)
168         {
169         }
170         public inline nothrow const SizeF& Get() const
171         {
172             return size;
173         }
174         public nothrow void Set(const SizeF& size_)
175         {
176             size = size_;
177         }
178         public void Read(System.Dom.Element* parentElement)
179         {
180             UniquePtr<XPathObject> result = Evaluate(ToUtf32(name)parentElement);
181             if (!result.IsNull())
182             {
183                 if (result->Type() == XPathObjectType.nodeSet)
184                 {
185                     XPathNodeSet* nodeSet = cast<XPathNodeSet*>(result.Get());
186                     int n = nodeSet->Length();
187                     if (n == 1)
188                     {
189                         System.Dom.Node* node = (*nodeSet)[0];
190                         if (node->GetNodeType() == System.Dom.NodeType.elementNode)
191                         {
192                             System.Dom.Element* sizeElement = cast<System.Dom.Element*>(node);
193                             size.w = ParseFloat(ToUtf8(sizeElement->GetAttribute(u"width")));
194                             size.h = ParseFloat(ToUtf8(sizeElement->GetAttribute(u"height")));
195                         }
196                     }
197                 }
198             }
199         }
200         public void Write(System.Dom.Element* parentElement)
201         {
202             ustring en = ToUtf32(name);
203             UniquePtr<System.Dom.Element> sizeElement(new System.Dom.Element(en));
204             sizeElement->SetAttribute(u"width"ToUtf32(ToString(size.w)));
205             sizeElement->SetAttribute(u"height"ToUtf32(ToString(size.h)));
206             parentElement->AppendChild(UniquePtr<System.Dom.Node>(sizeElement.Release()));
207         }
208         private string name;
209         private SizeF size;
210     }
211 
212     public class Metrics
213     {
214         public nothrow Metrics() : 
215             useDefaults(false)dpiX(96)dpiY(96)
216             defaultButtonSize(8625)defaultButtonSizeElement("button")
217             defaultLabelSize(7119)defaultLabelSizeElement("label")
218             defaultTextBoxSize(9414)defaultTextBoxSizeElement("textBox")
219             defaultListBoxSize(12095)defaultListBoxSizeElement("listBox")
220             defaultCheckBoxSize(8017)defaultCheckBoxSizeElement("checkBox")
221             defaultControlSpacing(1010)defaultControlSpacingElement("controlSpacing")
222         {
223             SetElementValues();
224         }
225         public inline nothrow bool UseDefaults() const
226         {
227             return useDefaults;
228         }
229         public nothrow void SetUseDefaults(bool useDefaults_)
230         {
231             useDefaults = useDefaults_;
232         }
233         public void LoadFromFile(const string& fileName)
234         {
235             if (File.Exists(fileName))
236             {
237                 UniquePtr<System.Dom.Document> metricsDoc = System.Dom.ReadDocument(fileName);
238                 Read(metricsDoc->DocumentElement());
239                 LogView* logView = Application.GetLogView();
240                 if (logView != null)
241                 {
242                     logView->WriteLine("metrics loaded from '" + fileName + "'");
243                 }
244             }
245         }
246         public void SetElementValues()
247         {
248             defaultButtonSizeElement.Set(SizeF(HorizontalPixelsToMM(defaultButtonSize.w)VerticalPixelsToMM(defaultButtonSize.h)));
249             defaultLabelSizeElement.Set(SizeF(HorizontalPixelsToMM(defaultLabelSize.w)VerticalPixelsToMM(defaultLabelSize.h)));
250             defaultTextBoxSizeElement.Set(SizeF(HorizontalPixelsToMM(defaultTextBoxSize.w)VerticalPixelsToMM(defaultTextBoxSize.h)));
251             defaultListBoxSizeElement.Set(SizeF(HorizontalPixelsToMM(defaultListBoxSize.w)VerticalPixelsToMM(defaultListBoxSize.h)));
252             defaultCheckBoxSizeElement.Set(SizeF(HorizontalPixelsToMM(defaultCheckBoxSize.w)VerticalPixelsToMM(defaultCheckBoxSize.h)));
253             defaultControlSpacingElement.Set(SizeF(HorizontalPixelsToMM(defaultControlSpacing.w)VerticalPixelsToMM(defaultControlSpacing.h)));
254         }
255         public void SaveTofile(const string& fileNamebool setElementValues)
256         {
257             if (setElementValues)
258             {
259                 SetElementValues();
260             }
261             System.Dom.Document metricsDoc;
262             metricsDoc.AppendChild(UniquePtr<System.Dom.Node>(new System.Dom.Element(u"metrics")));
263             metricsDoc.DocumentElement()->AppendChild(UniquePtr<System.Dom.Node>(new System.Dom.Comment(u"metrics are in millimeters")));
264             metricsDoc.DocumentElement()->AppendChild(UniquePtr<System.Dom.Node>(new System.Dom.Text(u"\n ")));
265             Write(metricsDoc.DocumentElement());
266             StreamWriter writer = File.CreateText(fileName);
267             CodeFormatter formatter(writer);
268             formatter.SetIndentSize(1);
269             metricsDoc.Write(formatter);
270             LogView* logView = Application.GetLogView();
271             if (logView != null)
272             {
273                 logView->WriteLine("metrics saved to '" + fileName + "'");
274             }
275         }
276         public void Read(System.Dom.Element* parentElement)
277         {
278             defaultButtonSizeElement.Read(parentElement);
279             defaultLabelSizeElement.Read(parentElement);
280             defaultTextBoxSizeElement.Read(parentElement);
281             defaultListBoxSizeElement.Read(parentElement);
282             defaultCheckBoxSizeElement.Read(parentElement);
283             defaultControlSpacingElement.Read(parentElement);
284         }
285         public void Write(System.Dom.Element* parentElement)
286         {
287             defaultButtonSizeElement.Write(parentElement);
288             defaultLabelSizeElement.Write(parentElement);
289             defaultTextBoxSizeElement.Write(parentElement);
290             defaultListBoxSizeElement.Write(parentElement);
291             defaultCheckBoxSizeElement.Write(parentElement);
292             defaultControlSpacingElement.Write(parentElement);
293         }
294         public inline nothrow bool Calculated() const
295         {
296             return calculated;
297         }
298         public void Calculate(Graphics& graphics)
299         {
300             calculated = true;
301             dpiX = graphics.GetDpiX();
302             dpiY = graphics.GetDpiX();
303             if (useDefaults) return;
304             defaultButtonSize.w = MMToHorizontalPixels(defaultButtonSizeElement.Get().w);
305             defaultButtonSize.h = MMToVerticalPixels(defaultButtonSizeElement.Get().h);
306             defaultLabelSize.w = MMToHorizontalPixels(defaultLabelSizeElement.Get().w);
307             defaultLabelSize.h = MMToVerticalPixels(defaultLabelSizeElement.Get().h);
308             defaultTextBoxSize.w = MMToHorizontalPixels(defaultTextBoxSizeElement.Get().w);
309             defaultTextBoxSize.h = MMToVerticalPixels(defaultTextBoxSizeElement.Get().h);
310             defaultListBoxSize.w = MMToHorizontalPixels(defaultListBoxSizeElement.Get().w);
311             defaultListBoxSize.h = MMToVerticalPixels(defaultListBoxSizeElement.Get().h);
312             defaultCheckBoxSize.w = MMToHorizontalPixels(defaultCheckBoxSizeElement.Get().w);
313             defaultCheckBoxSize.h = MMToVerticalPixels(defaultCheckBoxSizeElement.Get().h);
314             defaultControlSpacing.w = MMToHorizontalPixels(defaultControlSpacingElement.Get().w);
315             defaultControlSpacing.h = MMToVerticalPixels(defaultControlSpacingElement.Get().h);
316         }
317         public void PrintToLog()
318         {
319             LogView* logView = Application.GetLogView();
320             if (logView != null)
321             {
322                 logView->WriteLine("DPIX=" + ToString(dpiX) + ", DPIY=" + ToString(dpiY));
323                 logView->WriteLine("Button: " + defaultButtonSize.ToString() + " - (" + ToString(HorizontalPixelsToMM(defaultButtonSize.w)) + "mm, " + ToString(VerticalPixelsToMM(defaultButtonSize.h)) + "mm)");
324                 logView->WriteLine("Label: " + defaultLabelSize.ToString() + " - (" + ToString(HorizontalPixelsToMM(defaultLabelSize.w)) + "mm, " + ToString(VerticalPixelsToMM(defaultLabelSize.h)) + "mm)");
325                 logView->WriteLine("TextBox: " + defaultTextBoxSize.ToString() + " - (" + ToString(HorizontalPixelsToMM(defaultTextBoxSize.w)) + "mm, " + ToString(VerticalPixelsToMM(defaultTextBoxSize.h)) + "mm)");
326                 logView->WriteLine("ListBox: " + defaultListBoxSize.ToString() + " - (" + ToString(HorizontalPixelsToMM(defaultListBoxSize.w)) + "mm, " + ToString(VerticalPixelsToMM(defaultListBoxSize.h)) + "mm)");
327                 logView->WriteLine("CheckBox: " + defaultCheckBoxSize.ToString() + " - (" + ToString(HorizontalPixelsToMM(defaultCheckBoxSize.w)) + "mm, " + ToString(VerticalPixelsToMM(defaultCheckBoxSize.h)) + "mm)");
328                 logView->WriteLine("Spacing: " + defaultControlSpacing.ToString() +  " - (" + ToString(HorizontalPixelsToMM(defaultControlSpacing.w)) + "mm, " + ToString(VerticalPixelsToMM(defaultControlSpacing.h)) + "mm)");
329             }
330         }
331         public inline nothrow float DpiX() const
332         {
333             return dpiX;
334         }
335         public inline nothrow float DpiY() const
336         {
337             return dpiY;
338         }
339         public inline nothrow int MMToHorizontalPixels(float mm) const
340         {
341             return MMToPixels(mmdpiX);
342         }
343         public inline nothrow float HorizontalPixelsToMM(int pixels) const
344         {
345             return PixelsToMM(pixelsdpiX);
346         }
347         public inline nothrow int MMToVerticalPixels(float mm) const
348         {
349             return MMToPixels(mmdpiY);
350         }
351         public inline nothrow float VerticalPixelsToMM(int pixels) const
352         {
353             return PixelsToMM(pixelsdpiY);
354         }
355         public inline nothrow const Size& DefaultButtonSize() const
356         {
357             return defaultButtonSize;
358         }
359         public nothrow void SetDefaultButtonSize(const Size& defaultButtonSize_)
360         {
361             defaultButtonSize = defaultButtonSize_;
362         }
363         public inline nothrow const Size& DefaultLabelSize() const
364         {
365             return defaultLabelSize;
366         }
367         public nothrow void SetDefaultLabelSize(const Size& defaultLabelSize_)
368         {
369             defaultLabelSize = defaultLabelSize_;
370         }
371         public inline nothrow const Size& DefaultTextBoxSize() const
372         {
373             return defaultTextBoxSize;
374         }
375         public nothrow void SetDefaultTextBoxSize(const Size& defaultTextBoxSize_)
376         {
377             defaultTextBoxSize = defaultTextBoxSize_;
378         }
379         public inline nothrow const Size& DefaultListBoxSize() const
380         {
381             return defaultListBoxSize;
382         }
383         public nothrow void SetDefaultListBoxSize(const Size& defaultListBoxSize_)
384         {
385             defaultListBoxSize = defaultListBoxSize_;
386         }
387         public inline nothrow const Size& DefaultCheckBoxSize() const
388         {
389             return defaultCheckBoxSize;
390         }
391         public nothrow void SetDefaultCheckBoxSize(const Size& defaultCheckBoxSize_)
392         {
393             defaultCheckBoxSize = defaultCheckBoxSize_;
394         }
395         public inline nothrow const Size& DefaultControlSpacing() const
396         {
397             return defaultControlSpacing;
398         }
399         public nothrow void SetDefaultControlSpacing(const Size& defaultControlSpacing_)
400         {
401             defaultControlSpacing = defaultControlSpacing_;
402         }
403         public nothrow SizeElement& DefaultButtonSizeElement()
404         {
405             return defaultButtonSizeElement;
406         }
407         public nothrow SizeElement& DefaultLabelSizeElement()
408         {
409             return defaultLabelSizeElement;
410         }
411         public nothrow SizeElement& DefaultTextBoxSizeElement()
412         {
413             return defaultTextBoxSizeElement;
414         }
415         public nothrow SizeElement& DefaultControlSpacingElement()
416         {
417             return defaultControlSpacingElement;
418         }
419         private bool useDefaults;
420         private bool calculated;
421         private float dpiX;
422         private float dpiY;
423         private Size defaultButtonSize;
424         private SizeElement defaultButtonSizeElement;
425         private Size defaultLabelSize;
426         private SizeElement defaultLabelSizeElement;
427         private Size defaultTextBoxSize;
428         private SizeElement defaultTextBoxSizeElement;
429         private Size defaultListBoxSize;
430         private SizeElement defaultListBoxSizeElement;
431         private Size defaultCheckBoxSize;
432         private SizeElement defaultCheckBoxSizeElement;
433         private Size defaultControlSpacing;
434         private SizeElement defaultControlSpacingElement;
435     }
436 
437     public static class ScreenMetrics
438     {
439         public static ScreenMetrics() : metrics()
440         {
441         }
442         public static nothrow void SetUseDefaults(bool useDefaults)
443         {
444             metrics.SetUseDefaults(useDefaults);
445         }
446         public static void Save(bool setElementValues)
447         {
448             string metricsFilePath = GetDefaultMetricsFilePath();
449             metrics.SaveTofile(metricsFilePathsetElementValues);
450         }
451         public static void Load()
452         {
453             string metricsFilePath = GetDefaultMetricsFilePath();
454             if (File.Exists(metricsFilePath))
455             {
456                 metrics.LoadFromFile(metricsFilePath);
457             }
458         }
459         public static bool Calculated()
460         {
461             return metrics.Calculated();
462         }
463         public static void Calculate(Graphics& graphics)
464         {
465             if (!metrics.UseDefaults())
466             {
467                 Load();
468             }
469             metrics.Calculate(graphics);
470         }
471         public static nothrow const Metrics& Get()
472         {
473             return metrics;
474         }
475         public static void Set(const Metrics& metrics_)
476         {
477             metrics = metrics_;
478         }
479         public static Metrics metrics;
480     }
481 }