[Solved] Resize restrained to vertical

Get help with using AutoHotkey and its commands and hotkeys
MegaloDon
Posts: 107
Joined: 22 Jul 2014, 17:54

[Solved] Resize restrained to vertical

13 Sep 2014, 00:45

I have tried to make a GUI resizable, but only vertically by using the following code:

Code: Select all

Gui,+Resize +MinSize980x0 +MaxSize980x4096
When I first run the script, the width is 980, but when I move or resize the GUI, the width changes to 996. Anyone know why this is happening?
Last edited by MegaloDon on 18 Sep 2014, 10:13, edited 1 time in total.
MegaloDon
Posts: 107
Joined: 22 Jul 2014, 17:54

Re: Resize restrained to vertical

13 Sep 2014, 01:44

I think I partially figured it out. Based on my experiments, I believe MinSize is based on inner dimensions and MaxSize is based on outer. If I change it to Gui,+Resize +MinSize964x0 +MaxSize980x4096, the gui doesn't change width when I move the window. Problem is that it still allows me to resize the width to 996. Also, I'm assuming this will change based on the border size of the Windows version or visual style each user has. Are my assumptions correct?
just me
Posts: 5969
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Resize restrained to vertical

13 Sep 2014, 03:14

Help - GUI - Gui, +/-Option1 +/-Option2 ... wrote:MinSize and MaxSize:
... The dimensions are in pixels, and they specify the size of the window's client area (which excludes borders, title bar, and menu bar).

Code: Select all

#NoEnv
Gui, +Resize +MinSize400x + MaxSize400x +LastFound
Gui, Add, Text, w100 h300, Dummy
Gui, Show, , Test
Return
GuiClose:
ExitApp
GuiSize:
WinSetTitle, %A_GuiWidth% - %A_GuiHeight%
Return
Using this sample, the Gui will be initially shown with a client width of 384 and switch to 400 on the first move or resizing. I don't think that this is intended.
(AHK 1.1.16.03 on Win 8.1 Pro x64)
MegaloDon
Posts: 107
Joined: 22 Jul 2014, 17:54

Re: Resize restrained to vertical

13 Sep 2014, 14:30

I found a solution.

Code: Select all

Gui,Show,w980,Test
Gui, +MinSize980 +MaxSize980
If I put the Gui, +MinSize980 +MaxSize980 after the Gui,Show, it works.
MinSize and MaxSize wrote:Specify the word MinSize and/or MaxSize with no suffix to use the window's current size as the limit (if the window has no current size, it will use the size from the first use of Gui Show)
The part about the first use of Gui Show doesn't seem to work properly if you set it before Gui,Show. Is this a bug?
MegaloDon
Posts: 107
Joined: 22 Jul 2014, 17:54

Re: Resize restrained to vertical

13 Sep 2014, 15:38

I tried the following:

Code: Select all

Gui,Show,,Test
Gui, +MinSize%A_GuiWidth% +MaxSize%A_GuiWidth%
And the following:

Code: Select all

Gui,Show,,Test
CurrentWidth := A_GuiWidth
Gui, +MinSize%CurrentWidth% +MaxSize%CurrentWidth%
When I do either of these, it locks both width and height. I would like to be able to lock the width only, without having to specify it (let the width be determined by the contents). I do have Gui,+Resize at the top of the script. Anyone know why it's locking both?
MegaloDon
Posts: 107
Joined: 22 Jul 2014, 17:54

Re: Resize restrained to vertical

13 Sep 2014, 17:39

I have found the following works quite nicely, but with one problem.

Code: Select all

SysGet, VirtualHeight, 79
Gui,+Resize +MinSize +MinSizex50 +MaxSize +MaxSizex%VirtualHeight%
I figured this out from the post where MinSize/MaxSize was born :) http://ahkscript.org/forum/viewtopic.ph ... b5ac41d7da

This can all be done before the Gui,Show and does not have the previous issue. However, there is another issue that was there before that I didn't notice until now. When you maximize the window, it goes below the taskbar. I tried the following as a temporary workaround:

Code: Select all

SysGet, VirtualHeight, 79
CurrentHeight := VirtualHeight - 70
Gui,+Resize +MinSize +MinSizex50 +MaxSize +MaxSizex%CurrentHeight%
This works on my multi-monitor system because it limits it from going below the taskbar. But if I move the window to the other monitor (which doesn't have a taskbar) it won't go all the way to the bottom. This would be acceptable except for the fact that taskbars can be different sizes on different systems. Here is an example if someone wants to try it.

Code: Select all

#SingleInstance, Force
SendMode Input
SetWorkingDir %A_ScriptDir%
SysGet, VirtualHeight, 79
Gui,+Resize +MinSize +MinSizex50 +MaxSize +MaxSizex%VirtualHeight%

Gui,Add,Edit,x10 y10 w200 h394
Gui,Add,Listbox,x220 yp w200 h394
Gui,Add,Listbox,x430 yp w200 h394
Gui,Add,Listbox,x640 yp w200 h394

Gui,Show,,Test
Return

GuiClose:
	ExitApp
Return
MegaloDon
Posts: 107
Joined: 22 Jul 2014, 17:54

Re: Resize restrained to vertical

16 Sep 2014, 00:46

I found the following compensates for different taskbar sizes.

Code: Select all

SysGet,VirtualHeight,79						; Get virtual height of desktop.
WinGetPos,,,,tbH, ahk_class Shell_TrayWnd	; Get the taskbar height.
CurrentHeight := VirtualHeight - (tbH + 23)	; For some reason, the taskbar height
											; seems to to be smaller than the actual height.
											; adding 23 seems to work for me.
Gui,+Resize +MinSize +MinSizex50 +MaxSize +MaxSizex%CurrentHeight%
It still does not fully maximize the height on another monitor without a taskbar or account for different screen resolutions. Anyone know if there is a better way of doing this? Is this unnecessary coding?

I guess what it comes down to is that Maximize does not work correctly when MaxSize is used. It seems to ignore the taskbar.

lexikos, is this a bug in Autohotkey? (v1.1.15.2)

Correction:
This works fine in Windows 7. It only seems to be happening in Windows 8.1.
just me
Posts: 5969
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Resize restrained to vertical

17 Sep 2014, 02:02

Are you trying to prevent GUIs with "MinWidth" and "MaxWidth" from maximizing into the taskbar? I can reproduce this on Win 8.1, but I am running "Classic Shell".
Last edited by just me on 17 Sep 2014, 03:24, edited 1 time in total.
just me
Posts: 5969
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Resize restrained to vertical

17 Sep 2014, 03:01

And to get back to your original question in the first post, it is obviously intended:

script_gui.cpp:

Code: Select all

		// v1.0.44.13: For code size reasons and due to rarity-of-need, the following isn't done (also, it
		// can't catch all such situations; e.g. when "Gui +MinSize" can be used after "Gui Show".
		// Plus it might add a bit of flexibility to allow "Gui Show" to override min/max:
		// Older: The following prevents situations in which the window starts off at a size that's
		// too big or too small, which in turn causes it to snap to the min/max size the moment
		// the user tries to drag-move or drag-resize it:
		//if (mMinWidth >= 0 && width < mMinWidth) // mMinWidth >= 0 covers both COORD_UNSPECIFIED and COORD_CENTERED.
		//	width = mMinWidth;
		//else if (mMaxWidth >= 0 && width > mMaxWidth)
		//	width = mMaxWidth;
		//if (mMinHeight >= 0 && height < mMinHeight)
		//	height = mMinHeight;
		//else if (mMaxHeight >= 0 && height > mMaxHeight)
		//	height = mMaxHeight;
just me
Posts: 5969
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Resize restrained to vertical

17 Sep 2014, 06:55

Well, this might work as you want, you'll have to test it:

Code: Select all

#NoEnv
Gui, +Resize +MinSize600 +MaxSize600 +LastFound
Gui, Add, Text, w400 h300
Gui, Show, , Test
; Install an own message handler for WM_MINMAXINFO to adjust the maximum width and height.
OnMessage(0x24, "MinMaxInfo")
Return
GuiClose:
ExitApp
GuiSize:
WinGetPos, X, Y, W, H
WinSetTitle, Test - %X% : %Y% : %W% : %H%
Return
; ----------------------------------------------------------------------------------------------------------------------
; We only change the maximum witdth and height here, the rest will be done by the built-in message handler.
; That's why we must not return a value.
; L -> MINMAXINFO structure <- msdn.microsoft.com/en-us/library/ms632605(v=vs.85).aspx
; Multiple Display Monitors Functions <- msdn.microsoft.com/en-us/library/dd145072(v=vs.85).aspx
; ----------------------------------------------------------------------------------------------------------------------
MinMaxInfo(W, L, M, H) {
   Static MIEX := 0, Dummy := NumPut(VarSetCapacity(MIEX, 40 + (32 << !!A_IsUnicode)), MIEX, 0, "UInt")
   Critical
   If (HMON := DllCall("User32.dll\MonitorFromWindow", "Ptr", H, "UInt", 0, "UPtr")) {
      If DllCall("User32.dll\GetMonitorInfo", "Ptr", HMON, "Ptr", &MIEX) {
         W := NumGet(MIEX, 28, "Int") - NumGet(MIEX, 20, "Int")
         H := NumGet(MIEX, 32, "Int") - NumGet(MIEX, 24, "Int")
         NumPut(W - NumGet(L + 16, "Int"), L + 8, "Int")
         NumPut(H - NumGet(L + 20, "Int"), L + 12, "Int")
      }
   }
}
*Edit: reduced functions*
MegaloDon
Posts: 107
Joined: 22 Jul 2014, 17:54

Re: Resize restrained to vertical

17 Sep 2014, 21:40

just me wrote:Are you trying to prevent GUIs with "MinWidth" and "MaxWidth" from maximizing into the taskbar?
Yes. In my script, I have buttons at the bottom which will be covered by the taskbar if it goes below it when maximized.

Your example works perfectly! (Other than the width slightly resizing when moving or resizing). This is solved by this: Gui,+Resize +MinSize +MinSizex50 +MaxSize +MaxSizex%VirtualHeight%. The %VirtualHeight% is not necessary to solve the problem. I just prefer that to using an arbitrary large number. Your solution even works with different screen resolutions! I have adapted your function to the following example:

Code: Select all

#NoEnv
SysGet,VirtualHeight,79
Gui,+Resize +MinSize +MinSizex50 +MaxSize +MaxSizex%VirtualHeight%

Gui,Add,Edit,x10 y10 w200 h394 vAddToQueue
Gui,Add,Listbox,0x100 x220 yp w200 h394 vCurrentlyScanning
Gui,Add,Listbox,0x100 x430 yp w200 h394 vInQueue
Gui,Add,Listbox,0x100 x640 yp w200 h394 vExpiredScans
Gui,Add,Button,xp y430 w50 vSubmitButton,Submit

; Install an own message handler for WM_MINMAXINFO to adjust the maximum width and height.
OnMessage(0x24, "MinMaxInfo")

Gui,Show,,Test
Return

GuiSize:
	EditHeight := (A_GuiHeight - 50)
	ButtonHeight := (A_GuiHeight - 30)
	GuiControl,Move,AddToQueue,h%EditHeight%
	GuiControl,Move,CurrentlyScanning,h%EditHeight%
	GuiControl,Move,InQueue,h%EditHeight%
	GuiControl,Move,ExpiredScans,h%EditHeight%
	GuiControl,Move,SubmitButton,y%ButtonHeight%
Return

GuiClose:
	ExitApp

MinMaxInfo(W, L, M, H) {
	Static MIEX := 0, Dummy := NumPut(VarSetCapacity(MIEX, 40 + (32 << !!A_IsUnicode)), MIEX, 0, "UInt")
	Critical
	If (HMON := DllCall("User32.dll\MonitorFromWindow", "Ptr", H, "UInt", 0, "UPtr")) {
		If DllCall("User32.dll\GetMonitorInfo", "Ptr", HMON, "Ptr", &MIEX) {
			W := NumGet(MIEX, 28, "Int") - NumGet(MIEX, 20, "Int")
			H := NumGet(MIEX, 32, "Int") - NumGet(MIEX, 24, "Int")
			NumPut(W - NumGet(L + 16, "Int"), L + 8, "Int")
			NumPut(H - NumGet(L + 20, "Int"), L + 12, "Int")
		}
	}
}
Can you please explain how the function works? Like how does OnMessage tie in with the function, etc.

Otherwise thank you very much for the awesome solution! It looks like it solves all the issues!

P.S. Other than your previous reply, I was starting to think I was just talking to myself. :lol:
just me
Posts: 5969
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Resize restrained to vertical

18 Sep 2014, 03:14

MegaloDon wrote:Can you please explain how the function works? Like how does OnMessage tie in with the function, etc.
Well, I'll try to do my best!
MSDN wrote:WM_GETMINMAXINFO message
Sent to a window when the size or position of the window is about to change. An application can use this message to override the window's default maximized size and position, or its default minimum or maximum tracking size.
Parameters
lParam
A pointer to a MINMAXINFO structure that contains the default maximized position and dimensions, and the default minimum and maximum tracking sizes. An application can override the defaults by setting the members of this structure.
Source
This is true for all resizable GUI windows.
MSDN wrote:MINMAXINFO structure

Code: Select all

typedef struct tagMINMAXINFO {
  POINT ptReserved;
  POINT ptMaxSize;
  POINT ptMaxPosition;
  POINT ptMinTrackSize;
  POINT ptMaxTrackSize;
} MINMAXINFO, *PMINMAXINFO, *LPMINMAXINFO;
Source
The WM_GETMINMAXINFO message is processed by the AHK GUI window procedure defined in script_gui.cpp:

Code: Select all

	case WM_GETMINMAXINFO: // Added for v1.0.44.13.
	{
		if (   !(pgui = GuiType::FindGui(hWnd))   )
			break; // Let default proc handle it.
		MINMAXINFO &mmi = *(LPMINMAXINFO)lParam;
		if (pgui->mMinWidth >= 0) // This check covers both COORD_UNSPECIFIED and COORD_CENTERED.
			mmi.ptMinTrackSize.x = pgui->mMinWidth;
		if (pgui->mMinHeight >= 0)
			mmi.ptMinTrackSize.y = pgui->mMinHeight;
		if (pgui->mMaxWidth >= 0)   // mmi.ptMaxSize.x/y aren't changed because it seems the OS
			mmi.ptMaxTrackSize.x = pgui->mMaxWidth; // automatically uses ptMaxTrackSize for them, at least when
		if (pgui->mMaxHeight >= 0)   // ptMaxTrackSize is smaller than the system's default for
			mmi.ptMaxTrackSize.y = pgui->mMaxHeight; // mmi.ptMaxSize.
		return 0; // "If an application processes this message, it should return zero."
	}
As you can see, it puts the specified Min/Max-Width/Height values into the assosiated structure members for tracking sizes, if any.

Looking on your attempts to solve your problem and as a consequence of my own testings it seems, that a maximizing GUI window ignores the taskbar area if a maximum width but no maximum height was specified, at least on Win 8.1. And looking at the MINMAXINFOstructure, I was wondering what the other members might be used for. We cannot change the AutoHotkey.exe, but we can catch some messages and pass them to our own functions before they are passed to the GUI window procedure using OnMessage():
Help wrote:OnMessage()
Specifies a function to call automatically when the script receives the specified message.
Source
And that's exactly what OnMessage(0x24, "MinMaxInfo") does. It causes that the WM_MINMAXINFO (0x0024) message will be passed to the MinMaxInfo() function before being processed by the script. As mentioned above the lParam (L) parameter of the message contains a pointer to a MINMAXINFO structure; i.e. we can change the content of the structure members within the MinMaxInfo() function.

What does the function?
  1. The Static part creates and initializes a MONITORINFOEX (MIEX) structure meeded for the GetMonitorInfo() call.
  2. The function calls the MonitorFromWindow() API function to get the monitor the window is belonging to.
  3. Then it calls the GetMonitorInfo() API function to get informations about this monitor.
  4. Amongst other things the variable MIEX (MONITORINFOEX) now contains the position and size of the monitor's work area:
    MSDN wrote:rcWork
    A RECT structure that specifies the work area rectangle of the display monitor that can be used by applications, expressed in virtual-screen coordinates. Windows uses this rectangle to maximize an application on the monitor. The rest of the area in rcMonitor contains system windows such as the task bar and side bars. Note that if the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.
    Source
  5. Now the function calculates the work areas' width and height

    Code: Select all

                W := NumGet(MIEX, 28, "Int") - NumGet(MIEX, 20, "Int")
                H := NumGet(MIEX, 32, "Int") - NumGet(MIEX, 24, "Int")
    
    subtracts the corresponding values of the ptMaxPosition member of the MINMAXINFO structure and puts the results into the ptMaxSize member of this structure

    Code: Select all

                NumPut(W - NumGet(L + 16, "Int"), L + 8, "Int")
                NumPut(H - NumGet(L + 20, "Int"), L + 12, "Int")
    
  6. If the function would return a value after all is done, the programm wouldn't process the message any further (see What the Function Should Return). Thats why it doesn't, and the message is passed to the AHK window procedure which will do the rest of the work, using the already changed MINMAXINFO structure.
  7. At last, this seems to prevent maximizing ignoring the taskbar area.
Phew, that's been my best. ;)
(Consider that English is not my native language, please.)
MegaloDon
Posts: 107
Joined: 22 Jul 2014, 17:54

Re: [Solved] Resize restrained to vertical

18 Sep 2014, 10:15

Very good explanation! Thank you very much! (And your English is very good.)

Return to “Ask For Help”

Who is online

Users browsing this forum: partof, Wigi and 171 guests