Page 1 of 1

Path Requester a simple way to control X Y?

Posted: Wed Oct 19, 2022 12:49 am
by IdeasVacuum
Is there a simple way to set the Path Requester's Window X and Y? It's quite a tall Window with long paths, so on a wide HD screen the bottom of the Window is off-screen. It's Y position is about 1/3 from the top of my screens. I know I could DIY the whole thing but if there is a lazy way.....

Re: Path Requester a simple way to control X Y?

Posted: Wed Oct 19, 2022 10:09 am
by BarryG
One way -> viewtopic.php?p=590402#p590402

You'll need to tweak it to support X and Y (and maybe W and H) parameters.

Re: Path Requester a simple way to control X Y?

Posted: Wed Oct 19, 2022 2:29 pm
by Axolotl
This code works with PathRequesters and MessageRequesters. Looking for the requester window by classname avoids problems with different system languages.

Code: Select all

; ---------------------------------------------------------------------------------------------------------------------

Structure TPosSize 
  X.i 
  Y.i 
  W.i 
  H.i 
EndStructure 


; ---------------------------------------------------------------------------------------------------------------------

Procedure PosSizeOfRequesterThread(*PosSize.TPosSize) 
  Protected hwnd, flags = 0  

  If *PosSize\X = #PB_Ignore Or *PosSize\Y = #PB_Ignore 
    flags = #SWP_NOMOVE  ; move the window with valid values for X, Y 
  EndIf 

  If *PosSize\W = #PB_Ignore Or *PosSize\H = #PB_Ignore 
    flags = #SWP_NOSIZE  ; size the window with valid values for W, H 
  EndIf 

  Repeat 
    hwnd = FindWindow_("#32770", 0)  ; look for classname / should work with different languages 
    If hwnd 
      SetWindowPos_(hwnd, #HWND_TOPMOST, *PosSize\X, *PosSize\Y, *PosSize\W, *PosSize\H, flags) 
    EndIf 
  Until hwnd  
EndProcedure 



; ---------------------------------------------------------------------------------------------------------------------
; Path$ = PathRequester(Title$, InitialPath$) 

Procedure.s PathRequesterEx(Title$, InitialPath$, X=#PB_Ignore, Y=#PB_Ignore, W=#PB_Ignore, H=#PB_Ignore) 
  Protected PosSize.TPosSize 

  PosSize\X = X : PosSize\Y = Y : PosSize\W = W : PosSize\H = H 
  CreateThread(@PosSizeOfRequesterThread(), @PosSize) 

  ProcedureReturn PathRequester(Title$, InitialPath$) 
EndProcedure 

; ---------------------------------------------------------------------------------------------------------------------
; MessageRequester(Title$, Text$, Flags) 

Procedure.i MessageRequesterEx(Title$, Text$, Flags, X=#PB_Ignore, Y=#PB_Ignore) 
  Protected PosSize.TPosSize 

  PosSize\X = X : PosSize\Y = Y : PosSize\W = #PB_Ignore : PosSize\H = #PB_Ignore 
  CreateThread(@PosSizeOfRequesterThread(), @PosSize) 

  ProcedureReturn MessageRequester(Title$, Text$, Flags) 
EndProcedure 


; ---------------------------------------------------------------------------------------------------------------------

CompilerIf #PB_Compiler_IsMainFile 
Debug "Test the Stuff ...." 

Debug PathRequesterEx("Select Directory:", "", 80, 40);, 400, 800) 

Debug MessageRequesterEx("Test Requester", ":1: This is a simple test only. ", #MB_ICONINFORMATION, 80, 40) 
Debug MessageRequesterEx("Test Requester", ":2: This is a simple test only. ", 0, 800, 400) 

CompilerEndIf 
Happy coding and stay healthy.

Re: Path Requester a simple way to control X Y?

Posted: Wed Oct 19, 2022 7:05 pm
by breeze4me
Here is one of the ways not to use any thread.
Using global variables instead of using the file map object will make it simpler. :mrgreen:

Code: Select all

#EVENT_SYSTEM_FOREGROUND = $0003
#WINEVENT_INCONTEXT = 4

Procedure WinEventProc(hWinEventHook, event.l, hwnd, idObject.l, idChild.l, idEventThread.l, dwmsEventTime.l)
  Protected Buffer.s{64}, *NewPosition.RECT, hMap, rt.RECT, hShell, hTree, hItem, x, y, w, h
  If hwnd
    If event = #EVENT_SYSTEM_FOREGROUND
      If GetClassName_(hwnd, @Buffer, 63)
        If Buffer = "#32770"
          UnhookWinEvent_(hWinEventHook)
          
          ;Get the data of the global memory.
          hMap = OpenFileMapping_(#FILE_MAP_ALL_ACCESS, 0, "AppPosData")
          If hMap
            *NewPosition = MapViewOfFile_(hMap, #FILE_MAP_ALL_ACCESS, 0, 0, SizeOf(RECT))
            If *NewPosition
              If GetWindowRect_(hwnd, rt)
                With rt
                  If *NewPosition\left   = #PB_Ignore : x = \left          : Else : x = *NewPosition\left   : EndIf
                  If *NewPosition\top    = #PB_Ignore : y = \top           : Else : y = *NewPosition\top    : EndIf
                  If *NewPosition\right  = #PB_Ignore : w = \right - \left : Else : w = *NewPosition\right  : EndIf
                  If *NewPosition\bottom = #PB_Ignore : h = \bottom - \top : Else : h = *NewPosition\bottom : EndIf
                EndWith
                SetWindowPos_(hwnd, 0, x, y, w, h, #SWP_NOZORDER | #SWP_NOOWNERZORDER | #SWP_FRAMECHANGED)
                
                ;Fix the problem that the selected item is sometimes not visible after resizing.
                hShell = GetDlgItem_(hwnd, 0)
                If hShell
                  hTree = GetDlgItem_(hShell, 100)
                  If hTree
                    If GetClassName_(hTree, @Buffer, 63)
                      If FindString(Buffer, "treeview", 1, #PB_String_NoCase)
                        hItem = SendMessage_(hTree, #TVM_GETNEXTITEM, #TVGN_CARET, 0)
                        If hItem
                          SendMessage_(hTree, #TVM_ENSUREVISIBLE, 0, hItem)
                        EndIf
                      EndIf
                    EndIf
                  EndIf
                EndIf
              EndIf
              UnmapViewOfFile_(*NewPosition)
            EndIf
            CloseHandle_(hMap)
          EndIf
        EndIf
      EndIf
    EndIf
  EndIf
EndProcedure

Procedure.s New_PathRequester(Title$, InitialPath$, x = #PB_Ignore, y = #PB_Ignore, w = #PB_Ignore, h = #PB_Ignore)
  Protected sPath.s, hMap, *NewPosition.RECT
  Protected hHook = SetWinEventHook_(#EVENT_SYSTEM_FOREGROUND, #EVENT_SYSTEM_FOREGROUND, GetModuleHandle_(0), @WinEventProc(), GetCurrentProcessId_(), GetCurrentThreadId_(), #WINEVENT_INCONTEXT)
  
  hMap = CreateFileMapping_(#INVALID_HANDLE_VALUE, 0, #PAGE_READWRITE, 0, SizeOf(RECT), "AppPosData")
  If hMap
    *NewPosition = MapViewOfFile_(hMap, #FILE_MAP_ALL_ACCESS, 0, 0, SizeOf(RECT))
    If *NewPosition
      *NewPosition\left = x
      *NewPosition\top = y
      *NewPosition\right = w
      *NewPosition\bottom = h
    EndIf
  EndIf
  
  sPath = PathRequester(Title$, InitialPath$)
  
  If hMap
    If *NewPosition
      UnmapViewOfFile_(*NewPosition)
    EndIf
    CloseHandle_(hMap)
  EndIf
  
  If hHook
    UnhookWinEvent_(hHook)
  EndIf
  ProcedureReturn sPath
EndProcedure

Debug New_PathRequester("test", "c:\", #PB_Ignore, #PB_Ignore, 300, 300)
Debug New_PathRequester("test", "c:\", 300, #PB_Ignore, 500, 500)
Debug New_PathRequester("test", "c:\", 100, 100)

Re: Path Requester a simple way to control X Y?

Posted: Wed Oct 19, 2022 9:22 pm
by RASHAD
With few lines you can do everything with any Requester

Code: Select all

Global Hook,px,py,pw,ph

Procedure HookCB ( uMsg , wParam , lParam)   
   Select uMsg
     Case #HCBT_ACTIVATE
        SetDlgItemText_ (wParam, 1, "Option #1")
        SetDlgItemText_ (wParam, 2, "Option #2")
        SetDlgItemText_ (wParam, 14150, "Option #3")
        MoveWindow_(wParam,px,py,pw,ph,1)
        UnhookWindowsHookEx_(Hook) 
   EndSelect
   
   ProcedureReturn #False
EndProcedure

Hook = SetWindowsHookEx_ ( #WH_CBT, @ HookCB () , 0, GetCurrentThreadId_ ())

InitialPath$ = "C:\"
px = 100 :py = 100
pw = 400 :ph = 450
Path.s = PathRequester("Please choose your path", InitialPath$)
Debug Path

Re: Path Requester a simple way to control X Y?

Posted: Thu Oct 20, 2022 3:08 am
by IdeasVacuum
Thanks BarryG, Axolotl, breeze4me and Rashad.

I'm sure I'm not the only one that will find these solution very useful. I'm using Rashad's code as it is very concise.

Re: Path Requester a simple way to control X Y?

Posted: Thu Oct 20, 2022 6:16 pm
by ChrisR
IdeasVacuum wrote: Thu Oct 20, 2022 3:08 am Thanks BarryG, Axolotl, breeze4me and Rashad.

I'm sure I'm not the only one that will find these solution very useful. I'm using Rashad's code as it is very concise.
Sure you're not the only one.
I have it for Open(Save)FileRequester but not for the path requester. So thanks

Code: Select all

If OpenWindow(1,40,40,0,0,"",#PB_Window_BorderLess)
  OpenFileRequester("Choose a file","","All files (*.*)|*.*",0)
  CloseWindow(1)
EndIf


#
Axolotl wrote: Wed Oct 19, 2022 2:29 pm Looking for the requester window by classname avoids problems with different system languages.
Yes but unfortunately it is not enough here on my windows 10 x64.
With FindWindow_("#32770", 0), it finds another window, hidden and with the same class

Code: Select all

Procedure EnumWindows(hwnd, lParam)
  Protected isOwned, winExStyle, title.s{1024}, class.s{64}
  
  isOwned = GetWindow_(hwnd, #GW_OWNER) 
  If isOwned = #Null
    winExStyle = GetWindowLong_(hwnd, #GWL_EXSTYLE)
    If (Not (winExStyle & #WS_EX_TOOLWINDOW)) Or (winExStyle & #WS_EX_APPWINDOW)
      If GetClassName_(hwnd, @class, 63)
        If class = "#32770"
          ;If IsWindowVisible_(hWnd) = lParam
            GetWindowText_(hwnd,@title,1024)
            Debug "WindowTitle: " + title + " - Class: " + class + " - Visible: " + IsWindowVisible_(hWnd)
          ;EndIf
        EndIf
      EndIf
     EndIf
  EndIf
  ProcedureReturn #True
EndProcedure

EnumWindows_(@EnumWindows(), #True)
==>
WindowTitle: The Event Manager Dashboard - Class: #32770 - Visible: 0
WindowTitle: Rechercher un dossier - Class: #32770 - Visible: 1

How to do it in this case with the 2 callbacks for EnumWindows and the thread ?

Or, else, how to find the Dll and the string identifier for "Browse for Folder", "Rechercher un dossier"

Code: Select all

Procedure.s LoadDllString(sDll.s, id)
  Protected hInstance, sReturn.s{261}, sExpand.s{261}
  ExpandEnvironmentStrings_(@sDll, @sExpand, 255)
  hInstance = LoadLibraryEx_(@sExpand, 0, #LOAD_LIBRARY_AS_DATAFILE)
  If hInstance
    LoadString_(hInstance, id, @sReturn, 256)
    FreeLibrary_(hInstance)
    ProcedureReturn sReturn
  EndIf
  ProcedureReturn ""
EndProcedure

Re: Path Requester a simple way to control X Y?

Posted: Fri Oct 21, 2022 12:22 pm
by Axolotl
Thanks @ChrisR for pointing that out ...
ChrisR wrote: Thu Oct 20, 2022 6:16 pm
IdeasVacuum wrote: Thu Oct 20, 2022 3:08 am
Sorry for sharing untested code.
I mainly use StringGadgets with this extension...

Code: Select all

 ; --- gathered together from different source files ---
CoInitialize_(#Null) ; for autocomplete in stringgadgets  
SHAutoComplete_(GadgetID(#GADGET_Main_StrDestDir), $50000021) ; #SHACF_AUTOAPPEND_FORCE_ON | #SHACF_AUTOSUGGEST_FORCE_ON | #SHACF_FILESYSTEM | #SHACF_FILESYS_DIRS 
CoUninitialize_()  ; autocomplete 
I found another solution.
Select Folder Dialog ... as a PathRequester Replacement on Windows