Proposed New GUI API for AutoHotkey v2
Re: Proposed New GUI API for AutoHotkey v2
Oh, and I forgot to say - Thank you Fincs SO MUCH for doing this!
Re: Proposed New GUI API for AutoHotkey v2
fincs wrote:See SciTE4AutoHotkey AHK v2 Support.
But that would then mean I have to choose AHK2 OR AHK1, to be associated with .ahkTo enable this feature, %AutoHotkeyDir%\v2-alpha\x86\AutoHotkey.exe (or x64) must exist [...] and .ahk files will now be detected as AutoHotkey v2 files
Would it be possible to do the same but use the extension .ahk2 ?
Re: Proposed New GUI API for AutoHotkey v2
No, sorry. Currently there's no standardised AHK v2 file extension and .ahk is used.
It is very easy to tell S4AHK whether to use v1.1 or v2 binaries; use the platform selection menu .
It is very easy to tell S4AHK whether to use v1.1 or v2 binaries; use the platform selection menu .
fincs
Windows 11 Pro (Version 22H2) | AMD Ryzen 7 3700X with 32 GB of RAM | AutoHotkey v2.0.0 + v1.1.36.02
Get SciTE4AutoHotkey v3.1.0 -[My project list]
Windows 11 Pro (Version 22H2) | AMD Ryzen 7 3700X with 32 GB of RAM | AutoHotkey v2.0.0 + v1.1.36.02
Get SciTE4AutoHotkey v3.1.0 -
Re: Proposed New GUI API for AutoHotkey v2
Ah I see, so I could have ahk associated with v1, but when I hit F5 in SciTe, it will pass the v2 code to the v2 binary?fincs wrote:No, sorry. Currently there's no standardised AHK v2 file extension and .ahk is used.
It is very easy to tell S4AHK whether to use v1.1 or v2 binaries; use the platform selection menu .
Re: Proposed New GUI API for AutoHotkey v2
Yes.
fincs
Windows 11 Pro (Version 22H2) | AMD Ryzen 7 3700X with 32 GB of RAM | AutoHotkey v2.0.0 + v1.1.36.02
Get SciTE4AutoHotkey v3.1.0 -[My project list]
Windows 11 Pro (Version 22H2) | AMD Ryzen 7 3700X with 32 GB of RAM | AutoHotkey v2.0.0 + v1.1.36.02
Get SciTE4AutoHotkey v3.1.0 -
Re: Proposed New GUI API for AutoHotkey v2
Yeah, looks to be working but it is unstable.
If I put a breakpoint in the OnSize method, it seems to stop at the breakpoint OK, but as soon as I hit F5 to continue, the script stops responding.
If I put a breakpoint in the OnSize method, it seems to stop at the breakpoint OK, but as soon as I hit F5 to continue, the script stops responding.
Last edited by evilC on 02 Aug 2014, 07:43, edited 1 time in total.
Re: Proposed New GUI API for AutoHotkey v2
Update: It does not seem to like it when you declare Critical
I did not need it in my code anyway, so I removed it.
When I debug with critical in the code and it hangs, it seems to leave processes (but no tray icon) - I had to reboot to fix it all as just killing the processes didn't seem to fix it.
I have seen one crash since removing critical though, so it doesn't seem quite 100% (Or I am doing something wrong...).
I did not need it in my code anyway, so I removed it.
When I debug with critical in the code and it hangs, it seems to leave processes (but no tray icon) - I had to reboot to fix it all as just killing the processes didn't seem to fix it.
I have seen one crash since removing critical though, so it doesn't seem quite 100% (Or I am doing something wrong...).
Re: Proposed New GUI API for AutoHotkey v2
Really starting to make some progress now
Two scrolling windows within a parent window - the left one holds the Child windows, the right one is going to be a "Task Bar" (Where Child Windows go when you minimize them). I decided against leaving the child windows on the main canvas when you minimize them, as if you resize the window they can go out of view. You could arrange them, but moving more than one or two is too slow, so I decided to pack all the minimized window into another "Task Bar", so resizing the main window will just cause scroll bars to be generated for the task bar.
I rigged the mouse wheel to act somewhat intelligently as described here.
video of it in action: http://screencast-o-matic.com/watch/c2jec3nK4Z
I still need to make the minimized windows tile neatly in the taskbar, but overall I am increasing happy with the result.
An OnMove() event for GUIs would be really nice though - that way I could have the scrollbars update when you drag windows around.
Two scrolling windows within a parent window - the left one holds the Child windows, the right one is going to be a "Task Bar" (Where Child Windows go when you minimize them). I decided against leaving the child windows on the main canvas when you minimize them, as if you resize the window they can go out of view. You could arrange them, but moving more than one or two is too slow, so I decided to pack all the minimized window into another "Task Bar", so resizing the main window will just cause scroll bars to be generated for the task bar.
I rigged the mouse wheel to act somewhat intelligently as described here.
video of it in action: http://screencast-o-matic.com/watch/c2jec3nK4Z
I still need to make the minimized windows tile neatly in the taskbar, but overall I am increasing happy with the result.
An OnMove() event for GUIs would be really nice though - that way I could have the scrollbars update when you drag windows around.
Re: Proposed New GUI API for AutoHotkey v2
A virtual "Windows" environment comlpete with TaskBar and independently scrolling sub-windows (With mousewheel input redirected accordingly).
You can also click TaskBar items to minimize / restore child windows.
Scrollbars updated as you drag stuff around also
http://screencast-o-matic.com/watch/c2jeYjnKgC
I will be using it for my Universal Control Remapper (UCR) project (A GUIfied version of AHK's remapping functionality) but I would love to make it so that anyone can use it as a base for their own applications - just extend the CChildWindow class to give the child windows whatever capability you desire!
https://github.com/evilC/UCR
You can also click TaskBar items to minimize / restore child windows.
Scrollbars updated as you drag stuff around also
http://screencast-o-matic.com/watch/c2jeYjnKgC
I will be using it for my Universal Control Remapper (UCR) project (A GUIfied version of AHK's remapping functionality) but I would love to make it so that anyone can use it as a base for their own applications - just extend the CChildWindow class to give the child windows whatever capability you desire!
https://github.com/evilC/UCR
Re: Proposed New GUI API for AutoHotkey v2
Really cool!
Windows 10 x64 Professional, Intel i5-8500, NVIDIA GTX 1060 6GB, 2x16GB Kingston FURY Beast - DDR4 3200 MHz | [About Me] | [About the AHK Foundation] | [Courses on AutoHotkey]
[ASPDM - StdLib Distribution] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library]
Re: Proposed New GUI API for AutoHotkey v2
I am trying to get my head around something, and could do with a little help.
Setting a GUI's position like so: Gui.Show("x0 y0 w200 h50") results in the GUI being positioned relative to the current viewport, not the canvas.
In other words, if you have one GUI parented to another via +Parent<hwnd>, and the parent is currently scrolled down (or right), then the Show() command positions the item relative to the current view.
This is not the problem, I am quite capable of dealing with that.
What I would like to work out how to do is override the GUI's Show() method and adjust for the offset accordingly.
Something along these lines:
I know there are other ways to achieve this, but I just wondered if there were a way to "extend" the gui objects like you could in AFC. I also preferred in AFC how the class and the gui object were one and the same - so instead of me having to do this._Gui.Show() I would like to be able to just do this.Show().
I am guessing maybe the solution may be __Call ? I am having some trouble understanding that, so if someone could help me out, that would be great.
Setting a GUI's position like so: Gui.Show("x0 y0 w200 h50") results in the GUI being positioned relative to the current viewport, not the canvas.
In other words, if you have one GUI parented to another via +Parent<hwnd>, and the parent is currently scrolled down (or right), then the Show() command positions the item relative to the current view.
This is not the problem, I am quite capable of dealing with that.
What I would like to work out how to do is override the GUI's Show() method and adjust for the offset accordingly.
Something along these lines:
Code: Select all
#SingleInstance force
myWin := new CWindow
Class CWindow {
__New(title := "", options := "", parent := 0){
this._Gui := GuiCreate(title, options, this)
this.parent := parent
this._Gui.Show("x0 y0 w600 h200")
; I want to be able to do this
;this._Gui.Show({x: 0, y: 0, w: 600, h: 200})
; ... and possibly this - ie "merge" GUI onto "this"
; this.AddButton(blah)
}
; Like Gui.Show, but relative to the viewport (ie 0,0 is top left of canvas, not top left of current view)
; Also uses assoc array (ie {x: 0, y: 0} instead of a string
Show(options := 0){
msgbox("Custom Show being used")
if (!options){
options := {x: 0, y: 0, w: 200, h: 50}
}
if (this.Parent){
offset := this.GetWindowOffSet(this.Parent.Hwnd)
} else {
offset := {x: 0, y: 0}
}
str := ""
ctr := 0
For key, value in options {
if (key = "x"){
value += offset.x
} else if (key = "y"){
value += offset.y
}
if (ctr){
str .= " "
}
str .= key . value
ctr++
}
this._Gui.Show(str)
}
; Get the offset of the canvas of a window due to scrollbar position
GetWindowOffSet(hwnd){
ret := {x: 0, y: 0}
info := this.GetScrollInfos(hwnd)
if (info[0] == 0){
; No x scroll bar
ret.x := 0
} else {
ret.x := info[0].nPos * -1
}
if (info[1] == 0){
; No y scroll bar
ret.y := 0
} else {
ret.y := info[1].nPos * -1
}
return ret
}
GetScrollInfos(hwnd){
ret := []
ret[0] := this.GetScrollInfo(hwnd, 0)
ret[1] := this.GetScrollInfo(hwnd, 1)
return ret
}
; Wrapper for GetScrollInfo DllCall
GetScrollInfo(hwnd, bar){
static SIF_ALL := 0x17
VarSetCapacity(si, 28, 0)
NumPut(28, si) ; cbSize
NumPut(SIF_ALL, si, 4) ; fMask
if (DllCall("GetScrollInfo", "uint", hwnd, "int", bar, "uint", &si)){
ret := {}
ret.cbSize := NumGet(si, 0, "uint") ; cbSize
ret.fMask := NumGet(si, 4, "uint") ; fMask
ret.nMin := NumGet(si, 8, "int") ; nMin
ret.nMax := NumGet(si, 12, "int") ; nMax
ret.nPage := NumGet(si, 16) ; nPage
ret.nPos := NumGet(si, 20) ; nPos
ret.nTrackPos := NumGet(si, 24) ; nTrackPos
return ret
} else {
return 0
}
}
}
I am guessing maybe the solution may be __Call ? I am having some trouble understanding that, so if someone could help me out, that would be great.
Re: Proposed New GUI API for AutoHotkey v2
Hmm, I think I worked it out, I used __Call to route Sets, Gets and Calls to the relevant places.
I ended up with something like this (working code):
Any comments on what i have done here? Bad practice? Better way to do it?
I ended up with something like this (working code):
Code: Select all
#SingleInstance force
test := new MyClass
Class MyClass {
__New(){
this.Gui := GuiCreate("First Title")
; Try some stuff with the regular this.Gui method...
this.Gui.Show("x0 y0 w500 h100") ; Start off in top left
msgbox("Pre Move Margin: " this.Gui.MarginX)
; Try to call Gui methods via "this"
this.Title := "Second Title"
this.BgColor := "Red"
this.Show("x100 y100") ; this._Show() is present, so overrides Gui.Show()
this.MarginX := 0 ; Set on this
msgbox("Post Move Margin: " this.Gui.MarginX) ; Margin was set on this, applied to this.Gui
this.Hide() ; _Hide not declared in class, so this routes direct to Gui's hide() method
msgbox("check margins match: " this.MarginX)
}
__Get(aName){
static GuiGets := {Title: 1, MarginX: 1, MarginY: 1, Hwnd: 1, Control: 1}
if (GuiGets[aName]){
return this["Gui"][aName]
}
}
__Set(aName, aValue){
static GuiSets := {Title: 1, MarginX: 1, MarginY: 1 , BgColor: 1, CtrlColor: 1, Menu: 1}
if (GuiSets[aName]){
this["Gui"][aName] := avalue
return
}
}
__Call(Method, p*) {
if (!IsObject(this[method])){
; If method not found on this class...
mf := "_" . method
if (IsObject(this[mf])){
; If underscore prefixed version exists - execute that
return this[mf](p*)
} else {
; Else try the Gui item
return this["Gui"][method](p*)
}
}
}
_Show(options){
; Do something fancy with the options, eg correct for scrolled parent
options .= " w200"
this.Gui.Show(options)
}
}
Re: Proposed New GUI API for AutoHotkey v2
I have a question regarding the OnClose() event of GUIs.
This event happens before the Gui is removed from view, but after the Gui object is counted as destroyed (ie calling MyGui.Destroy() throws an "The Gui is destroyed" error)
This is a bit of a problem for me at the moment.
I am working on a windows desktop style GUI in AHK - each "Child Window" GUI has a corresponding "Task Bar" Gui that you can click on to minimize / restore the GUI that it represents. See here for a video if you don't get what I mean: http://screencast-o-matic.com/watch/c2jeYjnKgC
OK, so when I close one of the main child windows (in the right pane), I must also remove the corresponding task bar entry (in the left pane).
Removing the task bar gui in the left pane means that tasks below it must be shuffled up to fill the space.
Doing this takes time.
So when you close one of the windows in the right pane, OnClose is called, but the child window in that pane has not disappeared yet.
It must then shuffle all of the taskbar items up ("pack") before that thread completes and the gui that you clicked "X" on disappears.
Is there maybe a way to avoid this?
You can hide the gui, but that just means that the program locks up until the pack completes.
I guess any solution would still mean that the pack completing would lock the program up?
I was gonna look into subscribing to the WM_PARENTNOTIFY message, so I can separate the threads out, dunno if that will help.
Maybe what I really need is a quicker way of moving multiple GUIs together. Whatever happens, deleting one task item will mean all tasks below it need to be moved up by the same amount, so I suppose if they could all be moved in one go, that may accelerate the whole thing considerably. Does anyone know of a way to move multiple HWNDs by the same amount all in one go?
Suggestions welcomed...
This event happens before the Gui is removed from view, but after the Gui object is counted as destroyed (ie calling MyGui.Destroy() throws an "The Gui is destroyed" error)
This is a bit of a problem for me at the moment.
I am working on a windows desktop style GUI in AHK - each "Child Window" GUI has a corresponding "Task Bar" Gui that you can click on to minimize / restore the GUI that it represents. See here for a video if you don't get what I mean: http://screencast-o-matic.com/watch/c2jeYjnKgC
OK, so when I close one of the main child windows (in the right pane), I must also remove the corresponding task bar entry (in the left pane).
Removing the task bar gui in the left pane means that tasks below it must be shuffled up to fill the space.
Doing this takes time.
So when you close one of the windows in the right pane, OnClose is called, but the child window in that pane has not disappeared yet.
It must then shuffle all of the taskbar items up ("pack") before that thread completes and the gui that you clicked "X" on disappears.
Is there maybe a way to avoid this?
You can hide the gui, but that just means that the program locks up until the pack completes.
I guess any solution would still mean that the pack completing would lock the program up?
I was gonna look into subscribing to the WM_PARENTNOTIFY message, so I can separate the threads out, dunno if that will help.
Maybe what I really need is a quicker way of moving multiple GUIs together. Whatever happens, deleting one task item will mean all tasks below it need to be moved up by the same amount, so I suppose if they could all be moved in one go, that may accelerate the whole thing considerably. Does anyone know of a way to move multiple HWNDs by the same amount all in one go?
Suggestions welcomed...
Re: Proposed New GUI API for AutoHotkey v2
ScrollWindow moves multiple child windows by the same amount in one go.
Re: Proposed New GUI API for AutoHotkey v2
Yeah, I thought about that, but that would only work if you closed the first task surely?
If you had 10 tasks and closed the 3rd task, you only want to move tasks 4-10 up, not 1-2
If you had 10 tasks and closed the 3rd task, you only want to move tasks 4-10 up, not 1-2
Re: Proposed New GUI API for AutoHotkey v2
Right. Perhaps BeginDeferWindowPos and related functions, then.
Re: Proposed New GUI API for AutoHotkey v2
Thankyou Lex, that sounds exactly like what I need.
[Update] Well that was surprisingly simple to implement.
For future reference, here is some test code (v1 code!) demonstrating use of DeferWindowPos
F2 uses normal WinMove, F3 uses DeferWindowPos.
DeferWindowPos is indeed effectively instant!
[Update] Well that was surprisingly simple to implement.
For future reference, here is some test code (v1 code!) demonstrating use of DeferWindowPos
Code: Select all
#SingleInstance force
Gui, New, +hwndMainHwnd
Gui, Show, x0 y0 w500 h500
y := 100
numchildren := 10
Loop %numchildren% {
Gui, New, +hwndChildHwnd%A_Index% +Parent%MainHwnd% -Border
Gui, Add, Text,, % "Hwnd " ChildHwnd%A_Index%
Gui, Show, x0 y%y% w500 h50
y += 50
}
HDWP := DllCall("BeginDeferWindowPos", "int", numchildren)
return
F2::
y := 0
Loop %numchildren% {
hwnd := ChildHwnd%A_Index%
WinMove, ahk_id %hwnd%,, 0, %y%
y += 50
}
return
F3::
y := 0
Loop %numchildren% {
hwnd := ChildHwnd%A_Index%
;WinMove, ahk_id %hwnd%,, 0, %y%
HDWP := DllCall("DeferWindowPos", "Ptr", HDWP, "Ptr", hwnd, "Ptr", , "int", 0, "int", y, "int", 500, "int", 50, "uint", 0)
y += 50
}
DllCall("EndDeferWindowPos", "Ptr", HDWP)
return
DeferWindowPos is indeed effectively instant!
Re: Proposed New GUI API for AutoHotkey v2
Could we maybe get a "Canvas Relative" coord mode for Child GUIs in V2?
As it stands, GUI coords for child GUIs (And controls I think) are relative to the parent's viewport, not to the parent's canvas.
So lets say you have a parent window that is scrolled down 100px
Doing a Gui, Show, x0 y0 +ParentHwnd on a child window positions the child window in the top left of the parent's viewport, not the top left of the parent's canvas. WinMove etc also seem to be susceptible also.
This issue permeates through all kinds of stuff...
For example:
Again, you have a parent window scrolled down 100px.
A Child window is placed at 0,0 - it appears at 0,100 relative to the canvas as mentioned before.
You then minimize the child window.
You then scroll the parent window back up to 0 offset.
Restore the child window - it will appear at 0,0 instead of 0,100 where it was when it was minimized!
As it stands, GUI coords for child GUIs (And controls I think) are relative to the parent's viewport, not to the parent's canvas.
So lets say you have a parent window that is scrolled down 100px
Doing a Gui, Show, x0 y0 +ParentHwnd on a child window positions the child window in the top left of the parent's viewport, not the top left of the parent's canvas. WinMove etc also seem to be susceptible also.
This issue permeates through all kinds of stuff...
For example:
Again, you have a parent window scrolled down 100px.
A Child window is placed at 0,0 - it appears at 0,100 relative to the canvas as mentioned before.
You then minimize the child window.
You then scroll the parent window back up to 0 offset.
Restore the child window - it will appear at 0,0 instead of 0,100 where it was when it was minimized!
Re: Proposed New GUI API for AutoHotkey v2
There are no such things as window viewports and canvases, just the client area. You implemented the scrolling, so you need to do your own coordinate translations.
Re: Proposed New GUI API for AutoHotkey v2
Oh don't get me wrong, I have done it, I just thought it would make a nice addition to AHK.
I am a little confused though (Sorry, the various flavors of windows GUIs - WPF, Forms etc are a bit beyond me atm) as from doing a little googling it does appear that canvases do exist in some form in some windows APIs. I guess just not in whatever AHK was written using?
It seems to me though that it would be relatively simple to make life easier for people implementing such things if AHK's GUI manipulation commands (Show, WinMove etc) were updated to check if the item being manipulated had a parent (GetParent API call) and if so checked the scroll bar status of the parent (GetScrollInfo API call) and if set, subtract the value for each scrollbar from the value passed to the x or y coordinate of the command. Yes, this is possible to do yourself, but requires extra steps that I guess you are already doing in your code - for example with Gui Show, if you pass a string like "x0 y0 w100 h50" then your code already has to parse the string and extract the variables (x,y etc) - it just seems wasteful for the user to be having to do that, only to concatenate them back into a string to pass to Show(), which does it all again. My current implementation works around this by having the user pass an associative array for the parameters, but this then breaks parameter compatibility which is kind of the opposite direction to where I thought we were going with v2. TBH, I would really love to see all AHK v2 GUI related commands accept associative arrays and do away with the old string system.
As a side note, is there any way that AHK's built-in commands can be "overridden"?
For example, declaring a function WinMove() seems to override the built in WinMove(), but I can find no equivalent of base.WinMove() to call the underlying function.
I can understand that many of the stuff that I am talking about is either not on the drawing board or so far off that it would be worth writing something in the meantime, so I have started up a project page here.
I am a little confused though (Sorry, the various flavors of windows GUIs - WPF, Forms etc are a bit beyond me atm) as from doing a little googling it does appear that canvases do exist in some form in some windows APIs. I guess just not in whatever AHK was written using?
It seems to me though that it would be relatively simple to make life easier for people implementing such things if AHK's GUI manipulation commands (Show, WinMove etc) were updated to check if the item being manipulated had a parent (GetParent API call) and if so checked the scroll bar status of the parent (GetScrollInfo API call) and if set, subtract the value for each scrollbar from the value passed to the x or y coordinate of the command. Yes, this is possible to do yourself, but requires extra steps that I guess you are already doing in your code - for example with Gui Show, if you pass a string like "x0 y0 w100 h50" then your code already has to parse the string and extract the variables (x,y etc) - it just seems wasteful for the user to be having to do that, only to concatenate them back into a string to pass to Show(), which does it all again. My current implementation works around this by having the user pass an associative array for the parameters, but this then breaks parameter compatibility which is kind of the opposite direction to where I thought we were going with v2. TBH, I would really love to see all AHK v2 GUI related commands accept associative arrays and do away with the old string system.
As a side note, is there any way that AHK's built-in commands can be "overridden"?
For example, declaring a function WinMove() seems to override the built in WinMove(), but I can find no equivalent of base.WinMove() to call the underlying function.
I can understand that many of the stuff that I am talking about is either not on the drawing board or so far off that it would be worth writing something in the meantime, so I have started up a project page here.