forked from dmnd/Caffeinated
-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathBaseForm.cs
More file actions
144 lines (119 loc) · 4.67 KB
/
BaseForm.cs
File metadata and controls
144 lines (119 loc) · 4.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.Reflection;
namespace Caffeinated;
// Base class for all forms. See Stackoverflow for reasons:
// http://stackoverflow.com/questions/297701/default-font-for-windows-forms-application/4076183#4076183
public class BaseForm : Form {
protected bool IsDarkMode => Application.IsDarkModeEnabled;
public BaseForm() {
// Provides design-time support for the default font on Visa/Win7.
// Falls back to something decent if system lacks the font.
Font = SystemFonts.MessageBoxFont;
}
protected override void OnLoad(System.EventArgs e) {
base.OnLoad(e);
UpdateTheme();
}
protected override void OnSystemColorsChanged(System.EventArgs e) {
base.OnSystemColorsChanged(e);
UpdateTheme();
}
protected virtual void UpdateTheme() {
// Override in derived classes to respond to theme changes
BackColor = IsDarkMode ? Color.FromArgb(32, 32, 32) : SystemColors.Control;
ForeColor = IsDarkMode ? Color.FromArgb(255, 255, 255) : SystemColors.ControlText;
}
public void PositionNearTrayIcon(NotifyIcon? notifyIcon) {
if (notifyIcon == null)
return;
Rectangle iconRect = GetNotifyIconRect(notifyIcon);
if (iconRect.IsEmpty) {
// Fallback to taskbar positioning
PositionNearTaskbar();
return;
}
PositionFormNearRect(iconRect);
}
private Rectangle GetNotifyIconRect(NotifyIcon notifyIcon) {
try {
FieldInfo? windowField = typeof(NotifyIcon).GetField(
"window",
BindingFlags.NonPublic | BindingFlags.Instance);
if (windowField?.GetValue(notifyIcon) is NativeWindow window) {
NativeMethods.NOTIFYICONIDENTIFIER identifier = new() {
cbSize = System.Runtime.InteropServices.Marshal.SizeOf<NativeMethods.NOTIFYICONIDENTIFIER>(),
hWnd = window.Handle,
uID = (uint)notifyIcon.GetHashCode()
};
int result = NativeMethods.Shell_NotifyIconGetRect(
ref identifier,
out NativeMethods.RECT rect);
if (result == 0) {
return rect.ToRectangle();
}
}
}
catch {
// Fall through to return empty rectangle
}
return Rectangle.Empty;
}
private void PositionNearTaskbar() {
Taskbar taskbar = new();
Rectangle taskbarBounds = taskbar.Bounds;
// Position based on taskbar location
PositionFormNearRect(taskbarBounds);
}
private void PositionFormNearRect(Rectangle targetRect) {
Taskbar taskbar = new();
Screen screen = Screen.FromRectangle(targetRect);
Rectangle workingArea = screen.WorkingArea;
// Form dimensions are already DPI-scaled by WinForms
int formWidth = Width;
int formHeight = Height;
int x, y;
const int margin = 5;
switch (taskbar.Position) {
case TaskbarPosition.Bottom:
x = targetRect.Right - formWidth;
y = targetRect.Top - formHeight - margin;
break;
case TaskbarPosition.Top:
x = targetRect.Right - formWidth;
y = targetRect.Bottom + margin;
break;
case TaskbarPosition.Left:
x = targetRect.Right + margin;
y = targetRect.Bottom - formHeight;
break;
case TaskbarPosition.Right:
x = targetRect.Left - formWidth - margin;
y = targetRect.Bottom - formHeight;
break;
default:
// Fallback to bottom-right
x = workingArea.Right - formWidth - margin;
y = workingArea.Bottom - formHeight - margin;
break;
}
// Ensure form stays within screen bounds
x = System.Math.Max(workingArea.Left, System.Math.Min(x, workingArea.Right - formWidth));
y = System.Math.Max(workingArea.Top, System.Math.Min(y, workingArea.Bottom - formHeight));
StartPosition = FormStartPosition.Manual;
Location = new Point(x, y);
}
private void InitializeComponent()
{
ComponentResourceManager resources = new(typeof(BaseForm));
SuspendLayout();
//
// BaseForm
//
ClientSize = new Size(278, 244);
Icon = resources.GetObject("$this.Icon") as Icon;
Name = "BaseForm";
ResumeLayout(false);
}
}