Page 1 of 1

Window position and size just before maximize

Posted: Sun Oct 13, 2024 12:27 am
by Jeromyal
I am trying to save a windows x, y and width, height into integers just before maximization, so the window can be restore capable after application restart if closed while maximized.
I thought there would be an event that could be accessed just before maximize when the maximize gadget is pressed.

am I missing something? Thank you.

Re: Window position and size just before maximize

Posted: Sun Oct 13, 2024 1:11 am
by JHPJHP
Hi Jeromyal,

For Windows only, but can be used at any stage:
WINDOWPLACEMENT structure
GetWindowPlacement function

Code: Select all

lpwndpl.WINDOWPLACEMENT
GetWindowPlacement_(WindowID(#MainWindow), @lpwndpl)
X = lpwndpl\rcNormalPosition\left
Y = lpwndpl\rcNormalPosition\top
W = lpwndpl\rcNormalPosition\right - lpwndpl\rcNormalPosition\left
H = lpwndpl\rcNormalPosition\bottom - lpwndpl\rcNormalPosition\top

Re: Window position and size just before maximize

Posted: Sun Oct 13, 2024 3:28 am
by Jeromyal
Thanks,
I see how that should work for me but then I guess I still am messing things up.
I will post my program before it get much bigger for review if you dare try to follow my insane code style.
maybe you can spot it. It won't run as is due to other files not included. Sorry.

Code: Select all

EnableExplicit

#APP_NAME         = "Vintage Story Portable Launcher"
#APP_VERSION      = "0.1.0"
#APP_AUTHOR       = "Jeromy Alexander"
#APP_AUTHOR_EMAIL = "kyja72@hotmail.com"
#USE_ON_ERROR     = #True
#Space$           = Chr(32)
#Dark             = $191919
#Light            = $F0F0F0

Global *Mutex = CreateMutex_(#Null, 1, ReplaceString(#APP_NAME, #Space$, "_"))
If *Mutex <> 0 And GetLastError_() = #ERROR_ALREADY_EXISTS
  CloseHandle_(*Mutex)
  End #ERROR_ALREADY_EXISTS
EndIf

XIncludeFile("Vintage Story Portable_Declares.pbi")
XIncludeFile("OnError.pbi")
XIncludeFile("ObjectTheme.pbi")
UseModule ObjectTheme

Macro DQ_String(String)
  #DQUOTE$ + string + #DQUOTE$
EndMacro

CreateDirectory("installs")

Enumeration
  #Window
  #installWindow
  #progress
  #installtext
  #about
  #options
  #help
  #statusbar
  #field
  #oCheckDark
  #editHelp
  #editAbout
EndEnumeration

Global wx, wy, ww, wh, wm, event
Global x, y, w, h, dm

If FileSize("VSPL.ini") = -1
  If CreateFile(0, "VSPL.ini")
    CloseFile(0)
  EndIf
EndIf

OpenPreferences("VSPL.ini")

wx = ReadPreferenceInteger("wx", 0)
wy = ReadPreferenceInteger("wy", 0)
ww = ReadPreferenceInteger("ww", 640)
wh = ReadPreferenceInteger("wh", 480)
wm = ReadPreferenceInteger("wm", 0)

OpenWindow(#Window, wx, wy, ww, wh, #APP_NAME + #Space$ + #APP_VERSION, #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget | #PB_Window_Invisible)
CreateStatusBar(#statusbar, WindowID(#window))
AddStatusBarField(#PB_Ignore)
StatusBarText(#statusbar, 0, "No Selection")
CreateMenu(0, WindowID(#Window))
MenuTitle("File")
MenuItem(1, "&Install...")
MenuItem(2, "&Uninstall...")
MenuBar()
MenuItem(3, "&Preferences")
MenuBar()
MenuItem(4, "&Quit")
MenuTitle("Help")
MenuItem(5, "&Help")
MenuBar()
MenuItem(6, "&About")
DisableMenuItem(0, 2, 1)

ListIconGadget(#field, 0, 0, WindowWidth(#Window), WindowHeight(#Window) - StatusBarHeight(#statusbar) - MenuHeight(), "huh?", WindowWidth(#Window), #PB_ListIcon_AlwaysShowSelection)
SetGadgetAttribute(#field, #PB_ListIcon_DisplayMode, #PB_ListIcon_LargeIcon)
ResizeWindow(#window, wx, wy, ww, wh)
WindowBounds(#Window, 400, 200, #PB_Ignore, #PB_Ignore)
If wm = 16777216
  SetWindowState(#Window, 16777216)
EndIf
BindEvent(#PB_Event_SizeWindow, @WindowResize(), #Window)
BindEvent(#PB_Event_MaximizeWindow, @maximized(), #Window)
BindEvent(#PB_Event_RestoreWindow, @restored(), #Window)
If ReadPreferenceInteger("dm", 0)
  SetObjectTheme(#ObjectTheme_Auto, #Dark)
Else
  SetObjectTheme(#ObjectTheme_Auto, #light)
EndIf
HideWindow(#Window, #False)
loadfield()

Repeat
  event = WaitWindowEvent(10)
  Select EventWindow()
    Case #Window
      Select event
        Case #PB_Event_CloseWindow
          quiting()
          Break
        Case #PB_Event_Menu
          Select EventMenu()
            Case 1 ; install
              DisableWindow(#Window, #True)
              install()
            Case 2 ; uninstall
              DisableWindow(#Window, #True)
              Uninstall()
            Case 3 ; preferences
              DisableWindow(#Window, #True)
              preferences()
            Case 4 ; quit
              quiting()
              Break
            Case 5 ; help
              DisableWindow(#Window, #True)
              help()
            Case 6 ; about
              DisableWindow(#Window, #True)
              about()
          EndSelect
      EndSelect
    Case #about
      Select event
        Case #PB_Event_CloseWindow
          CloseWindow(#about)
          DisableWindow(#Window, #False)
          SetActiveWindow(#Window)
      EndSelect
    Case #options
      Select event
        Case #PB_Event_CloseWindow
          CloseWindow(#options)
          DisableWindow(#Window, #False)
          SetActiveWindow(#Window)
        Case #PB_Event_Gadget
          If EventGadget() = #oCheckDark
            If GetGadgetState(#oCheckDark)
              SetObjectTheme(#ObjectTheme_Auto, #Dark)
              WritePreferenceInteger("dm", 1)
            Else
              SetObjectTheme(#ObjectTheme_Auto, #light)
              WritePreferenceInteger("dm", 0)
            EndIf
          EndIf
          
      EndSelect
    Case #help
      Select event
        Case #PB_Event_CloseWindow
          CloseWindow(#help)
          DisableWindow(#Window, #False)
          SetActiveWindow(#Window)
      EndSelect
  EndSelect
ForEver

Procedure WindowResize()
  ResizeGadget(#field, 0, 0, WindowWidth(#Window), WindowHeight(#Window) - StatusBarHeight(#statusbar) - MenuHeight())
  wx = x : wy = y : ww = w : wh = h
EndProcedure

Procedure install()
  If FileSize("innounp.exe") > 0
    Protected installer$ = OpenFileRequester("Select Vintage Story installer", GetUserDirectory(#PB_Directory_Downloads), "Vintage Story Installer|vs_install_win*.exe|Any Executable|*.exe", 0)
    If installer$
      If RunProgram(".\innounp.exe", " -q -x -b -y " + DQ_String(installer$) + " -d" + DQ_String("..\installs") + " install_script.iss", "installs", #PB_Program_Wait | #PB_Program_Hide)
        OpenPreferences(".\installs\install_script.iss")
        PreferenceGroup("Setup")
        Protected appname.s = ReadPreferenceString("AppName", "Unknown")
        Protected appversion.s = ReadPreferenceString("AppVersion", "Unknown")
        OpenPreferences("VSPL.ini")
        Protected file
        If ReadFile(file, ".\installs\install_script.iss")
          Protected string.s = ReadString(file, #PB_File_IgnoreEOL)
          CloseFile(file)
        EndIf
        Protected comp, s
        Protected line.s
        OpenWindow(#installWindow, 0, 0, 500, 120, "Inatalling", #PB_Window_WindowCentered | #PB_Window_TitleBar, WindowID(#Window))
        TextGadget(#installtext, 5, 5, WindowWidth(#installWindow) - 10, 80, "Installing " + appname + " " + appversion)
        ProgressBarGadget(#progress, 5 , WindowHeight(#installWindow) - 30, WindowWidth(#installWindow) - 10, 24, 0, CountString(string, "Source:") + 1)
        comp = RunProgram(".\innounp.exe", "-x -b -y " + DQ_String(installer$) + " -d" + DQ_String("..\installs"), "installs", $E | #PB_Program_Hide)
        If comp : s = 0
          While ProgramRunning(comp)
            If AvailableProgramOutput(comp)
              line = ReadProgramString(comp)
              s = s + 1
              SetGadgetState(#progress, s)
              SetGadgetText(#installtext, "Installing " + appname + " " + appversion + Chr(13) + Chr(13) + Str(s) + " of " + Str(CountString(string, "Source:") + 1)+ " files." + Chr(13) + Chr(13) + GetFilePart(line))
            EndIf
            WindowEvent()
          Wend
          CloseProgram(comp)
          CloseWindow(#installWindow)
          DeleteDirectory(".\installs\{autofonts}", "*.*", #PB_FileSystem_Recursive)
          DeleteDirectory(".\installs\{tmp}", "*.*", #PB_FileSystem_Recursive)
          DeleteFile(".\installs\install_script.iss")
          RenameFile(".\installs\{app}", ".\installs\" + appname + " " + appversion)
        EndIf
      EndIf
      
    EndIf
    loadfield()
  Else
    MessageRequester("Error", ~"innounp.exe is missing.\n\nInstalls can not be done.", #PB_MessageRequester_Error | #PB_MessageRequester_Ok, WindowID(#Window))
  EndIf
  DisableWindow(#Window, #False)
EndProcedure

Procedure Uninstall()
  
  loadfield()
  DisableWindow(#Window, #False)
EndProcedure

Procedure help()
  OpenWindow(#help, 0, 0, 500, 400, #APP_NAME + " - Help", #PB_Window_WindowCentered | #PB_Window_Tool | #PB_Window_SystemMenu, WindowID(#Window))
  EditorGadget(#editHelp, 0, 0, 500, 400, #PB_Editor_ReadOnly | #PB_Editor_WordWrap)
  
EndProcedure

Procedure about()
  OpenWindow(#about, 0, 0, 500, 400, #APP_NAME + " - About", #PB_Window_WindowCentered | #PB_Window_Tool | #PB_Window_SystemMenu, WindowID(#Window))
  EditorGadget(#editAbout, 0, 0, 500, 400, #PB_Editor_ReadOnly | #PB_Editor_WordWrap)
  
EndProcedure

Procedure preferences()
  OpenWindow(#options, 0, 0, 500, 400, #APP_NAME + " - Preferences", #PB_Window_WindowCentered | #PB_Window_Tool | #PB_Window_SystemMenu, WindowID(#Window))
  CheckBoxGadget(#oCheckDark, 5, 5, 480, 24, "Use Darkmode")
  dm = ReadPreferenceInteger("dm", GetGadgetState(#oCheckDark))
  SetGadgetState(#oCheckDark, dm)
  If GetGadgetState(#oCheckDark)
    SetObjectTheme(#ObjectTheme_Auto, #Dark)
    WritePreferenceInteger("dm", 1)
  Else
    SetObjectTheme(#ObjectTheme_Auto, #light)
    WritePreferenceInteger("dm", 0)
  EndIf
EndProcedure

Procedure maximized()
  Protected lpwndpl.WINDOWPLACEMENT
  GetWindowPlacement_(WindowID(#Window), @lpwndpl)
  X  = lpwndpl\rcNormalPosition\left
  Y  = lpwndpl\rcNormalPosition\top
  W  = lpwndpl\rcNormalPosition\right - lpwndpl\rcNormalPosition\left
  H  = lpwndpl\rcNormalPosition\bottom - lpwndpl\rcNormalPosition\top
  wx = x : wy = y : ww = w : wh = h
EndProcedure

Procedure restored()
  
EndProcedure

Procedure loadfield()
  
EndProcedure

Procedure quiting()
  
  WritePreferenceInteger("wx", WindowX(#Window))
  WritePreferenceInteger("wy", WindowY(#Window))
  WritePreferenceInteger("ww", WindowWidth(#Window))
  WritePreferenceInteger("wh", WindowHeight(#Window))
  WritePreferenceInteger("wm", GetWindowState(#window))
  
  ClosePreferences()
EndProcedure

Re: Window position and size just before maximize

Posted: Sun Oct 13, 2024 3:39 am
by Jeromyal
oh I am a dummy.

found it.

the following change now works along with the code you gave me. Thank you.

Code: Select all

Procedure quiting()
  
  WritePreferenceInteger("wx", wx)
  WritePreferenceInteger("wy", wy)
  WritePreferenceInteger("ww", ww)
  WritePreferenceInteger("wh", wh)
  WritePreferenceInteger("wm", GetWindowState(#window))
  
  ClosePreferences()
EndProcedure

Re: Window position and size just before maximize

Posted: Sun Oct 13, 2024 5:55 am
by AZJIO
And if the window is minimized to the taskbar, what will you do? You must remember the last window state before exiting the program.
You don't need to remember the size when maximizing the window, otherwise the user will be forced to manually configure the normal mode each time.

Code: Select all

If GetWindowState(#window) = #PB_Window_Maximize
	wm = 1
Else
	wm = 0
EndIf

wm = Bool(GetWindowState(#window)) = #PB_Window_Maximize)

; ...
If wm
	SetWindowState(#window, #PB_Window_Maximize)
EndIf

Code: Select all

	Repeat
		Select WaitWindowEvent()
			Case #PB_Event_MaximizeWindow
				win\wm = 1
			Case #PB_Event_RestoreWindow
				win\wm = 0

Code: Select all

EnableExplicit

#Window = 0

Structure win
	x.i
	y.i
	w.i
	h.i
	m.i
EndStructure

Global win.win
win\w = 222
win\h = 111

Procedure WinCallback(hWnd, Message, WParam, LParam)
	Protected w, h
	Protected *Rest.RECT = LParam
	Protected Result = #PB_ProcessPureBasicEvents
	
	Select Message
		Case #WM_SIZE
			w = LParam & $FFFF ; LoWord
			h = LParam >> 16   ; HiWord
			ResizeGadget(1, #PB_Ignore, #PB_Ignore, w-20,  h-20)
		Case #WM_EXITSIZEMOVE
			If Not win\m
				win\w = WindowWidth(#Window)
				win\h = WindowHeight(#Window)
			EndIf
			w = WindowWidth(#Window)
			h = WindowHeight(#Window)
			ResizeGadget(1, #PB_Ignore, #PB_Ignore, w-20,  h-20)
		Case #WM_MOVING
			win\x = *Rest\left
			win\y = *Rest\top
	EndSelect
	
	
	ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure


win\x = 222
win\y = 222

Global ini$ = Left(ProgramFilename(), Len(ProgramFilename()) - 3) + "ini"
If FileSize(ini$) = -1
	If CreatePreferences(ini$)
		PreferenceGroup("Set")
		WritePreferenceInteger("x",  win\x)
		WritePreferenceInteger("y",  win\y)
		WritePreferenceInteger("width",  win\w)
		WritePreferenceInteger("height",  win\h)
		WritePreferenceInteger("maxim",  win\m)
		ClosePreferences()
	EndIf
Else
	If OpenPreferences(ini$)
		PreferenceGroup("Set")
		win\x = ReadPreferenceInteger("x", win\x)
		win\y = ReadPreferenceInteger("y", win\y)
		win\w = ReadPreferenceInteger("width", win\w)
		win\h = ReadPreferenceInteger("height", win\h)
		win\m = ReadPreferenceInteger("maxim", win\m)
		ClosePreferences()
	EndIf
EndIf

Procedure Exit()
	If OpenPreferences(ini$)
		PreferenceGroup("Set")
		WritePreferenceInteger("x",  win\x)
		WritePreferenceInteger("y",  win\y)
		WritePreferenceInteger("width",  win\w)
		WritePreferenceInteger("height",  win\h)
		WritePreferenceInteger("maxim",  win\m)
		ClosePreferences()
	EndIf
EndProcedure


If OpenWindow(#Window, win\x, win\y, win\w, win\h, "Example...",
              #PB_Window_SystemMenu | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget)
	ButtonGadget(1, 10, 10, win\w - 20, win\h - 20, "Button")
	If win\m
		SetWindowState(#window, #PB_Window_Maximize)
	EndIf
	
; 	BindEvent(#PB_Event_SizeWindow, @SizeWindowHandler())
	SetWindowCallback(@WinCallback())
	
	;- Loop
	Repeat
		Select WaitWindowEvent()
			Case #PB_Event_MaximizeWindow
				win\m = 1
				ResizeGadget(1, #PB_Ignore, #PB_Ignore, WindowWidth(#Window) - 20,  WindowHeight(#Window)-20)
			Case #PB_Event_RestoreWindow
				win\m = 0
			Case #PB_Event_Gadget
				Select EventGadget()
					Case 1
						Debug 1
				EndSelect
			Case #PB_Event_CloseWindow
				CloseWindow(#Window)
				Exit()
				End
		EndSelect
	ForEver
EndIf
You will also need _SetCoor (to check if the screen size is smaller than the specified coordinates)

Re: Window position and size just before maximize

Posted: Tue Oct 15, 2024 4:56 pm
by JHPJHP
Hi AZJIO,

I agree that it make more sense positioning the code before the window is closed to return the last window (re)size, but your assumption is wrong about the GetWindowPlacement API; see my previous post for links to documentation.
JHPJHP wrote:can be used at any stage
Try the following:
• Minimize the example and close it from the Taskbar.

Code: Select all

Macro ScaleFactor
  DesktopResolutionX()
EndMacro

Macro ScaleFactorD(value)
  (value) / ScaleFactor
EndMacro

If OpenWindow(0, 0, 0, 500, 400, "GetWindowPlacement", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget)
  Debug WindowX(0)
  Debug WindowY(0)
  Debug WindowWidth(0, #PB_Window_FrameCoordinate)
  Debug WindowHeight(0, #PB_Window_FrameCoordinate)

  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow

  lpwndpl.WINDOWPLACEMENT
  GetWindowPlacement_(WindowID(0), @lpwndpl)
  X = ScaleFactorD(lpwndpl\rcNormalPosition\left)
  Y = ScaleFactorD(lpwndpl\rcNormalPosition\top)
  W = ScaleFactorD(lpwndpl\rcNormalPosition\right - lpwndpl\rcNormalPosition\left)
  H = ScaleFactorD(lpwndpl\rcNormalPosition\bottom - lpwndpl\rcNormalPosition\top)

  Debug "---"
  Debug X
  Debug Y
  Debug W
  Debug H
EndIf

Re: Window position and size just before maximize

Posted: Tue Oct 15, 2024 5:52 pm
by ChrisR
Thanks for the GetWindowPlacement Api
Great, it indeed recovers the good positions whatever the state normal, minimized or maximized.
I will be able to improve the save part in my example Keep Windows Size & Position Between Run (Win), it's really much better than

Code: Select all

If GetWindowState(Window) <> #PB_Window_Normal
  SetWindowState(Window, #PB_Window_Normal)
EndIf
GetWindowRect_(WindowID(Window), @WinRect)

Re: Window position and size just before maximize

Posted: Tue Oct 15, 2024 7:34 pm
by AZJIO
I am aware of GetWindowPlacement, but it cannot open a window beautifully if it is saved on one monitor and opened on another with smaller dimensions. In this case, you will get a window outside the viewport of the screen.