|
@@ -0,0 +1,1469 @@
|
|
|
|
|
+/********************************************************************************************
|
|
|
|
|
+ * Notify - Simplifies the creation and display of notification GUIs.
|
|
|
|
|
+ * @author Martin Chartier (XMCQCX)
|
|
|
|
|
+ * @date 2024/11/20
|
|
|
|
|
+ * @version 1.7.0
|
|
|
|
|
+ * @see {@link https://github.com/XMCQCX/NotifyClass-NotifyCreator GitHub}
|
|
|
|
|
+ * @see {@link https://www.autohotkey.com/boards/viewtopic.php?f=83&t=129635 AHK Forum}
|
|
|
|
|
+ * @license MIT license
|
|
|
|
|
+ * @credits
|
|
|
|
|
+ * - JSON by thqby, HotKeyIt. {@link https://github.com/thqby/ahk2_lib/blob/master/JSON.ahk GitHub}
|
|
|
|
|
+ * - FrameShadow by Klark92. {@link https://www.autohotkey.com/boards/viewtopic.php?f=6&t=29117&hilit=FrameShadow AHK Forum}
|
|
|
|
|
+ * - DrawBorder by ericreeves. {@link https://gist.github.com/ericreeves/fd426cc0457a5a47058e1ad1a29d9bd6 GitHub}
|
|
|
|
|
+ * - CalculatePopupWindowPosition by lexikos {@link https://www.autohotkey.com/boards/viewtopic.php?t=103459 AHK Forum}
|
|
|
|
|
+ * - Notify by gwarble. {@link https://www.autohotkey.com/board/topic/44870-notify-multiple-easy-tray-area-notifications-v04991/ AHK Forum}
|
|
|
|
|
+ * - Notify by the-Automator. {@link https://www.the-automator.com/downloads/maestrith-notify-class-v2/ the-automator.com}
|
|
|
|
|
+ * - WiseGui by SKAN. {@link https://www.autohotkey.com/boards/viewtopic.php?t=94044 AHK Forum}
|
|
|
|
|
+ * @features
|
|
|
|
|
+ * - Customize various parameters such as text, font, color, image, sound, animation, and more.
|
|
|
|
|
+ * - Choose from built-in themes or create your own custom themes with Notify Creator.
|
|
|
|
|
+ * - Rounded or edged corners.
|
|
|
|
|
+ * - Position at different locations on the screen.
|
|
|
|
|
+ * - GUI stacking and repositioning.
|
|
|
|
|
+ * - Multi-Monitor support.
|
|
|
|
|
+ * - Multi-Script support.
|
|
|
|
|
+ * - Call a function when clicking on it.
|
|
|
|
|
+ * @methods
|
|
|
|
|
+ * - Show(title, msg, image, sound, callback, options) - Builds and displays a notification GUI.
|
|
|
|
|
+ * - Destroy(param) - Destroys GUIs.
|
|
|
|
|
+ * - Window handle (hwnd) - Destroys the GUI with the specified window handle.
|
|
|
|
|
+ * - tag - Destroys every GUI containing this tag across all scripts.
|
|
|
|
|
+ * - 'oldest' or no param - Destroys the oldest GUI.
|
|
|
|
|
+ * - 'latest' - Destroys the most recent GUI.
|
|
|
|
|
+ * - DestroyAllOnMonitorAtPosition(monitorNumber, position) - Destroys all GUIs on a specific monitor at a given position.
|
|
|
|
|
+ * - DestroyAllOnAllMonitorAtPosition(position) - Destroys all GUIs on all monitors at a specific position.
|
|
|
|
|
+ * - DestroyAllOnMonitor(monitorNumber) - Destroys all GUIs on a specific monitor.
|
|
|
|
|
+ * - DestroyAll() - Destroys all GUIs.
|
|
|
|
|
+ * - Exist(tag) - Checks if a GUI with the specified tag exists and returns the unique ID (HWND) of the first matching GUI.
|
|
|
|
|
+ * - SetDefaultTheme(theme) - Set a different theme as the default.
|
|
|
|
|
+ ********************************************************************************************/
|
|
|
|
|
+Class Notify {
|
|
|
|
|
+
|
|
|
|
|
+/********************************************************************************************
|
|
|
|
|
+ * @method Show(title, msg, image, sound, callback, options)
|
|
|
|
|
+ * @description Builds and displays a notification GUI.
|
|
|
|
|
+ * @param title Title
|
|
|
|
|
+ * @param msg Message
|
|
|
|
|
+ * @param image
|
|
|
|
|
+ * - The path of an image.
|
|
|
|
|
+ * - String: `'icon!'`, `'icon?'`, `'iconx'`, `'iconi'`
|
|
|
|
|
+ * - Icon from dll. For example: `'C:\Windows\System32\imageres.dll|icon19'`
|
|
|
|
|
+ * - Image Handle. For example: 'HICON:' hwnd
|
|
|
|
|
+ * - Filename of image located in "Pictures\Notify".
|
|
|
|
|
+ * - Supported file types: `.ico, .dll, .exe, .cpl, .png, .jpeg, .jpg, .gif, .bmp, .tif`
|
|
|
|
|
+ * @param sound
|
|
|
|
|
+ * - The path of the WAV file to be played.
|
|
|
|
|
+ * - String: `'soundx'`, `'soundi'`
|
|
|
|
|
+ * - Filename of WAV file located in "C:\Windows\Media" or "Music\Sounds". For example: `'Ding'`, `'tada'`, `'Windows Error'` etc.
|
|
|
|
|
+ * - Use Notify Creator to view and play all available notification sounds.
|
|
|
|
|
+ * @param callback Function object to call when left-clicking on the GUI.
|
|
|
|
|
+ * @param options For example: `'POS=TL DUR=6 IW=70 TF=Impact TS=42 TC=GREEN MC=blue BC=Silver STYLE=edge SHOW=Fade Hide=Fade@250'`
|
|
|
|
|
+ * - The string is case-insensitive.
|
|
|
|
|
+ * - The asterisk (*) indicates the default option.
|
|
|
|
|
+ * - `THEME` - Built-in themes and user-created themes.
|
|
|
|
|
+ * - Use Notify Creator to view all themes and their visual appearance.
|
|
|
|
|
+ * - `POS` - Position
|
|
|
|
|
+ * - `BR` - Bottom right*
|
|
|
|
|
+ * - `BC` - Bottom center
|
|
|
|
|
+ * - `BL` - Bottom left
|
|
|
|
|
+ * - `TL` - Top left
|
|
|
|
|
+ * - `TC` - Top center
|
|
|
|
|
+ * - `TR` - Top right
|
|
|
|
|
+ * - `CT` - Center
|
|
|
|
|
+ * - `CTL` - Center left
|
|
|
|
|
+ * - `CTR` - Center right
|
|
|
|
|
+ * - `Mouse` - Near the cursor.
|
|
|
|
|
+ * - `DUR` - Display duration (in seconds). Set to 0 to keep it on the screen until left-clicking on the GUI or programmatically destroying it. `*8`
|
|
|
|
|
+ * - `MON` - Monitor number to display the GUI. AutoHotkey monitor numbers differ from those in Windows Display settings or NVIDIA Control Panel.
|
|
|
|
|
+ * - `Primary`* - The primary monitor.
|
|
|
|
|
+ * - `Active` - The monitor on which the active window is displayed.
|
|
|
|
|
+ * - `Mouse` - The monitor on which the mouse is currently positioned.
|
|
|
|
|
+ * - `IW` - Image width - `*32` If only one dimension is specified, the other dimension will automatically adjust to preserve the aspect ratio.
|
|
|
|
|
+ * - `IH` - Image height `*-1`
|
|
|
|
|
+ * - `iw=0` or `ih=0` - Uses the actual dimensions of the image.
|
|
|
|
|
+ * - `TF` - Title font `*Segoe UI`
|
|
|
|
|
+ * - `TFO` - Title font options. `*Bold` For example: `tfo=underline italic strike`
|
|
|
|
|
+ * - `TS` - Title size `*15`
|
|
|
|
|
+ * - `TC` - Title color `*White`
|
|
|
|
|
+ * - `TALI` - Title alignment
|
|
|
|
|
+ * - `LEFT`*
|
|
|
|
|
+ * - `RIGHT`
|
|
|
|
|
+ * - `CENTER`
|
|
|
|
|
+ * - `MF` - Message font `*Segoe UI`
|
|
|
|
|
+ * - `MFO` - Message font options. For example: `mfo=underline italic strike`
|
|
|
|
|
+ * - `MS` - Message size `*12`
|
|
|
|
|
+ * - `MC` - Message color `*0xEAEAEA`
|
|
|
|
|
+ * - `MALI` - Message alignment
|
|
|
|
|
+ * - `LEFT`*
|
|
|
|
|
+ * - `RIGHT`
|
|
|
|
|
+ * - `CENTER`
|
|
|
|
|
+ * - `PROG` - Progress bar. For example: `prog=1`, `prog=h40 cGreen`, `prog=w400`, {@link https://www.autohotkey.com/docs/v2/lib/GuiControls.htm#Progress Progress Options}
|
|
|
|
|
+ * - `BC` - Background color `*0x1F1F1F`
|
|
|
|
|
+ * - `STYLE` - Notification Appearance
|
|
|
|
|
+ * - `ROUND` - Rounded corners*
|
|
|
|
|
+ * - `EDGE` - Edged corners
|
|
|
|
|
+ * - `BDR` - Border. For example: `bdr=Aqua`,`bdr=Red,4`
|
|
|
|
|
+ * - The round style's maximum border width is limited to 1 pixel, while the edge style allows up to 5 pixels.
|
|
|
|
|
+ * - If the theme includes a border and the style is set to edge, you can specify only the border width like this: `bdr=,3`
|
|
|
|
|
+ * - `0` - No border
|
|
|
|
|
+ * - `1` - Border
|
|
|
|
|
+ * - `Default`
|
|
|
|
|
+ * - `Color`
|
|
|
|
|
+ * - `Color,border width` - Specify color and width, separated by a comma.
|
|
|
|
|
+ * - `PAD` - Comma-separated values. Can range from 0 to 25. For example: `pad=0,0,15,15,5,10`, `pad=,10`
|
|
|
|
|
+ * - If values aren’t specified, the default padding settings for the style will be set.
|
|
|
|
|
+ * - PadX - Padding between the left or right edge of the GUI and the screen's edge.
|
|
|
|
|
+ * - PadY - Padding between the top or bottom edge of the GUI and the screen's edge.
|
|
|
|
|
+ * - GMX - Left/right margins of the GUI.
|
|
|
|
|
+ * - GMY - Top/bottom margins of the GUI.
|
|
|
|
|
+ * - SpX - Horizontal spacing between the right side of the image and other controls.
|
|
|
|
|
+ * - SpY - Vertical spacing between the title, message, and progress bar.
|
|
|
|
|
+ * - `MAXW` - Maximum width of the GUI (excluding image width and margins).
|
|
|
|
|
+ * - `WSTC` - WinSetTransColor. Not compatible with the round style, fade animation. For example: `style=edge bdr=0 bc=black WSTC=black` {@link https://www.autohotkey.com/docs/v2/lib/WinSetTransColor.htm WinSetTransColor}
|
|
|
|
|
+ * - `WSTP` - WinSetTransparent. Not compatible with the round style, fade animation. For example: `style=edge wstp=120` {@link https://www.autohotkey.com/docs/v2/lib/WinSetTransparent.htm WinSetTransparent}
|
|
|
|
|
+ * - `SHOW` and `HIDE` - Animation when showing and destroying the GUI. The duration, which is optional, can range from 1 to 2500 milliseconds. For example: `STYLE=EDGE SHOW=SlideNorth HIDE=SlideSouth@250`
|
|
|
|
|
+ * - The round style is not compatible with most animations. It renders only the fade-in (Show=fade) animation correctly. If the round style and fade-out (Hide=fade) are used, the corners become edged during the animation.
|
|
|
|
|
+ * - If animations aren’t specified, the default animations for the style and position will be set.
|
|
|
|
|
+ * - `None`
|
|
|
|
|
+ * - `Fade`
|
|
|
|
|
+ * - `Expand`
|
|
|
|
|
+ * - `SlideEast`
|
|
|
|
|
+ * - `SlideWest`
|
|
|
|
|
+ * - `SlideNorth`
|
|
|
|
|
+ * - `SlideSouth`
|
|
|
|
|
+ * - `SlideNorthEast`
|
|
|
|
|
+ * - `SlideNorthWest`
|
|
|
|
|
+ * - `SlideSouthEast`
|
|
|
|
|
+ * - `SlideSouthWest`
|
|
|
|
|
+ * - `RollEast`
|
|
|
|
|
+ * - `RollWest`
|
|
|
|
|
+ * - `RollNorth`
|
|
|
|
|
+ * - `RollSouth`
|
|
|
|
|
+ * - `RollNorthEast`
|
|
|
|
|
+ * - `RollNorthWest`
|
|
|
|
|
+ * - `RollSouthEast`
|
|
|
|
|
+ * - `RollSouthWest`
|
|
|
|
|
+ * - `TAG` - Marker to identify a GUI. The Destroy method accepts a handle or a tag, it destroys every GUI containing this tag across all scripts.
|
|
|
|
|
+ * - `DGC` - Destroy GUI click. Allow or prevent the GUI from being destroyed when clicked.
|
|
|
|
|
+ * - `0` - Clicking on the GUI does not destroy it.
|
|
|
|
|
+ * - `1` - Clicking on the GUI destroys it.*
|
|
|
|
|
+ * - `DG` - Destroy GUIs before creating the new GUI.
|
|
|
|
|
+ * - `0` - Do not destroy GUIs.*
|
|
|
|
|
+ * - `1` - Destroy all GUIs on the monitor option at the position option.
|
|
|
|
|
+ * - `2` - Destroy all GUIs on all monitors at the position option.
|
|
|
|
|
+ * - `3` - Destroy all GUIs on the monitor option.
|
|
|
|
|
+ * - `4` - Destroy all GUIs.
|
|
|
|
|
+ * - `5` - Destroy all GUIs containing the tag. For example: `dg=5 tag=myTAG`
|
|
|
|
|
+ * - `OPT` - Sets various options and styles for the appearance and behavior of the window. `*+Owner -Caption +AlwaysOnTop` {@link https://www.autohotkey.com/docs/v2/lib/Gui.htm#Opt GUI Opt}
|
|
|
|
|
+ * @returns Map object
|
|
|
|
|
+********************************************************************************************/
|
|
|
|
|
+ static Show(title:='', msg:='', image:='', sound:='', callback:='', options:='') => this._Show(title, msg, image, sound, callback, options)
|
|
|
|
|
+
|
|
|
|
|
+ static __New()
|
|
|
|
|
+ {
|
|
|
|
|
+ this.mNotifyGUIs := this.MapCI()
|
|
|
|
|
+ this.mThemesStrings := this.MapCI().Set(
|
|
|
|
|
+ 'Light', 'tc=Black mc=Black bc=White',
|
|
|
|
|
+ 'Dark', 'tc=White mc=0xEAEAEA bc=0x1F1F1F',
|
|
|
|
|
+ 'Matrix', 'tc=Lime mc=0x00FF7F bc=Black bdr=0x00FF7F tf=Consolas mf=Lucida Console',
|
|
|
|
|
+ 'Cyberpunk', 'tc=0xFF005F mc=Aqua bc=0x0D0D0D bdr=Aqua tf=Consolas mf=Lucida Console',
|
|
|
|
|
+ 'Cybernetic', 'tc=Aqua mc=0xFF005F bc=0x1A1A1A bdr=0xFF005F tf=Lucida Console mf=Consolas',
|
|
|
|
|
+ 'Synthwave', 'tc=Fuchsia mc=Aqua bc=0x1A0E2F bdr=Aqua tf=Consolas mf=Arial',
|
|
|
|
|
+ 'Dracula', 'tc=0xFF79C6 mc=0x8BE9FD bc=0x282A36 bdr=0x8BE9FD tf=Consolas mf=Arial',
|
|
|
|
|
+ 'Monokai', 'tc=0xF8F8F2 mc=0xA6E22E bc=0x272822 bdr=0xE8F7C8 tf=Lucida Console mf=Tahoma',
|
|
|
|
|
+ 'Solarized Dark', 'tc=0xB58900 mc=0x839496 bc=0x002B36 bdr=0x839496 tf=Consolas mf=Calibri',
|
|
|
|
|
+ 'Atomic', 'tc=0xE49013 mc=0xDFCA9B bc=0x1F1F1F bdr=0xDFCA9B tf=Consolas mf=Lucida Console',
|
|
|
|
|
+ 'PCB', 'tc=0xCCAA00 mc=0x00CC00 bc=0x002200 bdr=0x00CC00 tf=Consolas mf=Arial',
|
|
|
|
|
+ 'Aurora', 'tc=0x47F0AC mc=0xEAEAEA bc=0x0C1631 bdr=0x47F0AC',
|
|
|
|
|
+ 'Milky Way', 'tc=0x9370DB mc=0xE0E1DD bc=0x0D1B2A bdr=0xE0E1DD tf=Trebuchet MS mf=Calibri',
|
|
|
|
|
+ 'Venom', 'tc=0xF9EA2C mc=0xFAF2A4 bc=0x317140 tf=Segoe UI mf=Segoe UI bdr=0x86EE99',
|
|
|
|
|
+ 'Gator', 'tc=0xADFF2F mc=0xF0FFF0 bc=0x006400 bdr=0x7CCD7C',
|
|
|
|
|
+ 'Forum', 'tc=0x3F5770 mc=0x272727 bc=0xDFDFDF bdr=0x686868',
|
|
|
|
|
+ 'Cappuccino', 'tc=0x6F4E37 mc=0x886434 bc=0xFFF8DC bdr=0x886434 tf=Trebuchet MS mf=Times New Roman',
|
|
|
|
|
+ 'Earthy', 'tc=0xF5FFFA mc=0x4DCA22 bc=0x3E2723 bdr=0x41A91D tf=Lucida Console mf=Arial',
|
|
|
|
|
+ 'Rust', 'tc=0xFFC107 mc=0xF5DEB3 bc=0x8F3209 bdr=0xF5DEB3 tf=Georgia mf=Arial',
|
|
|
|
|
+ 'Galactic', 'tc=0xFFD700 mc=White bc=Black bdr=White tf=Verdana mf=Arial',
|
|
|
|
|
+ 'Steampunk', 'tc=0xFFD700 mc=0xB87333 bc=0x3E2723 bdr=0xFFD700 tf=Trebuchet MS mf=Times New Roman',
|
|
|
|
|
+ 'Pastel', 'tc=0xFF69B4 mc=0x0072E3 bc=0xFFF0F5 bdr=0x0072E3 tf=Calibri',
|
|
|
|
|
+ 'Nature', 'tc=0x2E8B57 mc=0x4A5E4A bc=0xE8F3E8 bdr=0x4A5E4A tf=Trebuchet MS',
|
|
|
|
|
+ 'Pink Light', 'tc=0xFF1493 mc=0xFF69B4 bc=0xFFE4E1 bdr=0xFF69B4 tf=Comic Sans MS mf=Verdana',
|
|
|
|
|
+ 'Pink Dark', 'tc=0xFF1493 mc=0xFF69B4 bc=0x1F1F1F bdr=0xFF69B4 tf=Comic Sans MS mf=Verdana',
|
|
|
|
|
+ 'Sticky', 'tc=Black mc=0x333333 bc=0xF9E15B bdr=0x5F5103 tf=Arial mf=Verdana',
|
|
|
|
|
+ 'OK', 'tc=Black mc=Black bc=0x49C149 bdr=0x336F50',
|
|
|
|
|
+ 'OKLight', 'tc=0x52CB43 mc=Black bc=0xF1F8F4 bdr=0x52CB43',
|
|
|
|
|
+ 'OKDark', 'tc=0x52CB43 mc=0xEAEAEA bc=0x1F1F1F bdr=0x52CB43 ',
|
|
|
|
|
+ 'x', 'tc=White mc=0xEAEAEA bc=0xC61111 bdr=0xEAEAEA image=iconx',
|
|
|
|
|
+ 'i', 'tc=White mc=0xEAEAEA bc=0x4682B4 bdr=0xEAEAEA image=iconi',
|
|
|
|
|
+ '!', 'tc=Black mc=Black bc=0xFFD953 bdr=0x6F5600 image=icon!',
|
|
|
|
|
+ '?', 'tc=White mc=0xEAEAEA bc=0x4682B4 bdr=0xEAEAEA image=icon?',
|
|
|
|
|
+ 'xLight', 'tc=0xC61111 mc=Black bc=0xFBEFEB bdr=0xC61111 image=iconx',
|
|
|
|
|
+ '!Light', 'tc=0xE1AA04 mc=Black bc=0xFEF8EB bdr=0xE1AA04 image=icon!',
|
|
|
|
|
+ 'iLight', 'tc=0x2543AC mc=Black bc=0xE7EFFA bdr=0x2543AC image=iconi',
|
|
|
|
|
+ '?Light', 'tc=0x2543AC mc=Black bc=0xE7EFFA bdr=0x2543AC image=icon?',
|
|
|
|
|
+ 'xDark', 'tc=0xC61111 mc=0xEAEAEA bc=0x1F1F1F bdr=0xC61111 image=iconx',
|
|
|
|
|
+ '!Dark', 'tc=0xDEA309 mc=0xEAEAEA bc=0x1F1F1F bdr=0xDEA309 image=icon!',
|
|
|
|
|
+ 'iDark', 'tc=0x41A5EE mc=0xEAEAEA bc=0x1F1F1F bdr=0x41A5EE image=iconi',
|
|
|
|
|
+ '?Dark', 'tc=0x41A5EE mc=0xEAEAEA bc=0x1F1F1F bdr=0x41A5EE image=icon?',
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ this.mDefaults := this.MapCI().Set(
|
|
|
|
|
+ 'theme', 'Default',
|
|
|
|
|
+ 'style', 'Round',
|
|
|
|
|
+ 'mon', 'Primary', ; Monitor
|
|
|
|
|
+ 'pos', 'BR', ; Position
|
|
|
|
|
+ 'dur', 8, ; Duration
|
|
|
|
|
+ 'iw', 32, ; Image width
|
|
|
|
|
+ 'ih', -1, ; Image height
|
|
|
|
|
+ 'tf', 'Segoe UI', ; Title font
|
|
|
|
|
+ 'tfo', 'norm Bold', ; Title font options
|
|
|
|
|
+ 'ts', 15, ; Title size
|
|
|
|
|
+ 'tc', 'White', ; Title color
|
|
|
|
|
+ 'tali', 'Left', ; Title alignment
|
|
|
|
|
+ 'mf', 'Segoe UI', ; Message font
|
|
|
|
|
+ 'mfo', 'norm', ; Message font options
|
|
|
|
|
+ 'ms', 12, ; Message size
|
|
|
|
|
+ 'mc', '0xEAEAEA', ; Message color
|
|
|
|
|
+ 'mali', 'Left', ; Message alignment
|
|
|
|
|
+ 'bc', '0x1F1F1F', ; Background color
|
|
|
|
|
+ 'dg', 0, ; Destroy GUIs
|
|
|
|
|
+ 'dgc', 1, ; Destroy GUI click
|
|
|
|
|
+ 'bdr', 'Default', ; Border
|
|
|
|
|
+ 'prog', '', ; Progress bar
|
|
|
|
|
+ 'wstc', '', ; WinSetTransColor
|
|
|
|
|
+ 'wstp', '', ; WinSetTransparent
|
|
|
|
|
+ 'maxW', '', ; Maximum width
|
|
|
|
|
+ 'tag', '', ; GUI window title identifying marker
|
|
|
|
|
+ 'opt', '+Owner -Caption +AlwaysOnTop',
|
|
|
|
|
+ 'image', 'None',
|
|
|
|
|
+ 'sound', 'None',
|
|
|
|
|
+ 'pad', ',,16,16,8,10'
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ this.padG := 10 ; Pad between GUIs
|
|
|
|
|
+ this.bdrWdefaultEdge := 2
|
|
|
|
|
+ this.arrBdrWrange := [1,5]
|
|
|
|
|
+ this.arrPadRange := [0,25]
|
|
|
|
|
+ this.ParsePadOption(this.mDefaults)
|
|
|
|
|
+ this.arrFonts := Array()
|
|
|
|
|
+ this.isTooManyFonts := false
|
|
|
|
|
+
|
|
|
|
|
+ this.mAHKcolors := this.MapCI().Set(
|
|
|
|
|
+ 'Black', '0x000000', 'Silver', '0xC0C0C0',
|
|
|
|
|
+ 'Gray', '0x808080', 'White', '0xFFFFFF',
|
|
|
|
|
+ 'Maroon', '0x800000', 'Red', '0xFF0000',
|
|
|
|
|
+ 'Purple', '0x800080', 'Fuchsia','0xFF00FF',
|
|
|
|
|
+ 'Green', '0x008000', 'Lime', '0x00FF00',
|
|
|
|
|
+ 'Olive', '0x808000', 'Yellow', '0xFFFF00',
|
|
|
|
|
+ 'Navy', '0x000080', 'Blue', '0x0000FF',
|
|
|
|
|
+ 'Teal', '0x008080', 'Aqua', '0x00FFFF'
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ this.mAW := this.MapCI().Set(
|
|
|
|
|
+ 'none', '',
|
|
|
|
|
+ 'fade', '0x80000', ; AW_BLEND
|
|
|
|
|
+ 'expand', '0x00010', ; AW_CENTER
|
|
|
|
|
+ 'slideEast', '0x40001', ; AW_SLIDE | AW_HOR_POSITIVE
|
|
|
|
|
+ 'slideWest', '0x40002', ; AW_SLIDE | AW_HOR_NEGATIVE
|
|
|
|
|
+ 'slideNorth', '0x40008', ; AW_SLIDE | AW_VER_NEGATIVE
|
|
|
|
|
+ 'slideSouth', '0x40004', ; AW_SLIDE | AW_VER_POSITIVE
|
|
|
|
|
+ 'slideNorthEast', '0x40009', ; AW_SLIDE | AW_VER_NEGATIVE | AW_HOR_POSITIVE
|
|
|
|
|
+ 'slideNorthWest', '0x4000A', ; AW_SLIDE | AW_VER_NEGATIVE | AW_HOR_NEGATIVE
|
|
|
|
|
+ 'slideSouthEast', '0x40005', ; AW_SLIDE | AW_VER_POSITIVE | AW_HOR_POSITIVE
|
|
|
|
|
+ 'slideSouthWest', '0x40006', ; AW_SLIDE | AW_VER_POSITIVE | AW_HOR_NEGATIVE
|
|
|
|
|
+ 'rollEast', '0x00001', ; AW_HOR_POSITIVE
|
|
|
|
|
+ 'rollWest', '0x00002', ; AW_HOR_NEGATIVE
|
|
|
|
|
+ 'rollNorth', '0x00008', ; AW_VER_NEGATIVE
|
|
|
|
|
+ 'rollSouth', '0x00004', ; AW_VER_POSITIVE
|
|
|
|
|
+ 'rollNorthEast', '0x00009', ; ROLL_DIAG_BL_TO_TR
|
|
|
|
|
+ 'rollNorthWest', '0x0000a', ; ROLL_DIAG_BR_TO_TL
|
|
|
|
|
+ 'rollSouthEast', '0x00005', ; ROLL_DIAG_TL_TO_BR
|
|
|
|
|
+ 'rollSouthWest', '0x00006' ; ROLL_DIAG_TR_TO_BL
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ this.pathImagesFolder := RegRead('HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders', 'My Pictures') '\Notify'
|
|
|
|
|
+ this.arrImageExt := ['ico', 'dll', 'exe', 'cpl', 'png', 'jpeg', 'jpg', 'gif', 'bmp', 'tif']
|
|
|
|
|
+ this.strImageExt := this.ArrayToString(this.arrImageExt, '|')
|
|
|
|
|
+ this.mImages := this.MapCI().Set('icon!', 2, 'icon?', 3, 'iconx', 4, 'iconi', 5)
|
|
|
|
|
+
|
|
|
|
|
+ Loop Files this.pathImagesFolder '\*.*'
|
|
|
|
|
+ if RegExMatch(A_LoopFileExt, 'i)^(' this.strImageExt ')$')
|
|
|
|
|
+ SplitPath(A_LoopFilePath,,,, &fileName), this.mImages[fileName] := A_LoopFilePath
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ this.pathSoundsFolder := RegRead('HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders', 'My Music') '\Sounds'
|
|
|
|
|
+ this.mSounds := this.MapCI().Set('soundx', '*16', 'soundi', '*64')
|
|
|
|
|
+
|
|
|
|
|
+ for path in [A_WinDir '\Media', this.pathSoundsFolder]
|
|
|
|
|
+ Loop Files path '\*.wav'
|
|
|
|
|
+ SplitPath(A_LoopFilePath,,,, &fileName), this.mSounds[fileName] := A_LoopFilePath
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ this.mThemes := this.MapCI()
|
|
|
|
|
+
|
|
|
|
|
+ for theme, str in this.mThemesStrings
|
|
|
|
|
+ this.OptionsStringToMap(this.mThemes[theme] := this.MapCI(), str)
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ this.mOrig_mDefaults := this.MapCI()
|
|
|
|
|
+
|
|
|
|
|
+ for key, value in this.mDefaults
|
|
|
|
|
+ this.mOrig_mDefaults[key] := value
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ this.mOrig_mThemes := this.MapCI()
|
|
|
|
|
+
|
|
|
|
|
+ for theme, mTheme in this.mThemes {
|
|
|
|
|
+ this.mOrig_mThemes[theme] := this.MapCI()
|
|
|
|
|
+
|
|
|
|
|
+ for key, value in mTheme
|
|
|
|
|
+ this.mOrig_mThemes[theme][key] := value
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ sourceFile := A_IsCompiled ? A_ScriptFullPath : A_LineFile
|
|
|
|
|
+ SplitPath(sourceFile,, &pathDir)
|
|
|
|
|
+
|
|
|
|
|
+ if (FileExist(pathDir '\Preferences.json')) {
|
|
|
|
|
+ objFile := FileOpen(pathDir '\Preferences.json', 'r', 'UTF-8')
|
|
|
|
|
+ mJSON := _JSON_thqby.parse(objFile.Read(), keepbooltype := false, as_map := true)
|
|
|
|
|
+ objFile.Close()
|
|
|
|
|
+
|
|
|
|
|
+ if (mJSON.Has('mDefaults')) {
|
|
|
|
|
+ this.mThemes['Default'] := this.MapCI()
|
|
|
|
|
+
|
|
|
|
|
+ for key, value in mJSON['mDefaults']
|
|
|
|
|
+ this.mThemes['Default'][key] := value
|
|
|
|
|
+
|
|
|
|
|
+ for key, value in this.mDefaults
|
|
|
|
|
+ if this.mThemes['Default'].Has(key)
|
|
|
|
|
+ this.mDefaults[key] := this.mThemes['Default'][key]
|
|
|
|
|
+
|
|
|
|
|
+ for key in ['padX', 'padY', 'gmX', 'gmY', 'spX', 'spY']
|
|
|
|
|
+ if this.mDefaults.Has(key)
|
|
|
|
|
+ this.mDefaults.Delete(key)
|
|
|
|
|
+
|
|
|
|
|
+ this.ParsePadOption(this.mDefaults)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (mJSON.Has('mThemes')) {
|
|
|
|
|
+ for key, value in mJSON['mThemes'] {
|
|
|
|
|
+ this.mThemes[key] := this.MapCI()
|
|
|
|
|
+
|
|
|
|
|
+ for k, v in value
|
|
|
|
|
+ this.mThemes[key][k] := v
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ this.mThemes['Default'] := this.MapCI()
|
|
|
|
|
+
|
|
|
|
|
+ if !this.mThemes.Has(this.mDefaults['theme'])
|
|
|
|
|
+ this.mDefaults['theme'] := 'Default'
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ for value in ['mThemes', 'mOrig_mThemes'] {
|
|
|
|
|
+ for theme, mTheme in this.%value% {
|
|
|
|
|
+ if (theme != 'default') {
|
|
|
|
|
+ arrKeyDefined := Array()
|
|
|
|
|
+
|
|
|
|
|
+ for key, v in mTheme
|
|
|
|
|
+ arrKeyDefined.Push(key)
|
|
|
|
|
+
|
|
|
|
|
+ mTheme['arrKeyDefined'] := arrKeyDefined
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ for theme, mTheme in this.mThemes {
|
|
|
|
|
+ this.ParseBorderOption(mTheme)
|
|
|
|
|
+
|
|
|
|
|
+ for value in ['show', 'hide']
|
|
|
|
|
+ if mtheme.Has(value)
|
|
|
|
|
+ mtheme.Delete(value)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static _Show(title:='', msg:='', image:='', sound:='', callback:='', options:='')
|
|
|
|
|
+ {
|
|
|
|
|
+ static gIndex := 0
|
|
|
|
|
+ this.OptionsStringToMap(m := this.MapCI(), options)
|
|
|
|
|
+
|
|
|
|
|
+ if !m.Has('theme') || !this.mThemes.Has(m['theme'])
|
|
|
|
|
+ m['theme'] := this.mDefaults['theme']
|
|
|
|
|
+
|
|
|
|
|
+ this.SetThemeSettings(m, this.mThemes[m['theme']])
|
|
|
|
|
+ this.SetDefault_MiscValues(m)
|
|
|
|
|
+ this.ParseAnimationOption(m)
|
|
|
|
|
+ this.SetAnimationDefault(m)
|
|
|
|
|
+ this.ParsePadOption(m)
|
|
|
|
|
+ this.SetPadDefault(m)
|
|
|
|
|
+ this.ParseBorderOption(m)
|
|
|
|
|
+ this.SetBorderOption(m)
|
|
|
|
|
+
|
|
|
|
|
+ if image
|
|
|
|
|
+ m['image'] := image
|
|
|
|
|
+
|
|
|
|
|
+ if sound
|
|
|
|
|
+ m['sound'] := sound
|
|
|
|
|
+
|
|
|
|
|
+ if (!title && !msg && (m['image'] = '' || m['image'] = 'none'))
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ switch {
|
|
|
|
|
+ case (m['mon'] = 'mouse' || m['pos'] = 'mouse'): m['mon'] := this.MonitorGetMouseIsIn()
|
|
|
|
|
+ case m['mon'] = 'active': m['mon'] := this.MonitorGetWindowIsIn('A')
|
|
|
|
|
+ case (m['mon'] = 'primary' || m['mon'] < 1 || m['mon'] > MonitorGetCount()) : m['mon'] := MonitorGetPrimary()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ switch m['dg'] {
|
|
|
|
|
+ case 1: this.DestroyAllOnMonitorAtPosition(m['mon'], m['pos'])
|
|
|
|
|
+ case 2: this.DestroyAllOnAllMonitorAtPosition(m['pos'])
|
|
|
|
|
+ case 3: this.DestroyAllOnMonitor(m['mon'])
|
|
|
|
|
+ case 4: this.DestroyAll()
|
|
|
|
|
+ case 5: m['tag'] && this.Destroy(m['tag'])
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ g := Gui(m['opt'], 'NotifyGUI_' m['mon'] '_' m['pos'] '_' m['style'] '_' m['bdrC'] '_' m['bdrW'] '_' m['padY'] '_' A_Now A_MSec (m['tag'] && '_' m['tag']))
|
|
|
|
|
+ g.BackColor := m['bc']
|
|
|
|
|
+ g.MarginX := m['gmX'] + m['bdrW']
|
|
|
|
|
+ g.MarginY := m['gmY'] + m['bdrW']
|
|
|
|
|
+ g.gIndex := ++gIndex
|
|
|
|
|
+ m['hwnd'] := g.handle := g.hwnd
|
|
|
|
|
+
|
|
|
|
|
+ for value in ['pos', 'mon', 'hideHex', 'hideDur', 'tag']
|
|
|
|
|
+ g.%value% := m[value]
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ switch {
|
|
|
|
|
+ case RegExMatch(m['image'], 'i)^(icon!|icon\?|iconx|iconi)$'):
|
|
|
|
|
+ try m['pic'] := g.Add('Picture', 'w' m['iw'] ' h' m['ih'] ' Icon' this.mImages[m['image']], A_WinDir '\system32\user32.dll')
|
|
|
|
|
+
|
|
|
|
|
+ case this.mImages.Has(m['image']) && FileExist(this.mImages[m['image']]):
|
|
|
|
|
+ try m['pic'] := g.Add('Picture', 'w' m['iw'] ' h' m['ih'], this.mImages[m['image']])
|
|
|
|
|
+
|
|
|
|
|
+ case RegExMatch(m['image'], 'i)^(.+?\.(?:dll|exe|cpl))\|icon(\d+)$', &matchIcon) && FileExist(matchIcon[1]):
|
|
|
|
|
+ try m['pic'] := g.Add('Picture', 'w' m['iw'] ' h' m['ih'] ' Icon' matchIcon[2], matchIcon[1])
|
|
|
|
|
+
|
|
|
|
|
+ case FileExist(m['image']) || RegExMatch(m['image'], 'i)^h(icon|bitmap).*\d+'):
|
|
|
|
|
+ try m['pic'] := g.Add('Picture', 'w' m['iw'] ' h' m['ih'], m['image'])
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ MonitorGetWorkArea(m['mon'], &monWALeft, &monWATop, &monWARight, &monWABottom)
|
|
|
|
|
+ monWAwidth := Abs(monWARight - monWALeft)
|
|
|
|
|
+ monWAheight := Abs(monWABottom - monWATop)
|
|
|
|
|
+ visibleScreenWidth := monWAwidth / (A_ScreenDPI / 96)
|
|
|
|
|
+
|
|
|
|
|
+ if m.Has('pic')
|
|
|
|
|
+ picWidth := this.GetPicWidth(m['pic'], monWALeft, monWATop) + m['spX'] + g.MarginX*2
|
|
|
|
|
+
|
|
|
|
|
+ if title
|
|
|
|
|
+ titleCtrlW := this.GetTextWidth(title, m['tf'], m['ts'], m['tfo'], monWALeft, monWATop)
|
|
|
|
|
+
|
|
|
|
|
+ if msg
|
|
|
|
|
+ msgCtrlW := this.GetTextWidth(msg, m['mf'], m['ms'], m['mfo'], monWALeft, monWATop)
|
|
|
|
|
+
|
|
|
|
|
+ if title && (titleCtrlW + (picWidth ?? g.MarginX*2)) > visibleScreenWidth
|
|
|
|
|
+ titleWidth := visibleScreenWidth - m['padX']*2 - (picWidth ?? g.MarginX*2)
|
|
|
|
|
+
|
|
|
|
|
+ if msg && (msgCtrlW + (picWidth ?? g.MarginX*2)) > visibleScreenWidth
|
|
|
|
|
+ msgWidth := visibleScreenWidth - m['padX']*2 - (picWidth ?? g.MarginX*2)
|
|
|
|
|
+
|
|
|
|
|
+ if m['prog'] && RegExMatch(m['prog'], 'i)\bw(\d+)\b', &match_width)
|
|
|
|
|
+ progUserW := match_width[1]
|
|
|
|
|
+
|
|
|
|
|
+ if (m['prog'] && IsSet(progUserW)) && ((progUserW + (picWidth ?? g.MarginX*2)) > (visibleScreenWidth))
|
|
|
|
|
+ progWidth := visibleScreenWidth - m['padX']*2 - (picWidth ?? g.MarginX*2)
|
|
|
|
|
+
|
|
|
|
|
+ maxWidth := Max(
|
|
|
|
|
+ (title ? (titleWidth ?? titleCtrlW ?? 0) : 0),
|
|
|
|
|
+ (msg ? (msgWidth ?? msgCtrlW ?? 0) : 0),
|
|
|
|
|
+ (m['prog'] ? (progWidth ?? progUserW ?? 0) : 0)
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ if m['maxW'] && (m['maxW'] < maxWidth)
|
|
|
|
|
+ maxWidth := m['maxW']
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ if (title) {
|
|
|
|
|
+ this.SetFont(g, 's' m['ts'] ' c' m['tc'] ' ' m['tfo'], m['tf'])
|
|
|
|
|
+ m['title'] := g.Add('Text', m['tali'] (IsSet(picWidth) ? ' x+' m['spX'] : '') ' w' maxWidth, title)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (m['prog']) {
|
|
|
|
|
+ switch {
|
|
|
|
|
+ case !IsSet(progUserW): m['prog'] := m['prog'] ' w' maxWidth
|
|
|
|
|
+ case IsSet(progUserW): m['prog'] := progUserW > maxWidth ? RegExReplace(m['prog'], 'w\d+', 'w' maxWidth) : m['prog']
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ g.MarginY := title ? m['spY'] : m['gmY'] + m['bdrW']
|
|
|
|
|
+ m['prog'] := g.Add('Progress', (!title && IsSet(picWidth) ? ' x+' m['spX'] : '') ' ' m['prog'])
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (msg) {
|
|
|
|
|
+ g.MarginY := title || m['prog'] ? m['spY'] : m['gmY'] + m['bdrW']
|
|
|
|
|
+ this.SetFont(g, 's' m['ms'] ' c' m['mc'] ' ' m['mfo'], m['mf'])
|
|
|
|
|
+ m['msg'] := g.Add('Text', m['mali'] ((!title && !m['prog']) && IsSet(picWidth) ? ' x+' m['spX'] : '') ' w' maxWidth, msg)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ g.MarginY := m['gmY'] + m['bdrW']
|
|
|
|
|
+ g.Show('Hide')
|
|
|
|
|
+ WinGetPos(,, &gW, &gH, g)
|
|
|
|
|
+ clickArea := g.Add('Text', 'x0 y0 w' gW ' h' gH ' BackgroundTrans')
|
|
|
|
|
+
|
|
|
|
|
+ if callback
|
|
|
|
|
+ clickArea.OnEvent('Click', callback)
|
|
|
|
|
+
|
|
|
|
|
+ if m['dgc']
|
|
|
|
|
+ clickArea.OnEvent('Click', this.gDestroy.Bind(this, g, 'clickArea'))
|
|
|
|
|
+
|
|
|
|
|
+ g.OnEvent('Close', this.gDestroy.Bind(this, g, 'close'))
|
|
|
|
|
+ g.boundFuncTimer := this.gDestroy.Bind(this, g, 'timer')
|
|
|
|
|
+
|
|
|
|
|
+ if m['sound']
|
|
|
|
|
+ this.Sound(m['sound'])
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ switch m['pos'], false {
|
|
|
|
|
+ case 'br', 'bc', 'bl': minMaxPosY := monWABottom
|
|
|
|
|
+ case 'tr', 'tc', 'tl', 'ct', 'ctl', 'ctr': minMaxPosY := monWATop
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ mDhwTmm := this.Set_DHWindows_TMMode(0, 'RegEx')
|
|
|
|
|
+
|
|
|
|
|
+ for id in WinGetList('i)^NotifyGUI_' m['mon'] '_' m['pos'] '_ ahk_class AutoHotkeyGUI') {
|
|
|
|
|
+ try {
|
|
|
|
|
+ WinGetPos(, &guiY,, &guiH, 'ahk_id ' id)
|
|
|
|
|
+ switch m['pos'], false {
|
|
|
|
|
+ case 'br', 'bc', 'bl': minMaxPosY := Min(minMaxPosY, guiY)
|
|
|
|
|
+ case 'tr', 'tc', 'tl', 'ct', 'ctl', 'ctr': minMaxPosY := Max(minMaxPosY, guiY + guiH)
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.Set_DHWindows_TMMode(mDhwTmm['dhwPrev'], mDhwTmm['tmmPrev'])
|
|
|
|
|
+
|
|
|
|
|
+ switch m['pos'], false {
|
|
|
|
|
+ case 'br': gPos := 'x' monWARight - gW - m['padX'] ' y' ((minMaxPosY = monWABottom) ? monWABottom - gH - m['padY'] : minMaxPosY - gH - this.padG)
|
|
|
|
|
+ case 'bc': gPos := 'x' monWARight - monWAwidth/2 - gW/2 ' y' ((minMaxPosY = monWABottom) ? monWABottom - gH - m['padY'] : minMaxPosY - gH - this.padG)
|
|
|
|
|
+ case 'bl': gPos := 'x' monWALeft + m['padX'] ' y' ((minMaxPosY = monWABottom) ? monWABottom - gH - m['padY'] : minMaxPosY - gH - this.padG)
|
|
|
|
|
+ case 'tl': gPos := 'x' monWALeft + m['padX'] ' y' ((minMaxPosY = monWATop) ? monWATop + m['padY'] : minMaxPosY + this.padG)
|
|
|
|
|
+ case 'tc': gPos := 'x' monWARight - monWAwidth/2 - gW/2 ' y' ((minMaxPosY = monWATop) ? monWATop + m['padY'] : minMaxPosY + this.padG)
|
|
|
|
|
+ case 'tr': gPos := 'x' monWARight - m['padX'] - gW ' y' ((minMaxPosY = monWATop) ? monWATop + m['padY'] : minMaxPosY + this.padG)
|
|
|
|
|
+ case 'ct': gPos := 'x' monWARight - monWAwidth/2 - gW/2 ' y' ((minMaxPosY = monWATop) ? monWATop + monWAheight/2 - gH/2 : minMaxPosY + this.padG)
|
|
|
|
|
+ case 'ctl': gPos := 'x' monWALeft + m['padX'] ' y' ((minMaxPosY = monWATop) ? monWATop + monWAheight/2 - gH/2 : minMaxPosY + this.padG)
|
|
|
|
|
+ case 'ctr': gPos := 'x' monWARight - m['padX'] - gW ' y' ((minMaxPosY = monWATop) ? monWATop + monWAheight/2 - gH/2 : minMaxPosY + this.padG)
|
|
|
|
|
+ case 'mouse': gPos := this.CalculatePopupWindowPosition(g.hwnd)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ switch g.pos, false {
|
|
|
|
|
+ case 'br', 'bc', 'bl': outOfWorkArea := (minMaxPosY < (monWATop + gH + this.padG))
|
|
|
|
|
+ case 'tr', 'tc', 'tl', 'ct', 'ctl', 'ctr': outOfWorkArea := (minMaxPosY > (monWABottom - gH - this.padG))
|
|
|
|
|
+ case 'mouse': outOfWorkArea := false
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ this.mNotifyGUIs[gIndex] := g
|
|
|
|
|
+
|
|
|
|
|
+ switch m['style'], false {
|
|
|
|
|
+ case 'round': this.FrameShadow(g.hwnd), !RegExMatch(m['bdrC'], 'i)^(default|1|0)$') && this.DrawBorderRound(g.hwnd, m['bdrC'])
|
|
|
|
|
+ case 'edge': RegExMatch(m['bdrC'], 'i)^(default|1)$') && g.Opt('+Border')
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if m['wstp'] || m['wstp'] = 0
|
|
|
|
|
+ WinSetTransparent(m['wstp'], g)
|
|
|
|
|
+
|
|
|
|
|
+ if m['wstc']
|
|
|
|
|
+ WinSetTransColor(m['wstc'], g)
|
|
|
|
|
+
|
|
|
|
|
+ if m['showHex']
|
|
|
|
|
+ g.Show(gPos ' NoActivate Hide'), DllCall('AnimateWindow', 'Ptr', g.hwnd, 'Int', m['showDur'], 'Int', m['showHex'])
|
|
|
|
|
+ else
|
|
|
|
|
+ g.Show(gPos ' NoActivate')
|
|
|
|
|
+
|
|
|
|
|
+ if m['style'] = 'edge' && !RegExMatch(m['bdrC'], 'i)^(default|1|0)$')
|
|
|
|
|
+ try this.DrawBorderEdge(g.Hwnd, m['bdrC'], m['bdrW'])
|
|
|
|
|
+
|
|
|
|
|
+ if m['dur']
|
|
|
|
|
+ SetTimer(g.boundFuncTimer, - ((m['dur'] + (outOfWorkArea ? 8 : 0)) * 1000))
|
|
|
|
|
+
|
|
|
|
|
+ return m
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static gDestroy(g, fromMethod:='', *)
|
|
|
|
|
+ {
|
|
|
|
|
+ SetTimer(g.boundFuncTimer, 0)
|
|
|
|
|
+
|
|
|
|
|
+ if g.hideHex && !RegExMatch(fromMethod, 'i)^(destroy|close)')
|
|
|
|
|
+ try DllCall('AnimateWindow', 'Ptr', g.hwnd, 'Int', g.hideDur, 'Int', Format("{:#X}", g.hideHex + 0x10000))
|
|
|
|
|
+
|
|
|
|
|
+ g.Destroy()
|
|
|
|
|
+
|
|
|
|
|
+ if this.mNotifyGUIs.Has(g.gIndex)
|
|
|
|
|
+ this.mNotifyGUIs.Delete(g.gIndex)
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+ Sleep(25)
|
|
|
|
|
+ arrGUIs := Array()
|
|
|
|
|
+ mDhwTmm := this.Set_DHWindows_TMMode(0, 'RegEx')
|
|
|
|
|
+
|
|
|
|
|
+ for id in WinGetList('i)^NotifyGUI_' g.mon '_' g.pos '_ ahk_class AutoHotkeyGUI') {
|
|
|
|
|
+ try {
|
|
|
|
|
+ WinGetPos(, &gY,, &gH, 'ahk_id ' id)
|
|
|
|
|
+ RegExMatch(WinGetTitle('ahk_id ' id), 'i)^NotifyGUI_\d+_([a-z]+)_([a-z]+)_(\w+)_(\d+)_(\d+)_\d+', &match)
|
|
|
|
|
+
|
|
|
|
|
+ if match[1] = 'mouse'
|
|
|
|
|
+ continue
|
|
|
|
|
+
|
|
|
|
|
+ arrGUIs.Push(this.MapCI().Set('gY', gY, 'gH', gH, 'id', id, 'style', match[2], 'bdrC', match[3], 'bdrW', match[4], 'padY', match[5]))
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ arrGUIs := Array()
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (arrGUIs.Length) {
|
|
|
|
|
+ try MonitorGetWorkArea(g.mon,, &monWATop,, &monWABottom)
|
|
|
|
|
+ catch {
|
|
|
|
|
+ this.RedrawAllBorderEdge()
|
|
|
|
|
+ this.Set_DHWindows_TMMode(mDhwTmm['dhwPrev'], mDhwTmm['tmmPrev'])
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ monWAheight := Abs(monWABottom - monWATop)
|
|
|
|
|
+ SetWinDelay(0)
|
|
|
|
|
+
|
|
|
|
|
+ switch g.pos, false {
|
|
|
|
|
+ case 'br', 'bc', 'bl': arrGUIs := this.SortArrayGUIPosY(arrGUIs, true), posY := monWABottom - arrGUIs[1]['padY']
|
|
|
|
|
+ case 'tr', 'tc', 'tl', 'ct', 'ctl', 'ctr': arrGUIs := this.SortArrayGUIPosY(arrGUIs), posY := monWATop + arrGUIs[1]['padY']
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for value in arrGUIs {
|
|
|
|
|
+ switch g.pos, false{
|
|
|
|
|
+ case 'br', 'bc', 'bl': posY -= value['gH']
|
|
|
|
|
+ case 'ct', 'ctl', 'ctr': (A_Index = 1 && posY := monWATop + monWAheight/2 - value['gH']/2)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (Abs(posY - value['gY']) > 10) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ WinMove(, posY,,, 'ahk_id ' value['id'])
|
|
|
|
|
+ this.ReDrawBorderEdge(value['id'], value['style'], value['bdrC'], value['bdrW'])
|
|
|
|
|
+ }
|
|
|
|
|
+ catch
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ switch g.pos, false {
|
|
|
|
|
+ case 'br', 'bc', 'bl': posY -= this.padG
|
|
|
|
|
+ case 'tr', 'tc', 'tl', 'ct', 'ctl', 'ctr': posY += value['gH'] + this.padG
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.RedrawAllBorderEdge()
|
|
|
|
|
+ this.Set_DHWindows_TMMode(mDhwTmm['dhwPrev'], mDhwTmm['tmmPrev'])
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /********************************************************************************************
|
|
|
|
|
+ * Destroys GUIs.
|
|
|
|
|
+ * @param {integer|string} param
|
|
|
|
|
+ * - Window handle (hwnd) - Destroys the GUI with the specified window handle.
|
|
|
|
|
+ * - Tag - destroys every GUI containing this tag across all scripts.
|
|
|
|
|
+ * - 'oldest' or no param - Destroys the oldest GUI.
|
|
|
|
|
+ * - 'latest' - Destroys the most recent GUI.
|
|
|
|
|
+ */
|
|
|
|
|
+ static Destroy(param:='')
|
|
|
|
|
+ {
|
|
|
|
|
+ mDhwTmm := this.Set_DHWindows_TMMode(0, A_TitleMatchMode)
|
|
|
|
|
+ SetWinDelay(25)
|
|
|
|
|
+
|
|
|
|
|
+ if (WinExist('ahk_id ' param)) {
|
|
|
|
|
+ for gIndex, value in this.mNotifyGUIs.Clone() {
|
|
|
|
|
+ if (param = value.handle && this.mNotifyGUIs.Has(gIndex)) {
|
|
|
|
|
+ this.gDestroy(this.mNotifyGUIs[gIndex], 'destroy')
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ SetTitleMatchMode(1)
|
|
|
|
|
+ for id in WinGetList('NotifyGUI_ ahk_class AutoHotkeyGUI') {
|
|
|
|
|
+ if (param = id) {
|
|
|
|
|
+ try WinClose('ahk_id ' id)
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ if (param) {
|
|
|
|
|
+ for gIndex, value in this.mNotifyGUIs.Clone()
|
|
|
|
|
+ if param = value.tag && this.mNotifyGUIs.Has(gIndex)
|
|
|
|
|
+ this.gDestroy(this.mNotifyGUIs[gIndex], 'destroy')
|
|
|
|
|
+
|
|
|
|
|
+ SetTitleMatchMode('RegEx')
|
|
|
|
|
+ for id in WinGetList('i)^NotifyGUI_\d+_[a-z]+_[a-z]+_\w+_\d+_\d+_\d+_\Q' param '\E$ ahk_class AutoHotkeyGUI')
|
|
|
|
|
+ try WinClose('ahk_id ' id)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ if (param = 'oldest' || param = 'latest' || param = '') {
|
|
|
|
|
+ m := Map()
|
|
|
|
|
+ SetTitleMatchMode(1)
|
|
|
|
|
+ for id in WinGetList('NotifyGUI_ ahk_class AutoHotkeyGUI') {
|
|
|
|
|
+ try {
|
|
|
|
|
+ RegExMatch(WinGetTitle('ahk_id ' id), 'i)^NotifyGUI_\d+_[a-z]+_[a-z]+_\w+_\d+_\d+_(\d+)', &match)
|
|
|
|
|
+ m[match[1]] := id
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (param = 'latest') {
|
|
|
|
|
+ for timestamp, id in m
|
|
|
|
|
+ destroyId := id
|
|
|
|
|
+ } else {
|
|
|
|
|
+ for timestamp, id in m {
|
|
|
|
|
+ destroyId := id
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if IsSet(destroyId)
|
|
|
|
|
+ try WinClose('ahk_id ' destroyId)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;==============================================
|
|
|
|
|
+
|
|
|
|
|
+ this.Set_DHWindows_TMMode(mDhwTmm['dhwPrev'], mDhwTmm['tmmPrev'])
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static DestroyAllOnMonitorAtPosition(monNum, position)
|
|
|
|
|
+ {
|
|
|
|
|
+ for gIndex, value in this.mNotifyGUIs.Clone()
|
|
|
|
|
+ if value.mon = monNum && value.pos = position && this.mNotifyGUIs.Has(gIndex)
|
|
|
|
|
+ this.gDestroy(this.mNotifyGUIs[gIndex], 'destroyAllOnMonitorAtPosition')
|
|
|
|
|
+
|
|
|
|
|
+ this.WinGetList_WinClose('i)^NotifyGUI_' monNum '_' position '_ ahk_class AutoHotkeyGUI', 0, 'RegEx')
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static DestroyAllOnAllMonitorAtPosition(position)
|
|
|
|
|
+ {
|
|
|
|
|
+ for gIndex, value in this.mNotifyGUIs.Clone()
|
|
|
|
|
+ if value.pos = position && this.mNotifyGUIs.Has(gIndex)
|
|
|
|
|
+ this.gDestroy(this.mNotifyGUIs[gIndex], 'destroyAllOnAllMonitorAtPosition')
|
|
|
|
|
+
|
|
|
|
|
+ this.WinGetList_WinClose('i)^NotifyGUI_\d+_' position '_ ahk_class AutoHotkeyGUI', 0, 'RegEx')
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static DestroyAllOnMonitor(monNum)
|
|
|
|
|
+ {
|
|
|
|
|
+ for gIndex, value in this.mNotifyGUIs.Clone()
|
|
|
|
|
+ if value.mon = monNum && this.mNotifyGUIs.Has(gIndex)
|
|
|
|
|
+ this.gDestroy(this.mNotifyGUIs[gIndex], 'destroyAllOnMonitor')
|
|
|
|
|
+
|
|
|
|
|
+ this.WinGetList_WinClose('i)NotifyGUI_' monNum '_ ahk_class AutoHotkeyGUI', 0, 'RegEx')
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static DestroyAll()
|
|
|
|
|
+ {
|
|
|
|
|
+ for gIndex, value in this.mNotifyGUIs.Clone()
|
|
|
|
|
+ if this.mNotifyGUIs.Has(gIndex)
|
|
|
|
|
+ this.gDestroy(this.mNotifyGUIs[gIndex], 'destroyAll')
|
|
|
|
|
+
|
|
|
|
|
+ this.WinGetList_WinClose('NotifyGUI_ ahk_class AutoHotkeyGUI', 0, 1)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static WinGetList_WinClose(winTitle, dhWindows, tmMode)
|
|
|
|
|
+ {
|
|
|
|
|
+ mDhwTmm := this.Set_DHWindows_TMMode(dhWindows, tmMode)
|
|
|
|
|
+ SetWinDelay(25)
|
|
|
|
|
+
|
|
|
|
|
+ for id in WinGetList(winTitle)
|
|
|
|
|
+ try WinClose('ahk_id ' id)
|
|
|
|
|
+
|
|
|
|
|
+ this.Set_DHWindows_TMMode(mDhwTmm['dhwPrev'], mDhwTmm['tmmPrev'])
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static Exist(tag)
|
|
|
|
|
+ {
|
|
|
|
|
+ mDhwTmm := this.Set_DHWindows_TMMode(0, 'RegEx')
|
|
|
|
|
+
|
|
|
|
|
+ for id in WinGetList('i)^NotifyGUI_\d+_[a-z]+_[a-z]+_\w+_\d+_\d+_\d+_\Q' tag '\E$ ahk_class AutoHotkeyGUI') {
|
|
|
|
|
+ idFound := id
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.Set_DHWindows_TMMode(mDhwTmm['dhwPrev'], mDhwTmm['tmmPrev'])
|
|
|
|
|
+ return idFound ?? 0
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static SetDefaultTheme(theme:='')
|
|
|
|
|
+ {
|
|
|
|
|
+ switch {
|
|
|
|
|
+ case this.mThemes.Has(theme): this.mDefaults['theme'] := theme
|
|
|
|
|
+ case !theme: this.mDefaults['theme'] := 'default'
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static SetDefault_MiscValues(m)
|
|
|
|
|
+ {
|
|
|
|
|
+ switch {
|
|
|
|
|
+ case (m.has('iw') && !m.has('ih')) : m['ih'] := -1
|
|
|
|
|
+ case (m.has('ih') && !m.has('iw')) : m['iw'] := -1
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for key, value in this.mDefaults
|
|
|
|
|
+ if !m.has(key)
|
|
|
|
|
+ m[key] := value
|
|
|
|
|
+
|
|
|
|
|
+ if !RegExMatch(m['style'], 'i)^(round|edge)$')
|
|
|
|
|
+ m['style'] := this.mDefaults['style']
|
|
|
|
|
+
|
|
|
|
|
+ for value in ['tfo', 'mfo'] {
|
|
|
|
|
+ m['arr' value] := Array()
|
|
|
|
|
+
|
|
|
|
|
+ for v in ['bold', 'italic', 'strike', 'underline']
|
|
|
|
|
+ if InStr(m[value], v)
|
|
|
|
|
+ m['arr' value].Push(v)
|
|
|
|
|
+
|
|
|
|
|
+ if !InStr(m[value], 'norm')
|
|
|
|
|
+ m[value] := Trim('norm ' m[value])
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static ParseAnimationOption(m)
|
|
|
|
|
+ {
|
|
|
|
|
+ for value in ['show', 'hide'] {
|
|
|
|
|
+ if (m.has(value)) {
|
|
|
|
|
+ arrAnim := StrSplit(m[value], '@', A_Space)
|
|
|
|
|
+ m[value 'Hex'] := this.mAW[arrAnim[1] = 0 ? 'none' : arrAnim[1]]
|
|
|
|
|
+ arrAnim.Has(2) && (m[value 'Dur'] := Min(2500, Max(1, integer(arrAnim[2]))))
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static SetAnimationDefault(m)
|
|
|
|
|
+ {
|
|
|
|
|
+ switch m['style'], false {
|
|
|
|
|
+ case 'edge':
|
|
|
|
|
+ {
|
|
|
|
|
+ if !m.has('showHex') {
|
|
|
|
|
+ switch m['pos'], false {
|
|
|
|
|
+ case 'br', 'tr', 'ctr': m['showHex'] := this.mAW['slideWest']
|
|
|
|
|
+ case 'bl', 'tl', 'ctl': m['showHex'] := this.mAW['slideEast']
|
|
|
|
|
+ case 'bc': m['showHex'] := this.mAW['slideNorth']
|
|
|
|
|
+ case 'tc': m['showHex'] := this.mAW['slideSouth']
|
|
|
|
|
+ case 'ct': m['showHex'] := this.mAW['expand']
|
|
|
|
|
+ case 'mouse': m['showHex'] := this.mAW['none']
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if !m.has('hideHex') {
|
|
|
|
|
+ switch m['pos'], false {
|
|
|
|
|
+ case 'br', 'tr', 'ctr': m['hideHex'] := this.mAW['slideEast']
|
|
|
|
|
+ case 'bl', 'tl', 'ctl': m['hideHex'] := this.mAW['slideWest']
|
|
|
|
|
+ case 'bc': m['hideHex'] := this.mAW['slideSouth']
|
|
|
|
|
+ case 'tc': m['hideHex'] := this.mAW['slideNorth']
|
|
|
|
|
+ case 'ct': m['hideHex'] := this.mAW['expand']
|
|
|
|
|
+ case 'mouse': m['hideHex'] := this.mAW['none']
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ m['showDur'] := m.Get('showDur', 75)
|
|
|
|
|
+ m['hideDur'] := m.Get('hideDur', 100)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ case 'round':
|
|
|
|
|
+ {
|
|
|
|
|
+ m['showHex'] := m.Get('showHex', this.mAW['fade'])
|
|
|
|
|
+ m['hideHex'] := m.Get('hideHex', this.mAW['none'])
|
|
|
|
|
+ m['showDur'] := m.Get('showDur', 1)
|
|
|
|
|
+ m['hideDur'] := m.Get('hideDur', 1)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static ParsePadOption(m)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (m.has('pad')) {
|
|
|
|
|
+ arrPad := StrSplit(m['pad'], ',', A_Space)
|
|
|
|
|
+
|
|
|
|
|
+ for index, value in ['padX', 'padY', 'gmX', 'gmY', 'spX', 'spY']
|
|
|
|
|
+ if arrPad.Has(index) && arrPad[index] != ''
|
|
|
|
|
+ m[value] := Min(this.arrPadRange[2], Max(this.arrPadRange[1], Integer(arrPad[index])))
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static SetPadDefault(m)
|
|
|
|
|
+ {
|
|
|
|
|
+ m['padX'] := m.Has('padX') ? m['padX'] : (m['style'] = 'edge' ? 0 : 10)
|
|
|
|
|
+ m['padY'] := m.Has('padY') ? m['padY'] : (m['style'] = 'edge' ? 0 : 10)
|
|
|
|
|
+
|
|
|
|
|
+ for key in ['gmX', 'gmY', 'spX', 'spY']
|
|
|
|
|
+ if !m.has(key)
|
|
|
|
|
+ m[key] := this.mDefaults[key]
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static ParseBorderOption(m)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (m.has('bdr')) {
|
|
|
|
|
+ arrBdr := StrSplit(m['bdr'], ',', A_Space)
|
|
|
|
|
+ m['bdr'] := this.NormAHKColor(m['bdr'])
|
|
|
|
|
+ m['bdrC'] := this.NormAHKColor(arrBdr[1])
|
|
|
|
|
+ arrBdr.Has(2) && (m['bdrW'] := this.SetValidBorderWidth(arrBdr[2]))
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static SetBorderOption(m)
|
|
|
|
|
+ {
|
|
|
|
|
+ mTheme := this.mThemes.Has(m['theme']) ? this.mThemes[m['theme']] : this.MapCI()
|
|
|
|
|
+
|
|
|
|
|
+ switch {
|
|
|
|
|
+ case m['bdr'] = 0: m['bdrC'] := 0
|
|
|
|
|
+ case m.Has('bdrC') && m['bdrC']: m['bdrC'] := m['bdrC']
|
|
|
|
|
+ case (!m.Has('bdrC') || !m['bdrC']) && mTheme.Has('bdrC'): m['bdrC'] := mTheme['bdrC']
|
|
|
|
|
+ case (!m.Has('bdrC') || !m['bdrC']) && !mTheme.Has('bdrC'): m['bdrC'] := 'default'
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ switch {
|
|
|
|
|
+ case RegExMatch(m['bdrC'], 'i)^(default|1|0)$'): m['bdrW'] := 0
|
|
|
|
|
+ case !m.Has('bdrW'): m['bdrW'] := (m['style'] = 'edge' ? this.bdrWdefaultEdge : 0)
|
|
|
|
|
+ case m.Has('bdrW'):
|
|
|
|
|
+ switch m['style'], false {
|
|
|
|
|
+ case 'edge': m['bdrW'] := this.SetValidBorderWidth(m['bdrW'])
|
|
|
|
|
+ case 'round': m['bdrW'] := 0
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static SetValidBorderWidth(width) => Min(this.arrBdrWrange[2], Max(this.arrBdrWrange[1], Integer(width)))
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static SetFont(g, options, fontName)
|
|
|
|
|
+ {
|
|
|
|
|
+ g.SetFont(options, fontName)
|
|
|
|
|
+
|
|
|
|
|
+ if !this.HasVal(strFont := options ' ' fontName, this.arrFonts)
|
|
|
|
|
+ this.arrFonts.Push(strFont)
|
|
|
|
|
+
|
|
|
|
|
+ if (this.arrFonts.Length >= 190) {
|
|
|
|
|
+ this.isTooManyFonts := true
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return true
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static Set_DHWindows_TMMode(dhw, tmm)
|
|
|
|
|
+ {
|
|
|
|
|
+ dhwPrev := A_DetectHiddenWindows
|
|
|
|
|
+ tmmPrev := A_TitleMatchMode
|
|
|
|
|
+ DetectHiddenWindows(dhw)
|
|
|
|
|
+ SetTitleMatchMode(tmm)
|
|
|
|
|
+ return Map('dhwPrev', dhwPrev, 'tmmPrev', tmmPrev)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static Sound(sound)
|
|
|
|
|
+ {
|
|
|
|
|
+ if this.mSounds.Has(sound)
|
|
|
|
|
+ sound := this.mSounds[sound]
|
|
|
|
|
+
|
|
|
|
|
+ if FileExist(sound) || RegExMatch(sound,'^\*\-?\d+')
|
|
|
|
|
+ try Soundplay(sound)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static OptionsStringToMap(m, haystack)
|
|
|
|
|
+ {
|
|
|
|
|
+ pos := 1
|
|
|
|
|
+ while (pos := RegExMatch(haystack, 'i)(\w+)\s*=\s*(.*?)\s*(?=\s*\w+\s*=|$)', &match, pos))
|
|
|
|
|
+ m[match[1]] := match[2], pos += StrLen(match[0])
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static SetThemeSettings(m, mTheme)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (m['theme'] != 'default')
|
|
|
|
|
+ for key in mTheme['arrKeyDefined']
|
|
|
|
|
+ if !m.Has(key)
|
|
|
|
|
+ m[key] := mTheme[key]
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static GetTextWidth(str:='', font:='', fontSize:='', fontOption:='', monWALeft:='', monWATop:='')
|
|
|
|
|
+ {
|
|
|
|
|
+ g := Gui()
|
|
|
|
|
+ g.SetFont('s' fontSize ' ' fontOption, font)
|
|
|
|
|
+ g.txt := g.Add('Text',, str)
|
|
|
|
|
+ g.Show('x' monWALeft ' y' monWATop ' Hide')
|
|
|
|
|
+ g.txt.GetPos(,, &ctrlWidth)
|
|
|
|
|
+ g.Destroy()
|
|
|
|
|
+ return ctrlWidth
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static GetPicWidth(picCtrl, monWALeft:='', monWATop:='')
|
|
|
|
|
+ {
|
|
|
|
|
+ g := Gui()
|
|
|
|
|
+ g.pic := picCtrl
|
|
|
|
|
+ g.Show('x' monWALeft ' y' monWATop ' Hide')
|
|
|
|
|
+ g.pic.GetPos(,, &ctrlWidth)
|
|
|
|
|
+ g.Destroy()
|
|
|
|
|
+ return ctrlWidth
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static SortArrayGUIPosY(arr, sortReverse := false)
|
|
|
|
|
+ {
|
|
|
|
|
+ for value in arr
|
|
|
|
|
+ listValueY .= value['gY'] ','
|
|
|
|
|
+
|
|
|
|
|
+ listSortValueY := Sort(RTrim(listValueY, ','), (sortReverse ? 'RN' : 'N') ' D,')
|
|
|
|
|
+ sortArray := Array()
|
|
|
|
|
+
|
|
|
|
|
+ for value in StrSplit(listSortValueY, ',')
|
|
|
|
|
+ for v in arr
|
|
|
|
|
+ if v['gY'] = value
|
|
|
|
|
+ sortArray.Push(v)
|
|
|
|
|
+
|
|
|
|
|
+ return sortArray
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;=============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static HasVal(needle, haystack, caseSensitive := false)
|
|
|
|
|
+ {
|
|
|
|
|
+ for index, value in haystack
|
|
|
|
|
+ if (caseSensitive && value == needle) || (!caseSensitive && value = needle)
|
|
|
|
|
+ return index
|
|
|
|
|
+
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static ArrayToString(arr, delim)
|
|
|
|
|
+ {
|
|
|
|
|
+ for value in arr
|
|
|
|
|
+ str .= value delim
|
|
|
|
|
+
|
|
|
|
|
+ return RTrim(str, delim)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static NormAllColors(m)
|
|
|
|
|
+ {
|
|
|
|
|
+ for key in ['tc', 'mc', 'bc']
|
|
|
|
|
+ if m.Has(key)
|
|
|
|
|
+ m[key] := NormColor(m[key])
|
|
|
|
|
+
|
|
|
|
|
+ for key in ['bdr', 'bdrC']
|
|
|
|
|
+ if m.Has(key) && !RegExMatch(m[key], 'i)^(1|0|default)$')
|
|
|
|
|
+ m[key] := NormColor(m[key])
|
|
|
|
|
+
|
|
|
|
|
+ NormColor(key) => this.NormAHKColor(this.NormHexClrCode(key))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static NormAHKColor(color)
|
|
|
|
|
+ {
|
|
|
|
|
+ if RegExMatch(color, '^(0|1)$')
|
|
|
|
|
+ return color
|
|
|
|
|
+
|
|
|
|
|
+ for colorName, colorValue in this.mAHKcolors {
|
|
|
|
|
+ if (colorValue = color) {
|
|
|
|
|
+ color := colorName
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return color
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static NormHexClrCode(color)
|
|
|
|
|
+ {
|
|
|
|
|
+ if this.mAHKcolors.Has(color)
|
|
|
|
|
+ color := this.mAHKcolors[color]
|
|
|
|
|
+
|
|
|
|
|
+ if RegExMatch(Color, '^[0-9A-Fa-f]{1,6}$') && SubStr(color, 1, 2) != '0x'
|
|
|
|
|
+ color := '0x' color
|
|
|
|
|
+
|
|
|
|
|
+ if (RegExMatch(color, '^0x[0-9A-Fa-f]{1,6}$')) {
|
|
|
|
|
+ hexPart := SubStr(color, 3)
|
|
|
|
|
+ while StrLen(hexPart) < 6
|
|
|
|
|
+ hexPart := '0' hexPart
|
|
|
|
|
+ color := '0x' hexPart
|
|
|
|
|
+ }
|
|
|
|
|
+ else color := '0xFFFFFF'
|
|
|
|
|
+
|
|
|
|
|
+ return color
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /********************************************************************************************
|
|
|
|
|
+ * @credits Klark92 (original author), XMCQCX (v2 conversion)
|
|
|
|
|
+ * @see {@link https://www.autohotkey.com/boards/viewtopic.php?f=6&t=29117&hilit=FrameShadow AHK Forum}
|
|
|
|
|
+ */
|
|
|
|
|
+ static FrameShadow(hwnd)
|
|
|
|
|
+ {
|
|
|
|
|
+ DllCall("dwmapi.dll\DwmIsCompositionEnabled", "int*", &dwmEnabled:=0)
|
|
|
|
|
+
|
|
|
|
|
+ if !dwmEnabled {
|
|
|
|
|
+ DllCall("user32.dll\SetClassLongPtr", "ptr", hwnd, "int", -26, "ptr", DllCall("user32.dll\GetClassLongPtr", "ptr", hwnd, "int", -26) | 0x20000)
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ margins := Buffer(16, 0)
|
|
|
|
|
+ NumPut("int", 1, "int", 1, "int", 1, "int", 1, margins)
|
|
|
|
|
+ DllCall("dwmapi.dll\DwmSetWindowAttribute", "ptr", hwnd, "Int", 2, "Int*", 2, "Int", 4)
|
|
|
|
|
+ DllCall("dwmapi.dll\DwmExtendFrameIntoClientArea", "ptr", hwnd, "ptr", margins)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /********************************************************************************************
|
|
|
|
|
+ * @credits ericreeves
|
|
|
|
|
+ * @see {@link https://gist.github.com/ericreeves/fd426cc0457a5a47058e1ad1a29d9bd6 GitHub Gist}
|
|
|
|
|
+ */
|
|
|
|
|
+ static DrawBorderRound(hwnd, color)
|
|
|
|
|
+ {
|
|
|
|
|
+ color := this.RGB_BGR(this.NormHexClrCode(color))
|
|
|
|
|
+ DllCall("dwmapi\DwmSetWindowAttribute", "ptr", hwnd, "int", DWMWA_BORDER_COLOR := 34, "int*", color, "int", 4)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static DrawBorderEdge(hwnd, color, width)
|
|
|
|
|
+ {
|
|
|
|
|
+ color := this.RGB_BGR(this.NormHexClrCode(color))
|
|
|
|
|
+ rect := Buffer(16)
|
|
|
|
|
+ DllCall("GetClientRect", "ptr", hwnd, "ptr", rect)
|
|
|
|
|
+ left := NumGet(rect, 0, "int")
|
|
|
|
|
+ top := NumGet(rect, 4, "int")
|
|
|
|
|
+ right := NumGet(rect, 8, "int")
|
|
|
|
|
+ bottom := NumGet(rect, 12, "int")
|
|
|
|
|
+ hdc := DllCall("GetDC", "ptr", hwnd)
|
|
|
|
|
+ hBrush := DllCall("gdi32\CreateSolidBrush", "uint", color, "ptr")
|
|
|
|
|
+ hOldBrush := DllCall("gdi32\SelectObject", "ptr", hdc, "ptr", hBrush, "ptr")
|
|
|
|
|
+ DllCall("gdi32\PatBlt", "ptr", hdc, "int", left, "int", top, "int", right - left, "int", width, "uint", 0x00F00021) ; Top border
|
|
|
|
|
+ DllCall("gdi32\PatBlt", "ptr", hdc, "int", left, "int", bottom - width, "int", right - left, "int", width, "uint", 0x00F00021) ; Bottom border
|
|
|
|
|
+ DllCall("gdi32\PatBlt", "ptr", hdc, "int", left, "int", top, "int", width, "int", bottom - top, "uint", 0x00F00021) ; Left border
|
|
|
|
|
+ DllCall("gdi32\PatBlt", "ptr", hdc, "int", right - width, "int", top, "int", width, "int", bottom - top, "uint", 0x00F00021) ; Right border
|
|
|
|
|
+ DllCall("gdi32\SelectObject", "ptr", hdc, "ptr", hOldBrush)
|
|
|
|
|
+ DllCall("gdi32\DeleteObject", "ptr", hBrush)
|
|
|
|
|
+ DllCall("ReleaseDC", "ptr", hwnd, "ptr", hdc)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static ReDrawBorderEdge(hwnd, style, color, width)
|
|
|
|
|
+ {
|
|
|
|
|
+ if style = 'edge' && !RegExMatch(color, 'i)^(default|1|0)$')
|
|
|
|
|
+ this.DrawBorderEdge(hwnd, color, width)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static RedrawAllBorderEdge()
|
|
|
|
|
+ {
|
|
|
|
|
+ mDhwTmm := this.Set_DHWindows_TMMode(0, 1)
|
|
|
|
|
+
|
|
|
|
|
+ for id in WinGetList('NotifyGUI_ ahk_class AutoHotkeyGUI') {
|
|
|
|
|
+ try {
|
|
|
|
|
+ RegExMatch(WinGetTitle('ahk_id ' id), 'i)^NotifyGUI_\d+_([a-z]+)_([a-z]+)_(\w+)_(\d+)_(\d+)_\d+', &match)
|
|
|
|
|
+ this.ReDrawBorderEdge(id, match[2], match[3], match[4])
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.Set_DHWindows_TMMode(mDhwTmm['dhwPrev'], mDhwTmm['tmmPrev'])
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static MonitorGetMouseIsIn()
|
|
|
|
|
+ {
|
|
|
|
|
+ point := Buffer(8)
|
|
|
|
|
+ DllCall("user32\GetCursorPos", "Ptr", point)
|
|
|
|
|
+ x := NumGet(point, 0, "Int")
|
|
|
|
|
+ y := NumGet(point, 4, "Int")
|
|
|
|
|
+ hMonitor := DllCall("user32\MonitorFromPoint", "Int64", (y << 32) | (x & 0xFFFFFFFF), "UInt", 0x2, "Ptr")
|
|
|
|
|
+ return hMonitor ? this.MonitorGetNumberFromHandle(hMonitor) : MonitorGetPrimary()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static MonitorGetWindowIsIn(winTitle)
|
|
|
|
|
+ {
|
|
|
|
|
+ hMonitor := DllCall("user32\MonitorFromWindow", "Ptr", WinExist(winTitle), "UInt", 0x2, "Ptr")
|
|
|
|
|
+ return hMonitor ? this.MonitorGetNumberFromHandle(hMonitor) : MonitorGetPrimary()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static MonitorGetNumberFromHandle(hMonitor)
|
|
|
|
|
+ {
|
|
|
|
|
+ NumPut("UInt", 104, MONITORINFOEX := Buffer(104), 0)
|
|
|
|
|
+ return DllCall("user32\GetMonitorInfo", "Ptr", hMonitor, "Ptr", MONITORINFOEX)
|
|
|
|
|
+ ? RegExReplace( StrGet(MONITORINFOEX.Ptr + 40, 32) , ".*(\d+)$", "$1")
|
|
|
|
|
+ : MonitorGetPrimary()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /********************************************************************************************
|
|
|
|
|
+ * @credits lexikos
|
|
|
|
|
+ * @see {@link https://www.autohotkey.com/boards/viewtopic.php?t=103459 AHK Forum}
|
|
|
|
|
+ */
|
|
|
|
|
+ static CalculatePopupWindowPosition(hwnd)
|
|
|
|
|
+ {
|
|
|
|
|
+ CoordMode('Mouse', 'Screen')
|
|
|
|
|
+ MouseGetPos(&x, &y)
|
|
|
|
|
+ anchorPt := Buffer(8)
|
|
|
|
|
+ windowRect := Buffer(16), windowSize := windowRect.ptr + 8
|
|
|
|
|
+ excludeRect := Buffer(16)
|
|
|
|
|
+ outRect := Buffer(16)
|
|
|
|
|
+ DllCall("GetClientRect", "ptr", hwnd, "ptr", windowRect)
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ Windows 7 permits overlap with the taskbar, whereas Windows 10 requires the
|
|
|
|
|
+ tooltip to be within the work area (WinMove can subvert that, so this is just
|
|
|
|
|
+ for consistency with the normal behaviour).
|
|
|
|
|
+ */
|
|
|
|
|
+ flags := VerCompare(A_OSVersion, "6.2") < 0 ? 0 : 0x10000 ; TPM_WORKAREA
|
|
|
|
|
+
|
|
|
|
|
+ NumPut("int", x+16, "int", y+16, anchorPt) ; ToolTip normally shows at an offset of 16,16 from the cursor.
|
|
|
|
|
+ NumPut("int", x-3, "int", y-3, "int", x+3, "int", y+3, excludeRect) ; Avoid the area around the mouse pointer.
|
|
|
|
|
+ DllCall("CalculatePopupWindowPosition", "ptr", anchorPt, "ptr", windowSize, "uint", flags, "ptr", excludeRect, "ptr", outRect)
|
|
|
|
|
+ return 'x' NumGet(outRect, 0, 'int') ' y' NumGet(outRect, 4, 'int')
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static RGB_BGR(c) => ((c & 0xFF) << 16 | c & 0xFF00 | c >> 16)
|
|
|
|
|
+
|
|
|
|
|
+ ;============================================================================================
|
|
|
|
|
+
|
|
|
|
|
+ static MapCI() => (m := Map(), m.CaseSense := false, m)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/****************************************************************************************************************************************
|
|
|
|
|
+ * @description: JSON格式字符串序列化和反序列化, 修改自[HotKeyIt/Yaml](https://github.com/HotKeyIt/Yaml)
|
|
|
|
|
+ * 增加了对true/false/null类型的支持, 保留了数值的类型
|
|
|
|
|
+ * @author thqby, HotKeyIt
|
|
|
|
|
+ * @date 2024/02/24
|
|
|
|
|
+ * @version 1.0.7
|
|
|
|
|
+ ************************************************************************************************/
|
|
|
|
|
+class _JSON_thqby {
|
|
|
|
|
+ static null := ComValue(1, 0), true := ComValue(0xB, 1), false := ComValue(0xB, 0)
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Converts a AutoHotkey Object Notation JSON string into an object.
|
|
|
|
|
+ * @param text A valid JSON string.
|
|
|
|
|
+ * @param keepbooltype convert true/false/null to JSON.true / JSON.false / JSON.null where it's true, otherwise 1 / 0 / ''
|
|
|
|
|
+ * @param as_map object literals are converted to map, otherwise to object
|
|
|
|
|
+ */
|
|
|
|
|
+ static parse(text, keepbooltype := false, as_map := true) {
|
|
|
|
|
+ keepbooltype ? (_true := this.true, _false := this.false, _null := this.null) : (_true := true, _false := false, _null := "")
|
|
|
|
|
+ as_map ? (map_set := (maptype := Map).Prototype.Set) : (map_set := (obj, key, val) => obj.%key% := val, maptype := Object)
|
|
|
|
|
+ NQ := "", LF := "", LP := 0, P := "", R := ""
|
|
|
|
|
+ D := [C := (A := InStr(text := LTrim(text, " `t`r`n"), "[") = 1) ? [] : maptype()], text := LTrim(SubStr(text, 2), " `t`r`n"), L := 1, N := 0, V := K := "", J := C, !(Q := InStr(text, '"') != 1) ? text := LTrim(text, '"') : ""
|
|
|
|
|
+ Loop Parse text, '"' {
|
|
|
|
|
+ Q := NQ ? 1 : !Q
|
|
|
|
|
+ NQ := Q && RegExMatch(A_LoopField, '(^|[^\\])(\\\\)*\\$')
|
|
|
|
|
+ if !Q {
|
|
|
|
|
+ if (t := Trim(A_LoopField, " `t`r`n")) = "," || (t = ":" && V := 1)
|
|
|
|
|
+ continue
|
|
|
|
|
+ else if t && (InStr("{[]},:", SubStr(t, 1, 1)) || A && RegExMatch(t, "m)^(null|false|true|-?\d+(\.\d*(e[-+]\d+)?)?)\s*[,}\]\r\n]")) {
|
|
|
|
|
+ Loop Parse t {
|
|
|
|
|
+ if N && N--
|
|
|
|
|
+ continue
|
|
|
|
|
+ if InStr("`n`r `t", A_LoopField)
|
|
|
|
|
+ continue
|
|
|
|
|
+ else if InStr("{[", A_LoopField) {
|
|
|
|
|
+ if !A && !V
|
|
|
|
|
+ throw Error("Malformed JSON - missing key.", 0, t)
|
|
|
|
|
+ C := A_LoopField = "[" ? [] : maptype(), A ? D[L].Push(C) : map_set(D[L], K, C), D.Has(++L) ? D[L] := C : D.Push(C), V := "", A := Type(C) = "Array"
|
|
|
|
|
+ continue
|
|
|
|
|
+ } else if InStr("]}", A_LoopField) {
|
|
|
|
|
+ if !A && V
|
|
|
|
|
+ throw Error("Malformed JSON - missing value.", 0, t)
|
|
|
|
|
+ else if L = 0
|
|
|
|
|
+ throw Error("Malformed JSON - to many closing brackets.", 0, t)
|
|
|
|
|
+ else C := --L = 0 ? "" : D[L], A := Type(C) = "Array"
|
|
|
|
|
+ } else if !(InStr(" `t`r,", A_LoopField) || (A_LoopField = ":" && V := 1)) {
|
|
|
|
|
+ if RegExMatch(SubStr(t, A_Index), "m)^(null|false|true|-?\d+(\.\d*(e[-+]\d+)?)?)\s*[,}\]\r\n]", &R) && (N := R.Len(0) - 2, R := R.1, 1) {
|
|
|
|
|
+ if A
|
|
|
|
|
+ C.Push(R = "null" ? _null : R = "true" ? _true : R = "false" ? _false : IsNumber(R) ? R + 0 : R)
|
|
|
|
|
+ else if V
|
|
|
|
|
+ map_set(C, K, R = "null" ? _null : R = "true" ? _true : R = "false" ? _false : IsNumber(R) ? R + 0 : R), K := V := ""
|
|
|
|
|
+ else throw Error("Malformed JSON - missing key.", 0, t)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ; Added support for comments without '"'
|
|
|
|
|
+ if A_LoopField == '/' {
|
|
|
|
|
+ nt := SubStr(t, A_Index + 1, 1), N := 0
|
|
|
|
|
+ if nt == '/' {
|
|
|
|
|
+ if nt := InStr(t, '`n', , A_Index + 2)
|
|
|
|
|
+ N := nt - A_Index - 1
|
|
|
|
|
+ } else if nt == '*' {
|
|
|
|
|
+ if nt := InStr(t, '*/', , A_Index + 2)
|
|
|
|
|
+ N := nt + 1 - A_Index
|
|
|
|
|
+ } else nt := 0
|
|
|
|
|
+ if N
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ throw Error("Malformed JSON - unrecognized character.", 0, A_LoopField " in " t)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if A || InStr(t, ':') > 1
|
|
|
|
|
+ throw Error("Malformed JSON - unrecognized character.", 0, SubStr(t, 1, 1) " in " t)
|
|
|
|
|
+ } else if NQ && (P .= A_LoopField '"', 1)
|
|
|
|
|
+ continue
|
|
|
|
|
+ else if A
|
|
|
|
|
+ LF := P A_LoopField, C.Push(InStr(LF, "\") ? UC(LF) : LF), P := ""
|
|
|
|
|
+ else if V
|
|
|
|
|
+ LF := P A_LoopField, map_set(C, K, InStr(LF, "\") ? UC(LF) : LF), K := V := P := ""
|
|
|
|
|
+ else
|
|
|
|
|
+ LF := P A_LoopField, K := InStr(LF, "\") ? UC(LF) : LF, P := ""
|
|
|
|
|
+ }
|
|
|
|
|
+ return J
|
|
|
|
|
+ UC(S, e := 1) {
|
|
|
|
|
+ static m := Map('"', '"', "a", "`a", "b", "`b", "t", "`t", "n", "`n", "v", "`v", "f", "`f", "r", "`r")
|
|
|
|
|
+ local v := ""
|
|
|
|
|
+ Loop Parse S, "\"
|
|
|
|
|
+ if !((e := !e) && A_LoopField = "" ? v .= "\" : !e ? (v .= A_LoopField, 1) : 0)
|
|
|
|
|
+ v .= (t := m.Get(SubStr(A_LoopField, 1, 1), 0)) ? t SubStr(A_LoopField, 2) :
|
|
|
|
|
+ (t := RegExMatch(A_LoopField, "i)^(u[\da-f]{4}|x[\da-f]{2})\K")) ?
|
|
|
|
|
+ Chr("0x" SubStr(A_LoopField, 2, t - 2)) SubStr(A_LoopField, t) : "\" A_LoopField,
|
|
|
|
|
+ e := A_LoopField = "" ? e : !e
|
|
|
|
|
+ return v
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Converts a AutoHotkey Array/Map/Object to a Object Notation JSON string.
|
|
|
|
|
+ * @param obj A AutoHotkey value, usually an object or array or map, to be converted.
|
|
|
|
|
+ * @param expandlevel The level of JSON string need to expand, by default expand all.
|
|
|
|
|
+ * @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
|
|
|
|
|
+ */
|
|
|
|
|
+ static stringify(obj, expandlevel := unset, space := " ") {
|
|
|
|
|
+ expandlevel := IsSet(expandlevel) ? Abs(expandlevel) : 10000000
|
|
|
|
|
+ return Trim(CO(obj, expandlevel))
|
|
|
|
|
+ CO(O, J := 0, R := 0, Q := 0) {
|
|
|
|
|
+ static M1 := "{", M2 := "}", S1 := "[", S2 := "]", N := "`n", C := ",", S := "- ", E := "", K := ":"
|
|
|
|
|
+ if (OT := Type(O)) = "Array" {
|
|
|
|
|
+ D := !R ? S1 : ""
|
|
|
|
|
+ for key, value in O {
|
|
|
|
|
+ F := (VT := Type(value)) = "Array" ? "S" : InStr("Map,Object", VT) ? "M" : E
|
|
|
|
|
+ Z := VT = "Array" && value.Length = 0 ? "[]" : ((VT = "Map" && value.count = 0) || (VT = "Object" && ObjOwnPropCount(value) = 0)) ? "{}" : ""
|
|
|
|
|
+ D .= (J > R ? "`n" CL(R + 2) : "") (F ? (%F%1 (Z ? "" : CO(value, J, R + 1, F)) %F%2) : ES(value)) (OT = "Array" && O.Length = A_Index ? E : C)
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ D := !R ? M1 : ""
|
|
|
|
|
+ for key, value in (OT := Type(O)) = "Map" ? (Y := 1, O) : (Y := 0, O.OwnProps()) {
|
|
|
|
|
+ F := (VT := Type(value)) = "Array" ? "S" : InStr("Map,Object", VT) ? "M" : E
|
|
|
|
|
+ Z := VT = "Array" && value.Length = 0 ? "[]" : ((VT = "Map" && value.count = 0) || (VT = "Object" && ObjOwnPropCount(value) = 0)) ? "{}" : ""
|
|
|
|
|
+ D .= (J > R ? "`n" CL(R + 2) : "") (Q = "S" && A_Index = 1 ? M1 : E) ES(key) K (F ? (%F%1 (Z ? "" : CO(value, J, R + 1, F)) %F%2) : ES(value)) (Q = "S" && A_Index = (Y ? O.count : ObjOwnPropCount(O)) ? M2 : E) (J != 0 || R ? (A_Index = (Y ? O.count : ObjOwnPropCount(O)) ? E : C) : E)
|
|
|
|
|
+ if J = 0 && !R
|
|
|
|
|
+ D .= (A_Index < (Y ? O.count : ObjOwnPropCount(O)) ? C : E)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if J > R
|
|
|
|
|
+ D .= "`n" CL(R + 1)
|
|
|
|
|
+ if R = 0
|
|
|
|
|
+ D := RegExReplace(D, "^\R+") (OT = "Array" ? S2 : M2)
|
|
|
|
|
+ return D
|
|
|
|
|
+ }
|
|
|
|
|
+ ES(S) {
|
|
|
|
|
+ switch Type(S) {
|
|
|
|
|
+ case "Float":
|
|
|
|
|
+ if (v := '', d := InStr(S, 'e'))
|
|
|
|
|
+ v := SubStr(S, d), S := SubStr(S, 1, d - 1)
|
|
|
|
|
+ if ((StrLen(S) > 17) && (d := RegExMatch(S, "(99999+|00000+)\d{0,3}$")))
|
|
|
|
|
+ S := Round(S, Max(1, d - InStr(S, ".") - 1))
|
|
|
|
|
+ return S v
|
|
|
|
|
+ case "Integer":
|
|
|
|
|
+ return S
|
|
|
|
|
+ case "String":
|
|
|
|
|
+ S := StrReplace(S, "\", "\\")
|
|
|
|
|
+ S := StrReplace(S, "`t", "\t")
|
|
|
|
|
+ S := StrReplace(S, "`r", "\r")
|
|
|
|
|
+ S := StrReplace(S, "`n", "\n")
|
|
|
|
|
+ S := StrReplace(S, "`b", "\b")
|
|
|
|
|
+ S := StrReplace(S, "`f", "\f")
|
|
|
|
|
+ S := StrReplace(S, "`v", "\v")
|
|
|
|
|
+ S := StrReplace(S, '"', '\"')
|
|
|
|
|
+ return '"' S '"'
|
|
|
|
|
+ default:
|
|
|
|
|
+ return S == this.true ? "true" : S == this.false ? "false" : "null"
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ CL(i) {
|
|
|
|
|
+ Loop (s := "", space ? i - 1 : 0)
|
|
|
|
|
+ s .= space
|
|
|
|
|
+ return s
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|