1 /*
2  *  "GEDKeeper", the personal genealogical database editor.
3  *  Copyright (C) 2009-2021 by Sergey V. Zhdanovskih, Ruslan Garipov.
4  *
5  *  This file is part of "GEDKeeper".
6  *
7  *  This program is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 using System;
22 using System.Drawing;
23 using System.Windows.Forms;
24 using BSLib;
25 using BSLib.Design;
26 using BSLib.Design.Graphics;
27 using BSLib.Design.Handlers;
28 using GDModel;
29 using GKCore;
30 using GKCore.Interfaces;
31 using GKCore.Lists;
32 using GKCore.Options;
33 
34 namespace GKUI.Components
35 {
36     #if !MONO
37     using Microsoft.Win32;
38     #endif
39 
40     /// <summary>
41     /// Static functions only for UI implementation.
42     /// </summary>
43     public static class UIHelper
44     {
Rt2Rt(ExtRect ert)45         public static Rectangle Rt2Rt(ExtRect ert)
46         {
47             return new Rectangle(ert.Left, ert.Top, ert.GetWidth(), ert.GetHeight());
48         }
49 
Rt2Rt(ExtRectF ert)50         public static RectangleF Rt2Rt(ExtRectF ert)
51         {
52             return new RectangleF(ert.Left, ert.Top, ert.GetWidth(), ert.GetHeight());
53         }
54 
NormalizeFormRect(ExtRect winRect)55         public static ExtRect NormalizeFormRect(ExtRect winRect)
56         {
57             // Travis CI does not have access to UI and tests aren't performed.
58             #if !CI_MODE
59 
60             //------------------------------------------------------------------
61             // 2016-09-30 Ruslan Garipov <brigadir15@gmail.com>
62             // Restrict position and size of the main window.
63             // FIXME: DPI-aware code still required here.
64             //------------------------------------------------------------------
65 
66             Screen screen = Screen.FromRectangle(Rt2Rt(winRect));
67             if (screen != null) {
68                 Rectangle workArea = screen.WorkingArea;
69 
70                 int width = winRect.GetWidth();
71                 int height = winRect.GetHeight();
72 
73                 // Besides disallowing to the main window to have its right
74                 // and bottom borders overhanged entire virtual workspace,
75                 // combined from all available monitors, this code also
76                 // does not allow to have this window "between" two
77                 // monitors. This may be UNWANTED BEHAVIOR.
78                 winRect.Left = Math.Max(workArea.Left, Math.Min(workArea.Right - width, winRect.Left));
79                 winRect.Top = Math.Max(workArea.Top, Math.Min(workArea.Bottom - height, winRect.Top));
80                 winRect.Right = winRect.Left + width - 1;
81                 winRect.Bottom = winRect.Top + height - 1;
82             }
83 
84             #endif
85 
86             return winRect;
87         }
88 
GetFormRect(Form form)89         public static ExtRect GetFormRect(Form form)
90         {
91             if (form == null) return ExtRect.CreateEmpty();
92 
93             // You must not expect user has a top window located on the primary
94             // monitor. If a top window ain't on the primary monitor,
95             // `x` and `y` may be negative numbers.
96 
97             // 2016-09-30 Ruslan Garipov <brigadir15@gmail.com>
98             // GK doesn't check size and position of the `form` here anymore.
99             // `GetFormRect` is called **before** closing the application, but
100             // there's no guarantees that user won't change a monitor settings
101             // after that. GK should restrict position of a top window on the
102             // application startup. And I'm still not sured GK should constrain
103             // a window size (either top one or child).
104             // FIXME: If `Control::Left`, `Control::Top`, `Control::Width` and
105             // `Control::Height` return physical values (device depended), code
106             // here or code that uses the result of `GetFormRect` must convert
107             // them to logical values (device independed) before storing it as
108             // the application settings. Had GK been a native Windows
109             // application, it had to do that. But since it's a .NET application
110             // I don't know is it a true.
111             return ExtRect.Create(form.Left, form.Top, form.Right, form.Bottom);
112         }
113 
RestoreFormRect(Form form, ExtRect rt, FormWindowState winState)114         public static void RestoreFormRect(Form form, ExtRect rt, FormWindowState winState)
115         {
116             // check for new and empty struct
117             if (form == null || rt.IsEmpty()) return;
118 
119             if (winState != FormWindowState.Minimized) {
120                 form.Left = rt.Left;
121                 form.Top = rt.Top;
122                 form.Width = rt.GetWidth();
123                 form.Height = rt.GetHeight();
124 
125                 form.WindowState = winState;
126             } else {
127                 form.WindowState = FormWindowState.Maximized;
128             }
129         }
130 
CenterFormByParent(Form form, IntPtr parent)131         public static void CenterFormByParent(Form form, IntPtr parent)
132         {
133             if (form == null) return;
134 
135             form.StartPosition = FormStartPosition.Manual;
136 
137             // Center the new window on a monitor, where the parent window
138             // is located.
139             Screen screen = Screen.FromHandle(parent);
140             if (screen != null) {
141                 Rectangle workArea = screen.WorkingArea;
142 
143                 form.Left = workArea.Left + ((workArea.Width - form.Width) >> 1);
144                 form.Top = workArea.Top + ((workArea.Height - form.Height) >> 1);
145             }
146         }
147 
GetSelectedTag(this ComboBox comboBox)148         public static T GetSelectedTag<T>(this ComboBox comboBox)
149         {
150             var comboItem = comboBox.SelectedItem as ComboItem<T>;
151             T itemTag = (comboItem != null) ? comboItem.Tag : default(T);
152             return itemTag;
153         }
154 
SetSelectedTag(this ComboBox comboBox, T tagValue, bool allowDefault = true)155         public static void SetSelectedTag<T>(this ComboBox comboBox, T tagValue, bool allowDefault = true)
156         {
157             foreach (object item in comboBox.Items) {
158                 var comboItem = item as ComboItem<T>;
159 
160                 if (comboItem != null && object.Equals(comboItem.Tag, tagValue)) {
161                     comboBox.SelectedItem = item;
162                     return;
163                 }
164             }
165 
166             if (allowDefault) {
167                 comboBox.SelectedIndex = 0;
168             }
169         }
170 
AddToolStripItem(ContextMenuStrip contextMenu, string text, object tag, EventHandler clickHandler)171         public static ToolStripMenuItem AddToolStripItem(ContextMenuStrip contextMenu, string text, object tag, EventHandler clickHandler)
172         {
173             var tsItem = new ToolStripMenuItem(text, null, clickHandler);
174             tsItem.Tag = tag;
175             contextMenu.Items.Add(tsItem);
176             return tsItem;
177         }
178 
GetMenuItemTag(ContextMenuStrip contextMenu, object sender)179         public static T GetMenuItemTag<T>(ContextMenuStrip contextMenu, object sender)
180         {
181             foreach (ToolStripMenuItem tsItem in contextMenu.Items) {
182                 tsItem.Checked = false;
183             }
184             var senderItem = ((ToolStripMenuItem)sender);
185             ((ToolStripMenuItem)sender).Checked = true;
186             return (T)senderItem.Tag;
187         }
188 
SetMenuItemTag(ContextMenuStrip contextMenu, T value)189         public static void SetMenuItemTag<T>(ContextMenuStrip contextMenu, T value)
190         {
191             foreach (ToolStripMenuItem tsItem in contextMenu.Items) {
192                 T itemTag = (T)tsItem.Tag;
193                 if (Equals(itemTag, value)) {
194                     tsItem.PerformClick();
195                     break;
196                 }
197             }
198         }
199 
CreateRecordsView(Control parent, IBaseContext baseContext, GDMRecordType recType)200         public static GKListView CreateRecordsView(Control parent, IBaseContext baseContext, GDMRecordType recType)
201         {
202             if (parent == null)
203                 throw new ArgumentNullException("parent");
204 
205             if (baseContext == null)
206                 throw new ArgumentNullException("baseContext");
207 
208             GKListView recView = new GKListView();
209             recView.HideSelection = false;
210             recView.LabelEdit = false;
211             recView.FullRowSelect = true;
212             recView.View = View.Details;
213             recView.ListMan = ListManager.Create(baseContext, recType);
214             recView.Dock = DockStyle.Fill;
215 
216             parent.Controls.Add(recView);
217             parent.Controls.SetChildIndex(recView, 0);
218 
219             return recView;
220         }
221 
CreateListView(Control parent)222         public static GKListView CreateListView(Control parent)
223         {
224             if (parent == null)
225                 throw new ArgumentNullException("parent");
226 
227             GKListView listView = new GKListView();
228             listView.Dock = DockStyle.Fill;
229             parent.Controls.Add(listView);
230 
231             return listView;
232         }
233 
ConvertColor(Color color)234         public static IColor ConvertColor(Color color)
235         {
236             return new ColorHandler(color);
237         }
238 
ConvertColor(IColor color)239         public static Color ConvertColor(IColor color)
240         {
241             return ((ColorHandler)color).Handle;
242         }
243 
Darker(Color color, float fraction)244         public static Color Darker(Color color, float fraction)
245         {
246             int rgb = color.ToArgb();
247             return Color.FromArgb(GfxHelper.Darker(rgb, fraction));
248         }
249 
Lighter(Color color, float fraction)250         public static Color Lighter(Color color, float fraction)
251         {
252             int rgb = color.ToArgb();
253             return Color.FromArgb(GfxHelper.Lighter(rgb, fraction));
254         }
255 
LoadResourceImage(string resName)256         public static Bitmap LoadResourceImage(string resName)
257         {
258             return new Bitmap(GKUtils.LoadResourceStream(resName));
259         }
260 
SetControlEnabled(Control ctl, bool enabled)261         public static void SetControlEnabled(Control ctl, bool enabled)
262         {
263             if (ctl != null) {
264                 ctl.Enabled = enabled;
265                 ctl.BackColor = enabled ? SystemColors.Window : SystemColors.Control;
266             }
267         }
268 
SetClipboardText(string text)269         public static void SetClipboardText(string text)
270         {
271             Clipboard.SetDataObject(text);
272         }
273 
ProcessName(object sender)274         public static void ProcessName(object sender)
275         {
276             TextBox tb = (sender as TextBox);
277             if (tb != null && GlobalOptions.Instance.FirstCapitalLetterInNames) {
278                 tb.Text = ConvertHelper.UniformName(tb.Text);
279             }
280 
281             ComboBox cmb = (sender as ComboBox);
282             if (cmb != null && GlobalOptions.Instance.FirstCapitalLetterInNames) {
283                 cmb.Text = ConvertHelper.UniformName(cmb.Text);
284             }
285         }
286 
FixToolStrip(ToolStrip toolStrip)287         public static void FixToolStrip(ToolStrip toolStrip)
288         {
289             #if MONO
290             // dirty hack: Mono ToolStrip does not support correct AutoSize
291             toolStrip.AutoSize = false;
292             toolStrip.Height = 27;
293             #endif
294         }
295 
296         #region Application's autorun
297         #if !MONO
298 
RegisterStartup()299         public static void RegisterStartup()
300         {
301             if (!IsStartupItem()) {
302                 RegistryKey rkApp = GetRunKey();
303                 if (rkApp != null) {
304                     string trayPath = GKUtils.GetAppPath() + "GKTray.exe";
305                     rkApp.SetValue(GKData.APP_TITLE, trayPath);
306                 }
307             }
308         }
309 
310         public static void UnregisterStartup()
311         {
312             if (IsStartupItem()) {
313                 RegistryKey rkApp = GetRunKey();
314                 if (rkApp != null) {
315                     rkApp.DeleteValue(GKData.APP_TITLE, false);
316                 }
317             }
318         }
319 
320         public static bool IsStartupItem()
321         {
322             RegistryKey rkApp = GetRunKey();
323             return (rkApp != null && rkApp.GetValue(GKData.APP_TITLE) != null);
324         }
325 
326         private static RegistryKey GetRunKey()
327         {
328             RegistryKey rkApp = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
329             return rkApp;
330         }
331 
332         #endif
333         #endregion
334     }
335 }
336