Additional flag for MessageRequester to center requester on app window
Additional flag for MessageRequester to center requester on app window
Hi, I'd like to request an additional flag for the MessageRequester command that tells it to center the requester window on the calling app's window. Similar to what the #PB_Window_WindowCentered flag does with OpenWindow.
I'll probably make a custom requester with this capability for my projects, as the #PB_Gadget_RequiredSize flag for GadgetHeight seems to return useful values for multi-line text gadgets now ( https://www.purebasic.fr/english/viewtopic.php?t=65761 ). This is a request for the standard MessageRequester command (adding this before anyone tells me to just make my own requester).
I'll probably make a custom requester with this capability for my projects, as the #PB_Gadget_RequiredSize flag for GadgetHeight seems to return useful values for multi-line text gadgets now ( https://www.purebasic.fr/english/viewtopic.php?t=65761 ). This is a request for the standard MessageRequester command (adding this before anyone tells me to just make my own requester).
Re: Additional flag for MessageRequester to center requester on app window
On Windows, the MessageRequester() just calls MessageBox_() API behind the scenes, and a center flag isn't supported by that, so your request can never be done.
But see here -> https://www.purebasic.fr/english/viewtopic.php?t=6680
And there's other posts with code if you search for "requester position".
But see here -> https://www.purebasic.fr/english/viewtopic.php?t=6680
And there's other posts with code if you search for "requester position".
Re: Additional flag for MessageRequester to center requester on app window
Fair point. I'll probably just start using a custom requester, as that gives me more control.
Re: Additional flag for MessageRequester to center requester on app window
A custom requester with all available flags is probably more work than this...Axeman wrote: Sun Dec 12, 2021 7:17 am Fair point. I'll probably just start using a custom requester, as that gives me more control.
Code: Select all
#PB_MessageRequester_WinCenter = 128
Procedure MonitorEnumProc(hMonitor, hdcMonitor, *lprcMonitor.RECT, dwData)
Protected rgn = CreateRectRgnIndirect_(*lprcMonitor)
CombineRgn_(dwData, dwData, rgn, #RGN_OR)
DeleteObject_(rgn)
ProcedureReturn #True
EndProcedure
Procedure CBTProc(nCode, wParam, lParam)
If nCode < 0 : Goto rethook : EndIf
If nCode = #HCBT_CREATEWND
Protected *cw.CBT_CREATEWND = lParam
Protected *cs.CREATESTRUCT = *cw\lpcs
If *cs\lpszClass = 32770
Protected pRect.RECT, rgn, x, y
rgn = CreateRectRgn_(0, 0, 0, 0)
EnumDisplayMonitors_(0, 0, @MonitorEnumProc(), rgn)
GetWindowRect_(*cs\hWndParent, pRect)
x = pRect\left + (pRect\right - pRect\left - *cs\cx)/2
y = pRect\top + (pRect\bottom - pRect\top - *cs\cy)/2
If PtInRegion_(rgn, x, y) And PtInRegion_(rgn, x + *cs\cx, y) And PtInRegion_(rgn, x, y + *cs\cy) And PtInRegion_(rgn, x + *cs\cx, y + *cs\cy)
*cs\x = x
*cs\y = y
EndIf
DeleteObject_(rgn)
EndIf
EndIf
rethook:
ProcedureReturn CallNextHookEx_(0, nCode, wParam, lParam)
EndProcedure
Procedure _MessageRequester(title$, text$, flags=0)
If flags & #PB_MessageRequester_WinCenter
Protected hook = SetWindowsHookEx_(#WH_CBT, @CBTProc(), 0, GetCurrentThreadId_())
EndIf
Protected ret = MessageRequester(title$, text$, flags&~#PB_MessageRequester_WinCenter)
If hook : UnhookWindowsHookEx_(hook) : EndIf
ProcedureReturn ret
EndProcedure
Macro MessageRequester(title, text, flags)
_MessageRequester(title, text, flags)
EndMacro
; ------------------------------------------------------------------------------------
CompilerIf #PB_Compiler_IsMainFile
OpenWindow(0, 0, 0, 640, 400, "MessageRequester_WinCenter", #PB_Window_SystemMenu|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget|#PB_Window_ScreenCentered|#PB_Window_Invisible)
ButtonGadget(0, 10, 10, 100, 30, "Show")
HideWindow(0, #False)
Repeat
Define event = WaitWindowEvent()
Select event
Case #PB_Event_Gadget
Select EventGadget()
Case 0
MessageRequester("Info", ~"This MessageRequester is always CENTERED on the parent window,\nbut only if the client area of the MR is fully visible on the desktop(s).", #PB_MessageRequester_Info|#PB_MessageRequester_WinCenter)
EndSelect
EndSelect
Until event = #PB_Event_CloseWindow
CompilerEndIf

Last edited by chi on Wed Dec 15, 2021 1:42 am, edited 2 times in total.
Et cetera is my worst enemy
Re: Additional flag for MessageRequester to center requester on app window
Nice, Chi! Just what the doctor ordered. Thanks!
Re: Additional flag for MessageRequester to center requester on app window
Hehe np. I have changed the code slightly to account for offscreen MessageRequesters.
Et cetera is my worst enemy
Re: Additional flag for MessageRequester to center requester on app window
I calculated the place of appearance of the child window in such a way that it was not centered, but as close as possible to the edge for which the parent window was shifted.
Re: Additional flag for MessageRequester to center requester on app window
+1
I created a similar solution to chi's for my own apps. Especially on an 4k monitor it is really enoying if your tool shows at an edge and the message requestor appears screen centered.
I created a similar solution to chi's for my own apps. Especially on an 4k monitor it is really enoying if your tool shows at an edge and the message requestor appears screen centered.
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
Re: Additional flag for MessageRequester to center requester on app window
I have adjusted the code to consider all 4 corner points (instead of just TL & RB). Now it works regardless of the multi-screen setup.
Et cetera is my worst enemy
Re: Additional flag for MessageRequester to center requester on app window
So many apps do that! Very annoying and unprofessional.Axolotl wrote: Mon Dec 13, 2021 4:53 pmEspecially on an 4k monitor it is really enoying if your tool shows at an edge and the message requestor appears screen centered.
@Chi: Why the check for "If nCode<0" and Goto? Because if nCode<>#HCBT_CREATEWND (3) then it's going to skip the If/EndIf block anyway.
Code: Select all
If nCode < 0 : Goto rethook : EndIf
If nCode = #HCBT_CREATEWND
; Blah
EndIf
rethook:
ProcedureReturn CallNextHookEx_(0, nCode, wParam, lParam)
Re: Additional flag for MessageRequester to center requester on app window
From CBTProc callback function:BarryG wrote: Wed Dec 15, 2021 3:37 am @Chi: Why the check for "If nCode<0" and Goto? Because if nCode<>#HCBT_CREATEWND (3) then it's going to skip the If/EndIf block anyway.
I think it is somewhat time sensitive, especially when more nCode checks are involved. I used a DLL without it for many years and never had any problems tho. It's up to you, but better safe than sorryIf nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx.

Et cetera is my worst enemy
Re: Additional flag for MessageRequester to center requester on app window
Code: Select all
EnableExplicit
Enumeration Window
#Window_Main
#Window_Child
EndEnumeration
Enumeration Gadget
#a1
#b1
#a2
#b2
#yzit
EndEnumeration
Enumeration Gadget
#ok
#txt
#chb
EndEnumeration
Structure MXYWH
x.l
y.l
w.l
h.l
m.l
EndStructure
Global WinRect.MXYWH
Global WWE
Declare _MsgBox(txt$, w = 270, h = 180, t = 0)
Declare _ChildCoor(nWin, w, h, c=0, d=0)
If OpenWindow(#Window_Main, 0, 0, 420, 250, "Example...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ButtonGadget (#a1, 5, 5, 50, 30, "corner")
ButtonGadget (#b1, 5, 45, 50, 30, "center")
ButtonGadget (#a2, 360, 170, 50, 30, "corner")
ButtonGadget (#b2, 360, 210, 50, 30, "center")
ButtonGadget (#yzit, 170, 110, 70, 30, "reduce")
Repeat
WWE = WaitWindowEvent()
Select EventWindow()
Case #Window_Main
Select WWE
Case #PB_Event_Gadget
Select EventGadget()
Case #a1, #a2
_MsgBox("Close the program window?", 0, 0, 1)
Case #b1, #b2
_MsgBox("Close the program window?")
Case #yzit
ResizeWindow(#Window_Main, #PB_Ignore, #PB_Ignore, 200, 70)
ResizeGadget(#a1, 5, 3, #PB_Ignore, #PB_Ignore)
ResizeGadget(#b1, 5, 35, #PB_Ignore, #PB_Ignore)
ResizeGadget(#a2, 140, 3, #PB_Ignore, #PB_Ignore)
ResizeGadget(#b2, 140, 35, #PB_Ignore, #PB_Ignore)
ResizeGadget(#yzit, 60, 30, #PB_Ignore, #PB_Ignore)
EndSelect
Case #PB_Event_CloseWindow
CloseWindow(#Window_Main)
End
EndSelect
Case #Window_Child
Select WWE
Case #PB_Event_Gadget
Select EventGadget()
Case #ok
CloseWindow(#Window_Child)
DisableWindow(#Window_Main, #False)
EndSelect
Case #PB_Event_CloseWindow
CloseWindow(#Window_Child)
DisableWindow(#Window_Main, #False)
EndSelect
EndSelect
ForEver
EndIf
Procedure _MsgBox(txt$, w = 270, h = 180, t = 0)
If Not w
w = 270
EndIf
If Not h
h = 180
EndIf
_ChildCoor(#Window_Main, w, h, t, 30)
With WinRect
OpenWindow(#Window_Child, \x, \y, \w, \h, "Message", #PB_Window_SystemMenu)
EndWith
SetWindowLongPtr_(WindowID(#Window_Child), #GWL_HWNDPARENT, WindowID(#Window_Main))
TextGadget(#txt, 10, 10, 250, 60, txt$)
CheckBoxGadget(#chb, 20, h-80, 240, 20, "Don't ask again")
ButtonGadget (#ok, (w-50)/2, h - 40, 50, 30, "Ок")
DisableWindow(#Window_Main, #True)
EndProcedure
Procedure _ChildCoor(nWin, w, h, c=0, d=0)
Protected DX, DY
With WinRect
\h = WindowHeight(nWin)
\w = WindowWidth(nWin)
\x = WindowX(nWin)
\y = WindowY(nWin)
ExamineDesktops()
DX=DesktopWidth(0)
DY=DesktopHeight(0)
If c = 0
\x+(\w-w)/2
\y+(\h-h)/2
EndIf
If \x+w+d>DX
\x=DX-w-10-d
EndIf
If \y+h+60+d>DY
\y=DY-h-70-d
EndIf
If \x<=d
\x=d
EndIf
If \y<=d
\y=d
EndIf
\w=w
\h=h
EndWith
EndProcedure
Last edited by AZJIO on Thu Dec 16, 2021 2:00 pm, edited 2 times in total.
Re: Additional flag for MessageRequester to center requester on app window
@Chi: Okay, I see what you mean. I've amended it to use short-circuit evaluation and lose the Goto; so the timing should be the same because anything less than 0 will immediately exit the procedure as required, along with passing the less-than-zero nCode value with it.
Code: Select all
If nCode > -1 And nCode = #HCBT_CREATEWND
; Blah
EndIf
ProcedureReturn CallNextHookEx_(0, nCode, wParam, lParam)