Gui Edit (TextBox) auto show/hide scrollbar on mouse hover?

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
william_ahk
Posts: 499
Joined: 03 Dec 2018, 20:02

Gui Edit (TextBox) auto show/hide scrollbar on mouse hover?

29 Apr 2024, 20:20

I attempted the following. But it's a bit buggy - when the mouse flies over the scrollbar it would get stuck.

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance Force

WM_COMMAND		:=	0x0111
WM_MOUSEMOVE	:=	0x0200
WM_MOUSELEAVE	:=	0x02A3

G := Gui()
TB := G.AddEdit("-E0x200 +ReadOnly w200 r5", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
TB.Opt("-VScroll")
; Remove Edit's initial focus
OnMessage(WM_COMMAND, OnFocus:=(WP,LP,*)=>((WP>>16)=0x100&&(PostMessage(0xB1,-1,0,LP),OnMessage(0x111,OnFocus,0))))
; Auto show/hide scrollbar on mouse in
OnMessage(WM_MOUSEMOVE, OnMouse)
OnMessage(WM_MOUSELEAVE, OnMouse)
G.Show()

OnMouse(wParam, lParam, msg, hwnd) {
	static hasVScroll := false
	if msg = WM_MOUSEMOVE && hwnd = TB.hwnd && !hasVScroll {
		hasVScroll := true
		TB.Opt("+VScroll")
		TB.Redraw()
	} else if msg = WM_MOUSELEAVE {
		SetTimer(() => (
			TB.Opt("-VScroll"),
			TB.Redraw()
			hasVScroll := false
		), -300)
	}
}

User avatar
Seven0528
Posts: 391
Joined: 23 Jan 2023, 04:52
Location: South Korea
Contact:

Re: Gui Edit (TextBox) auto show/hide scrollbar on mouse hover?

30 Apr 2024, 08:53

 Your topic sounds quite intriguing, and I've tried to tackle it personally, but could only achieve partial success.

Since the scroll area corresponds to the non-client area of the window, that needs to be considered.
I managed to pinpoint when the cursor enters and leaves the Edit control by considering WM_NCMOUSELEAVE.
However, despite removing WS_VSCROLL, I'm still puzzled by why occasional remnants of the scroll graphics persist.
I've even tried using GetScrollBarInfo to determine if the STATE_SYSTEM_INVISIBLE bit is indeed present, but honestly, I'm at a loss.

I hope someone with more insight into this issue can offer some assistance...

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance Force
GWL_STYLE       := -16
WM_SHOWWINDOW   := 0x0018
WM_MOUSEMOVE	:= 0x0200
WM_NCMOUSELEAVE := 0x02A2
WM_MOUSELEAVE 	:= 0x02A3
WS_HSCROLL      := 0x00100000
WS_VSCROLL      := 0x00200000

onMessage(WM_SHOWWINDOW, winProc)
onMessage(WM_MOUSEMOVE, winProc)
onMessage(WM_NCMOUSELEAVE, winProc)
onMessage(WM_MOUSELEAVE, winProc)

G:=gui()
TB:=G.addEdit("-E0x200 +ReadOnly x100 y50 w200 r10", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
TB.opt("+VScroll")
G.show("w400 h300")
dllCall("User32.dll\SetFocus", "Ptr",0, "Ptr")

winProc(wParam, lParam, Msg, hWnd)    {
    static prevHwnd:=0
    prevIC:=critical("On")
    switch (hRootWnd:=winExist())
    {
        case G.Hwnd:
            switch (Msg)
            {
                case WM_SHOWWINDOW:
                    if (wParam)
                        prevHwnd:=0
                    return
                case WM_MOUSEMOVE:
                    if (prevHwnd!==hWnd)    {
                        switch (prevHwnd:=hWnd)
                        {
                            case TB.Hwnd:           newShow:=true
                        }
                    }
                case WM_NCMOUSELEAVE, WM_MOUSELEAVE:
                    POINT:=buffer(8,0)
                    dllCall("User32.dll\GetCursorPos", "Ptr",POINT.Ptr)
                    x:=numGet(POINT,0,"Int")
                    y:=numGet(POINT,4,"Int")
                    hPoint:=dllCall("User32.dll\WindowFromPoint", "Int64",(x&0xFFFFFFFF)|(y<<32), "Ptr")
                    if (hWnd!==hPoint)    {
                        switch (hWnd)
                        {
                            case TB.Hwnd:           newShow:=false
                        }
                    }
            }
            if (isSet(newShow))    {
                currShow:=!!(WS_VSCROLL&dllCall("User32.dll\GetWindowLong" (A_PtrSize==8?"Ptr":""), "Ptr",hWnd, "Int",GWL_STYLE, (A_PtrSize==8?"Ptr":"Int")))
                if (newShow!==currShow)    {
                    ;  TB_VScroll.show(newShow)
                    TB_VScroll.delayedShow(newShow, 100)
                }
            }
    }
    critical(prevIC)
}

class TB_VScroll
{
    static bShow:=0
        ,objbmShow:=objBindMethod(this,"show")
    static delayedShow(newShow, tick)    {
        this.bShow:=newShow
        setTimer this.objbmShow, -abs(tick)
    }
    static show(bShow?)    {
        static OBJID_VSCROLL:=0xFFFFFFFB
            ,STATE_SYSTEM_INVISIBLE:=0x00008000
        if (!dllCall("User32.dll\IsWindow", "Ptr",TB.Gui.Hwnd))
            return
        bShow:=bShow??this.bShow
        TB.opt((bShow?"+":"-") "VScroll")
        TB.redraw()
        /*
        tooltip isVisible:=!!(WS_VSCROLL&dllCall("User32.dll\GetWindowLong" (A_PtrSize==8?"Ptr":""), "Ptr",TB.Hwnd, "Int",GWL_STYLE, (A_PtrSize==8?"Ptr":"Int")))
        */
        /*
        this._getScrollBarInfo(TB.Hwnd,OBJID_VSCROLL,&objsbi)
        tooltip isVisible:=!(objsbi.rgstate.0&STATE_SYSTEM_INVISIBLE)
        */
    }
    static _getScrollBarInfo(hWnd, idObject, &objsbi)    {
        objsbi:={cbSize:"",rcScrollBar:{left:"",top:"",right:"",bottom:""},dxyLineButton:"",xyThumbTop:"",xyThumbBottom:"",reserved:"",rgstate:{0:"",1:"",2:"",3:"",4:"",5:""}}
        ,psbi:=buffer(60,0)
        ,numPut("UInt",60,psbi,0)
        if (bRet:=dllCall("User32.dll\GetScrollBarInfo", "Ptr",hWnd, "Int",idObject, "Ptr",psbi.Ptr))    {
             objsbi.cbSite:=numGet(psbi,0,"UInt")
            ,objsbi.rcScrollBar.left:=numGet(psbi,4,"Int")
            ,objsbi.rcScrollBar.top:=numGet(psbi,8,"Int")
            ,objsbi.rcScrollBar.right:=numGet(psbi,12,"Int")
            ,objsbi.rcScrollBar.bottom:=numGet(psbi,16,"Int")
            ,objsbi.dxyLineButton:=numGet(psbi,20,"Int")
            ,objsbi.xyThumbTop:=numGet(psbi,24,"Int")
            ,objsbi.xyThumbBottom:=numGet(psbi,28,"Int")
            ,objsbi.reserved:=numGet(psbi,32,"Int")
            loop 6
                objsbi.rgstate.%A_Index-1%:=numGet(psbi,32+A_Index*4,"Int")
        }
        return bRet
    }
}
  • English is not my native language. Please forgive any awkward expressions.
  • 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.
User avatar
kczx3
Posts: 1648
Joined: 06 Oct 2015, 21:39

Re: Gui Edit (TextBox) auto show/hide scrollbar on mouse hover?

30 Apr 2024, 09:42

I don't see any artifacts but if you move the cursor quickly in a diagonal over the corner of the edit then the scrollbar just appears or disappears even though the mouse isn't over the control. Additionally, moving the mouse out of the Edit control in such a way that it passes over the scrollbar makes the scrollbar fade briefly and then reappear. The same occurs if you move the mouse into the control while passing over the scrollbar. Maybe a delay/debounce would help here?
teadrinker
Posts: 4362
Joined: 29 Mar 2015, 09:41
Contact:

Re: Gui Edit (TextBox) auto show/hide scrollbar on mouse hover?

30 Apr 2024, 12:15

ActiveX?

Code: Select all

#Requires AutoHotkey v2

HoverScrollbarGui()

HoverScrollbarGui() {
    wnd := Gui()
    document := wnd.AddActiveX('w200 h100', 'HTMLFILE').Value
    document.Write('
    (
        <!DOCTYPE html>
        <html>
        <head>
            <style>
            * {
                margin: 0;
                padding: 0;
                overflow: hidden;
            }
            textarea {
                position: absolute;
                width: 100%;
                height: 100%;
                font-family: Calibri;
                font-size: 14px;
                border: none;
            }
            textarea:hover {
                overflow-y: scroll;
            }
            </style>
        </head>
        <body>
            <textarea/>
        </body>
        <html>
    )')
    document.getElementsByTagName('textarea').0.innerText := '
    ( Join
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore e
        t dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut ali
        quip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum d
        olore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui off
        icia deserunt mollit anim id est laborum.
    )'
    wnd.Show()
}
william_ahk
Posts: 499
Joined: 03 Dec 2018, 20:02

Re: Gui Edit (TextBox) auto show/hide scrollbar on mouse hover?

30 Apr 2024, 21:00

@Seven0528 Thank you for taking an interest. That's a lot of code! :crazy: During my testing it seems like there's something fishy about the Redraw function. It would reshow the scrollbar despite -VScroll. If we call it three or more times with some delay in between, the scrollbar would be finally gone.

@kczx3 That could work. I haven't figured out a smoother way than my poor workaround above.

@teadrinker I was actually trying to emulate this exact web UX with win32 gui. :D
User avatar
Seven0528
Posts: 391
Joined: 23 Jan 2023, 04:52
Location: South Korea
Contact:

Re: Gui Edit (TextBox) auto show/hide scrollbar on mouse hover?

30 Apr 2024, 21:14

 @william_ahk
I've tried ShowScrollBar, but still encountered failures.
The official documentation states the following:
You should not call this function to hide a scroll bar while processing a scroll bar message.

This implies that you cannot remove a scroll bar while processing its message.
The problem is, that I don't know how to control the scroll bar message.
Is it WM_VSCROLL? I'm not sure.
I speculated that if I could monitor scroll bar messages using OnMessage or similar methods and interrupt them using return 0 or something similar, I could immediately remove the scroll bar.
However, I'm not even sure which messages to monitor, or if this is even possible.
  • English is not my native language. Please forgive any awkward expressions.
  • 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.
User avatar
Noitalommi_2
Posts: 264
Joined: 16 Aug 2023, 10:58

Re: Gui Edit (TextBox) auto show/hide scrollbar on mouse hover?

02 May 2024, 11:37

Hi.

After some testing with ControlGetStyle, i figured that the problem is Redraw(). Seems like the scroll bar can't be redrawn while the scroll bar up/down arrows fading away.
So, waiting until the animation is finished, could be used as a workaround.
Animation lengths is about 1.3s.

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance Force

WM_COMMAND		:=	0x0111
WM_MOUSEMOVE	:=	0x0200
;WM_MOUSELEAVE	:=	0x02A3
WM_NCMOUSELEAVE := 0x02A2

G := Gui()
TB := G.AddEdit("-E0x200 +ReadOnly w200 r5", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
TB.Opt("-VScroll")
; Remove Edit's initial focus
OnMessage(WM_COMMAND, OnFocus:=(WP,LP,*)=>((WP>>16)=0x100&&(PostMessage(0xB1,-1,0,LP),OnMessage(0x111,OnFocus,0))))
; Auto show/hide scrollbar on mouse in
OnMessage(WM_MOUSEMOVE, OnMouse)
OnMessage(WM_NCMOUSELEAVE, OnMouse)
G.Show()

OnMouse(wParam, lParam, msg, hwnd) {

	static hasVScroll := false
	if msg = WM_MOUSEMOVE && hwnd = TB.hwnd && !hasVScroll {
		hasVScroll := true
		TB.Opt("+VScroll")
		TB.Redraw()
	} else if msg = WM_NCMOUSELEAVE && hwnd = TB.hwnd { ; cursor leaves the gui via the right side
			TB.Opt("-VScroll")
			SetTimer(() => TB.Redraw(), -1300) ; waits 1.3s until redraw()
			hasVScroll := false
	} else if msg = WM_NCMOUSELEAVE { ; else
			TB.Opt("-VScroll")
			hasVScroll := false
			TB.Redraw()
	}
}

Or you could use another control style with “-theme”, then you have to use ShowScrollBar but everything happens instantly. Unfortunately, the text width changes when the scroll bar is hidden.

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance Force

WM_COMMAND		:=	0x0111
WM_MOUSEMOVE	:=	0x0200
;WM_MOUSELEAVE	:=	0x02A3
WM_NCMOUSELEAVE := 0x02A2

G := Gui()
G.Opt("-Theme")
TB := G.AddEdit("-E0x200 +ReadOnly w200 r5", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
G.Opt("+Theme")

DllCall("ShowScrollBar", "Ptr", TB.Hwnd, "Int", 0x1, "Int", false)
; Remove Edit's initial focus
OnMessage(WM_COMMAND, OnFocus:=(WP,LP,*)=>((WP>>16)=0x100&&(PostMessage(0xB1,-1,0,LP),OnMessage(0x111,OnFocus,0))))
; Auto show/hide scrollbar on mouse in
OnMessage(WM_MOUSEMOVE, OnMouse)
OnMessage(WM_NCMOUSELEAVE, OnMouse)
G.Show()

OnMouse(wParam, lParam, msg, hwnd) {

	static hasVScroll := false
	if msg = WM_MOUSEMOVE && hwnd = TB.hwnd && !hasVScroll {
		DllCall("ShowScrollBar", "Ptr", TB.Hwnd, "Int", 0x1, "Int", true)
		hasVScroll := true
	} else if msg = WM_NCMOUSELEAVE {
			DllCall("ShowScrollBar", "Ptr", TB.Hwnd, "Int", 0x1, "Int", false)
			hasVScroll := false
	}
}

Return to “Ask for Help (v2)”

Who is online

Users browsing this forum: Gio710, kunkel321 and 58 guests