POC - Scrollable GUI

Post your working scripts, libraries and tools.
just me
Posts: 9467
Joined: 02 Oct 2013, 08:51
Location: Germany

POC - Scrollable GUI

Post by just me » 15 Jan 2023, 08:43

This is my v2 version of an old script originally created by Lexikos (@lexikos) :arrow: https://autohotkey.com/board/topic/26033-scrollable-gui-proof-of-concept/#entry168174. You might find it useful.

Code: Select all

#Requires AutoHotkey v2.0.2
;[edited to make it x64/x32 compatible]
;Scrollable Gui - Proof of Concept - Scripts and Functions - AutoHotkey Community
;https://autohotkey.com/board/topic/26033-scrollable-gui-proof-of-concept/#entry168174
; MK_SHIFT = 0x0004, WM_MOUSEWHEEL = 0x020A, WM_MOUSEHWHEEL = 0x020E, WM_NCHITTEST = 0x0084
Lines := "1`n2`n3`n4`n5`n6`n7`n8`n9`n10"
ScrollGui := Gui("+Resize +0x300000", "Scrollable GUI") ; WS_VSCROLL | WS_HSCROLL
ScrollGui.OnEvent("Size", ScrollGui_Size)
ScrollGui.OnEvent("Close", ScrollGui_Close)
Loop 8
    ScrollGui.AddEdit("r5 w600", Lines)
ScrollGui.AddButton( , "Do absolutely nothing")
ScrollGui.Show("w400 h300")
OnMessage(0x0115, OnScroll) ; WM_VSCROLL
OnMessage(0x0114, OnScroll) ; WM_HSCROLL
OnMessage(0x020A, OnWheel)  ; WM_MOUSEWHEEL
Return
; ======================================================================================================================
ScrollGui_Size(GuiObj, MinMax, Width, Height) {
   If (MinMax != 1)
      UpdateScrollBars(GuiObj)
}
; ======================================================================================================================
ScrollGui_Close(*) {
   ExitApp
}
; ======================================================================================================================
UpdateScrollBars(GuiObj) {
   ; SIF_RANGE = 0x1, SIF_PAGE = 0x2, SIF_DISABLENOSCROLL = 0x8, SB_HORZ = 0, SB_VERT = 1
   ; Calculate scrolling area.
   WinGetClientPos( , , &GuiW, &GuiH, GuiObj.Hwnd)
   L := T := 2147483647   ; Left, Top
   R := B := -2147483648  ; Right, Bottom
   For CtrlHwnd In WinGetControlsHwnd(GuiObj.Hwnd) {
      ControlGetPos(&CX, &CY, &CW, &CH, CtrlHwnd)
      L := Min(CX, L)
      T := Min(CY, T)
      R := Max(CX + CW, R)
      B := Max(CY + CH, B)
   }
   L -= 8, T -= 8
   R += 8, B += 8
   ScrW := R - L ; scroll width
   ScrH := B - T ; scroll height
   ; Initialize SCROLLINFO.
   SI := Buffer(28, 0)
   NumPut("UInt", 28, "UInt", 3, SI, 0) ; cbSize , fMask: SIF_RANGE | SIF_PAGE
   ; Update horizontal scroll bar.
   NumPut("Int", ScrW, "Int", GuiW, SI, 12) ; nMax , nPage
   DllCall("SetScrollInfo", "Ptr", GuiObj.Hwnd, "Int", 0, "Ptr", SI, "Int", 1) ; SB_HORZ
   ; Update vertical scroll bar.
   ; NumPut("UInt", SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL, SI, 4) ; fMask
   NumPut("Int", ScrH, "UInt", GuiH,  SI, 12) ; nMax , nPage
   DllCall("SetScrollInfo", "Ptr", GuiObj.Hwnd, "Int", 1, "Ptr", SI, "Int", 1) ; SB_VERT
   ; Scroll if necessary
   X := (L < 0) && (R < GuiW) ? Min(Abs(L), GuiW - R) : 0
   Y := (T < 0) && (B < GuiH) ? Min(Abs(T), GuiH - B) : 0
   If (X || Y)
      DllCall("ScrollWindow", "Ptr", GuiObj.Hwnd, "Int", X, "Int", Y, "Ptr", 0, "Ptr", 0)
}
; ======================================================================================================================
OnWheel(W, L, M, H) {
   If !(HWND := WinExist()) || GuiCtrlFromHwnd(H)
      Return
   HT := DllCall("SendMessage", "Ptr", HWND, "UInt", 0x0084, "Ptr", 0, "Ptr", l) ; WM_NCHITTEST = 0x0084
   If (HT = 6) || (HT = 7) { ; HTHSCROLL = 6, HTVSCROLL = 7
      SB := (W & 0x80000000) ? 1 : 0 ; SB_LINEDOWN = 1, SB_LINEUP = 0
      SM := (HT = 6) ? 0x0114 : 0x0115 ;  WM_HSCROLL = 0x0114, WM_VSCROLL = 0x0115
      OnScroll(SB, 0, SM, HWND)
      Return 0
   }
}
; ======================================================================================================================
OnScroll(WP, LP, M, H) {
   Static SCROLL_STEP := 10
   Bar := (M = 0x0115) ; SB_HORZ=0, SB_VERT=1
   SI := Buffer(28, 0)
   NumPut("UInt", 28, "UInt", 0x17, SI) ; cbSize, fMask: SIF_ALL
   If !DllCall("GetScrollInfo", "Ptr", H, "Int", Bar, "Ptr", SI)
      Return
   RC := Buffer(16, 0)
   DllCall("GetClientRect", "Ptr", H, "Ptr", RC)
   NewPos := NumGet(SI, 20, "Int") ; nPos
   MinPos := NumGet(SI,  8, "Int") ; nMin
   MaxPos := NumGet(SI, 12, "Int") ; nMax
   Switch (WP & 0xFFFF) {
      Case 0: NewPos -= SCROLL_STEP ; SB_LINEUP
      Case 1: NewPos += SCROLL_STEP ; SB_LINEDOWN
      Case 2: NewPos -= NumGet(RC, 12, "Int") - SCROLL_STEP ; SB_PAGEUP
      Case 3: NewPos += NumGet(RC, 12, "Int") - SCROLL_STEP ; SB_PAGEDOWN
      Case 4, 5: NewPos := WP >> 16 ; SB_THUMBTRACK, SB_THUMBPOSITION
      Case 6: NewPos := MinPos ; SB_TOP
      Case 7: NewPos := MaxPos ; SB_BOTTOM
      Default: Return
   }
   MaxPos -= NumGet(SI, 16, "Int") ; nPage
   NewPos := Min(NewPos, MaxPos)
   NewPos := Max(MinPos, NewPos)
   OldPos := NumGet(SI, 20, "Int") ; nPos
   X := (Bar = 0) ? OldPos - NewPos : 0
   Y := (Bar = 1) ? OldPos - NewPos : 0
   If (X || Y) {
      ; Scroll contents of window and invalidate uncovered area.
      DllCall("ScrollWindow", "Ptr", H, "Int", X, "Int", Y, "Ptr", 0, "Ptr", 0)
      ; Update scroll bar.
      NumPut("Int", NewPos, SI, 20) ; nPos
      DllCall("SetScrollInfo", "ptr", H, "Int", Bar, "Ptr", SI, "Int", 1)
   }
}

songdg
Posts: 575
Joined: 04 Oct 2017, 20:04

Re: POC - Scrollable GUI

Post by songdg » 09 Apr 2024, 11:12

Wonderful job :bravo:

Post Reply

Return to “Scripts and Functions (v2)”