Path Requester a simple way to control X Y?

Windows specific forum
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Path Requester a simple way to control X Y?

Post 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.....
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
BarryG
Addict
Addict
Posts: 4128
Joined: Thu Apr 18, 2019 8:17 am

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

Post 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.
Axolotl
Addict
Addict
Posts: 802
Joined: Wed Dec 31, 2008 3:36 pm

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

Post 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.
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).
breeze4me
Enthusiast
Enthusiast
Posts: 633
Joined: Thu Mar 09, 2006 9:24 am
Location: S. Kor

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

Post 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)
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

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

Post 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
Egypt my love
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

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

Post 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.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
ChrisR
Addict
Addict
Posts: 1466
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

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

Post 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
Axolotl
Addict
Addict
Posts: 802
Joined: Wed Dec 31, 2008 3:36 pm

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

Post 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
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).
Post Reply