.Create;
100 |
101 | // allowed virtual keys
102 | VKMap.Add('LBUTTON',VK_LBUTTON );
103 | VKMap.Add('RBUTTON',VK_RBUTTON );
104 | VKMap.Add('CANCEL',VK_CANCEL );
105 | VKMap.Add('MBUTTON',VK_MBUTTON );
106 | VKMap.Add('XBUTTON1',VK_XBUTTON1 );
107 | VKMap.Add('XBUTTON2',VK_XBUTTON2 );
108 | VKMap.Add('BACK',VK_BACK );
109 | VKMap.Add('TAB',VK_TAB );
110 | VKMap.Add('CLEAR',VK_CLEAR );
111 | VKMap.Add('RETURN',VK_RETURN );
112 | VKMap.Add('SHIFT',VK_SHIFT );
113 | VKMap.Add('CONTROL',VK_CONTROL );
114 | // VKMap.Add('MENU',VK_MENU );
115 | VKMap.Add('ALT',VK_MENU );
116 | VKMap.Add('PAUSE',VK_PAUSE );
117 | VKMap.Add('CAPITAL',VK_CAPITAL );
118 | VKMap.Add('KANA',VK_KANA );
119 | VKMap.Add('HANGUL',VK_HANGUL );
120 | VKMap.Add('JUNJA',VK_JUNJA );
121 | VKMap.Add('FINAL',VK_FINAL );
122 | VKMap.Add('HANJA',VK_HANJA );
123 | VKMap.Add('KANJI',VK_KANJI );
124 | VKMap.Add('CONVERT',VK_CONVERT );
125 | VKMap.Add('NONCONVERT',VK_NONCONVERT );
126 | VKMap.Add('ACCEPT',VK_ACCEPT );
127 | VKMap.Add('MODECHANGE',VK_MODECHANGE );
128 | VKMap.Add('ESCAPE',VK_ESCAPE );
129 | VKMap.Add('SPACE',VK_SPACE );
130 | VKMap.Add('PRIOR',VK_PRIOR );
131 | VKMap.Add('NEXT',VK_NEXT );
132 | VKMap.Add('END',VK_END );
133 | VKMap.Add('HOME',VK_HOME );
134 | VKMap.Add('LEFT',VK_LEFT );
135 | VKMap.Add('UP',VK_UP );
136 | VKMap.Add('RIGHT',VK_RIGHT );
137 | VKMap.Add('DOWN',VK_DOWN );
138 | VKMap.Add('SELECT',VK_SELECT );
139 | VKMap.Add('PRINT',VK_PRINT );
140 | VKMap.Add('EXECUTE',VK_EXECUTE );
141 | VKMap.Add('SNAPSHOT',VK_SNAPSHOT );
142 | VKMap.Add('INSERT',VK_INSERT );
143 | VKMap.Add('DELETE',VK_DELETE );
144 | VKMap.Add('HELP',VK_HELP );
145 | VKMap.Add('WIN',VK_LWIN );
146 | VKMap.Add('RWIN',VK_RWIN );
147 | VKMap.Add('APPS',VK_APPS );
148 | VKMap.Add('SLEEP',VK_SLEEP );
149 | VKMap.Add('NUMPAD0',VK_NUMPAD0 );
150 | VKMap.Add('NUMPAD1',VK_NUMPAD1 );
151 | VKMap.Add('NUMPAD2',VK_NUMPAD2 );
152 | VKMap.Add('NUMPAD3',VK_NUMPAD3 );
153 | VKMap.Add('NUMPAD4',VK_NUMPAD4 );
154 | VKMap.Add('NUMPAD5',VK_NUMPAD5 );
155 | VKMap.Add('NUMPAD6',VK_NUMPAD6 );
156 | VKMap.Add('NUMPAD7',VK_NUMPAD7 );
157 | VKMap.Add('NUMPAD8',VK_NUMPAD8 );
158 | VKMap.Add('NUMPAD9',VK_NUMPAD9 );
159 | VKMap.Add('MULTIPLY',VK_MULTIPLY );
160 | VKMap.Add('ADD',VK_ADD );
161 | VKMap.Add('SEPARATOR',VK_SEPARATOR );
162 | VKMap.Add('SUBTRACT',VK_SUBTRACT );
163 | VKMap.Add('DECIMAL',VK_DECIMAL );
164 | VKMap.Add('DIVIDE',VK_DIVIDE );
165 | VKMap.Add('F1',VK_F1 );
166 | VKMap.Add('F2',VK_F2 );
167 | VKMap.Add('F3',VK_F3 );
168 | VKMap.Add('F4',VK_F4 );
169 | VKMap.Add('F5',VK_F5 );
170 | VKMap.Add('F6',VK_F6 );
171 | VKMap.Add('F7',VK_F7 );
172 | VKMap.Add('F8',VK_F8 );
173 | VKMap.Add('F9',VK_F9 );
174 | VKMap.Add('F10',VK_F10 );
175 | VKMap.Add('F11',VK_F11 );
176 | VKMap.Add('F12',VK_F12 );
177 | VKMap.Add('F13',VK_F13 );
178 | VKMap.Add('F14',VK_F14 );
179 | VKMap.Add('F15',VK_F15 );
180 | VKMap.Add('F16',VK_F16 );
181 | VKMap.Add('F17',VK_F17 );
182 | VKMap.Add('F18',VK_F18 );
183 | VKMap.Add('F19',VK_F19 );
184 | VKMap.Add('F20',VK_F20 );
185 | VKMap.Add('F21',VK_F21 );
186 | VKMap.Add('F22',VK_F22 );
187 | VKMap.Add('F23',VK_F23 );
188 | VKMap.Add('F24',VK_F24 );
189 | VKMap.Add('NUMLOCK',VK_NUMLOCK );
190 | VKMap.Add('SCROLL',VK_SCROLL );
191 | //VK_L & VK_R - left and right Alt, Ctrl and Shift virtual keys.
192 | //Used only as parameters to GetAsyncKeyState() and GetKeyState().);
193 | //No other API or message will distinguish left and right keys in this way. });
194 | VKMap.Add('LSHIFT',VK_LSHIFT );
195 | VKMap.Add('RSHIFT',VK_RSHIFT );
196 | VKMap.Add('LCONTROL',VK_LCONTROL );
197 | VKMap.Add('RCONTROL',VK_RCONTROL );
198 | VKMap.Add('LMENU',VK_LMENU );
199 | VKMap.Add('RMENU',VK_RMENU );
200 | VKMap.Add('BROWSER_BACK',VK_BROWSER_BACK );
201 | VKMap.Add('BROWSER_FORWARD',VK_BROWSER_FORWARD );
202 | VKMap.Add('BROWSER_REFRESH',VK_BROWSER_REFRESH );
203 | VKMap.Add('BROWSER_STOP',VK_BROWSER_STOP );
204 | VKMap.Add('BROWSER_SEARCH',VK_BROWSER_SEARCH );
205 | VKMap.Add('BROWSER_FAVORITES',VK_BROWSER_FAVORITES );
206 | VKMap.Add('BROWSER_HOME',VK_BROWSER_HOME );
207 | VKMap.Add('VOLUME_MUTE',VK_VOLUME_MUTE );
208 | VKMap.Add('VOLUME_DOWN',VK_VOLUME_DOWN );
209 | VKMap.Add('VOLUME_UP',VK_VOLUME_UP );
210 | VKMap.Add('MEDIA_NEXT_TRACK',VK_MEDIA_NEXT_TRACK );
211 | VKMap.Add('MEDIA_PREV_TRACK',VK_MEDIA_PREV_TRACK );
212 | VKMap.Add('MEDIA_STOP',VK_MEDIA_STOP );
213 | VKMap.Add('MEDIA_PLAY_PAUSE',VK_MEDIA_PLAY_PAUSE );
214 | VKMap.Add('LAUNCH_MAIL',VK_LAUNCH_MAIL );
215 | VKMap.Add('LAUNCH_MEDIA_SELECT',VK_LAUNCH_MEDIA_SELECT );
216 | VKMap.Add('LAUNCH_APP1',VK_LAUNCH_APP1 );
217 | VKMap.Add('LAUNCH_APP2',VK_LAUNCH_APP2 );
218 | VKMap.Add('OEM_1',VK_OEM_1 );
219 | VKMap.Add('OEM_PLUS',VK_OEM_PLUS );
220 | VKMap.Add('OEM_COMMA',VK_OEM_COMMA );
221 | VKMap.Add('OEM_MINUS',VK_OEM_MINUS );
222 | VKMap.Add('OEM_PERIOD',VK_OEM_PERIOD );
223 | VKMap.Add('OEM_2',VK_OEM_2 );
224 | VKMap.Add('OEM_3',VK_OEM_3 );
225 | VKMap.Add('OEM_4',VK_OEM_4 );
226 | VKMap.Add('OEM_5',VK_OEM_5 );
227 | VKMap.Add('OEM_6',VK_OEM_6 );
228 | VKMap.Add('OEM_7',VK_OEM_7 );
229 | VKMap.Add('OEM_8',VK_OEM_8 );
230 | VKMap.Add('OEM_102',VK_OEM_102 );
231 | VKMap.Add('PACKET',VK_PACKET );
232 | VKMap.Add('PROCESSKEY',VK_PROCESSKEY );
233 | VKMap.Add('ATTN',VK_ATTN );
234 | VKMap.Add('CRSEL',VK_CRSEL );
235 | VKMap.Add('EXSEL',VK_EXSEL );
236 | VKMap.Add('EREOF',VK_EREOF );
237 | VKMap.Add('PLAY',VK_PLAY );
238 | VKMap.Add('ZOOM',VK_ZOOM );
239 | VKMap.Add('NONAME',VK_NONAME );
240 | VKMap.Add('PA1',VK_PA1 );
241 | VKMap.Add('OEM_CLEAR',VK_OEM_CLEAR);
242 | end;
243 |
244 | destructor THotkeyInvoker.Destroy;
245 | begin
246 | if FHook <> 0 then
247 | UnhookWindowsHookEx(FHook);
248 | VKMap.Clear;
249 | VKMap.Free;
250 | BlockedKeys.Free;
251 |
252 | inherited;
253 | end;
254 |
255 | class function THotkeyInvoker.GetInstance: THotkeyInvoker;
256 | begin
257 | if FInstance = nil then
258 | FInstance := THotkeyInvoker.Create;
259 | Result := FInstance;
260 | end;
261 |
262 | function THotkeyInvoker.InvokeHotKey(const Hotkey: string; Delay,
263 | RepeatCount: Integer): Boolean;
264 | var
265 | Keys: TStringList;
266 | Key: string;
267 | VK: Byte;
268 | IsHoldDown, IsRelease: Boolean;
269 | I, J: Integer;
270 | HeldKeys: TList;
271 |
272 | procedure SendKey(VirtualKey: Byte; Flag: DWORD);
273 | begin
274 | keybd_event(VirtualKey, MapVirtualKey(VirtualKey, 0), Flag, 0);
275 | Sleep(Delay);
276 | end;
277 |
278 | function GetVirtualKey(const Key: string): Byte;
279 | var
280 | VK: Byte;
281 | begin
282 | if VKMap.TryGetValue(Key,VK) then
283 | Result := VK
284 | else
285 | Result := Ord(Key[1]);
286 | end;
287 |
288 |
289 | begin
290 | Result := False;
291 | Keys := TStringList.Create;
292 | HeldKeys := TList.Create;
293 | try
294 | Keys.Delimiter := '+';
295 | Keys.DelimitedText := UpperCase(HotKey);// StringReplace(Hotkey, '\+', #1, [rfReplaceAll]);
296 |
297 | // for I := 0 to Keys.Count - 1 do
298 | // Keys[I] := StringReplace(Keys[I], #1, '+', [rfReplaceAll]);
299 |
300 | BlockedKeys.Clear;
301 | for I := 0 to Keys.Count - 1 do
302 | begin
303 | Key := Keys[I];
304 | IsHoldDown := StartsWith(Key, '_');
305 | IsRelease := EndsWith(Key, '_');
306 | Key := TrimUnderscores(Key);
307 |
308 | // if Key = 'CTRL' then VK := VK_CONTROL
309 | // else if Key = 'ALT' then VK := VK_MENU
310 | // else if Key = 'SHIFT' then VK := VK_SHIFT
311 | // else if Key = 'WIN' then VK := VK_LWIN
312 | // else if Key = 'TAB' then VK := VK_TAB
313 | // else VK := Ord(UpperCase(Key)[1]);
314 | VK := GetVirtualKey(Key);
315 |
316 | BlockedKeys.Add(IntToStr(VK));
317 | end;
318 |
319 | BlockInput := True;
320 | try
321 | for J := 1 to RepeatCount do
322 | begin
323 | for I := 0 to Keys.Count - 1 do
324 | begin
325 | Key := Keys[I];
326 | IsHoldDown := StartsWith(Key, '_');
327 | IsRelease := EndsWith(Key, '_');
328 | Key := TrimUnderscores(Key);
329 |
330 | // if Key = 'CTRL' then VK := VK_CONTROL
331 | // else if Key = 'ALT' then VK := VK_MENU
332 | // else if Key = 'SHIFT' then VK := VK_SHIFT
333 | // else if Key = 'WIN' then VK := VK_LWIN
334 | // else if Key = 'TAB' then VK := VK_TAB
335 | // else VK := Ord(UpperCase(Key)[1]);
336 | VK := GetVirtualKey(Key);
337 |
338 | if IsHoldDown and not IsRelease then
339 | begin
340 | SendKey(VK, 0);
341 | HeldKeys.Add(Pointer(VK));
342 | end
343 | else if not IsHoldDown and not IsRelease then
344 | begin
345 | SendKey(VK, 0);
346 | SendKey(VK, KEYEVENTF_KEYUP);
347 | end
348 | else if IsRelease then
349 | begin
350 | if HeldKeys.IndexOf(Pointer(VK)) >= 0 then
351 | HeldKeys.Remove(Pointer(VK));
352 | SendKey(VK, KEYEVENTF_KEYUP);
353 | end;
354 | end;
355 |
356 | // Release any remaining held keys in reverse order
357 | for I := HeldKeys.Count - 1 downto 0 do
358 | begin
359 | SendKey(Byte(HeldKeys[I]), KEYEVENTF_KEYUP);
360 | end;
361 |
362 | HeldKeys.Clear;
363 |
364 | if J < RepeatCount then
365 | Sleep(Delay);
366 | end;
367 |
368 | Result := True;
369 |
370 | finally
371 | BlockInput := False;
372 | end;
373 |
374 |
375 | finally
376 | HeldKeys.Free;
377 | Keys.Free;
378 | end;
379 | end;
380 |
381 | procedure THotkeyInvoker.SetBlockInput(const value: Boolean);
382 | begin
383 | FBlockInput := Value;
384 | end;
385 |
386 | initialization
387 | THotkeyInvoker.FInstance := THotkeyInvoker.Create;
388 |
389 | finalization
390 | FreeAndNil(THotkeyInvoker.FInstance);
391 |
392 | end.
393 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # WinXcorners
4 |
5 |
27 |
28 |
55 |
56 |
62 |
63 | ## WinXcorners
64 | WinXcorners is a lightweight utility for Windows 10 and Windows 11 that enhances your desktop experience by allowing you to assign custom actions triggered when you hover your mouse cursor over the corners of your main monitor. Whether you're a power user, developer, or just someone who appreciates efficiency, WinXcorners provides a seamless way to streamline your workflow.
65 |
66 | ## Key Features ⬆️
67 |
68 | 1. **Corner Actions**: Choose from a variety of predefined actions for each corner:
69 | - [x] **Show All Windows**: Activate Windows' Task View `Win`+`Tab` to manage your open applications.
70 | - [x] **Show Desktop**: Quickly minimize all windows and reveal the desktop.
71 | - [x] **Start Screen Saver**: Trigger your screen saver for privacy or energy-saving purposes.
72 | - [x] **Turn Off Monitors**: Conveniently turn off your display when not in use.
73 | - [x] **Start Menu**: Invoke the Start Menu on hovering a corner.
74 | - [x] **Action Center**: Invoke the Action Center without hassle.
75 | - [x] **Hide Other Windows**: Just like `Win`+`Home`.
76 | - [x] **Custom**: Invoke other executables with command line params
77 | - [x] 🆕 **Custom**: Execute custom hotkeys (sequence of key hold/release) *___v1.3.1___ ( How to ⬇️)
78 |
79 | 2. **Customization**: Tailor WinXcorners to your preferences:
80 | - Assign different actions to different corners.
81 | - Fine-tune hover sensitivity and delay settings.
82 | - Enable or disable automatic startup with Windows.
83 |
84 | 3. **System Tray Integration**: WinXcorners runs discreetly in the system tray, ensuring it doesn't clutter your desktop or Taskbar.
85 |
86 | 4. **Unobstrusive**: Its usage won't interfere with your common tasks, unless you decide to do so.
87 | - It won't trigger actions while dragging content with your mouse.
88 | - It won't trigger while using a **Full Screen application**, like games or media, for instance.
89 | - You can disable it temporarily right from the popup window with the switch toggle.
90 |
91 | 5. **Visible Countdown Counter**: Helps you, visually, to know if a corner action is about to be triggered (Advanced feature).
92 |
93 | 6. **Windows 10/11 Theme aware**: Partially supports Windows 10 and 11 dark and light theme, so it will look like part of your OS.
94 | :crescent_moon:themes:high_brightness:
95 |
96 |
97 | | Dark Theme Windows 11 | Light Theme Windows 11 |
98 | |:-------------------------------------------------:|:-----------------------------------------------:|
99 | |  |  |
100 | | Dark Theme Windows 10 | Light Theme Windows 10 May 2019 Update onwards |
101 | | | |
102 |
103 | ## Demo Video
104 |
105 |
106 | 🎞
107 |
108 | This demonstration would change on following versions.
109 |
110 |
111 |
112 | ## Installation (Portable) ⬆️
113 | 1. Download the latest release from the GitHub repository.
114 | 2. Just unzip into a secure folder.
115 | 3. Run the single small executable, settings will be written/saved there.
116 | 4. 💡 It will run minimized and hidden in the **System Tray**
117 |
118 | ## Requirements
119 |
120 | — OS: Windows 10 x86/x64 | Windows 11
121 | — HDD: 1.4 MB
122 | — RAM: 9 MB
123 |
124 |
125 |
126 | ## Download and Installation *(?)*
127 |
128 | 
129 |
130 | | v1.3.2 (2024) | v1.3.0 (2024) | v1.2.1b (2019) |
131 | |:---------------:|:---------------:|:-----------------:|
132 | | | | |
133 | | [](https://github.com/vhanla/winxcorners/releases/download/1.3.2/winxcorners1.3.2.zip) | [](https://github.com/vhanla/winxcorners/releases/download/1.3.0/winxcorners130.zip) | [](https://github.com/vhanla/winxcorners/releases/download/1.2.1b/WinXCornersRegistryFix.zip) |
134 |
135 |
136 |
137 | ## How To Use ⬆️
138 | 1. Launch WinXcorners popup window from the system tray icon.
139 | 2. Configure your preferred actions for each corner.
140 | 3. Hover your mouse cursor over a corner to trigger the assigned action.
141 |
142 | ## Advanced Usage
143 | 1. Right click the WinXcorners tray icon.
144 | 2. Select **Advanced** to open the more advanced options.
145 |
146 | | | |
147 | |:-------------------------------------------------:|:-------------------------------------------------:|
148 | |||
149 | |Advanced options v 1.3.0 | Advanced options v 1.2.1b *old snapshot* |
150 |
151 | 3. There you can:
152 | - Set a global delay, so the action will trigger after some few seconds.
153 | - Set specific delay for each corner.
154 | - Enable or Disable the triggering of actions while on Full Screen applications, it can also be done via the right click on the system tray icon for WinXcorners.
155 | 4. Add up to 4 custom actions: Just write the commands and its respective arguments to launch, set hidden launch or visible.
156 |
157 | ## Custom Hotkeys ⬆️
158 | *___v1.3.1___
159 |
160 | The hotkeys will be as follows:
161 | `_control` or `control` or `control_` where `_` means hold or release (prefixed, appended) and without it, a full key press. This will be useful if you have a sequence of hotkeys to do, like `_control+k+control_+_control+_b` for VSCode for instance, that will do a `ctrl+k` then `ctrl+b` to toggle the sidebar.
162 |
163 | There is more, it will check for windows on foreground/currently focused, or globally, whether by only its classname or with titlebar text too. The conditional pseudo script will be as follows:
164 | ```
165 | ! = follows sequence of hotkeys as mentioned above
166 | # = follows [classname,title] there title is optional to match with current focused window
167 | @ = follows [classname,title] there title is optional to match with any opened window
168 | ```
169 |
170 | ### Rule:
171 |
172 | `#[classname,title]:(sequence of hotkeys)?(optional sequence of hotkeys in case condition is not met)`
173 |
174 | For instance the following will check if current window is VSCode's and will invoke `ctrl+k` `ctrl+b` sequence of hotkeys, other wise if not on VSCode, just invoke the Start Menu.
175 |
176 | `#[Chrome_WidgetWin_1]:(_control+k+control_+_control+_b)?(win)`
177 |
178 | E.g. `#[conditional match]:(hotkey if match)?(hotkey if not)`
179 |
180 | Another example for Windows 10:
181 |
182 | This will check if Alt+Tab's window is visible, if so, it will hide it, otherwise it will invoke it, as a faster alternative to Task View.
183 | `#[MultitaskingViewFrame]:(escape)?(_control+_alt+tab)`
184 |
185 | 
186 |
187 | ## Notes
188 | - WinXcorners works seamlessly on your primary monitor but secondary monitors haven't been tested throughfully, consider it partially supported.
189 | - If you encounter issues with elevated privileges software, try restarting WinXcorners as an administrator specially if you use those kind of elevated privileged software most of the time, otherwise triggering won't work due to the nature of separate privileges.
190 | - If you encounter other unknown issues, please fill a bug report at the GitHub issues page.
191 |
192 | **Limitations**:
193 |
194 | Sometimes the application won't detect the screen edges if you are using (focused) an elevated privileged application. But you can always restart the application as administrator.
195 |
196 | ## Development ⬆️
197 |
198 | Build with Delphi 2006 onwards, third party units are in thirdparty and all rights belong to each of them, they're open source too.
199 |
200 | ## Contribution ⬆️
201 |
202 | You're welcome to PR your improvements.
203 |
204 | MIT License
205 |
206 | Copyright (c) 2015 Victor Alberto Gil (vhanla)
207 |
208 | Permission is hereby granted, free of charge, to any person obtaining a copy
209 | of this software and associated documentation files (the "Software"), to deal
210 | in the Software without restriction, including without limitation the rights
211 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
212 | copies of the Software, and to permit persons to whom the Software is
213 | furnished to do so, subject to the following conditions:
214 |
215 | The above copyright notice and this permission notice shall be included in all
216 | copies or substantial portions of the Software.
217 |
218 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
219 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
220 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
221 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
222 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
223 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
224 | SOFTWARE.
225 |
--------------------------------------------------------------------------------
/frmAdvanced.dfm:
--------------------------------------------------------------------------------
1 | object frmAdvSettings: TfrmAdvSettings
2 | Left = 0
3 | Top = 0
4 | AlphaBlend = True
5 | Caption = 'WinXCorners - Advanced Options'
6 | ClientHeight = 427
7 | ClientWidth = 438
8 | Color = 2960685
9 | Font.Charset = DEFAULT_CHARSET
10 | Font.Color = clWhite
11 | Font.Height = -11
12 | Font.Name = 'Tahoma'
13 | Font.Style = []
14 | OldCreateOrder = False
15 | OnCreate = FormCreate
16 | OnDestroy = FormDestroy
17 | OnShow = FormShow
18 | DesignSize = (
19 | 438
20 | 427)
21 | PixelsPerInch = 96
22 | TextHeight = 13
23 | object Label4: TLabel
24 | Left = 16
25 | Top = 398
26 | Width = 91
27 | Height = 15
28 | Cursor = crHandPoint
29 | Margins.Left = 2
30 | Margins.Top = 2
31 | Margins.Right = 2
32 | Margins.Bottom = 2
33 | Anchors = [akLeft, akBottom]
34 | Caption = 'Support my work'
35 | Font.Charset = ANSI_CHARSET
36 | Font.Color = 15626577
37 | Font.Height = -12
38 | Font.Name = 'Segoe UI'
39 | Font.Style = []
40 | ParentFont = False
41 | OnClick = Label4Click
42 | end
43 | object Label5: TLabel
44 | Left = 147
45 | Top = 398
46 | Width = 96
47 | Height = 15
48 | Cursor = crHandPoint
49 | Margins.Left = 2
50 | Margins.Top = 2
51 | Margins.Right = 2
52 | Margins.Bottom = 2
53 | Anchors = [akLeft, akBottom]
54 | Caption = 'Check for updates'
55 | Color = 16744448
56 | Font.Charset = ANSI_CHARSET
57 | Font.Color = 15626577
58 | Font.Height = -12
59 | Font.Name = 'Segoe UI'
60 | Font.Style = []
61 | ParentColor = False
62 | ParentFont = False
63 | OnClick = Label5Click
64 | end
65 | object Label2: TLabel
66 | Left = 307
67 | Top = 163
68 | Width = 124
69 | Height = 14
70 | Margins.Left = 2
71 | Margins.Top = 2
72 | Margins.Right = 2
73 | Margins.Bottom = 2
74 | Caption = 'Beta build (20240630)'
75 | Color = clWhite
76 | Font.Charset = DEFAULT_CHARSET
77 | Font.Color = clGray
78 | Font.Height = -12
79 | Font.Name = 'Tahoma'
80 | Font.Style = []
81 | ParentColor = False
82 | ParentFont = False
83 | end
84 | object btnCancel: TButton
85 | Left = 351
86 | Top = 394
87 | Width = 75
88 | Height = 25
89 | Anchors = [akRight, akBottom]
90 | Caption = '&Cancel'
91 | TabOrder = 1
92 | OnClick = btnCancelClick
93 | end
94 | object btnOK: TButton
95 | Left = 270
96 | Top = 394
97 | Width = 75
98 | Height = 25
99 | Anchors = [akRight, akBottom]
100 | Caption = '&OK'
101 | TabOrder = 0
102 | OnClick = btnOKClick
103 | end
104 | object ATTabs1: TATTabs
105 | AlignWithMargins = True
106 | Left = 8
107 | Top = 191
108 | Width = 422
109 | Height = 35
110 | Margins.Left = 8
111 | Margins.Right = 8
112 | Margins.Bottom = 0
113 | Align = alBottom
114 | Tabs = <
115 | item
116 | TabCaption = 'Command 1'
117 | TabHideXButton = True
118 | end
119 | item
120 | TabCaption = 'Command 2'
121 | TabHideXButton = True
122 | end
123 | item
124 | TabCaption = 'Command 3'
125 | TabHideXButton = True
126 | end
127 | item
128 | TabCaption = 'Command 4'
129 | TabHideXButton = True
130 | end>
131 | DoubleBuffered = True
132 | ColorBg = 2960685
133 | ColorBorderPassive = 6579300
134 | ColorTabPassive = 2960685
135 | ColorActiveMark = 16744448
136 | OptButtonLayout = '<>,v'
137 | OptShowAngleTangent = 2.599999904632568000
138 | OptShowFlat = True
139 | OptShowFlatSepar = False
140 | OptShowXButtons = atbxShowNone
141 | OptShowPlusTab = False
142 | OptShowModifiedText = '*'
143 | OptMouseDragOutEnabled = False
144 | OptHintForX = 'Close tab'
145 | OptHintForPlus = 'Add tab'
146 | OptHintForArrowLeft = 'Scroll tabs left'
147 | OptHintForArrowRight = 'Scroll tabs right'
148 | OptHintForArrowMenu = 'Show tabs list'
149 | OptHintForUser0 = '0'
150 | OptHintForUser1 = '1'
151 | OptHintForUser2 = '2'
152 | OptHintForUser3 = '3'
153 | OptHintForUser4 = '4'
154 | OnTabClick = ATTabs1TabClick
155 | end
156 | object Panel1: TPanel
157 | AlignWithMargins = True
158 | Left = 8
159 | Top = 8
160 | Width = 422
161 | Height = 145
162 | Margins.Left = 8
163 | Margins.Top = 8
164 | Margins.Right = 8
165 | Margins.Bottom = 8
166 | Align = alTop
167 | BevelOuter = bvNone
168 | BorderStyle = bsSingle
169 | Caption = 'Panel1'
170 | Ctl3D = False
171 | ParentCtl3D = False
172 | ShowCaption = False
173 | TabOrder = 3
174 | object chkDelayBotLeft: TXCheckbox
175 | Left = 24
176 | Top = 71
177 | Width = 44
178 | Height = 20
179 | Caption = 'Top Bottom Delay'
180 | Color = 16744448
181 | DisabledColor = 5592405
182 | PressedColor = 6710886
183 | Checked = False
184 | OnClick = chkDelayBotLeftClick
185 | Font.Charset = DEFAULT_CHARSET
186 | Font.Color = clWhite
187 | Font.Height = -12
188 | Font.Name = 'Segoe UI'
189 | Font.Style = []
190 | ParentColor = True
191 | Labeled = True
192 | LabelPosition = lpRight
193 | end
194 | object chkDelayBotRight: TXCheckbox
195 | Left = 213
196 | Top = 71
197 | Width = 44
198 | Height = 20
199 | Caption = 'Top Bottom delay'
200 | Color = 16744448
201 | DisabledColor = 5592405
202 | PressedColor = 6710886
203 | Checked = False
204 | OnClick = chkDelayBotRightClick
205 | Font.Charset = DEFAULT_CHARSET
206 | Font.Color = clWhite
207 | Font.Height = -12
208 | Font.Name = 'Segoe UI'
209 | Font.Style = []
210 | ParentColor = True
211 | Labeled = True
212 | LabelPosition = lpRight
213 | end
214 | object chkDelayGlobal: TXCheckbox
215 | Left = 16
216 | Top = 5
217 | Width = 44
218 | Height = 20
219 | Caption = 'Set a global delay in seconds:'
220 | Color = 16744448
221 | DisabledColor = 5592405
222 | PressedColor = 6710886
223 | Checked = False
224 | OnClick = chkDelayGlobalClick
225 | Font.Charset = DEFAULT_CHARSET
226 | Font.Color = clWhite
227 | Font.Height = -12
228 | Font.Name = 'Segoe UI'
229 | Font.Style = []
230 | ParentColor = True
231 | Labeled = True
232 | LabelPosition = lpRight
233 | end
234 | object chkDelayTopLeft: TXCheckbox
235 | Left = 24
236 | Top = 37
237 | Width = 44
238 | Height = 20
239 | Caption = 'Top Left Delay'
240 | Color = 16744448
241 | DisabledColor = 5592405
242 | PressedColor = 6710886
243 | Checked = False
244 | OnClick = chkDelayTopLeftClick
245 | Font.Charset = DEFAULT_CHARSET
246 | Font.Color = clWhite
247 | Font.Height = -12
248 | Font.Name = 'Segoe UI'
249 | Font.Style = []
250 | ParentColor = True
251 | Labeled = True
252 | LabelPosition = lpRight
253 | end
254 | object chkDelayTopRight: TXCheckbox
255 | Left = 213
256 | Top = 37
257 | Width = 44
258 | Height = 20
259 | Caption = 'Top Right delay'
260 | Color = 16744448
261 | DisabledColor = 5592405
262 | PressedColor = 6710886
263 | Checked = False
264 | OnClick = chkDelayTopRightClick
265 | Font.Charset = DEFAULT_CHARSET
266 | Font.Color = clWhite
267 | Font.Height = -12
268 | Font.Name = 'Segoe UI'
269 | Font.Style = []
270 | ParentColor = True
271 | Labeled = True
272 | LabelPosition = lpRight
273 | end
274 | object chkFullScreen: TXCheckbox
275 | Left = 163
276 | Top = 116
277 | Width = 44
278 | Height = 20
279 | Caption = 'Do nothing on Full Screen'
280 | Color = 16744448
281 | DisabledColor = 5592405
282 | PressedColor = 6710886
283 | Checked = False
284 | OnClick = chkFullScreenClick
285 | Font.Charset = DEFAULT_CHARSET
286 | Font.Color = clWhite
287 | Font.Height = -12
288 | Font.Name = 'Segoe UI'
289 | Font.Style = []
290 | ParentColor = True
291 | Labeled = True
292 | LabelPosition = lpRight
293 | end
294 | object chkShowCount: TXCheckbox
295 | Left = 16
296 | Top = 116
297 | Width = 44
298 | Height = 20
299 | Caption = 'Show Countdown'
300 | Color = 16744448
301 | DisabledColor = 5592405
302 | PressedColor = 6710886
303 | Checked = False
304 | Font.Charset = DEFAULT_CHARSET
305 | Font.Color = clWhite
306 | Font.Height = -12
307 | Font.Name = 'Segoe UI'
308 | Font.Style = []
309 | ParentColor = True
310 | Labeled = True
311 | LabelPosition = lpRight
312 | end
313 | object cbValDelayGlobal: TComboBox
314 | Left = 240
315 | Top = 5
316 | Width = 40
317 | Height = 21
318 | Style = csDropDownList
319 | Color = clNone
320 | ItemHeight = 13
321 | TabOrder = 0
322 | Items.Strings = (
323 | '0.25'
324 | '0.50'
325 | '0.75'
326 | '1.00'
327 | '1.25'
328 | '1.50')
329 | end
330 | object cbValDelayTopLeft: TComboBox
331 | Left = 172
332 | Top = 38
333 | Width = 40
334 | Height = 21
335 | Style = csDropDownList
336 | Color = clNone
337 | ItemHeight = 13
338 | TabOrder = 1
339 | Items.Strings = (
340 | '0.25'
341 | '0.50'
342 | '0.75'
343 | '1.00'
344 | '1.25'
345 | '1.50')
346 | end
347 | object cbValDelayBotLeft: TComboBox
348 | Left = 172
349 | Top = 72
350 | Width = 40
351 | Height = 21
352 | Style = csDropDownList
353 | Color = clNone
354 | ItemHeight = 13
355 | TabOrder = 2
356 | Items.Strings = (
357 | '0.25'
358 | '0.50'
359 | '0.75'
360 | '1.00'
361 | '1.25'
362 | '1.50')
363 | end
364 | object cbValDelayTopRight: TComboBox
365 | Left = 364
366 | Top = 38
367 | Width = 40
368 | Height = 21
369 | Style = csDropDownList
370 | Color = clNone
371 | ItemHeight = 13
372 | TabOrder = 3
373 | Items.Strings = (
374 | '0.25'
375 | '0.50'
376 | '0.75'
377 | '1.00'
378 | '1.25'
379 | '1.50')
380 | end
381 | object cbValDelayBotRight: TComboBox
382 | Left = 364
383 | Top = 72
384 | Width = 40
385 | Height = 21
386 | Style = csDropDownList
387 | Color = clNone
388 | ItemHeight = 13
389 | TabOrder = 4
390 | Items.Strings = (
391 | '0.25'
392 | '0.50'
393 | '0.75'
394 | '1.00'
395 | '1.25'
396 | '1.50')
397 | end
398 | end
399 | object Panel2: TPanel
400 | AlignWithMargins = True
401 | Left = 8
402 | Top = 226
403 | Width = 422
404 | Height = 153
405 | Margins.Left = 8
406 | Margins.Top = 0
407 | Margins.Right = 8
408 | Margins.Bottom = 48
409 | Align = alBottom
410 | BevelOuter = bvNone
411 | BorderStyle = bsSingle
412 | Caption = 'Panel2'
413 | Ctl3D = False
414 | ParentCtl3D = False
415 | ShowCaption = False
416 | TabOrder = 4
417 | object chkCustom: TXCheckbox
418 | Left = 16
419 | Top = 121
420 | Width = 44
421 | Height = 20
422 | Caption = 'Enable Custom Commands'
423 | Color = 16744448
424 | DisabledColor = 5592405
425 | PressedColor = 6710886
426 | Checked = False
427 | Font.Charset = DEFAULT_CHARSET
428 | Font.Color = clWhite
429 | Font.Height = -12
430 | Font.Name = 'Segoe UI'
431 | Font.Style = []
432 | ParentColor = True
433 | Labeled = True
434 | LabelPosition = lpRight
435 | end
436 | object chkHidden: TXCheckbox
437 | Left = 251
438 | Top = 121
439 | Width = 44
440 | Height = 20
441 | Caption = 'Launch Hidden'
442 | Color = 16744448
443 | DisabledColor = 5592405
444 | PressedColor = 6710886
445 | Checked = False
446 | OnClick = chkHiddenClick
447 | Font.Charset = DEFAULT_CHARSET
448 | Font.Color = clWhite
449 | Font.Height = -12
450 | Font.Name = 'Segoe UI'
451 | Font.Style = []
452 | ParentColor = True
453 | Labeled = True
454 | LabelPosition = lpRight
455 | end
456 | object Label1: TLabel
457 | Left = 16
458 | Top = 70
459 | Width = 104
460 | Height = 13
461 | Margins.Left = 2
462 | Margins.Top = 2
463 | Margins.Right = 2
464 | Margins.Bottom = 2
465 | Caption = 'Parameters (optional)'
466 | Color = clBackground
467 | ParentColor = False
468 | end
469 | object Label3: TLabel
470 | Left = 16
471 | Top = 26
472 | Width = 370
473 | Height = 13
474 | Margins.Left = 2
475 | Margins.Top = 2
476 | Margins.Right = 2
477 | Margins.Bottom = 2
478 | Caption =
479 | 'Write a custom command (executable path + parameters): e.g. note' +
480 | 'pad.exe'
481 | Color = 2960685
482 | ParentColor = False
483 | end
484 | object edCommand: TButtonedEdit
485 | Left = 16
486 | Top = 46
487 | Width = 368
488 | Height = 19
489 | Color = clNone
490 | Ctl3D = False
491 | ParentCtl3D = False
492 | TabOrder = 0
493 | TextHint =
494 | 'You can also trigger hotkeys by prepending !, eg. !_control+_alt' +
495 | '+tab'
496 | OnChange = edCommandChange
497 | end
498 | object edParams: TButtonedEdit
499 | Left = 16
500 | Top = 88
501 | Width = 368
502 | Height = 19
503 | Color = clNone
504 | Ctl3D = False
505 | ParentCtl3D = False
506 | TabOrder = 1
507 | TextHint =
508 | 'You can also trigger hotkeys by prepending !, eg. !_control+_alt' +
509 | '+tab'
510 | OnChange = edParamsChange
511 | end
512 | end
513 | end
514 |
--------------------------------------------------------------------------------
/XCombobox.pas:
--------------------------------------------------------------------------------
1 | {
2 | XCheckbox, mimics the Windows 10's checkbox capable of
3 | adding over an aero glass form on Delphi
4 |
5 | Author: vhanla
6 |
7 | Changelog:
8 | TODO:
9 | Add touch support
10 | Add items support using maybe XPopupMenu
11 | - 16-08-05
12 | Change rendering text method for gdiplus to make it look better
13 | https://theartofdev.com/2014/03/02/blurryfuzzy-gdi-text-rendering-using-antialias-and-floating-point-y-coordinates/
14 | http://stackoverflow.com/questions/11307509/drawing-text-on-glass-background-becomes-blurred-as-alpha-is-lowered
15 |
16 | - 15-10-14
17 | Looks like Windows'
18 | Twetaked to use it as a label when disabled, temporary solution :P
19 | Fixed OnClick property in order to programmatically assign a function
20 | to handle it, just removed the extra read an write events
21 | }
22 | unit XCombobox;
23 |
24 | interface
25 |
26 | uses
27 | Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
28 | StdCtrls, PNGimage, functions, GDIPApi, GDIPobj;
29 |
30 | type
31 | TXCombobox = class(TGraphicControl)
32 | private
33 | _caption: string;
34 | _disabledColor: TColor;
35 | _enabledColor: TColor;
36 | _pressedColor: TColor;
37 | _chkstate: Boolean;
38 | _mousehover: Boolean;
39 | _mousepressed: Boolean;
40 | _enabled: Boolean;
41 |
42 | MDown: TMouseEvent;
43 | MUp: TMouseEvent;
44 | MLeave: TNotifyEvent;
45 | BtnClick: TNotifyEvent;
46 | FOnclick: TNotifyEvent;
47 | _font: TFont;
48 |
49 | procedure SetDisabledColor(Value: TColor);
50 | procedure SetEnabledColor(Value: TColor);
51 | procedure SetEnabled(Value: Boolean);
52 | procedure SetPressedColor(Value: TColor);
53 | procedure SetCaption(Value: string);
54 | procedure SetCheckState(Value: Boolean);
55 | procedure SetFont(Value: TFont);
56 |
57 | protected
58 | procedure Paint; override;
59 | procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
60 | procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
61 | procedure MouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
62 | procedure MouseEnter(var Message: TMessage); message CM_MOUSEENTER;
63 | procedure Click; override;
64 | procedure SetParent(Value: TWinControl); override;
65 | public
66 | constructor Create(AOwner: TComponent); override;
67 | destructor Destroy; override;
68 | published
69 | property Caption: string read _caption write SetCaption;
70 | property Color: TColor read _enabledColor write SetEnabledColor;
71 | property DisabledColor: TColor read _disabledColor write SetDisabledColor;
72 | property PressedColor: TColor read _pressedColor write SetPressedColor;
73 | property Checked: Boolean read _chkstate write SetCheckState;
74 |
75 | property OnMouseDown: TMouseEvent read MDown write MDown;
76 | property OnMouseUp: TMouseEvent read MUp write MUp;
77 | property OnMouseLeave: TNotifyEvent read MLeave write MLeave;
78 | property ShowHint;
79 | property ParentShowHint;
80 | property OnMouseMove;
81 | // property Font;
82 | property Font: TFont read _font write SetFont;
83 | property Enabled: Boolean read _enabled write SetEnabled;
84 | property OnClick; //: TNotifyEvent read FOnClick write FOnClick;
85 |
86 | end;
87 |
88 | procedure Register;
89 |
90 | implementation
91 |
92 | procedure Register;
93 | begin
94 | RegisterComponents('codigobit', [TXCombobox]);
95 | end;
96 |
97 | { TXCombobox }
98 |
99 | procedure TXCombobox.Click;
100 | begin
101 | inherited;
102 | // ShowMessage(inttostr(Width));
103 | // _chkstate := not _chkstate;
104 | //Paint;
105 | end;
106 |
107 | constructor TXCombobox.Create(AOwner: TComponent);
108 | begin
109 | inherited Create(AOwner);
110 | // Width := MulDiv(167, Screen.PixelsPerInch, 96); //win10
111 | Width := MulDiv(151, Screen.PixelsPerInch, 96);
112 | Height := MulDiv(31, Screen.PixelsPerInch, 96);
113 | _enabledcolor := clOlive;
114 | _disabledColor := clBlack;
115 | _enabled := True; // this will show as label if disabled
116 | _pressedColor := $666666;
117 | _mousehover := False;
118 | _mousepressed := False;
119 | Canvas.Brush.Color := clBlack;
120 | _font := TFont.Create;
121 | _font.Color := clWhite;
122 | _font.Size := 14; //12 win10
123 | FOnclick := nil;
124 | ShowHint := False;
125 | end;
126 |
127 | destructor TXCombobox.Destroy;
128 | begin
129 | _font.Free;
130 | inherited;
131 | end;
132 |
133 | procedure TXCombobox.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
134 | Y: Integer);
135 | begin
136 | inherited;
137 | _mousepressed := True;
138 | Paint;
139 | end;
140 |
141 | procedure TXCombobox.MouseEnter(var Message: TMessage);
142 | begin
143 | _mousehover := True;
144 | Paint;
145 | end;
146 |
147 | procedure TXCombobox.MouseLeave(var Message: TMessage);
148 | begin
149 | _mousehover := False;
150 | Paint;
151 | end;
152 |
153 | procedure TXCombobox.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
154 | Y: Integer);
155 | begin
156 | inherited;
157 | _mousepressed := False;
158 | Paint;
159 | end;
160 |
161 | procedure TXCombobox.Paint;
162 |
163 | function MakeGDIPColor(C: TColor; A: Integer = 255): Cardinal;
164 | var
165 | tmpRGB: TColorRef;
166 | begin
167 | tmpRGB := ColorToRGB(C);
168 | Result := ((DWORD(GetBValue(tmpRGB)) shl BlueShift) or
169 | (DWORD(GetGValue(tmpRGB)) shl GreenShift) or
170 | (DWORD(GetRValue(tmpRGB)) shl RedShift) or
171 | (DWORD(A) shl AlphaShift));
172 | end;
173 |
174 | function hidpi(value: Integer): Integer;
175 | begin
176 | Result := MulDiv(value, Screen.PixelsPerInch, 96);
177 | end;
178 |
179 | var
180 | bmp: TBitmap;
181 | xfont: TGPFont;
182 | style: Integer;
183 | graph: TGPGraphics;
184 | pen: TGPPen;
185 | brush: TGPSolidBrush;
186 | stringFormat: TGPStringFormat;
187 | l, t, w, h, d, s, radio: Integer;
188 | txt: WideString;
189 | DPI: Integer;
190 | ScaleFactor: Single;
191 | path: TGPGraphicsPath;
192 | begin
193 | inherited;
194 |
195 | DPI := Screen.PixelsPerInch;
196 | ScaleFactor := 1; //DPI / 96; // Assuming 96 DPI as the baseline
197 |
198 | radio := 42;
199 | d := radio div 2;
200 | s := d div 2; // guide for lines width
201 |
202 | bmp := TBitmap.Create;
203 | try
204 | bmp.PixelFormat := pf32bit;
205 | bmp.SetSize(Width, Height);
206 |
207 | // Clear the canvas with appropriate color
208 | if TaskbarAccented then
209 | bmp.Canvas.Brush.Handle := CreateSolidBrushWithAlpha(BlendColors(clBlack, GetAccentColor, 50), 200)
210 | else if SystemUsesLightTheme then
211 | bmp.Canvas.Brush.Handle := CreateSolidBrushWithAlpha($DDDDDD, 200)
212 | else
213 | begin
214 | if isWindows11 then
215 | bmp.Canvas.Brush.Handle := CreateSolidBrushWithAlpha(BlendColors($2d2d2d, clBlack,25), 200)
216 | else
217 | bmp.Canvas.Brush.Handle := CreateSolidBrushWithAlpha($222222, 200);
218 | end;
219 |
220 | bmp.Canvas.FillRect(Rect(0, 0, Width, Height));
221 |
222 | graph := TGPGraphics.Create(bmp.Canvas.Handle);
223 | try
224 | graph.SetSmoothingMode(SmoothingModeAntiAlias);
225 |
226 | l := 0; t := 0; w := Width - 1; h := Height - 1;
227 | style := FontStyleRegular;
228 |
229 | xfont := TGPFont.Create(_font.Name, hidpi(_font.Size), style, UnitPixel);
230 | try
231 | brush := TGPSolidBrush.Create(MakeGDIPColor(_disabledColor));
232 | try
233 | if SystemUsesLightTheme then
234 | pen := TGPPen.Create(MakeGDIPColor(clBlack, 100), 2 * ScaleFactor)
235 | else
236 | pen := TGPPen.Create(MakeGDIPColor(_disabledColor, 100), 2 * ScaleFactor);
237 |
238 | try
239 | if _enabled then
240 | begin
241 | if _mousepressed then
242 | begin
243 | if isWindows11 then
244 | begin
245 | end
246 | else // win10
247 | begin
248 | brush.SetColor(MakeGDIPColor(_pressedColor));
249 | graph.FillRectangle(brush, MakeRect(0, 0, Width - 1, Height - 1));
250 | brush.SetColor(MakeGDIPColor(_disabledColor));
251 | end;
252 | end
253 | else if _mousehover then
254 | begin
255 | if SystemUsesLightTheme then
256 | pen.SetColor(MakeGDIPColor($333333))
257 | else
258 | pen.SetColor(MakeGDIPColor(_disabledColor));
259 | end;
260 |
261 | //draw button
262 | d := HighDpi(8); //radio
263 |
264 | if isWindows11 then
265 | begin
266 | path := TGPGraphicsPath.Create();
267 | try
268 | path.AddArc(l + 1, t + 1, d, d, 180, 90);
269 | path.AddArc(l + w - d - 1, t + 1, d, d, 270, 90);
270 | path.AddArc(l + w - d - 1, t + h - 1 - d, d, d, 0, 90);
271 | path.AddArc(l + 1, t + h - d - 1, d, d, 90, 90);
272 | path.CloseFigure;
273 | if _mousepressed then
274 | brush.SetColor(MakeGDIPColor($303030))
275 | else
276 | begin
277 | if SystemUsesLightTheme then
278 | brush.SetColor(MakeGDIPColor($cccccc))
279 | else
280 | brush.SetColor($FF353535);
281 | end;
282 | graph.FillPath(brush, path);
283 | finally
284 | path.Free;
285 | end;
286 | path := TGPGraphicsPath.Create();
287 | try
288 | path.AddArc(l + 2, t + 2, d, d, 180, 90);
289 | path.AddArc(l + w - d - 2, t + 2, d, d, 270, 90);
290 | path.AddArc(l + w - d - 2, t + h - 2 - d, d, d, 0, 90);
291 | path.AddArc(l + 2, t + h - d - 2, d, d, 90, 90);
292 | path.CloseFigure;
293 | if _mousehover then
294 | begin
295 | if SystemUsesLightTheme then
296 | brush.SetColor($FFF5F5F5)
297 | else
298 | brush.SetColor($FF323232)
299 | end
300 | else
301 | if SystemUsesLightTheme then
302 | brush.SetColor($effbfbfb)
303 | else
304 | brush.SetColor($FF2D2D2D);
305 |
306 | if _mousepressed then
307 | begin
308 | if SystemUsesLightTheme then
309 | brush.SetColor($FFf5f5f5)
310 | else
311 | brush.SetColor($FF272727);
312 | end;
313 |
314 | graph.FillPath(brush, path);
315 | finally
316 | path.Free;
317 | end;
318 |
319 | end
320 | else //win10
321 | begin
322 | graph.DrawLine(pen, l, t, l + w, t);
323 | graph.DrawLine(pen, l, t, l, t + h);
324 | graph.DrawLine(pen, l, t + h, l + w, t + h);
325 | graph.DrawLine(pen, l + w, t, l + w, t + h);
326 | end;
327 |
328 | // Draw knob
329 | pen.SetWidth(1);
330 | if SystemUsesLightTheme then
331 | pen.SetColor($FF333333)
332 | else
333 | pen.SetColor(MakeGDIPColor(_disabledColor, 100));
334 | graph.DrawLine(pen, l + w - hidpi(22), t + hidpi(13), l + w - hidpi(22) + 6, t + hidpi(13) + 6);
335 | graph.DrawLine(pen, l + w - hidpi(22) + 6 + 1, t + hidpi(13) + 6, l + w - hidpi(22) + 6 + 1 + 6, t + hidpi(13));
336 | pen.SetWidth(2);
337 | end;
338 |
339 | // Draw the caption
340 | stringFormat := TGPStringFormat.Create;
341 | try
342 | stringFormat.SetAlignment(StringAlignmentNear);
343 | stringFormat.SetLineAlignment(StringAlignmentCenter);
344 | stringFormat.SetTrimming(StringTrimmingEllipsisCharacter);
345 | stringFormat.SetFormatFlags(StringFormatFlagsNoWrap);
346 |
347 | brush.SetColor(MakeGDIPColor($BBBBBB));
348 | graph.SetTextRenderingHint(TextRenderingHintAntiAliasGridFit);
349 | txt := _caption;
350 | graph.DrawString(txt, Length(txt), xfont, MakePoint(15.0 * ScaleFactor, (Height / 2 - hidpi(_font.Size)) * ScaleFactor + hidpi(_font.size div 3)), nil, brush);
351 |
352 | graph.SetTextRenderingHint(TextRenderingHintSingleBitPerPixelGridFit);
353 | if SystemUsesLightTheme then
354 | brush.SetColor(MakeGDIPColor($333333))
355 | else
356 | brush.SetColor(MakeGDIPColor($FFFFFF));
357 |
358 | if SystemUsesLightTheme then
359 | graph.DrawString(txt, Length(txt), xfont, MakePoint(15.0 * ScaleFactor, (Height / 2 - _font.Size) * ScaleFactor), nil, brush);
360 | finally
361 | stringFormat.Free;
362 | end;
363 | finally
364 | pen.Free;
365 | end;
366 | finally
367 | brush.Free;
368 | end;
369 | finally
370 | xfont.Free;
371 | end;
372 | finally
373 | graph.Free;
374 | end;
375 |
376 | Canvas.Draw(0, 0, bmp);
377 | finally
378 | bmp.Free;
379 | end;
380 | end;
381 |
382 |
383 | procedure TXCombobox.SetCaption(Value: string);
384 | begin
385 | _caption := Value;
386 | Paint;
387 | end;
388 |
389 | procedure TXCombobox.SetCheckState(Value: Boolean);
390 | begin
391 | _chkstate := Value;
392 | Paint;
393 | end;
394 |
395 | procedure TXCombobox.SetDisabledColor(Value: TColor);
396 | begin
397 | _disabledColor := Value;
398 | Paint;
399 | end;
400 |
401 | procedure TXCombobox.SetEnabled(Value: Boolean);
402 | begin
403 | _enabled := Value;
404 | Paint;
405 | end;
406 |
407 | procedure TXCombobox.SetEnabledColor(Value: TColor);
408 | begin
409 | _enabledColor := Value;
410 | Paint;
411 | end;
412 |
413 | procedure TXCombobox.SetFont(Value: TFont);
414 | begin
415 | _font.Assign(Value);
416 | Invalidate;
417 | end;
418 |
419 | procedure TXCombobox.SetParent(Value: TWinControl);
420 | begin
421 | inherited;
422 | if Value <> nil then _caption := Name;
423 |
424 | end;
425 |
426 | procedure TXCombobox.SetPressedColor(Value: TColor);
427 | begin
428 | _pressedColor := Value;
429 | Paint;
430 | end;
431 |
432 | end.
433 |
434 |
--------------------------------------------------------------------------------
/XCheckbox.pas:
--------------------------------------------------------------------------------
1 | {
2 | XCheckbox, mimics the Windows 10's checkbox capable of
3 | adding over an aero glass form on Delphi
4 |
5 | Author: vhanla
6 |
7 | Changelog:
8 | TODO:
9 | Add animation, and mouse drag
10 | Add touch support
11 | - 24-07-02
12 | Add TCustomLabel as optional companion
13 | (!weird that adding TLabel was detected by Kaspersky as not-a-virus:HEUR:AdWare.Win32.Generic)
14 | - 24-07-01
15 | Fix click event rushing to mouseup for bad checkstate setting
16 | - 24-06-11
17 | Fix HighDpi support to draw radius correctly
18 | Add Windows 11 style
19 | - 17-06-02
20 | Fixed vertical disabled line on HiDpi 125% or more
21 | Fixed knob ellipse relative to height ratio
22 | - 15-10-14
23 | Works as expected
24 | Added functions.pas to use custom alpha brush to draw, but it looks ugly,... butttt now is
25 | FIXED using GDIPlus mixing with custom brush to set transparency hack
26 | }
27 | unit XCheckbox;
28 |
29 | interface
30 |
31 | uses
32 | Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
33 | StdCtrls, PNGimage, functions, GDIPApi, GDIPobj, Types;
34 |
35 | type
36 | TLabelPosition = (lpLeft, lpRight);
37 |
38 | TXCheckBoxLabel = class(TCustomLabel)
39 | published
40 | property Caption;
41 | property Font;
42 | end;
43 |
44 | TXCheckbox = class(TGraphicControl)
45 | private
46 | FCaption : string;
47 | FDisabledColor: TColor;
48 | FEnabledColor: TColor;
49 | FPressedColor: TColor;
50 | FChecked: Boolean;
51 | FMouseHover: Boolean;
52 | FMousePressed: Boolean;
53 |
54 | FOnMouseDown: TMouseEvent;
55 | FOnMouseUp: TMouseEvent;
56 | FOnMouseLeave: TNotifyEvent;
57 | FOnClick: TNotifyEvent;
58 |
59 | FLabel: TXCheckBoxLabel;
60 | FLabeled: Boolean;
61 | FLabelPosition: TLabelPosition;
62 | FLabelSpacing: Integer;
63 | FParentColor: TColor;
64 |
65 | procedure SetDisabledColor(Value: TColor);
66 | procedure SetEnabledColor(Value: TColor);
67 | procedure SetPressedColor(Value: TColor);
68 | procedure SetCaption(Value: string);
69 | procedure SetChecked(Value: Boolean);
70 |
71 | procedure SetLabeled(Value: Boolean);
72 | procedure SetLabelPosition(Value: TLabelPosition);
73 | procedure SetLabelSpacing(Value: Integer);
74 | procedure UpdateLabelPosition;
75 | protected
76 | procedure Paint; override;
77 | procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X,Y: Integer); override;
78 | procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X,Y: Integer); override;
79 | procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
80 | procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
81 | procedure Click; override;
82 | procedure SetParent(Value: TWinControl); override;
83 | procedure Resize; override;
84 |
85 | procedure Notification(AComponent: TComponent; Operation: TOperation); override;
86 | procedure RepaintLabel;
87 | public
88 | constructor Create(AOwner: TComponent); override;
89 | destructor Destroy; override;
90 | published
91 | property Caption: string read FCaption write SetCaption;
92 | property Color: TColor read FEnabledColor write SetEnabledColor;
93 | property DisabledColor: TColor read FDisabledColor write SetDisabledColor;
94 | property PressedColor: TColor read FPressedColor write SetPressedColor;
95 | property Checked: Boolean read FChecked write SetChecked;
96 |
97 | property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
98 | property OnMouseUp: TMouseEvent read FOnMouseUp write FOnMouseUp;
99 | property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
100 | property OnClick: TNotifyEvent read FOnClick write FOnClick;
101 | property ShowHint;
102 | property ParentShowHint;
103 | property OnMouseMove;
104 | property Font;
105 | property Enabled;
106 | property ParentColor default False;
107 |
108 | property Labeled: Boolean read FLabeled write SetLabeled default False;
109 | property LabelPosition: TLabelPosition read FLabelPosition write SetLabelPosition default lpLeft;
110 | property LabelSpacing: Integer read FLabelSpacing write SetLabelSpacing default 3;
111 | end;
112 |
113 | procedure Register;
114 |
115 | implementation
116 |
117 | uses
118 | Math;
119 |
120 | procedure Register;
121 | begin
122 | RegisterComponents('codigobit', [TXCheckbox]);
123 | end;
124 |
125 | { Helper Functions }
126 | function DimColor(Color: TColor; DimLevel: Byte): TColor;
127 | var
128 | R, G, B: Byte;
129 | begin
130 | // Extract the red, green, and blue components from the TColor
131 | R := GetRValue(Color);
132 | G := GetGValue(Color);
133 | B := GetBValue(Color);
134 |
135 | // Reduce the brightness of each component by the DimLevel
136 | R := Max(0, R - DimLevel);
137 | G := Max(0, G - DimLevel);
138 | B := Max(0, B - DimLevel);
139 |
140 | // Combine the dimmed components back into a TColor
141 | Result := RGB(R, G, B);
142 | end;
143 |
144 |
145 | { TXCheckbox }
146 |
147 | procedure TXCheckbox.Click;
148 | begin
149 | if Assigned(FOnClick) then
150 | FOnClick(Self);
151 |
152 | end;
153 |
154 | constructor TXCheckbox.Create(AOwner: TComponent);
155 | begin
156 | inherited Create(AOwner);
157 | Width := HighDpi(44);
158 | Height := HighDpi(20);
159 | FEnabledColor := clOlive;
160 | FDisabledColor := clBlack;
161 | FPressedColor := $666666;
162 | FMouseHover := False;
163 | FMousePressed := False;
164 | Canvas.Brush.Color := clBlack;
165 | Font.Name := 'Segoe UI';
166 | Font.Size := 10;
167 | Font.Style := [];
168 | ShowHint := False;
169 | ParentColor := False;
170 |
171 | FLabeled := False;
172 | FLabelPosition := lpLeft;
173 | FLabelSpacing := 3;
174 | end;
175 |
176 | destructor TXCheckbox.Destroy;
177 | begin
178 | if Assigned(FLabel) then
179 | FLabel.Free;
180 |
181 | inherited;
182 | end;
183 |
184 | procedure TXCheckbox.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
185 | Y: Integer);
186 | begin
187 | inherited;
188 | FMousePressed := True;
189 | if Assigned(FOnMouseDown) then
190 | FOnMouseDown(Self, Button, Shift, X, Y);
191 | Invalidate;
192 | end;
193 |
194 | procedure TXCheckbox.CMMouseEnter(var Message: TMessage);
195 | begin
196 | inherited;
197 | FMouseHover := True;
198 | Invalidate;
199 | end;
200 |
201 | procedure TXCheckbox.CMMouseLeave(var Message: TMessage);
202 | begin
203 | inherited;
204 | FMouseHover := False;
205 | FMousePressed := False;
206 | if Assigned(FOnMouseLeave) then
207 | FOnMouseLeave(Self);
208 | Invalidate;
209 | end;
210 |
211 | procedure TXCheckbox.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
212 | Y: Integer);
213 | var
214 | MousePos: TPoint;
215 | begin
216 | inherited;
217 | FMousePressed := False;
218 |
219 | if (PtInRect(ClientRect, Point(X, Y))) and (Button = mbLeft) then
220 | begin
221 | SetChecked(not FChecked);
222 | if Assigned(FLabel) then
223 | if Checked then
224 | FLabel.Font.Color := Font.Color
225 | else
226 | FLabel.Font.Color := FDisabledColor;
227 | Click;
228 | end;
229 |
230 | if Assigned(FOnMouseUp) then
231 | FOnMouseUp(Self, Button, Shift, X, Y);
232 | Invalidate;
233 | end;
234 |
235 | procedure TXCheckbox.Notification(AComponent: TComponent;
236 | Operation: TOperation);
237 | begin
238 | inherited;
239 | if (Operation = opRemove) and (AComponent = FLabel) then
240 | FLabel := nil;
241 | end;
242 |
243 | procedure TXCheckbox.Paint;
244 | function MakeGDIPColor(C: TColor; A: Integer = 255): Cardinal;
245 | var
246 | tmpRGB : TColorRef;
247 | begin
248 | tmpRGB := ColorToRGB(C);
249 | result := ((DWORD(GetBValue(tmpRGB)) shl BlueShift) or
250 | (DWORD(GetGValue(tmpRGB)) shl GreenShift) or
251 | (DWORD(GetRValue(tmpRGB)) shl RedShift) or
252 | (DWORD(A) shl AlphaShift));
253 | end;
254 |
255 | var
256 | bmp: TBitmap;
257 | path: TGPGraphicsPath;
258 | graph: TGPGraphics;
259 | pen: TGPPen;
260 | brush: TGPSolidBrush;
261 | l,t,w,h,d,s,radio: integer;
262 | begin
263 | inherited;
264 |
265 | radio := HighDpi(42);
266 | d := radio div 2;
267 | s := d div 2; // guide for lines width
268 |
269 | bmp := TBitmap.Create;
270 | try
271 | bmp.PixelFormat := pf32bit;
272 | bmp.SetSize(Width, Height);
273 | // let's clear the canvas with the color that is used as translucent in our aero
274 | // it needs some tweaks though
275 | if TaskbarAccented then
276 | bmp.Canvas.Brush.Handle := CreateSolidBrushWithAlpha(BlendColors(clBlack,GetAccentColor,50),200)
277 | else
278 | begin
279 | if SystemUsesLightTheme then
280 | bmp.Canvas.Brush.Handle := CreateSolidBrushWithAlpha($dddddd,200)
281 | else
282 | begin
283 | if ParentColor then
284 | bmp.Canvas.Brush.Handle := CreateSolidBrushWithAlpha(FParentColor,255)
285 | else
286 | begin
287 | if isWindows11 then
288 | bmp.Canvas.Brush.Handle := CreateSolidBrushWithAlpha(BlendColors($2d2d2d, clBlack,25), 200)
289 | else
290 | bmp.Canvas.Brush.Handle := CreateSolidBrushWithAlpha($222222,200);
291 | end;
292 | end;
293 | end;
294 | bmp.Canvas.FillRect(Rect(0,0,Width,Height));
295 |
296 | graph := TGPGraphics.Create(bmp.Canvas.Handle);
297 | try
298 | graph.SetSmoothingMode(SmoothingModeAntiAlias);
299 |
300 | l := 0; t := 0; w := Width-1; h := Height-1;
301 | path := TGPGraphicsPath.Create();
302 | try
303 | path.AddArc(l,t,d,d,180,90);
304 | path.AddArc(l+w-d,t,d,d,270,90);
305 | path.AddArc(l+w-d,t+h-d,d,d,0,90);
306 | path.AddArc(l,t+h-d,d,d,90,90);
307 | path.CloseFigure;
308 |
309 | // let's draw
310 | brush := TGPSolidBrush.Create(MakeGDIPColor(FDisabledColor));//any color for now
311 | try
312 | if not Enabled then
313 | pen := TGPPen.Create(MakeGDIPColor(DimColor(FDisabledColor, 30)))
314 | else
315 | pen := TGPPen.Create(MakeGDIPColor(FDisabledColor),2); // any color for now
316 | try
317 | if FChecked then
318 | begin
319 | if FMouseHover then
320 | brush.SetColor(MakeGDIPColor(BlendColors(clWhite, FEnabledColor,20)))
321 | else
322 | brush.SetColor(MakeGDIPColor(FEnabledColor));
323 | if FMousePressed then
324 | brush.SetColor(MakeGDIPColor(FPressedColor));
325 | graph.FillPath(brush, path );
326 | brush.SetColor(MakeGDIPColor(clWhite));
327 |
328 | graph.FillEllipse(brush,MakeRect(Width-5-(h-10)-1,5,h-10,h-10));//white circle
329 | end
330 | else
331 | begin
332 | if FMousePressed then
333 | begin
334 | brush.SetColor(MakeGDIPColor(FPressedColor));
335 | graph.FillPath(brush, path );
336 | brush.SetColor(MakeGDIPColor(FDisabledColor));
337 | end
338 | else
339 | begin
340 | if not Enabled then
341 | brush.SetColor(MakeGDIPColor(DimColor(FDisabledColor, 30)));
342 |
343 |
344 | graph.DrawArc(pen,l+1,t+1,d-2,d-2,180,90);
345 | graph.DrawLine(pen,l+s,t+1,l+w-s,t+1);
346 | graph.DrawArc(pen,l+w-d+1,t+1,d-2,d-2,270,90);
347 | graph.DrawLine(pen,l+w-1,t+s, l+w-1, t+h-s);
348 | graph.DrawArc(pen,l+w-d+1,t+h-d+1,d-2,d-2,0,90);
349 | graph.DrawArc(pen,l+1,t+h-d+1,d-2,d-2,90,90);
350 | graph.DrawLine(pen,l+s,t+h-1,l+w-s,t+h-1);
351 | graph.DrawLine(pen,l+1,t+s, l+1, t+h-s);
352 | end;
353 |
354 | graph.FillEllipse(brush,MakeRect(5,5,h-10,h-10));
355 | end;
356 | finally
357 | pen.Free;
358 | end;
359 | finally
360 | brush.Free;
361 | end;
362 | finally
363 | path.Free;
364 | end;
365 | //
366 | if FCaption <> '' then
367 | begin
368 | end;
369 |
370 | finally
371 | graph.Free;
372 | end;
373 | canvas.Draw(0,0,bmp);
374 | finally
375 | bmp.Free;
376 | end;
377 |
378 | if not (FLabeled and Assigned(FLabel)) then
379 | begin
380 | end;
381 | end;
382 |
383 | procedure TXCheckbox.RepaintLabel;
384 | begin
385 | if Assigned(FLabel) then
386 | begin
387 | if Enabled then
388 | FLabel.Font.Color := Font.Color
389 | else
390 | FLabel.Font.Color := FDisabledColor;
391 | if not Checked then
392 | FLabel.Font.Color := FDisabledColor;
393 |
394 | FLabel.Repaint;
395 |
396 | end;
397 | end;
398 |
399 | procedure TXCheckbox.Resize;
400 | begin
401 | inherited;
402 | Invalidate;
403 | end;
404 |
405 | procedure TXCheckbox.SetCaption(Value: string);
406 | begin
407 | if FCaption <> Value then
408 | begin
409 | FCaption := Value;
410 | if Assigned(FLabel) then
411 | FLabel.Caption := Value;
412 |
413 | Invalidate;
414 | RepaintLabel;
415 | end;
416 | end;
417 |
418 | procedure TXCheckbox.SetChecked(Value: Boolean);
419 | begin
420 | if FChecked <> Value then
421 | begin
422 | FChecked := Value;
423 | Invalidate;
424 | RepaintLabel;
425 | end;
426 | end;
427 |
428 | procedure TXCheckbox.SetDisabledColor(Value: TColor);
429 | begin
430 | if FDisabledColor <> Value then
431 | begin
432 | FDisabledColor := Value;
433 | Invalidate;
434 | end;
435 | end;
436 |
437 | procedure TXCheckbox.SetEnabledColor(Value: TColor);
438 | begin
439 | if FEnabledColor <> Value then
440 | begin
441 | FEnabledColor := Value;
442 | Invalidate;
443 | RepaintLabel;
444 | end;
445 | end;
446 |
447 | procedure TXCheckbox.SetLabeled(Value: Boolean);
448 | begin
449 | if FLabeled <> Value then
450 | begin
451 | FLabeled := Value;
452 | if FLabeled then
453 | begin
454 | if not Assigned(FLabel) then
455 | begin
456 | FLabel := TXCheckBoxLabel.Create(Self);
457 | FLabel.Font := Font;
458 | if Checked then
459 | FLabel.Font.Color := Font.Color
460 | else
461 | FLabel.Font.Color := FDisabledColor;
462 | FLabel.Parent := Parent;
463 | FLabel.FreeNotification(Self);
464 | end;
465 | FLabel.Caption := FCaption;
466 | UpdateLabelPosition;
467 | end
468 | else if Assigned(FLabel) then
469 | begin
470 | FLabel.Free;
471 | FLabel := nil;
472 | end;
473 | end;
474 | end;
475 |
476 | procedure TXCheckbox.SetLabelPosition(Value: TLabelPosition);
477 | begin
478 | if FLabelPosition <> Value then
479 | begin
480 | FLabelPosition := Value;
481 | UpdateLabelPosition;
482 | end;
483 |
484 | end;
485 |
486 | procedure TXCheckbox.SetLabelSpacing(Value: Integer);
487 | begin
488 | if FLabelSpacing <> Value then
489 | begin
490 | FLabelSpacing := Value;
491 | UpdateLabelPosition;
492 | end;
493 |
494 | end;
495 |
496 | procedure TXCheckbox.SetParent(Value: TWinControl);
497 | var
498 | ParentControl: TWinControl;
499 | begin
500 | inherited;
501 | if (Value <> nil) and (FCaption = '') then
502 | FCaption := Name;
503 | if Assigned(FLabel) then
504 | FLabel.Parent := Value;
505 | RepaintLabel;
506 |
507 | // Let's get the parent color
508 | ParentControl := Value;
509 | while Assigned(ParentControl) do
510 | begin
511 | if ParentControl is TCustomForm then
512 | begin
513 | FParentColor := TCustomForm(ParentControl).Color;
514 | break;
515 | end;
516 | ParentControl := ParentControl.Parent;
517 | end;
518 | end;
519 |
520 | procedure TXCheckbox.SetPressedColor(Value: TColor);
521 | begin
522 | if FPressedColor <> Value then
523 | begin
524 | FPressedColor := Value;
525 | Invalidate;
526 | RepaintLabel;
527 | end;
528 | end;
529 |
530 |
531 | procedure TXCheckbox.UpdateLabelPosition;
532 | begin
533 | if Assigned(FLabel) then
534 | begin
535 | case FLabelPosition of
536 | lpLeft:
537 | begin
538 | FLabel.Left := Left - FLabel.Width - FLabelSpacing;
539 | FLabel.Top := Top + (Height - FLabel.Height) div 2;
540 | end;
541 | lpRight:
542 | begin
543 | FLabel.Left := Left + Width + FLabelSpacing;
544 | FLabel.Top := Top + (Height - FLabel.Height) div 2;
545 | end;
546 | end;
547 | RepaintLabel;
548 | end;
549 | end;
550 |
551 |
552 | end.
553 |
554 |
--------------------------------------------------------------------------------
/frmAdvanced.pas:
--------------------------------------------------------------------------------
1 | unit frmAdvanced;
2 |
3 | interface
4 |
5 | uses
6 | Windows, Messages, SysUtils, Variants, Classes, Graphics,
7 | Controls, Forms, Dialogs, StdCtrls, Spin,
8 | ExtCtrls, ShellApi, IniFiles, ComCtrls, Buttons, Menus, rkSmartTabs, XCheckbox,
9 | Tabs, attabs;
10 |
11 | const
12 | VERSION = '1.3';
13 |
14 | type
15 |
16 | { TBitBtn = class(Buttons.TBitBtn)
17 | private
18 | procedure CNDrawItem(var Msg: TWMDrawItem); message CN_DRAWITEM;
19 | procedure CNFocusChanged(var Msg: TMessage); message CM_FOCUSCHANGED;
20 | protected
21 | procedure DrawButton(const DrawItemStruct: TDrawItemStruct); virtual;
22 | end;}
23 |
24 | TfrmAdvSettings = class(TForm)
25 | Label2: TLabel;
26 | Label3: TLabel;
27 | Label4: TLabel;
28 | Label1: TLabel;
29 | Label5: TLabel;
30 | edCommand: TButtonedEdit;
31 | edParams: TButtonedEdit;
32 | cbValDelayGlobal: TComboBox;
33 | btnCancel: TButton;
34 | btnOK: TButton;
35 | chkDelayGlobal: TXCheckbox;
36 | ATTabs1: TATTabs;
37 | chkShowCount: TXCheckbox;
38 | chkFullScreen: TXCheckbox;
39 | chkDelayTopLeft: TXCheckbox;
40 | chkDelayBotLeft: TXCheckbox;
41 | chkDelayTopRight: TXCheckbox;
42 | chkDelayBotRight: TXCheckbox;
43 | chkCustom: TXCheckbox;
44 | chkHidden: TXCheckbox;
45 | Panel1: TPanel;
46 | Panel2: TPanel;
47 | cbValDelayTopLeft: TComboBox;
48 | cbValDelayBotLeft: TComboBox;
49 | cbValDelayTopRight: TComboBox;
50 | cbValDelayBotRight: TComboBox;
51 | procedure FormCreate(Sender: TObject);
52 | procedure Label4Click(Sender: TObject);
53 | procedure chkDelayGlobalClick(Sender: TObject);
54 | procedure Label5Click(Sender: TObject);
55 | procedure chkFullScreenClick(Sender: TObject);
56 | procedure FormShow(Sender: TObject);
57 | procedure edCommandChange(Sender: TObject);
58 | procedure edParamsChange(Sender: TObject);
59 | procedure chkHiddenClick(Sender: TObject);
60 | procedure FormDestroy(Sender: TObject);
61 | procedure rkSmartTabs1TabChange(Sender: TObject);
62 | procedure btnCancelClick(Sender: TObject);
63 | procedure btnOKClick(Sender: TObject);
64 | procedure ATTabs1TabClick(Sender: TObject);
65 | procedure chkDelayTopLeftClick(Sender: TObject);
66 | procedure chkDelayTopRightClick(Sender: TObject);
67 | procedure chkDelayBotLeftClick(Sender: TObject);
68 | procedure chkDelayBotRightClick(Sender: TObject);
69 |
70 | protected
71 | FBitmap: TBitmap;
72 | FBrush: HBRUSH;
73 | procedure WndProc(var Msg: TMessage); override;
74 | private
75 | { Private declarations }
76 | FCurTab: Integer;
77 | procedure Temp2Cmd; // dump changes to official
78 | procedure Cmd2Temp; // restore from temp to official cmd
79 | public
80 | { Public declarations }
81 | procedure SaveAdvancedIni;
82 | procedure ReadAdvancedIni;
83 | procedure ToggleEachCornersDelay(Enable: Boolean);
84 | end;
85 |
86 | var
87 | frmAdvSettings: TfrmAdvSettings;
88 | cmdcli: array [0..3] of string;
89 | cmdarg: array [0..3] of string;
90 | cmdhid: array [0..3] of boolean;
91 | tmpcmdcli: array [0..3] of string;
92 | tmpcmdarg: array [0..3] of string;
93 | tmpcmdhid: array [0..3] of boolean;
94 |
95 |
96 | implementation
97 |
98 | {$R *.dfm}
99 |
100 | uses frmSettings, main, functions, conditionshelper;
101 |
102 | function SetWindowTheme(hwnd: HWND; pszSubAppName: LPCWSTR; pszSubIdList: LPCWSTR): HRESULT; stdcall;
103 | external 'uxtheme.dll';
104 |
105 | procedure TfrmAdvSettings.ATTabs1TabClick(Sender: TObject);
106 | begin
107 | FCurTab := ATTabs1.TabIndex;
108 | // caption := inttostr(curTab);
109 | edCommand.Text := tmpcmdcli[FCurTab];
110 | edParams.Text := tmpcmdarg[FCurTab];
111 | chkHidden.Checked := tmpcmdhid[FCurTab];
112 | end;
113 |
114 | procedure TfrmAdvSettings.btnCancelClick(Sender: TObject);
115 | begin
116 | ReadAdvancedIni;
117 | close
118 | end;
119 |
120 | procedure TfrmAdvSettings.btnOKClick(Sender: TObject);
121 | begin
122 | SaveAdvancedIni;
123 | Close
124 | end;
125 |
126 | procedure TfrmAdvSettings.chkDelayBotLeftClick(Sender: TObject);
127 | begin
128 | cbValDelayBotLeft.Enabled := chkDelayBotLeft.Checked;
129 | end;
130 |
131 | procedure TfrmAdvSettings.chkDelayBotRightClick(Sender: TObject);
132 | begin
133 | cbValDelayBotRight.Enabled := chkDelayBotRight.Checked;
134 | end;
135 |
136 | procedure TfrmAdvSettings.chkDelayGlobalClick(Sender: TObject);
137 | begin
138 | if chkDelayGlobal.Checked then
139 | begin
140 | cbValDelayGlobal.Enabled := True;
141 | ToggleEachCornersDelay(False);
142 | end
143 | else
144 | begin
145 | cbValDelayGlobal.Enabled := False;
146 | ToggleEachCornersDelay(True);
147 | end;
148 |
149 | end;
150 |
151 | procedure TfrmAdvSettings.chkDelayTopLeftClick(Sender: TObject);
152 | begin
153 | cbValDelayTopLeft.Enabled := chkDelayTopLeft.Checked;
154 | end;
155 |
156 | procedure TfrmAdvSettings.chkDelayTopRightClick(Sender: TObject);
157 | begin
158 | cbValDelayTopRight.Enabled := chkDelayTopRight.Checked;
159 | end;
160 |
161 | procedure TfrmAdvSettings.chkFullScreenClick(Sender: TObject);
162 | begin
163 | frmMain.tmFullScreen.Checked := chkFullScreen.Checked;
164 | end;
165 |
166 | procedure TfrmAdvSettings.chkHiddenClick(Sender: TObject);
167 | begin
168 | if Sender is TXCheckBox then
169 | tmpcmdhid[FCurTab] := chkHidden.Checked;
170 | end;
171 |
172 | procedure TfrmAdvSettings.Cmd2Temp;
173 | var
174 | I : Integer;
175 | begin
176 | for I := 0 to 3 do
177 | begin
178 | tmpcmdcli[I] := cmdcli[I];
179 | tmpcmdarg[I] := cmdarg[I];
180 | tmpcmdhid[I] := cmdhid[I];
181 | end;
182 | end;
183 |
184 |
185 | procedure TfrmAdvSettings.edCommandChange(Sender: TObject);
186 | begin
187 | if Sender is TButtonedEdit then
188 | tmpcmdcli[FCurTab] := edCommand.Text;
189 | end;
190 |
191 | procedure TfrmAdvSettings.edParamsChange(Sender: TObject);
192 | begin
193 | if Sender is TButtonedEdit then
194 | tmpcmdarg[FCurTab] := edParams.Text;
195 | end;
196 |
197 |
198 | procedure TfrmAdvSettings.FormCreate(Sender: TObject);
199 | begin
200 |
201 | FCurTab := 0;
202 | FBitmap := TBitmap.Create;
203 | FBitmap.SetSize(64,64);
204 | FBitmap.PixelFormat := pf24bit;
205 | FBitmap.Canvas.Brush.Style := bsSolid;
206 | FBitmap.Canvas.Brush.Color := $2d2d2d;
207 | FBitmap.Canvas.FillRect(ClientRect);
208 | // FBitmap.LoadFromFile('T:\Program Files (x86)\Caphyon\Advanced Installer 21.0.1\themes\surface\resources\variations\metropurple\background.bmp');
209 | FBrush := 0;
210 | FBrush := CreatePatternBrush(FBitmap.Handle);
211 | // if not SystemUsesLightTheme then
212 | // begin
213 | // AllowDarkModeForWindow(Handle, True);
214 | // AllowDarkModeForApp(True);
215 | // SetPreferredAppMode(1);
216 | // DarkMode;
217 | // end;
218 |
219 | FormStyle := fsStayOnTop;
220 | BorderStyle := bsSingle;
221 | BorderIcons := [biSystemMenu, biMinimize];
222 | Position := poScreenCenter;
223 | cbValDelayGlobal.Enabled := False;
224 | ReadAdvancedIni;
225 | UseImmersiveDarkMode(Handle, True);
226 | // EnableNCShadow(Handle);
227 | // setwindowtheme(Edit1.Handle, 'CFD', nil);
228 | // AllowDarkModeForWindow(Edit1.Handle, True);
229 | // sendmessagew(Edit1.Handle, WM_THEMECHANGED, 0, 0);
230 |
231 | setwindowtheme(cbValDelayGlobal.Handle, 'CFD', nil);
232 | AllowDarkModeForWindow(cbValDelayGlobal.Handle, True);
233 | sendmessagew(cbValDelayGlobal.Handle, WM_THEMECHANGED, 0, 0);
234 |
235 | setwindowtheme(cbValDelayTopLeft.Handle, 'CFD', nil);
236 | AllowDarkModeForWindow(cbValDelayTopLeft.Handle, True);
237 | sendmessagew(cbValDelayTopLeft.Handle, WM_THEMECHANGED, 0, 0);
238 |
239 | setwindowtheme(cbValDelayTopRight.Handle, 'CFD', nil);
240 | AllowDarkModeForWindow(cbValDelayTopRight.Handle, True);
241 | sendmessagew(cbValDelayTopRight.Handle, WM_THEMECHANGED, 0, 0);
242 |
243 | setwindowtheme(cbValDelayBotLeft.Handle, 'CFD', nil);
244 | AllowDarkModeForWindow(cbValDelayBotLeft.Handle, True);
245 | sendmessagew(cbValDelayBotLeft.Handle, WM_THEMECHANGED, 0, 0);
246 |
247 | setwindowtheme(cbValDelayBotRight.Handle, 'CFD', nil);
248 | AllowDarkModeForWindow(cbValDelayBotRight.Handle, True);
249 | sendmessagew(cbValDelayBotRight.Handle, WM_THEMECHANGED, 0, 0);
250 |
251 |
252 | // setwindowtheme(ComboBox2.Handle, 'CFD', nil);
253 | // AllowDarkModeForWindow(ComboBox2.Handle, True);
254 | // sendmessagew(ComboBox2.Handle, WM_THEMECHANGED, 0, 0);
255 |
256 |
257 | setwindowtheme(btnOK.Handle, 'Explorer', nil);
258 | AllowDarkModeForWindow(btnOK.Handle, True);
259 | sendmessagew(btnOK.Handle, WM_THEMECHANGED, 0, 0);
260 |
261 | setwindowtheme(btnCancel.Handle, 'Explorer', nil);
262 | AllowDarkModeForWindow(btnCancel.Handle, True);
263 | sendmessagew(btnCancel.Handle, WM_THEMECHANGED, 0, 0);
264 |
265 |
266 | end;
267 |
268 | procedure TfrmAdvSettings.FormDestroy(Sender: TObject);
269 | begin
270 | FBitmap.Free;
271 | end;
272 |
273 | procedure TfrmAdvSettings.FormShow(Sender: TObject);
274 | begin
275 | // if SystemUsesLightTheme then
276 | // begin
277 | // Color := clWhite;
278 | // AllowDarkModeForWindow(Handle, False);
279 | // AllowDarkModeForApp(False);
280 | // SetPreferredAppMode(0);
281 | // DarkMode;
282 | // UseImmersiveDarkMode(Handle, False);
283 | // end
284 | // else
285 | // begin
286 | // Color := $999999;
287 | // AllowDarkModeForWindow(Handle, True);
288 | // AllowDarkModeForApp(True);
289 | // SetPreferredAppMode(1);
290 | // DarkMode;
291 | // UseImmersiveDarkMode(Handle, True);
292 | // end;
293 |
294 | end;
295 |
296 | procedure TfrmAdvSettings.Label4Click(Sender: TObject);
297 | begin
298 | ShellExecute(Handle, 'OPEN', 'http://apps.codigobit.info/p/support.html','','',SW_SHOWNORMAL);
299 | end;
300 |
301 | procedure TfrmAdvSettings.Label5Click(Sender: TObject);
302 | var
303 | // jValue: TJSonValue;
304 | rversion: String;
305 | begin
306 | ShellExecute(0, 'OPEN', PChar('https://github.com/vhanla/winxcorners/releases'), nil, nil, SW_SHOWNORMAL);
307 | // ShowMessage(IntToStr(Windows.GetWindowTextLength(GetForegroundWindow)));
308 | { RESTClient1.BaseURL := 'https://updates.codigobit.net/app/winxcorners';
309 | RESTRequest1.Execute;
310 | try
311 | jValue := RESTResponse1.JSONValue;
312 | if Assigned(jValue) then
313 | begin
314 | rversion := jValue.GetValue('latestversion', '1.2');
315 | if rversion = VERSION then
316 | MessageDlg('You have the latest version.', mtInformation, [mbOK],0)
317 | else
318 | MessageDlg('', mtInformation, [mbOK],0);
319 | end
320 | else
321 | MessageDlg('Couldn''t retrieve info. Please visit official page.', mtError, [mbOK],0);
322 | except
323 | MessageDlg('Error', mtInformation, [mbOK],0);
324 | end;}
325 | end;
326 |
327 | procedure TfrmAdvSettings.ReadAdvancedIni;
328 | var
329 | ini: TIniFile;
330 | begin
331 | ini := TIniFile.Create(ExtractFilePath(ParamStr(0))+'settings.ini');
332 | try
333 | chkDelayGlobal.Checked := ini.ReadBool('Advanced','GlobalDelay',False);
334 | cbValDelayGlobal.ItemIndex := ini.ReadInteger('Advanced','GlobalDelayVal', 3);
335 |
336 | chkDelayTopLeft.Checked := ini.ReadBool('Advanced','TopLeftDelay', False);
337 | cbValDelayTopLeft.ItemIndex := ini.ReadInteger('Advanced','TopLeftVal', 3);
338 | chkDelayTopRight.Checked := ini.ReadBool('Advanced','TopRightDelay', False);
339 | cbValDelayTopRight.ItemIndex := ini.ReadInteger('Advanced','TopRightDelayVal', 3);
340 | chkDelayBotLeft.Checked := ini.ReadBool('Advanced','BotLeftDelay', False);
341 | cbValDelayBotLeft.ItemIndex := ini.ReadInteger('Advanced','BotLeftDelayVal', 3);
342 | chkDelayBotRight.Checked := ini.ReadBool('Advanced','BotRightDelay', False);
343 | cbValDelayBotRight.ItemIndex := ini.ReadInteger('Advanced','BotRightDelayVal', 3);
344 |
345 | ToggleEachCornersDelay(not chkDelayGlobal.Checked);
346 |
347 | chkShowCount.Checked := ini.ReadBool('Advanced', 'ShowCountDown', False);
348 |
349 | chkCustom.Checked := ini.ReadBool('Advanced', 'CustomCommand', False);
350 | frmTrayPopup.XPopupMenu.Items[6].Visible := chkCustom.Checked;
351 | frmTrayPopup.XPopupMenu.Items[7].Visible := chkCustom.Checked;
352 | frmTrayPopup.XPopupMenu.Items[8].Visible := chkCustom.Checked;
353 | frmTrayPopup.XPopupMenu.Items[9].Visible := chkCustom.Checked;
354 | frmTrayPopup.UpdateXCombos;
355 |
356 | cmdcli[0] := ini.ReadString('Advanced', 'CustomCommandline', '');
357 | cmdarg[0] := ini.ReadString('Advanced', 'CustomCommandparms', '');
358 | cmdhid[0] := ini.ReadBool('Advanced', 'CustomCommandHidden', False);
359 |
360 | cmdcli[1] := ini.ReadString('Advanced', 'CustomCommandline2', '');
361 | cmdarg[1] := ini.ReadString('Advanced', 'CustomCommandparms2', '');
362 | cmdhid[1] := ini.ReadBool('Advanced', 'CustomCommandHidden2', False);
363 |
364 | cmdcli[2] := ini.ReadString('Advanced', 'CustomCommandline3', '');
365 | cmdarg[2] := ini.ReadString('Advanced', 'CustomCommandparms3', '');
366 | cmdhid[2] := ini.ReadBool('Advanced', 'CustomCommandHidden3', False);
367 |
368 | cmdcli[3] := ini.ReadString('Advanced', 'CustomCommandline4', '');
369 | cmdarg[3] := ini.ReadString('Advanced', 'CustomCommandparms4', '');
370 | cmdhid[3] := ini.ReadBool('Advanced', 'CustomCommandHidden4', False);
371 |
372 | // clone values
373 | cmd2temp;
374 |
375 | edCommand.Text := cmdcli[FCurTab];
376 | edParams.Text := cmdarg[FCurTab];
377 | chkHidden.Checked := cmdhid[FCurTab];
378 |
379 | chkFullScreen.Checked := ini.ReadBool('Advanced', 'IgnoreFullScreen', True);
380 | frmMain.tmFullScreen.Checked := chkFullScreen.Checked;
381 | finally
382 | ini.Free;
383 | end;
384 | end;
385 |
386 | procedure TfrmAdvSettings.rkSmartTabs1TabChange(Sender: TObject);
387 | var
388 | curTab: Integer;
389 | begin
390 | //
391 | // curTab := rkSmartTabs1.ActiveTab;
392 | caption := inttostr(curTab);
393 | edCommand.Text := tmpcmdcli[curTab];
394 | edParams.Text := tmpcmdarg[curTab];
395 | chkHidden.Checked := tmpcmdhid[curTab];
396 | end;
397 |
398 | procedure TfrmAdvSettings.SaveAdvancedIni;
399 | var
400 | ini: TIniFile;
401 | begin
402 | ini := TIniFile.Create(ExtractFilePath(ParamStr(0))+'settings.ini');
403 | try
404 | ini.WriteBool('Advanced','GlobalDelay',chkDelayGlobal.Checked);
405 | ini.WriteInteger('Advanced','GlobalDelayVal', cbValDelayGlobal.ItemIndex);
406 |
407 | ini.WriteBool('Advanced','TopLeftDelay',chkDelayTopLeft.Checked);
408 | ini.WriteInteger('Advanced','TopLeftVal', cbValDelayTopLeft.ItemIndex);
409 | ini.WriteBool('Advanced','TopRightDelay',chkDelayTopRight.Checked);
410 | ini.WriteInteger('Advanced','TopRightDelayVal', cbValDelayTopRight.ItemIndex);
411 | ini.WriteBool('Advanced','BotLeftDelay',chkDelayBotLeft.Checked);
412 | ini.WriteInteger('Advanced','BotLeftDelayVal', cbValDelayBotLeft.ItemIndex);
413 | ini.WriteBool('Advanced','BotRightDelay',chkDelayBotRight.Checked);
414 | ini.WriteInteger('Advanced','BotRightDelayVal', cbValDelayBotRight.ItemIndex);
415 |
416 | ini.WriteBool('Advanced', 'ShowCountDown', chkShowCount.Checked);
417 |
418 | ini.WriteBool('Advanced', 'CustomCommand', chkCustom.Checked);
419 | frmTrayPopup.XPopupMenu.Items[6].Visible := chkCustom.Checked;
420 | frmTrayPopup.XPopupMenu.Items[7].Visible := chkCustom.Checked;
421 | frmTrayPopup.XPopupMenu.Items[8].Visible := chkCustom.Checked;
422 | frmTrayPopup.XPopupMenu.Items[9].Visible := chkCustom.Checked;
423 | frmTrayPopup.UpdateXCombos;
424 |
425 | temp2cmd; // accept all the changes to commands
426 |
427 | ini.WriteString('Advanced', 'CustomCommandline', cmdcli[0]);
428 | ini.WriteString('Advanced', 'CustomCommandparms', cmdarg[0]);
429 | ini.WriteBool('Advanced', 'CustomCommandHidden', cmdhid[0]);
430 |
431 | ini.WriteString('Advanced', 'CustomCommandline2', cmdcli[1]);
432 | ini.WriteString('Advanced', 'CustomCommandparms2', cmdarg[1]);
433 | ini.WriteBool('Advanced', 'CustomCommandHidden2', cmdhid[1]);
434 |
435 | ini.WriteString('Advanced', 'CustomCommandline3', cmdcli[2]);
436 | ini.WriteString('Advanced', 'CustomCommandparms3', cmdarg[2]);
437 | ini.WriteBool('Advanced', 'CustomCommandHidden3', cmdhid[2]);
438 |
439 | ini.WriteString('Advanced', 'CustomCommandline4', cmdcli[3]);
440 | ini.WriteString('Advanced', 'CustomCommandparms4', cmdarg[3]);
441 | ini.WriteBool('Advanced', 'CustomCommandHidden4', cmdhid[3]);
442 |
443 |
444 | ini.WriteBool('Advanced', 'IgnoreFullScreen', chkFullScreen.Checked);
445 | frmMain.tmFullScreen.Checked := chkFullScreen.Checked;
446 | finally
447 | ini.Free;
448 | end;
449 | end;
450 |
451 |
452 |
453 | procedure TfrmAdvSettings.Temp2Cmd;
454 | var
455 | I : Integer;
456 | begin
457 | for I := 0 to 3 do
458 | begin
459 | cmdcli[I] := tmpcmdcli[I];
460 | cmdarg[I] := tmpcmdarg[I];
461 | cmdhid[I] := tmpcmdhid[I];
462 | end;
463 | end;
464 |
465 | procedure TfrmAdvSettings.ToggleEachCornersDelay(Enable: Boolean);
466 | begin
467 | if Enable then
468 | begin
469 | chkDelayTopLeft.Enabled := True;
470 | cbValDelayTopLeft.Enabled := chkDelayTopLeft.Checked;
471 |
472 | chkDelayTopRight.Enabled := True;
473 | cbValDelayTopRight.Enabled := chkDelayTopRight.Checked;
474 |
475 | chkDelayBotLeft.Enabled := True;
476 | cbValDelayBotLeft.Enabled := chkDelayBotLeft.Checked;
477 |
478 | chkDelayBotRight.Enabled := True;
479 | cbValDelayBotRight.Enabled := chkDelayBotRight.Checked;
480 | end
481 | else
482 | begin
483 | chkDelayTopLeft.Enabled := False;
484 | chkDelayTopLeft.Checked := False;
485 | cbValDelayTopLeft.Enabled := False;
486 |
487 | chkDelayTopRight.Enabled := False;
488 | chkDelayTopRight.Checked := False;
489 | cbValDelayTopRight.Enabled := False;
490 |
491 | chkDelayBotLeft.Enabled := False;
492 | chkDelayBotLeft.Checked := False;
493 | cbValDelayBotLeft.Enabled := False;
494 |
495 | chkDelayBotRight.Enabled := False;
496 | chkDelayBotRight.Checked := False;
497 | cbValDelayBotRight.Enabled := False;
498 | end;
499 |
500 | end;
501 |
502 | procedure TfrmAdvSettings.WndProc(var Msg: TMessage);
503 | begin
504 | inherited;
505 |
506 | case Msg.Msg of
507 | WM_CTLCOLOREDIT, WM_CTLCOLORSTATIC:
508 | begin
509 | if ((Msg.LParam = edCommand.Handle) or (Msg.LParam = edParams.Handle) ) and (FBrush <> 0) then
510 | begin
511 | SetBkMode(Msg.WParam, TRANSPARENT);
512 | Msg.Result := FBrush;
513 | end;
514 | end;
515 | end;
516 | end;
517 |
518 | {procedure TfrmAdvSettings.XCheckbox1Click(Sender: TObject);
519 | begin
520 |
521 | end;
522 |
523 | TBitBtn }
524 |
525 | {procedure TBitBtn.CNDrawItem(var Msg: TWMDrawItem);
526 | begin
527 | DrawButton(Msg.DrawItemStruct^);
528 | Msg.Result := Integer(True);
529 | end;
530 |
531 | procedure TBitBtn.CNFocusChanged(var Msg: TMessage);
532 | begin
533 | inherited;
534 | Invalidate;
535 | end;
536 |
537 | procedure TBitBtn.DrawButton(const DrawItemStruct: TDrawItemStruct);
538 | var
539 | Canvas: TCanvas;
540 | begin
541 | Canvas := TCanvas.Create;
542 | try
543 | Canvas.Handle := DrawItemStruct.hDC;
544 |
545 | Canvas.Brush.Style := bsSolid;
546 | Canvas.Brush.Color := $2d2d2d;
547 | Canvas.Rectangle(ClientRect);
548 | Canvas.Brush.Style := bsClear;
549 | Canvas.Font.Assign(Font);
550 | Canvas.TextRect(ClientRect, 12,10,Self.Caption);//, [tfVerticalCenter, tfCenter, tfSingleLine]);
551 | finally
552 | // ReleaseDC(Canvas.Handle);
553 | Canvas.Handle := 0;
554 | Canvas.Free;
555 | end;
556 | end;}
557 |
558 |
559 |
560 | end.
561 |
562 |
--------------------------------------------------------------------------------
/thirparty/DwmApi.pas:
--------------------------------------------------------------------------------
1 | {*******************************************************}
2 | { }
3 | { Delphi Runtime Library }
4 | { }
5 | { File: dwmapi.h }
6 | { Copyright (c) Microsoft Corporation }
7 | { All Rights Reserved. }
8 | { }
9 | { Translator: Embarcadero Technologies, Inc. }
10 | { Copyright(c) 1995-2010 Embarcadero Technologies, Inc. }
11 | { }
12 | {*******************************************************}
13 |
14 |
15 | {*******************************************************}
16 | { Win32 API Desktop Window Manager Interface Unit }
17 | {*******************************************************}
18 |
19 | unit Dwmapi;
20 |
21 | {$WEAKPACKAGEUNIT}
22 |
23 | {$HPPEMIT ''}
24 | {$HPPEMIT '#include "dwmapi.h"'}
25 | {$HPPEMIT '#pragma link "dwmapi.lib"'}
26 | {$HPPEMIT ''}
27 |
28 | interface
29 |
30 | uses Windows, Uxtheme;
31 |
32 | const
33 | // Blur behind data structures
34 | DWM_BB_ENABLE = $00000001; // fEnable has been specified
35 | {$EXTERNALSYM DWM_BB_ENABLE}
36 | DWM_BB_BLURREGION = $00000002; // hRgnBlur has been specified
37 | {$EXTERNALSYM DWM_BB_BLURREGION}
38 | DWM_BB_TRANSITIONONMAXIMIZED = $00000004; // fTransitionOnMaximized has been specified
39 | {$EXTERNALSYM DWM_BB_TRANSITIONONMAXIMIZED}
40 |
41 | type
42 | PDWM_BLURBEHIND = ^DWM_BLURBEHIND;
43 | DWM_BLURBEHIND = record
44 | dwFlags: DWORD;
45 | fEnable: BOOL;
46 | hRgnBlur: HRGN;
47 | fTransitionOnMaximized: BOOL;
48 | end;
49 | _DWM_BLURBEHIND = DWM_BLURBEHIND;
50 | TDwmBlurBehind = DWM_BLURBEHIND;
51 | PDwmBlurBehind = ^TDwmBlurbehind;
52 | {$EXTERNALSYM DWM_BLURBEHIND}
53 | {$EXTERNALSYM PDWM_BLURBEHIND}
54 |
55 | // Window attributes
56 | DWMWINDOWATTRIBUTE = type Integer;
57 | {$EXTERNALSYM DWMWINDOWATTRIBUTE}
58 | const
59 | DWMWA_NCRENDERING_ENABLED = 1; // [get] Is non-client rendering enabled/disabled
60 | {$EXTERNALSYM DWMWA_NCRENDERING_ENABLED}
61 | DWMWA_NCRENDERING_POLICY = 2; // [set] Non-client rendering policy
62 | {$EXTERNALSYM DWMWA_NCRENDERING_POLICY}
63 | DWMWA_TRANSITIONS_FORCEDISABLED = 3; // [set] Potentially enable/forcibly disable transitions
64 | {$EXTERNALSYM DWMWA_TRANSITIONS_FORCEDISABLED}
65 | DWMWA_ALLOW_NCPAINT = 4; // [set] Allow contents rendered in the non-client area to be visible on the DWM-drawn frame.
66 | {$EXTERNALSYM DWMWA_ALLOW_NCPAINT}
67 | DWMWA_CAPTION_BUTTON_BOUNDS = 5; // [get] Bounds of the caption button area in window-relative space.
68 | {$EXTERNALSYM DWMWA_CAPTION_BUTTON_BOUNDS}
69 | DWMWA_NONCLIENT_RTL_LAYOUT = 6; // [set] Is non-client content RTL mirrored
70 | {$EXTERNALSYM DWMWA_NONCLIENT_RTL_LAYOUT}
71 | DWMWA_FORCE_ICONIC_REPRESENTATION = 7; // [set] Force this window to display iconic thumbnails.
72 | {$EXTERNALSYM DWMWA_FORCE_ICONIC_REPRESENTATION}
73 | DWMWA_FLIP3D_POLICY = 8; // [set] Designates how Flip3D will treat the window.
74 | {$EXTERNALSYM DWMWA_FLIP3D_POLICY}
75 | DWMWA_EXTENDED_FRAME_BOUNDS = 9; // [get] Gets the extended frame bounds rectangle in screen space
76 | {$EXTERNALSYM DWMWA_EXTENDED_FRAME_BOUNDS}
77 | DWMWA_HAS_ICONIC_BITMAP = 10; // [set] Indicates an available bitmap when there is no better thumbnail representation.
78 | {$EXTERNALSYM DWMWA_HAS_ICONIC_BITMAP}
79 | DWMWA_DISALLOW_PEEK = 11; // [set] Don't invoke Peek on the window.
80 | {$EXTERNALSYM DWMWA_DISALLOW_PEEK}
81 | DWMWA_EXCLUDED_FROM_PEEK = 12; // [set] LivePreview exclusion information
82 | {$EXTERNALSYM DWMWA_EXCLUDED_FROM_PEEK}
83 | DWMWA_LAST = 13;
84 | {$EXTERNALSYM DWMWA_LAST}
85 |
86 | // Non-client rendering policy attribute values
87 | {$EXTERNALSYM DWMNCRP_USEWINDOWSTYLE}
88 | DWMNCRP_USEWINDOWSTYLE = 0; // Enable/disable non-client rendering based on window style
89 | {$EXTERNALSYM DWMNCRP_DISABLED}
90 | DWMNCRP_DISABLED = 1; // Disabled non-client rendering; window style is ignored
91 | {$EXTERNALSYM DWMNCRP_ENABLED}
92 | DWMNCRP_ENABLED = 2; // Enabled non-client rendering; window style is ignored
93 | {$EXTERNALSYM DWMNCRP_LAST}
94 | DWMNCRP_LAST = 3;
95 |
96 | // Values designating how Flip3D treats a given window.
97 |
98 | {$EXTERNALSYM DWMFLIP3D_DEFAULT}
99 | DWMFLIP3D_DEFAULT = 0; // Hide or include the window in Flip3D based on window style and visibility.
100 | {$EXTERNALSYM DWMFLIP3D_EXCLUDEBELOW}
101 | DWMFLIP3D_EXCLUDEBELOW = 1; // Display the window under Flip3D and disabled.
102 | {$EXTERNALSYM DWMFLIP3D_EXCLUDEABOVE}
103 | DWMFLIP3D_EXCLUDEABOVE = 2; // Display the window above Flip3D and enabled.
104 | {$EXTERNALSYM DWMFLIP3D_LAST}
105 | DWMFLIP3D_LAST = 3;
106 |
107 |
108 | // Thumbnails
109 | type
110 | HTHUMBNAIL = THandle;
111 | {$EXTERNALSYM HTHUMBNAIL}
112 | PHTHUMBNAIL = ^HTHUMBNAIL;
113 | {$EXTERNALSYM PHTHUMBNAIL}
114 |
115 | const
116 | DWM_TNP_RECTDESTINATION = $00000001;
117 | {$EXTERNALSYM DWM_TNP_RECTDESTINATION}
118 | DWM_TNP_RECTSOURCE = $00000002;
119 | {$EXTERNALSYM DWM_TNP_RECTSOURCE}
120 | DWM_TNP_OPACITY = $00000004;
121 | {$EXTERNALSYM DWM_TNP_OPACITY}
122 | DWM_TNP_VISIBLE = $00000008;
123 | {$EXTERNALSYM DWM_TNP_VISIBLE}
124 | DWM_TNP_SOURCECLIENTAREAONLY = $00000010;
125 | {$EXTERNALSYM DWM_TNP_SOURCECLIENTAREAONLY}
126 |
127 | type
128 | PDWM_THUMBNAIL_PROPERTIES = ^DWM_THUMBNAIL_PROPERTIES;
129 | DWM_THUMBNAIL_PROPERTIES = record
130 | dwFlags: DWORD;
131 | rcDestination: TRect;
132 | rcSource: TRect;
133 | opacity: Byte;
134 | fVisible: BOOL;
135 | fSourceClientAreaOnly: BOOL;
136 | end;
137 | _DWM_THUMBNAIL_PROPERTIES = DWM_THUMBNAIL_PROPERTIES;
138 | TDwmThumbnailProperties = DWM_THUMBNAIL_PROPERTIES;
139 | PDwmThumbnailProperties = ^TDwmThumbnailProperties;
140 | {$EXTERNALSYM DWM_THUMBNAIL_PROPERTIES}
141 | {$EXTERNALSYM PDWM_THUMBNAIL_PROPERTIES}
142 |
143 | // Video enabling apis
144 |
145 | // DWM_FRAME_COUNT = ULONGLONG;
146 | // {$EXTERNALSYM DWM_FRAME_COUNT}
147 | // QPC_TIME = ULONGLONG;
148 | // {$EXTERNALSYM QPC_TIME}
149 |
150 | UNSIGNED_RATIO = record
151 | uiNumerator: Cardinal;
152 | uiDenominator: Cardinal;
153 | end;
154 | _UNSIGNED_RATIO = UNSIGNED_RATIO;
155 | TUnsignedRatio = UNSIGNED_RATIO;
156 | PUnsignedRatio = ^TUnsignedRatio;
157 | {$EXTERNALSYM UNSIGNED_RATIO}
158 |
159 | DWM_TIMING_INFO = record
160 | cbSize: Cardinal;
161 |
162 | // Data on DWM composition overall
163 |
164 | // Monitor refresh rate
165 | rateRefresh: TUnsignedRatio;
166 |
167 | // Actual period
168 | // qpcRefreshPeriod: QPC_TIME;
169 |
170 | // composition rate
171 | rateCompose: TUnsignedRatio;
172 |
173 | // QPC time at a VSync interupt
174 | // qpcVBlank: QPC_TIME;
175 |
176 | // DWM refresh count of the last vsync
177 | // DWM refresh count is a 64bit number where zero is
178 | // the first refresh the DWM woke up to process
179 | // cRefresh: DWM_FRAME_COUNT;
180 |
181 | // DX refresh count at the last Vsync Interupt
182 | // DX refresh count is a 32bit number with zero
183 | // being the first refresh after the card was initialized
184 | // DX increments a counter when ever a VSync ISR is processed
185 | // It is possible for DX to miss VSyncs
186 | //
187 | // There is not a fixed mapping between DX and DWM refresh counts
188 | // because the DX will rollover and may miss VSync interupts
189 | cDXRefresh: UINT;
190 |
191 | // QPC time at a compose time.
192 | // qpcCompose: QPC_TIME;
193 |
194 | // Frame number that was composed at qpcCompose
195 | // cFrame: DWM_FRAME_COUNT;
196 |
197 | // The present number DX uses to identify renderer frames
198 | cDXPresent: UINT;
199 |
200 | // Refresh count of the frame that was composed at qpcCompose
201 | // cRefreshFrame: DWM_FRAME_COUNT;
202 |
203 |
204 | // DWM frame number that was last submitted
205 | // cFrameSubmitted: DWM_FRAME_COUNT;
206 |
207 | // DX Present number that was last submitted
208 | cDXPresentSubmitted: UINT;
209 |
210 | // DWM frame number that was last confirmed presented
211 | // cFrameConfirmed: DWM_FRAME_COUNT;
212 |
213 | // DX Present number that was last confirmed presented
214 | cDXPresentConfirmed: UINT;
215 |
216 | // The target refresh count of the last
217 | // frame confirmed completed by the GPU
218 | // cRefreshConfirmed: DWM_FRAME_COUNT;
219 |
220 | // DX refresh count when the frame was confirmed presented
221 | cDXRefreshConfirmed: UINT;
222 |
223 | // Number of frames the DWM presented late
224 | // AKA Glitches
225 | // cFramesLate: DWM_FRAME_COUNT;
226 |
227 | // the number of composition frames that
228 | // have been issued but not confirmed completed
229 | cFramesOutstanding: UINT;
230 |
231 |
232 | // Following fields are only relavent when an HWND is specified
233 | // Display frame
234 |
235 |
236 | // Last frame displayed
237 | // cFrameDisplayed: DWM_FRAME_COUNT;
238 |
239 | // QPC time of the composition pass when the frame was displayed
240 | // qpcFrameDisplayed: QPC_TIME;
241 |
242 | // Count of the VSync when the frame should have become visible
243 | // cRefreshFrameDisplayed: DWM_FRAME_COUNT;
244 |
245 | // Complete frames: DX has notified the DWM that the frame is done rendering
246 |
247 | // ID of the the last frame marked complete (starts at 0)
248 | // cFrameComplete: DWM_FRAME_COUNT;
249 |
250 | // QPC time when the last frame was marked complete
251 | // qpcFrameComplete: QPC_TIME;
252 |
253 | // Pending frames:
254 | // The application has been submitted to DX but not completed by the GPU
255 |
256 | // ID of the the last frame marked pending (starts at 0)
257 | // cFramePending: DWM_FRAME_COUNT;
258 |
259 | // QPC time when the last frame was marked pending
260 | // qpcFramePending: QPC_TIME;
261 |
262 | // number of unique frames displayed
263 | // cFramesDisplayed: DWM_FRAME_COUNT;
264 |
265 | // number of new completed frames that have been received
266 | // cFramesComplete: DWM_FRAME_COUNT;
267 |
268 | // number of new frames submitted to DX but not yet complete
269 | // cFramesPending: DWM_FRAME_COUNT;
270 |
271 | // number of frames available but not displayed, used or dropped
272 | // cFramesAvailable: DWM_FRAME_COUNT;
273 |
274 | // number of rendered frames that were never
275 | // displayed because composition occured too late
276 | // cFramesDropped: DWM_FRAME_COUNT;
277 |
278 | // number of times an old frame was composed
279 | // when a new frame should have been used
280 | // but was not available
281 | // cFramesMissed: DWM_FRAME_COUNT;
282 |
283 | // the refresh at which the next frame is
284 | // scheduled to be displayed
285 | // cRefreshNextDisplayed: DWM_FRAME_COUNT;
286 |
287 | // the refresh at which the next DX present is
288 | // scheduled to be displayed
289 | // cRefreshNextPresented: DWM_FRAME_COUNT;
290 |
291 | // The total number of refreshes worth of content
292 | // for this HWND that have been displayed by the DWM
293 | // since DwmSetPresentParameters was called
294 | // cRefreshesDisplayed: DWM_FRAME_COUNT;
295 |
296 | // The total number of refreshes worth of content
297 | // that have been presented by the application
298 | // since DwmSetPresentParameters was called
299 | // cRefreshesPresented: DWM_FRAME_COUNT;
300 |
301 |
302 | // The actual refresh # when content for this
303 | // window started to be displayed
304 | // it may be different than that requested
305 | // DwmSetPresentParameters
306 | // cRefreshStarted: DWM_FRAME_COUNT;
307 |
308 | // Total number of pixels DX redirected
309 | // to the DWM.
310 | // If Queueing is used the full buffer
311 | // is transfered on each present.
312 | // If not queuing it is possible only
313 | // a dirty region is updated
314 | // cPixelsReceived: ULONGLONG;
315 |
316 | // Total number of pixels drawn.
317 | // Does not take into account if
318 | // if the window is only partial drawn
319 | // do to clipping or dirty rect management
320 | // cPixelsDrawn: ULONGLONG;
321 |
322 | // The number of buffers in the flipchain
323 | // that are empty. An application can
324 | // present that number of times and guarantee
325 | // it won't be blocked waiting for a buffer to
326 | // become empty to present to
327 | // cBuffersEmpty: DWM_FRAME_COUNT;
328 |
329 | end;
330 | _DWM_TIMING_INFO = DWM_TIMING_INFO;
331 | TDwmTimingInfo = DWM_TIMING_INFO;
332 | PDwmTimingInfo = ^TDwmTimingInfo;
333 | {$EXTERNALSYM DWM_TIMING_INFO}
334 |
335 | DWM_SOURCE_FRAME_SAMPLING = type Integer;
336 | {$EXTERNALSYM DWM_SOURCE_FRAME_SAMPLING}
337 | const
338 | // includes the first refresh of the output frame
339 | DWM_SOURCE_FRAME_SAMPLING_POINT = 0;
340 | {$EXTERNALSYM DWM_SOURCE_FRAME_SAMPLING_POINT}
341 |
342 | // use the source frame that includes the most
343 | // refreshes of out the output frame
344 | // in case of multiple source frames with the
345 | // same coverage the last will be used
346 | DWM_SOURCE_FRAME_SAMPLING_COVERAGE = 1;
347 | {$EXTERNALSYM DWM_SOURCE_FRAME_SAMPLING_COVERAGE}
348 |
349 | // Sentinel value
350 | DWM_SOURCE_FRAME_SAMPLING_LAST = 2;
351 | {$EXTERNALSYM DWM_SOURCE_FRAME_SAMPLING_LAST}
352 |
353 | const
354 | c_DwmMaxQueuedBuffers = 8;
355 | c_DwmMaxMonitors = 16;
356 | c_DwmMaxAdapters = 16;
357 |
358 | type
359 | DWM_PRESENT_PARAMETERS = record
360 | cbSize: Cardinal;
361 | fQueue: BOOL;
362 | // cRefreshStart: DWM_FRAME_COUNT;
363 | cBuffer: UINT;
364 | fUseSourceRate: BOOL;
365 | rateSource: TUnsignedRatio;
366 | cRefreshesPerFrame: UINT;
367 | eSampling: DWM_SOURCE_FRAME_SAMPLING;
368 | end;
369 | _DWM_PRESENT_PARAMETERS = DWM_PRESENT_PARAMETERS;
370 | TDwmPresentParameters = DWM_PRESENT_PARAMETERS;
371 | PDwmPresentParameters = ^TDwmPresentParameters;
372 | {$EXTERNALSYM DWM_PRESENT_PARAMETERS}
373 |
374 |
375 |
376 | const
377 | DWM_FRAME_DURATION_DEFAULT = -1;
378 | {$EXTERNALSYM DWM_FRAME_DURATION_DEFAULT}
379 |
380 | function DwmDefWindowProc(hWnd: HWND; msg: UINT; wParam: WPARAM; lParam: LPARAM;
381 | var plResult: LRESULT): BOOL; stdcall;
382 | {$EXTERNALSYM DwmDefWindowProc}
383 |
384 | function DwmEnableBlurBehindWindow(hWnd: HWND;
385 | var pBlurBehind: TDwmBlurbehind): HResult; stdcall;
386 | {$EXTERNALSYM DwmEnableBlurBehindWindow}
387 |
388 | const
389 | DWM_EC_DISABLECOMPOSITION = 0;
390 | {$EXTERNALSYM DWM_EC_DISABLECOMPOSITION}
391 | DWM_EC_ENABLECOMPOSITION = 1;
392 | {$EXTERNALSYM DWM_EC_ENABLECOMPOSITION}
393 |
394 |
395 | function DwmEnableComposition(uCompositionAction: UINT): HResult; stdcall;
396 | {$EXTERNALSYM DwmEnableComposition}
397 |
398 | function DwmEnableMMCSS(fEnableMMCSS: BOOL): HResult; stdcall;
399 | {$EXTERNALSYM DwmEnableMMCSS}
400 |
401 | function DwmExtendFrameIntoClientArea(hWnd: HWND; const pMarInset: TMargins): HResult; stdcall;
402 | {$EXTERNALSYM DwmExtendFrameIntoClientArea}
403 |
404 | function DwmGetColorizationColor(var pcrColorization: DWORD;
405 | var pfOpaqueBlend: BOOL): HResult; stdcall;
406 | {$EXTERNALSYM DwmGetColorizationColor}
407 |
408 | function DwmGetCompositionTimingInfo(hwnd: HWND;
409 | var pTimingInfo: TDwmTimingInfo): HResult; stdcall;
410 | {$EXTERNALSYM DwmGetCompositionTimingInfo}
411 |
412 |
413 | function DwmGetWindowAttribute(hwnd: HWND; dwAttribute: DWORD;
414 | pvAttribute: Pointer; cbAttribute: DWORD): HResult; stdcall;
415 | {$EXTERNALSYM DwmGetWindowAttribute}
416 |
417 | {$EXTERNALSYM DwmIsCompositionEnabled}
418 | function DwmIsCompositionEnabled(var pfEnabled: BOOL): HResult; stdcall;
419 |
420 | function DwmModifyPreviousDxFrameDuration(hwnd: HWND; cRefreshes: Integer;
421 | fRelative: BOOL): HResult; stdcall;
422 | {$EXTERNALSYM DwmModifyPreviousDxFrameDuration}
423 |
424 | function DwmQueryThumbnailSourceSize(hThumbnail: HTHUMBNAIL;
425 | pSize: PSIZE): HResult; stdcall;
426 | {$EXTERNALSYM DwmQueryThumbnailSourceSize}
427 |
428 | function DwmRegisterThumbnail(hwndDestination: HWND; hwndSource: HWND;
429 | phThumbnailId: PHTHUMBNAIL): HResult; stdcall;
430 | {$EXTERNALSYM DwmRegisterThumbnail}
431 |
432 | function DwmSetDxFrameDuration(hwnd: HWND; cRefreshes: Integer): HResult; stdcall;
433 | {$EXTERNALSYM DwmSetDxFrameDuration}
434 |
435 | function DwmSetPresentParameters(hwnd: HWND;
436 | var pPresentParams: TDwmPresentParameters): HResult; stdcall;
437 | {$EXTERNALSYM DwmSetPresentParameters}
438 |
439 | function DwmSetWindowAttribute(hwnd: HWND; dwAttribute: DWORD;
440 | pvAttribute: Pointer; cbAttribute: DWORD): HResult; stdcall;
441 | {$EXTERNALSYM DwmSetWindowAttribute}
442 |
443 | function DwmUnregisterThumbnail(hThumbnailId: HTHUMBNAIL): HResult; stdcall;
444 | {$EXTERNALSYM DwmUnregisterThumbnail}
445 |
446 | function DwmUpdateThumbnailProperties(hThumbnailId: HTHUMBNAIL;
447 | var ptnProperties: TDwmThumbnailProperties): HResult; stdcall;
448 | {$EXTERNALSYM DwmUpdateThumbnailProperties}
449 |
450 | const
451 | DWM_SIT_DISPLAYFRAME = $00000001; // Display a window frame around the provided bitmap
452 | {$EXTERNALSYM DWM_SIT_DISPLAYFRAME}
453 |
454 | function DwmSetIconicThumbnail(hwnd: HWND; hbmp: HBITMAP;
455 | dwSITFlags: DWORD): HResult; stdcall;
456 | {$EXTERNALSYM DwmSetIconicThumbnail}
457 |
458 | function DwmSetIconicLivePreviewBitmap(hwnd: HWND; hbmp: HBITMAP;
459 | var pptClient: TPoint; dwSITFlags: DWORD): HResult; stdcall;
460 | {$EXTERNALSYM DwmSetIconicLivePreviewBitmap}
461 |
462 | function DwmInvalidateIconicBitmaps(hwnd: HWND): HResult; stdcall;
463 | {$EXTERNALSYM DwmInvalidateIconicBitmaps}
464 |
465 | function DwmAttachMilContent(hwnd: HWND): HResult; stdcall;
466 | {$EXTERNALSYM DwmAttachMilContent}
467 |
468 | function DwmDetachMilContent(hwnd: HWND): HResult; stdcall;
469 | {$EXTERNALSYM DwmDetachMilContent}
470 |
471 | function DwmFlush: HResult; stdcall;
472 | {$EXTERNALSYM DwmFlush}
473 |
474 | type
475 | MilMatrix3x2D = record
476 | S_11: Double;
477 | S_12: Double;
478 | S_21: Double;
479 | S_22: Double;
480 | DX: Double;
481 | DY: Double;
482 | end;
483 | _MilMatrix3x2D = MilMatrix3x2D;
484 | TMilMatrix3x2D = MilMatrix3x2D;
485 | PMilMatrix3x2D = ^TMilMatrix3x2D;
486 | {$EXTERNALSYM MilMatrix3x2D}
487 |
488 | // Compatibility for Vista dwm api.
489 | MIL_MATRIX3X2D = MilMatrix3x2D;
490 | {$EXTERNALSYM MIL_MATRIX3X2D}
491 |
492 | function DwmGetGraphicsStreamTransformHint(uIndex: UINT;
493 | var pTransform: TMilMatrix3x2D): HResult;
494 | {$EXTERNALSYM DwmGetGraphicsStreamTransformHint}
495 |
496 | function DwmGetGraphicsStreamClient(uIndex: UINT;
497 | var pClientUuid: TGUID): HResult;
498 | {$EXTERNALSYM DwmGetGraphicsStreamClient}
499 |
500 | function DwmGetTransportAttributes(var pfIsRemoting: BOOL;
501 | var pfIsConnected: BOOL; var pDwGeneration: DWORD): HResult;
502 | {$EXTERNALSYM DwmGetTransportAttributes}
503 |
504 | function DwmCompositionEnabled: Boolean;
505 |
506 | implementation
507 |
508 | uses
509 | SysUtils;
510 |
511 | const
512 | ModName = 'DWMAPI.DLL';
513 |
514 | function DwmDefWindowProc; external ModName name 'DwmDefWindowProc';
515 | function DwmEnableBlurBehindWindow; external ModName name 'DwmEnableBlurBehindWindow';
516 | function DwmEnableComposition; external ModName name 'DwmEnableComposition';
517 | function DwmEnableMMCSS; external ModName name 'DwmEnableMMCSS';
518 | function DwmExtendFrameIntoClientArea; external ModName name 'DwmExtendFrameIntoClientArea';
519 | function DwmGetColorizationColor; external ModName name 'DwmGetColorizationColor';
520 | function DwmGetCompositionTimingInfo; external ModName name 'DwmGetCompositionTimingInfo';
521 | function DwmGetWindowAttribute; external ModName name 'DwmGetWindowAttribute';
522 | function DwmIsCompositionEnabled; external ModName name 'DwmIsCompositionEnabled';
523 | function DwmModifyPreviousDxFrameDuration; external ModName name 'DwmModifyPreviousDxFrameDuration';
524 | function DwmQueryThumbnailSourceSize; external ModName name 'DwmQueryThumbnailSourceSize';
525 | function DwmRegisterThumbnail; external ModName name 'DwmRegisterThumbnail';
526 | function DwmSetDxFrameDuration; external ModName name 'DwmSetDxFrameDuration';
527 | function DwmSetPresentParameters; external ModName name 'DwmSetPresentParameters';
528 | function DwmSetWindowAttribute; external ModName name 'DwmSetWindowAttribute';
529 | function DwmUnregisterThumbnail; external ModName name 'DwmUnregisterThumbnail';
530 | function DwmUpdateThumbnailProperties; external ModName name 'DwmUpdateThumbnailProperties';
531 | function DwmSetIconicThumbnail; external ModName name 'DwmSetIconicThumbnail';
532 | function DwmSetIconicLivePreviewBitmap; external ModName name 'DwmSetIconicLivePreviewBitmap';
533 | function DwmInvalidateIconicBitmaps; external ModName name 'DwmInvalidateIconicBitmaps';
534 | function DwmAttachMilContent; external ModName name 'DwmAttachMilContent';
535 | function DwmDetachMilContent; external ModName name 'DwmDetachMilContent';
536 | function DwmFlush; external ModName name 'DwmFlush';
537 | function DwmGetGraphicsStreamTransformHint; external ModName name 'DwmGetGraphicsStreamTransformHint';
538 | function DwmGetGraphicsStreamClient; external ModName name 'DwmGetGraphicsStreamClient';
539 | function DwmGetTransportAttributes; external ModName name 'DwmGetTransportAttributes';
540 |
541 | function DwmCompositionEnabled: Boolean;
542 | var
543 | LEnabled: BOOL;
544 | begin
545 | Result := (Win32MajorVersion >= 6) and (DwmIsCompositionEnabled(LEnabled) = S_OK) and LEnabled;
546 | end;
547 |
548 | end.
549 |
--------------------------------------------------------------------------------
/thirparty/AnimateEasing.pas:
--------------------------------------------------------------------------------
1 | {
2 | AnimateEasing v1.0.1.0
3 |
4 | Developed by Norbert Mereg
5 |
6 | Description:
7 | This component is an easing animation value calculator.
8 |
9 | Features:
10 | - 28 different easing style (in, out, in-out)
11 |
12 |
13 | History:
14 | v1.0.1 2010.06.14 - Added comment to methods
15 | v1.0.0 2010.05.14 - First release.
16 | }
17 | unit AnimateEasing;
18 |
19 | interface
20 |
21 | uses
22 | SysUtils, DateUtils, Math, Classes, StdCtrls, ExtCtrls;
23 |
24 | type
25 | TEasingFunction = function(p: Extended; firstNum, diff: integer): Extended of object;
26 | TAnimateTickEvent = reference to procedure(Sender: TObject; Value: Extended);
27 | TANotifyEvent = reference to procedure(Sender: TObject);
28 |
29 | TResultArray = array of Extended;
30 |
31 | TEasingType = (etBackEaseIn, etbackEaseOut, etBackEaseInOut,
32 | etBounceEaseIn, etBounceEaseOut,
33 | etCircEaseIn, etCircEaseOut, etCircEaseInOut,
34 | etCubicEaseIn, etCubicEaseOut, etCubicEaseInOut,
35 | etElasticEaseIn, etElasticEaseOut,
36 | etExpoEaseIn, etExpoEaseOut, etExpoEaseInOut,
37 | etQuadEaseIn, etQuadEaseOut, etQuadEaseInOut,
38 | etQuartEaseIn, etQuartEaseOut, etQuartEaseInOut,
39 | etQuintEaseIn, etQuintEaseOut, etQuintEaseInOut,
40 | etSineEaseIn, etSineEaseOut, etSineEaseInOut);
41 |
42 | TAnimateEasing = class(TObject)
43 | private
44 | FStartPos: integer;
45 | FAnimLength: integer;
46 | FDifferent: integer;
47 | FStartTime: TDateTime;
48 | FEasingFunc: TEasingFunction;
49 | FTimer: TTimer;
50 | FDelayTimer: TTimer;
51 | FOnTick: TAnimateTickEvent;
52 | FOnFinish: TANotifyEvent;
53 | procedure SetOnTick(const Value: TAnimateTickEvent);
54 | procedure FTimerTimer(Sender: TObject);
55 | procedure FDelayTimerTimer(Sender: TObject);
56 | procedure SetOnFinish(const Value: TANotifyEvent);
57 | procedure FinishAnim;
58 | public
59 | constructor Create;
60 | destructor Destroy; override;
61 |
62 | (*
63 | This method uses a timer to call the OnTick event with the calculated value.
64 |
65 | StartPos: The animating start value.
66 | Different: Difference between start and end position.
67 | Animlength: Full length of animation (millisecond)
68 | Easing: The animation easing type
69 | OnTickEvent: The event handler
70 | CycleTime: The timer cycle time (default 10ms)
71 | StartDelay: A delay before start the animation
72 | OnFinishEvent: The event what fire when the animation finished
73 | *)
74 |
75 | procedure Animating(StartPos, Different, AnimLength: integer; Easing: TEasingType); overload;
76 | procedure Animating(StartPos, Different, AnimLength: integer; Easing: TEasingType; OnTickEvent: TAnimateTickEvent; OnFinishEvent: TANotifyEvent); overload;
77 | procedure Animating(StartPos, Different, AnimLength: integer; Easing: TEasingType; CycleTime: integer); overload;
78 | procedure Animating(StartPos, Different, AnimLength: integer; Easing: TEasingType; CycleTime, StartDelay: integer); overload;
79 | procedure Animating(StartPos, Different, AnimLength: integer; Easing: TEasingType; CycleTime, StartDelay: integer; OnTickEvent: TAnimateTickEvent; OnFinishEvent: TANotifyEvent); overload;
80 |
81 | procedure StopAnimating;
82 |
83 | (* This method only generate the animation values to an array
84 |
85 | Different: Difference between start and end position.
86 | StepCount: Count of values
87 | Easing: The animation easing type *)
88 |
89 | class function GenerateValues(Different, StepCount: integer; Easing: TEasingType): TResultArray;
90 |
91 | (* This method calculate the current value
92 |
93 | p: The animation phase. Values between 0 and 1.
94 | firstNum: The start values of animation
95 | diff: Difference between start and end value of animation
96 | *)
97 | class function GetEasingFunc(Easing: TEasingType): TEasingFunction; static;
98 | class function backEaseIn(p: Extended; firstNum, diff: integer): Extended;
99 | class function backEaseOut(p: Extended; firstNum, diff: integer): Extended;
100 | class function backEaseInOut(p: Extended; firstNum, diff: integer): Extended;
101 | class function bounceEaseIn(p: Extended; firstNum, diff: integer): Extended;
102 | class function bounceEaseOut(p: Extended; firstNum, diff: integer): Extended;
103 | class function circEaseIn(p: Extended; firstNum, diff: integer): Extended;
104 | class function circEaseOut(p: Extended; firstNum, diff: integer): Extended;
105 | class function circEaseInOut(p: Extended; firstNum, diff: integer): Extended;
106 | class function cubicEaseIn(p: Extended; firstNum, diff: integer): Extended;
107 | class function cubicEaseInOut(p: Extended; firstNum, diff: integer): Extended;
108 | class function cubicEaseOut(p: Extended; firstNum, diff: integer): Extended;
109 | class function elasticEaseIn(p: Extended; firstNum, diff: integer): Extended;
110 | class function elasticEaseOut(p: Extended; firstNum, diff: integer): Extended;
111 | class function expoEaseIn(p: Extended; firstNum, diff: integer): Extended;
112 | class function expoEaseOut(p: Extended; firstNum, diff: integer): Extended;
113 | class function expoEaseInOut(p: Extended; firstNum, diff: integer): Extended;
114 | class function quadEaseIn(p: Extended; firstNum, diff: integer): Extended;
115 | class function quadEaseOut(p: Extended; firstNum, diff: integer): Extended;
116 | class function quadEaseInOut(p: Extended; firstNum, diff: integer): Extended;
117 | class function quartEaseIn(p: Extended; firstNum, diff: integer): Extended;
118 | class function quartEaseOut(p: Extended; firstNum, diff: integer): Extended;
119 | class function quartEaseInOut(p: Extended; firstNum, diff: integer): Extended;
120 | class function quintEaseIn(p: Extended; firstNum, diff: integer): Extended;
121 | class function quintEaseOut(p: Extended; firstNum, diff: integer): Extended;
122 | class function quintEaseInOut(p: Extended; firstNum, diff: integer): Extended;
123 | class function sineEaseIn(p: Extended; firstNum, diff: integer): Extended;
124 | class function sineEaseOut(p: Extended; firstNum, diff: integer): Extended;
125 | class function sineEaseInOut(p: Extended; firstNum, diff: integer): Extended;
126 | published
127 | property OnTick: TAnimateTickEvent read FOnTick write SetOnTick;
128 | property OnFinish: TANotifyEvent read FOnFinish write SetOnFinish;
129 | end;
130 |
131 |
132 | implementation
133 |
134 | procedure TAnimateEasing.Animating(StartPos, Different, AnimLength: integer; Easing: TEasingType);
135 | begin
136 | Animating(StartPos, Different, AnimLength, Easing, 10, -1, nil, nil);
137 | end;
138 |
139 | procedure TAnimateEasing.Animating(StartPos, Different, AnimLength: integer;
140 | Easing: TEasingType; OnTickEvent: TAnimateTickEvent;
141 | OnFinishEvent: TANotifyEvent);
142 | begin
143 | Animating(StartPos, Different, AnimLength, Easing, 10, -1, OnTickEvent, OnFinishEvent);
144 | end;
145 |
146 | procedure TAnimateEasing.Animating(StartPos, Different, AnimLength: integer;
147 | Easing: TEasingType; CycleTime: integer);
148 | begin
149 | Animating(StartPos, Different, AnimLength, Easing, CycleTime, -1, nil, nil);
150 | end;
151 |
152 | procedure TAnimateEasing.Animating(StartPos, Different, AnimLength: integer;
153 | Easing: TEasingType; CycleTime: integer; StartDelay: integer);
154 | begin
155 | Animating(StartPos, Different, AnimLength, Easing, CycleTime, StartDelay, nil, nil);
156 | end;
157 |
158 | procedure TAnimateEasing.Animating(StartPos, Different, AnimLength: integer;
159 | Easing: TEasingType; CycleTime, StartDelay: integer;
160 | OnTickEvent: TAnimateTickEvent; OnFinishEvent: TANotifyEvent);
161 | begin
162 | FEasingFunc := GetEasingFunc(Easing);
163 | FStartPos := StartPos;
164 | FStartTime := Now;
165 | FDifferent := Different;
166 | FAnimLength := AnimLength;
167 | if Assigned(OnTickEvent) then OnTick := OnTickEvent;
168 | if Assigned(OnFinishEvent) then OnFinish := OnFinishEvent;
169 |
170 | FTimer.Enabled := false;
171 | FTimer.Interval := CycleTime;
172 |
173 | if StartDelay = -1 then
174 | FTimer.Enabled := true
175 | else
176 | begin
177 | FDelayTimer.Interval := StartDelay;
178 | FDelayTimer.Enabled := true;
179 | end;
180 | end;
181 |
182 | class function TAnimateEasing.GenerateValues(Different, StepCount: integer;
183 | Easing: TEasingType): TResultArray;
184 | var
185 | I: Integer;
186 | Value: Extended;
187 | EasingFunc: TEasingFunction;
188 | begin
189 | if StepCount = 0 then Exit;
190 |
191 | EasingFunc := GetEasingFunc(Easing);
192 | SetLength(result, StepCount);
193 | for I := 0 to StepCount - 1 do
194 | begin
195 | Value := EasingFunc(I / StepCount, 0, Different);
196 | result[I] := Value;
197 | end;
198 | end;
199 |
200 |
201 |
202 | {$REGION 'Easing functions'}
203 |
204 | class function TAnimateEasing.GetEasingFunc(Easing: TEasingType): TEasingFunction;
205 | begin
206 | case Easing of
207 | etBackEaseIn: result := BackEaseIn;
208 | etbackEaseOut: result := backEaseOut;
209 | etBackEaseInOut: result := BackEaseInOut;
210 | etBounceEaseIn: result := BounceEaseIn;
211 | etBounceEaseOut: result := BounceEaseOut;
212 | etCircEaseIn: result := CircEaseIn;
213 | etCircEaseOut: result := CircEaseOut;
214 | etCircEaseInOut: result := CircEaseInOut;
215 | etCubicEaseIn: result := CubicEaseIn;
216 | etCubicEaseOut: result := CubicEaseOut;
217 | etCubicEaseInOut: result := CubicEaseInOut;
218 | etElasticEaseIn: result := ElasticEaseIn;
219 | etElasticEaseOut: result := ElasticEaseOut;
220 | etExpoEaseIn: result := ExpoEaseIn;
221 | etExpoEaseOut: result := ExpoEaseOut;
222 | etExpoEaseInOut: result := ExpoEaseInOut;
223 | etQuadEaseIn: result := QuadEaseIn;
224 | etQuadEaseOut: result := QuadEaseOut;
225 | etQuadEaseInOut: result := QuadEaseInOut;
226 | etQuartEaseIn: result := QuartEaseIn;
227 | etQuartEaseOut: result := QuartEaseOut;
228 | etQuartEaseInOut: result := QuartEaseInOut;
229 | etQuintEaseIn: result := QuintEaseIn;
230 | etQuintEaseOut: result := QuintEaseOut;
231 | etQuintEaseInOut: result := QuintEaseInOut;
232 | etSineEaseIn: result := SineEaseIn;
233 | etSineEaseOut: result := SineEaseOut;
234 | etSineEaseInOut: result := SineEaseInOut;
235 | else
236 | result := QuartEaseInOut;
237 | end;
238 | end;
239 |
240 | class function TAnimateEasing.backEaseIn(p: Extended; firstNum: integer; diff: integer): Extended;
241 | var
242 | c, s: Extended;
243 | begin
244 | c := diff;
245 | s := 1.70158;
246 | result := c*p*p*((s+1)*p - s) + firstNum; //return c*(p/=1)*p*((s+1)*p - s) + firstNum;
247 | end;
248 |
249 | class function TAnimateEasing.backEaseOut(p: Extended; firstNum: integer; diff: integer): Extended;
250 | var
251 | c, s: Extended;
252 | begin
253 | c := diff;
254 | s := 1.70158;
255 | p := p - 1;
256 | result := c*(p*p*((s+1)*p + s) + 1) + firstNum; //return c*((p=p/1-1)*p*((s+1)*p + s) + 1) + firstNum;
257 | end;
258 |
259 | class function TAnimateEasing.backEaseInOut(p: Extended; firstNum: integer; diff: integer): Extended;
260 | var
261 | c, s: Extended;
262 | begin
263 | c := diff;
264 | s := 1.70158 * 1.525;
265 | p := p / 0.5;
266 | if (p < 1) then
267 | result := c/2*(p*p*((s + 1)*p - s)) + firstNum //return c/2*(p*p*(((s*=(1.525))+1)*p - s)) + firstNum;
268 | else
269 | begin
270 | p := p - 2;
271 | result := c/2*(p*p*((s + 1)*p + s) + 2) + firstNum; //return c/2*((p-=2)*p*(((s*=(1.525))+1)*p + s) + 2) + firstNum;
272 | end;
273 | end;
274 |
275 | class function TAnimateEasing.bounceEaseIn(p: Extended; firstNum: integer; diff: integer): Extended;
276 | var
277 | c, inv: Extended;
278 | begin
279 | c := diff;
280 | inv := bounceEaseOut(1 - p, 0, diff);
281 | result := c - inv + firstNum;
282 | end;
283 |
284 | class function TAnimateEasing.bounceEaseOut(p: Extended; firstNum: integer; diff: integer): Extended;
285 | var
286 | c: Extended;
287 | begin
288 | c := diff;
289 | if ( p < 1/2.75) then
290 | result := c*(7.5625*p*p) + firstNum
291 | else if (p < 2/2.75) then
292 | begin
293 | p := p - (1.5/2.75);
294 | result := c*(7.5625*p*p + 0.75) + firstNum;
295 | end
296 | else if (p < 2.5/2.75) then
297 | begin
298 | p := p - (2.25/2.75);
299 | result := c*(7.5625*p*p + 0.9375) + firstNum;
300 | end
301 | else
302 | begin
303 | p := p - (2.625/2.75);
304 | result := c*(7.5625*p*p + 0.984375) + firstNum;
305 | end;
306 | end;
307 |
308 | class function TAnimateEasing.circEaseIn(p: Extended; firstNum: integer; diff: integer): Extended;
309 | var
310 | c: Extended;
311 | begin
312 | c := diff;
313 | result := -c * (sqrt(1 - p*p) - 1 ) + firstNum; //return -c * (Math.sqrt(1 - (p/=1)*p) - 1) + firstNum;
314 | end;
315 |
316 | class function TAnimateEasing.circEaseOut(p: Extended; firstNum: integer; diff: integer): Extended;
317 | var
318 | c: Extended;
319 | begin
320 | c := diff;
321 | p := p - 1;
322 | result := c * sqrt(1 - p*p) + firstNum; //return c * Math.sqrt(1 - (p=p/1-1)*p) + firstNum;
323 | end;
324 |
325 | class function TAnimateEasing.circEaseInOut(p: Extended; firstNum: integer; diff: integer): Extended;
326 | var
327 | c: Extended;
328 | begin
329 | c := diff;
330 | p := p / 0.5;
331 | if (p < 1) then
332 | result := -c/2 * (sqrt(1 - p*p) - 1) + firstNum //return -c/2 * (Math.sqrt(1 - p*p) - 1) + firstNum;
333 | else
334 | begin
335 | p := p - 2;
336 | result := c/2 * (sqrt(1 - p*p) + 1) + firstNum //return c/2 * (Math.sqrt(1 - (p-=2)*p) + 1) + firstNum;
337 | end;
338 | end;
339 |
340 | class function TAnimateEasing.cubicEaseIn(p: Extended; firstNum: integer; diff: integer): Extended;
341 | var
342 | c: Extended;
343 | begin
344 | c := diff;
345 | result := c * (p*p*p) + firstNum; //return c*(p/=1)*p*p + firstNum;
346 | end;
347 |
348 | class function TAnimateEasing.cubicEaseOut(p: Extended; firstNum: integer; diff: integer): Extended;
349 | var
350 | c: Extended;
351 | begin
352 | // c := diff;
353 | c := diff;
354 | p := p -1;
355 | result := c * (p*p*p + 1) + firstNum; //return c*(p/=1)*p*p + firstNum;
356 | end;
357 |
358 | class function TAnimateEasing.cubicEaseInOut(p: Extended; firstNum: integer; diff: integer): Extended;
359 | var
360 | c: Extended;
361 | begin
362 | c := diff;
363 | p := p / 0.5;
364 | if (p < 1) then
365 | result := c/2*p*p*p + firstNum //return c/2*p*p*p + firstNum;
366 | else
367 | begin
368 | p := p - 2;
369 | result := c/2*(p*p*p + 2) + firstNum; //return c/2*((p-=2)*p*p + 2) + firstNum;
370 | end;
371 | end;
372 |
373 | class function TAnimateEasing.elasticEaseIn(p: Extended; firstNum: integer; diff: integer): Extended;
374 | var
375 | c, period, s, amplitude: Extended;
376 | begin
377 | c := diff;
378 |
379 | if p = 0 then Exit(firstNum);
380 | if p = 1 then Exit(c);
381 |
382 | period := 0.25;
383 | amplitude := c;
384 |
385 | if (amplitude < abs(c)) then
386 | begin
387 | amplitude := c;
388 | s := period / 4;
389 | end
390 | else
391 | begin
392 | s := period/(2*PI) * Math.ArcSin(c/amplitude);
393 | end;
394 | p := p - 1;
395 | result := -(amplitude*Math.Power(2, 10*p) * sin( (p*1-s)*(2*PI)/period)) + firstNum;
396 | end;
397 |
398 | class function TAnimateEasing.elasticEaseOut(p: Extended; firstNum: integer; diff: integer): Extended;
399 | var
400 | c, period, s, amplitude: Extended;
401 | begin
402 | c := diff;
403 |
404 | if diff = 0 then Exit(c); //Divide by zero protect
405 | if p = 0 then Exit(firstNum);
406 | if p = 1 then Exit(c);
407 |
408 | period := 0.25;
409 | amplitude := c;
410 |
411 | if (amplitude < abs(c)) then
412 | begin
413 | amplitude := c;
414 | s := period / 4;
415 | end
416 | else
417 | begin
418 | s := period/(2*PI) * Math.ArcSin(c/amplitude);
419 | end;
420 | result := -(amplitude*Math.Power(2, -10*p) * sin( (p*1-s)*(2*PI)/period)) + c + firstNum;
421 | end;
422 |
423 | class function TAnimateEasing.expoEaseIn(p: Extended; firstNum: integer; diff: integer): Extended;
424 | var
425 | c: Extended;
426 | begin
427 | c := diff;
428 |
429 | if (p = 0) then
430 | result := firstNum
431 | else
432 | begin
433 | p := p - 1;
434 | result := c * Math.Power(2, 10*p) + firstNum - c * 0.001;
435 | end;
436 | end;
437 |
438 | class function TAnimateEasing.expoEaseOut(p: Extended; firstNum: integer; diff: integer): Extended;
439 | var
440 | c: Extended;
441 | begin
442 | c := diff;
443 |
444 | if (p = 1) then
445 | result := c
446 | else
447 | begin
448 | result := diff * 1.001 * (-Math.Power(2, -10*p) + 1) + firstNum;
449 | end;
450 | end;
451 |
452 | class function TAnimateEasing.expoEaseInOut(p: Extended; firstNum: integer; diff: integer): Extended;
453 | var
454 | c: Extended;
455 | begin
456 | c := diff;
457 |
458 | if (p = 0) then Exit(firstNum);
459 | if (p = 1) then Exit(c);
460 |
461 | p := p / 0.5;
462 | if p < 1 then
463 | result := c/2 * Math.Power(2, 10 * (p-1)) + firstNum - c * 0.0005
464 | else
465 | begin
466 | p := p - 1;
467 | result := c/2 * 1.0005 * (-Math.Power(2, -10 * p) + 2) + firstNum;
468 | end;
469 | end;
470 |
471 | class function TAnimateEasing.quadEaseIn(p: Extended; firstNum: integer; diff: integer): Extended;
472 | var
473 | c: Extended;
474 | begin
475 | c := diff;
476 |
477 | result := c * p*p + firstNum;
478 | end;
479 |
480 | class function TAnimateEasing.quadEaseOut(p: Extended; firstNum: integer; diff: integer): Extended;
481 | var
482 | c: Extended;
483 | begin
484 | c := diff;
485 |
486 | result := -c * p*(p-2) + firstNum;
487 | end;
488 |
489 | class function TAnimateEasing.quadEaseInOut(p: Extended; firstNum: integer; diff: integer): Extended;
490 | var
491 | c: Extended;
492 | begin
493 | c := diff;
494 |
495 | p := p / 0.5;
496 | if p < 1 then
497 | result := c/2*p*p + firstNum
498 | else
499 | begin
500 | p := p - 1;
501 | result := -c/2 * (p*(p-2) - 1) + firstNum;
502 | end;
503 | end;
504 |
505 | class function TAnimateEasing.quartEaseIn(p: Extended; firstNum: integer; diff: integer): Extended;
506 | var
507 | c: Extended;
508 | begin
509 | c := diff;
510 |
511 | result := c * p*p*p*p + firstNum;
512 | end;
513 |
514 | class function TAnimateEasing.quartEaseOut(p: Extended; firstNum: integer; diff: integer): Extended;
515 | var
516 | c: Extended;
517 | begin
518 | c := diff;
519 |
520 | p := p - 1;
521 | result := -c * (p*p*p*p - 1) + firstNum;
522 | end;
523 |
524 | class function TAnimateEasing.quartEaseInOut(p: Extended; firstNum: integer; diff: integer): Extended;
525 | var
526 | c: Extended;
527 | begin
528 | c := diff;
529 |
530 | p := p / 0.5;
531 | if p < 1 then
532 | result := c/2*p*p*p*p + firstNum
533 | else
534 | begin
535 | p := p - 2;
536 | result := -c/2 * (p*p*p*p - 2) + firstNum;
537 | end;
538 | end;
539 |
540 | class function TAnimateEasing.quintEaseIn(p: Extended; firstNum: integer; diff: integer): Extended;
541 | var
542 | c: Extended;
543 | begin
544 | c := diff;
545 |
546 | result := c * p*p*p*p*p + firstNum;
547 | end;
548 |
549 | class function TAnimateEasing.quintEaseOut(p: Extended; firstNum: integer; diff: integer): Extended;
550 | var
551 | c: Extended;
552 | begin
553 | c := diff;
554 |
555 | p := p - 1;
556 | result := c * (p*p*p*p*p + 1) + firstNum;
557 | end;
558 |
559 | class function TAnimateEasing.quintEaseInOut(p: Extended; firstNum: integer; diff: integer): Extended;
560 | var
561 | c: Extended;
562 | begin
563 | c := diff;
564 |
565 | p := p / 0.5;
566 | if p < 1 then
567 | result := c/2*p*p*p*p*p + firstNum
568 | else
569 | begin
570 | p := p - 2;
571 | result := c/2 * (p*p*p*p*p + 2) + firstNum;
572 | end;
573 | end;
574 |
575 | class function TAnimateEasing.sineEaseIn(p: Extended; firstNum: integer; diff: integer): Extended;
576 | var
577 | c: Extended;
578 | begin
579 | c := diff;
580 |
581 | result := -c * cos(p*(PI/2)) + c + firstNum;
582 | end;
583 |
584 | class function TAnimateEasing.sineEaseOut(p: Extended; firstNum: integer; diff: integer): Extended;
585 | var
586 | c: Extended;
587 | begin
588 | c := diff;
589 |
590 | result := c * sin(p*(PI/2)) + firstNum;
591 | end;
592 |
593 | class function TAnimateEasing.sineEaseInOut(p: Extended; firstNum: integer; diff: integer): Extended;
594 | var
595 | c: Extended;
596 | begin
597 | c := diff;
598 |
599 | result := -c/2 * (cos(PI*p) - 1) + firstNum;
600 | end;
601 | {$ENDREGION}
602 |
603 | constructor TAnimateEasing.Create;
604 | begin
605 | FTimer := TTimer.Create(nil);
606 | FTimer.Enabled := false;
607 | FTimer.Interval := 10;
608 | FTimer.OnTimer := FTimerTimer;
609 |
610 | FDelayTimer := TTimer.Create(nil);
611 | FDelayTimer.Enabled := false;
612 | FDelayTimer.OnTimer := FDelayTimerTimer;
613 | end;
614 |
615 | destructor TAnimateEasing.Destroy;
616 | begin
617 | FTimer.Free;
618 | FDelayTimer.Free;
619 |
620 | inherited;
621 | end;
622 |
623 |
624 | procedure TAnimateEasing.FDelayTimerTimer(Sender: TObject);
625 | begin
626 | FDelayTimer.Enabled := false;
627 | FStartTime := Now;
628 | FTimer.Enabled := true;
629 | end;
630 |
631 | procedure TAnimateEasing.FTimerTimer(Sender: TObject);
632 | var
633 | Value: Extended;
634 | begin
635 | FTimer.Enabled := false;
636 | Value := FEasingFunc(MilliSecondsBetween(FStartTime, Now) / FAnimLength, FStartPos, FDifferent);
637 | if Assigned(OnTick) then
638 | OnTick(Self, Value);
639 |
640 | if dateUtils.MilliSecondsBetween(FStartTime, Now) < FAnimLength then
641 | begin
642 | FTimer.Enabled := true;
643 | end
644 | else
645 | begin
646 | FinishAnim;
647 | end;
648 | end;
649 |
650 | procedure TAnimateEasing.FinishAnim;
651 | begin
652 | if Assigned(OnFinish) then
653 | OnFinish(Self);
654 | end;
655 |
656 | procedure TAnimateEasing.StopAnimating;
657 | begin
658 | FTimer.Enabled := false;
659 | FDelayTimer.Enabled := false;
660 | FinishAnim;
661 | end;
662 |
663 | procedure TAnimateEasing.SetOnFinish(const Value: TANotifyEvent);
664 | begin
665 | FOnFinish := Value;
666 | end;
667 |
668 | procedure TAnimateEasing.SetOnTick(const Value: TAnimateTickEvent);
669 | begin
670 | FOnTick := Value;
671 | end;
672 |
673 | end.
674 |
--------------------------------------------------------------------------------