Drag Child GUIs inside/outside of Parent

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
scriptor2016
Posts: 854
Joined: 21 Dec 2015, 02:34

Drag Child GUIs inside/outside of Parent

04 Aug 2017, 00:16

Hi

The script below is from the forums (written by Wicked) - it's a simple parent GUI with 2 Children inside it. When the parent is dragged, the children are dragged along with it accordingly.

Question - is it possible to allow the children to be dragged outside of the parent, and when done so, will not move along with the parent when it is dragged?

Then, if the children are dragged back inside the parent, they will again drag along with it?

Code: Select all

Gui, 99: +LastFound
Gui_99_ID := WinExist()
Gui, 99: Show, w800 h600, Parent

Gui, 1: +LastFound +E0x00010000 ;The ExStyle allows the parent to take focus if it's clicked.
DllCall("SetParent", "uint", WinExist(), "uint", Gui_99_ID)
Gui, 1: Show, x5 y5 w200 h200, Child #1

Gui, 2: +LastFound +E0x00010000
DllCall("SetParent", "uint", WinExist(), "uint", Gui_99_ID)
Gui, 2: Show, x215 y5 w200 h200, Child #2
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Drag Child GUIs inside/outside of Parent

04 Aug 2017, 07:06

It seems that SetParent forces the child windows to remain inside the parent window, so that would have to be discarded.

This might be useful, to determine if 2 windows overlap or not:
check if rectangles (windows) overlap - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 59#p163359

Also something like Dock or Anchor (which I haven't tested) might be useful:
Dock - Attach a window to another - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=30912
Dock window issues - Ask for Help - AutoHotkey Community
https://autohotkey.com/board/topic/8808 ... ow-issues/
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
FanaticGuru
Posts: 1906
Joined: 30 Sep 2013, 22:25

Re: Drag Child GUIs inside/outside of Parent

04 Aug 2017, 14:25

jeeswg wrote:It seems that SetParent forces the child windows to remain inside the parent window, so that would have to be discarded.
Not necessarily.

The approach I would take would be to have when the child window is clicked on to drag, it has its SetParent set to null to basically clear its parent and then depending on where it is when the drag is released the SetParent either stays null or is again set to make It a child of the window it is on.

Don't know if that would work but it is what I would try.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
scriptor2016
Posts: 854
Joined: 21 Dec 2015, 02:34

Re: Drag Child GUIs inside/outside of Parent

04 Aug 2017, 23:55

I think the detecting overlapping windows route might be an intereresting way to go - so the following script (which jeeswg referenced) gets the class of 2 different windows, then detects if they are overlapping or not. In this case it detetcs if notepad is overlapping notepad++ (or vice-versa):

Code: Select all

q:: ;check if 2 windows overlap using IntersectRect
WinGet, hWnd1, ID, ahk_class Notepad
WinGet, hWnd2, ID, ahk_class Notepad++
VarSetCapacity(RECT1, 16, 0)
VarSetCapacity(RECT2, 16, 0)
VarSetCapacity(RECT3, 16, 0)
DllCall("user32\GetWindowRect", Ptr,hWnd1, Ptr,&RECT1)
DllCall("user32\GetWindowRect", Ptr,hWnd2, Ptr,&RECT2)
vRet := DllCall("user32\IntersectRect", Ptr,&RECT3, Ptr,&RECT1, Ptr,&RECT2)
MsgBox, % "overlap: " (vRet ? "Y" : "N")
return
I'd lkike to see if the script can detect overlapping windows by getting their WinTitles instead of their Winclass. Here's what I've done:

Code: Select all

q:: ;check if 2 windows overlap using IntersectRect
WinGet, hWnd1, ID, ahk_class Notepad
WinGetTitle, title1, ahk_id %hWnd1%

WinGet, hWnd2, ID, ahk_class Notepad++
WinGetTitle, title2, ahk_id %hWnd2%

VarSetCapacity(RECT1, 16, 0)
VarSetCapacity(RECT2, 16, 0)
VarSetCapacity(RECT3, 16, 0)
DllCall("user32\GetWindowRect", Ptr,hWnd1, Ptr,&RECT1)
DllCall("user32\GetWindowRect", Ptr,hWnd2, Ptr,&RECT2)
vRet := DllCall("user32\IntersectRect", Ptr,&RECT3, Ptr,&RECT1, Ptr,&RECT2)
MsgBox, % "overlap: " (vRet ? "Y" : "N")
return
After each 'WinGet', I added a 'WinGetTitle' on the line below - am I headed in the right direction?
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Drag Child GUIs inside/outside of Parent

05 Aug 2017, 04:05

@FanaticGuru: ... SetParent also seems to have the unfortunate consequence of moving the child windows, whenever a new parent is set, otherwise that idea might have been useful. That is unless ... there are some other workarounds.

@scriptor2016:

Code: Select all

WinGet, hWnd1, ID, Untitled - Notepad ahk_class Notepad
WinGet, hWnd2, ID, Document - WordPad ahk_class WordPadClass
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Drag Child GUIs inside/outside of Parent

05 Aug 2017, 05:57

I've had a go at a script for this. There are likely other good/better approaches, so I would welcome other people sharing scripts.

Code: Select all

;if the main window is moved, any 'child' windows that overlap with it, are also moved
Gui, 99: +Resize +hwndhWnd1
Gui, 99: Show, w800 h600
Gui, 1: +Resize +hwndhWnd2 +AlwaysOnTop
Gui, 1: Show, x5 y5 w200 h200, Child #1
Gui, 2: +Resize +hwndhWnd3 +AlwaysOnTop
Gui, 2: Show, x215 y5 w200 h200, Child #2

WinGetPos, vWin1X, vWin1Y, vWin1W, vWin1H, % "ahk_id " hWnd1
WinGetPos, vWin2X, vWin2Y, vWin2W, vWin2H, % "ahk_id " hWnd2
WinGetPos, vWin3X, vWin3Y, vWin3W, vWin3H, % "ahk_id " hWnd3

vOverlap1 := JEE_WinOverlap(hWnd1, hWnd2)
vOverlap2 := JEE_WinOverlap(hWnd1, hWnd3)
return

;==================================================

JEE_WinOverlap(hWnd1, hWnd2)
{
	local RECT1, RECT2, RECT3
	VarSetCapacity(RECT1, 16, 0)
	VarSetCapacity(RECT2, 16, 0)
	VarSetCapacity(RECT3, 16, 0)
	DllCall("user32\GetWindowRect", Ptr,hWnd1, Ptr,&RECT1)
	DllCall("user32\GetWindowRect", Ptr,hWnd2, Ptr,&RECT2)
	return DllCall("user32\IntersectRect", Ptr,&RECT3, Ptr,&RECT1, Ptr,&RECT2)
}

;==================================================

onMove(hWinEventHook, event, hWnd)
{
	global
	DetectHiddenWindows, On
	;EVENT_SYSTEM_MOVESIZEEND := 0xB
	static _ := DllCall("SetWinEventHook", Int,0xB, Int,0xB, Int,0, Ptr,RegisterCallback("onMove"), Int,0, Int,0, Int,0)
	vWin1OldX := vWin1X, vWin1OldY := vWin1Y
	vWin2OldX := vWin2X, vWin2OldY := vWin2Y
	vWin3OldX := vWin3X, vWin3OldY := vWin3Y
	WinGetPos, vWin1X, vWin1Y, vWin1W, vWin1H, % "ahk_id " hWnd1
	WinGetPos, vWin2X, vWin2Y, vWin2W, vWin2H, % "ahk_id " hWnd2
	WinGetPos, vWin3X, vWin3Y, vWin3W, vWin3H, % "ahk_id " hWnd3
	if !WinActive("ahk_id " hWnd1)
		return
	if vOverlap1
	{
		vWin2X := vWin1X+vWin2OldX-vWin1OldX
		vWin2Y := vWin1Y+vWin2OldY-vWin1OldY
		WinMove, % "ahk_id " hWnd2,, % vWin2X, % vWin2Y
	}
	if vOverlap2
	{
		vWin3X := vWin1X+vWin3OldX-vWin1OldX
		vWin3Y := vWin1Y+vWin3OldY-vWin1OldY
		WinMove, % "ahk_id " hWnd3,, % vWin3X, % vWin3Y
	}
	vOverlap1 := JEE_WinOverlap(hWnd1, hWnd2)
	vOverlap2 := JEE_WinOverlap(hWnd1, hWnd3)
}

;==================================================
[EDIT:] Btw is there not some built-in GuiMove subroutine (cf. GuiSize)?
Last edited by jeeswg on 05 Aug 2017, 10:32, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Drag Child GUIs inside/outside of Parent

05 Aug 2017, 09:18

I also had a go at this. The result was originally a bit disappointing because of the flashing and jumping of the children. :(

Code: Select all

;-------------------------------------------------------------------------------
; Drag Child outside the Parent.ahk
; by wolf_II
;-------------------------------------------------------------------------------
; https://autohotkey.com/boards/viewtopic.php?p=163328#p163328
; attempt #2
;-------------------------------------------------------------------------------



#NoEnv
#SingleInstance, Force
SetBatchLines, -1

    ; parent
    Gui, Parent: New, +HWNDhParent +Resize, Parent
    Gui, Show, x50 y50 w900 h600

    ; child 1
    Gui, New, +HWNDhChild1 +Resize, Child 1
    Gui, +E0x00010000 ; WS_EX_CONTROLPARENT
    DllCall("SetParent", "Ptr", hChild1, "Ptr", hParent)
    Gui, Show, x50 y50 w300 h200

    ; child 2
    Gui, New, +HWNDhChild2 +Resize, Child 2
    Gui, +E0x00010000 ; WS_EX_CONTROLPARENT
    DllCall("SetParent", "Ptr", hChild2, "Ptr", hParent)
    Gui, Show, x400 y50 w300 h200

    ; ANCESTOR
    ANCESTOR := [hParent, hParent]

Return ; end of auto-execute section



ParentGuiClose:
ExitApp



;-------------------------------------------------------------------------------
~LButton Up:: ; fires when LMB is released
;-------------------------------------------------------------------------------
    hActive := WinExist("A")
    ThisChild := ""

    ; one of the children?
    If (hActive = hChild1)
        ThisChild := 1
    Else If (hActive = hChild2)
        ThisChild := 2

    ; restore lost parent when dropped inside
    If (ANCESTOR[ThisChild] = 0) { ; parent is lost
        WinGetPos, ChildX, ChildY, ChildW, ChildH, ahk_id %hActive%
        WinGetPos, ParentX, ParentY, ParentW, ParentH, ahk_id %hParent%

        If  (ChildX > ParentX) And (ChildX + ChildW < ParentX + ParentW)
        And (ChildY > ParentY) And (ChildY + ChildH < ParentY + ParentH)
        {
            DllCall("SetParent", "Ptr", hActive, "Ptr", hParent)
            ANCESTOR[ThisChild] := hParent ; keep track
        }
    }

Return



;-------------------------------------------------------------------------------
WM_NCLBUTTONDOWN(wParam, lParam, msg, hWnd) {
;-------------------------------------------------------------------------------
    ; The user pressed the left mouse button while the cursor is within the
    ; nonclient area of a window.
    ;---------------------------------------------------------------------------
    static init := OnMessage(0x00A1, "WM_NCLBUTTONDOWN")
    global hChild1, hChild2, ANCESTOR


    ;-----------------------------------
    ; one of the children?
    ;-----------------------------------
    If (hWnd = hChild1)
        ThisChild := 1
    Else If (hWnd = hChild2)
        ThisChild := 2
    Else
        Return ; exit


    ;-----------------------------------
    ; clicked in the title bar?
    ;-----------------------------------
    If (wParam != 2) ; HTCAPTION = 2
        Return ; exit


    ;-----------------------------------
    ; still here?
    ;-----------------------------------
    If ANCESTOR[ThisChild] {
        WinGetPos, ChildX, ChildY,,, ahk_id %hWnd%  ; get child's position
        Gui, Hide                                   ; reduce child's jumping
        DllCall("SetParent", "Ptr", hWnd, "Ptr", 0) ; makes the child jump
        Gui, Show, x%ChildX% y%ChildY%              ; move the child back
        ANCESTOR[ThisChild] := 0                    ; keep track
    }
}
Edit: Attempt #2: reduced jumping, children resizeable.
User avatar
FanaticGuru
Posts: 1906
Joined: 30 Sep 2013, 22:25

Re: Drag Child GUIs inside/outside of Parent

05 Aug 2017, 20:57

wolf_II wrote:I also had a go at this. The result was originally a bit disappointing because of the flashing and jumping of the children. :(

Edit: Attempt #2: reduced jumping, children resizeable.
Nicely done!

Pretty much exactly what I envisioned with someone else doing all the tedious work of actually doing it and working out the kinks.

I have absolutely no use for this at this time but it is so nifty I feel I need to think of something to use it for.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Drag Child GUIs inside/outside of Parent

05 Aug 2017, 22:29

FanaticGuru wrote:Nicely done!
Pretty much exactly what I envisioned with someone else doing all the tedious work of actually doing it and working out the kinks.
I have absolutely no use for this at this time but it is so nifty I feel I need to think of something to use it for.
Thank you very much! :D

There is one more issue, maybe you can enlighten me?
When I click a child's title bar while it is inside the parent, and then "fast enough" release the LMB => Child jumps inside the parent by an amount that looks to be equal to the coordinates of the parent.

What is "fast enough" ? When I hold the LMB about 1/4 of a second or longer before releasing, => no jumping.
Additional observation: When I hold the LMB about 1/4 of a second or longer before releasing, I see the mouse cursor flashing once. (may be irrelevant)
Additional observation: When I actually move the child, also no jumping.

My current understanding is: the jumping is caused by the call to SetParent() inside the hotkey ~LButton Up.
I tried to solve by keeping track of how far the mouse cursor moved (if at all). I get very unreliable results, which makes me think this approach is wrong.

Any ideas on how to smoothe the last kink?

Edit: I tried also to use Critical and Thread, Priority inside of WM_NCLBUTTONDOWN() when I thought there is a race condition involved in the cause of the problem. But I have only limited experience with using those commands, so I think even if a race condition is causing the problem and my unreliable results, I will not be able to solve the problem without help.
scriptor2016
Posts: 854
Joined: 21 Dec 2015, 02:34

Re: Drag Child GUIs inside/outside of Parent

06 Aug 2017, 21:13

Hi guys these responses look great- i'm super-excited to try them out - i'm out of town until next week so i have to wait until then to get back on my computer and give them a try. I will most definitely follow up on this when i return :)
scriptor2016
Posts: 854
Joined: 21 Dec 2015, 02:34

Re: Drag Child GUIs inside/outside of Parent

13 Aug 2017, 12:53

Well I followed up on these and they indeed work well - although I'm trying an additional approach in which I'll explain why shortly. Basically I have a window named MY_WINDOW (in this case it would be the 'parent' GUI just for argument's sakes)

What I would do is use this window as the 'container' window, meaning that I will be dragging any number of other small GUIs ontop of it. So for example, I'll drag 5 other small GUIs ontop of MY_WINDOW. Then, when MY_WINDOW is dragged anywhere else on screen, those small GUIs will drag along with it, maintaining their relative positions inside MY_WINDOW and also staying ontop. So MY_WINDOW is like a container. But when any of those small GUIs are independently dragged outside of MY_WINDOW, they no longer drag along with it.

I'm actually getting close with what I've tried - but I think the problem is in the 'If' line below - I think I might be doing something wrong:

Code: Select all

CoordMode,Mouse,Screen 
windowtofind = MY_WINDOW
WinGetPos, x1, y1, w1, h1, %windowtofind%

x2 := x1 + w1
y2 := y1 + h1
 
WinGetPos, A, B, Width, Height, % "ahk_id " windowtile%A_Index% ;I collect a list of all small GUI window titles, (I have only included this line so it makes some sense)

 
If A > %x1% and A < %x2% & B > %y1% and B < %y2% ;this is the line where I think the problem might be
{
do something here
}
I know some of it makes no sense, because I have omitted a lot of other stuff happening in the script to keep it short. My question, is the problem in the 'If" line - is there something I'm missing there?
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Drag Child GUIs inside/outside of Parent

13 Aug 2017, 13:10

Code: Select all

;I'd do it like this:
if (A > x1) && (A < x2) && (B > y1) && (B < y2)

;Or possibly like this:
if (A > x1) AND (A < x2) AND (B > y1) AND (B < y2)
Cheers.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
scriptor2016
Posts: 854
Joined: 21 Dec 2015, 02:34

Re: Drag Child GUIs inside/outside of Parent

13 Aug 2017, 13:49

That's it jeeswg, thanks!! That one line was causing me the trouble. I'll continue on with the code and report back once I've figured it out :)

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: AlFlo and 220 guests