AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Scrollable Gui - Proof of Concept
Goto page Previous  1, 2, 3, 4  Next
 
Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
HELLOJ
Guest





PostPosted: Wed Dec 03, 2008 12:21 pm    Post subject: Reply with quote

Lexikos wrote:
That adds the SIF_DISABLENOSCROLL flag, which causes the scroll bar to be disabled rather than hidden when it is not needed.


DataLife + Lexikos & ! This is really brilliant & smart and just what I needed. Quick question... I was trying to hook in this:

http://www.autohotkey.com/forum/viewtopic.php?t=21790

Do you know why it might not be registering with this control? It seems to work on notepad and other controls.., just not this one. Do you know why this might be happening? Confused
Back to top
Lexikos



Joined: 17 Oct 2006
Posts: 7299
Location: Australia

PostPosted: Tue Dec 09, 2008 11:00 am    Post subject: Reply with quote

It seems SetScrollInfo uses SB_THUMBPOSITION, which the script does not handle. Change
Code:
    else if action = 5 ; SB_THUMBTRACK
        new_pos := NumGet(si, 24, "int") ; nTrackPos
to
Code:
    else if (action = 5 || action = 4) ; SB_THUMBTRACK || SB_THUMBPOSITION
        new_pos := wParam>>16
The "si" structure contains the old position; the new position must be retrieved from wParam. I've updated my post on the first page.
Back to top
View user's profile Send private message Visit poster's website
FireGirl



Joined: 04 May 2007
Posts: 102

PostPosted: Tue Dec 09, 2008 9:34 pm    Post subject: Reply with quote

Hey that is really great! Smile

There was one other quandary... that concept you made for a hotkey to move the scrollbar, ... that concept does not seem to work here off the bat (though the smooth scrolling works via normal mouse grab & move... just not the hotkey function below)

It was from here: http://www.autohotkey.com/forum/post-153675.html#153675

I looked it over carefully, but didn't see anything obvious, liken to the changes needed for this GUI to work with smooth momentum scrolling normally Very Happy Can you see what is wrong? Confused

EDIT 1: If I am not mistaken, it looks like it is the HWND that is not being picked up somehow when the Kicktoolbar function is being called. I tried a few things, but it seems to have its own ID (as Static1), and generates a different HWND address when using the Kicktoolbar function, which is strange

EDIT 2: BUT HEY, to my surprise (!) when I combined the two scripts together, the thing malfunctions (the insides go wacky). When I ran them separately, it worked just fine (minus the hotkey(s) which are assigned to SCROLLMOMEMTUM, ... but I don't know how this could be conflicting Very Happy

Code:


#NoEnv

; CONFIGURATION
;

UPDATE_RATE = 10 ; milliseconds
SENSITIVITY = 0.5
INERTIA = 0.95

;
; WIN32 DEFINES
;
; SetWinEventHook Flags
WINEVENT_OUTOFCONTEXT       = 0x0000
; Events
EVENT_SYSTEM_SCROLLINGSTART = 0x0012
EVENT_SYSTEM_SCROLLINGEND   = 0x0013
; Scrollbar Constants
SB_HORZ = 0
SB_VERT = 1

GuiClose:
ExitApp

UpdateScrollBars(GuiNum, GuiWidth, GuiHeight)
{

  Global THIS_IS_SCROLL_TOKEN_LIT

    static SIF_RANGE=0x1, SIF_PAGE=0x2, SIF_DISABLENOSCROLL=0x8, SB_HORZ=0, SB_VERT=1
   
    Gui, %GuiNum%:Default
    Gui, +LastFound
   


    ; Calculate scrolling area.
    Left := Top := 9999
    Right := Bottom := 0
    WinGet, ControlList, ControlList
    Loop, Parse, ControlList, `n
    {
        GuiControlGet, c, Pos, %A_LoopField%
        if (cX < Left)
            Left := cX
        if (cY < Top)
            Top := cY
        if (cX + cW > Right)
            Right := cX + cW
        if (cY + cH > Bottom)
            Bottom := cY + cH
    }
    Left -= 8
    Top -= 8
    Right += 8
    Bottom += 8
    ScrollWidth := Right-Left
    ScrollHeight := Bottom-Top
   
    ; Initialize SCROLLINFO.
    VarSetCapacity(si, 28, 0)
    NumPut(28, si) ; cbSize
    NumPut(SIF_RANGE | SIF_PAGE, si, 4) ; fMask
   
    ; Update horizontal scroll bar.
    NumPut(ScrollWidth, si, 12) ; nMax
    NumPut(GuiWidth, si, 16) ; nPage
    DllCall("SetScrollInfo", "uint", WinExist(), "uint", SB_HORZ, "uint", &si, "int", 1)
   
THIS_IS_SCROLL_TOKEN_LIT:=WinExist()


    ; Update vertical scroll bar.
;     NumPut(SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL, si, 4) ; fMask
    NumPut(ScrollHeight, si, 12) ; nMax
    NumPut(GuiHeight, si, 16) ; nPage
    DllCall("SetScrollInfo", "uint", WinExist(), "uint", SB_VERT, "uint", &si, "int", 1)
   
    if (Left < 0 && Right < GuiWidth)
        x := Abs(Left) > GuiWidth-Right ? GuiWidth-Right : Abs(Left)
    if (Top < 0 && Bottom < GuiHeight)
        y := Abs(Top) > GuiHeight-Bottom ? GuiHeight-Bottom : Abs(Top)
    if (x || y)
        DllCall("ScrollWindow", "uint", WinExist(), "int", x, "int", y, "uint", 0, "uint", 0)
}

OnScroll(wParam, lParam, msg, hwnd)
{
    static SIF_ALL=0x17, SCROLL_STEP=10
   
    bar := msg=0x115 ; SB_HORZ=0, SB_VERT=1
   
    VarSetCapacity(si, 28, 0)
    NumPut(28, si) ; cbSize
    NumPut(SIF_ALL, si, 4) ; fMask
    if !DllCall("GetScrollInfo", "uint", hwnd, "int", bar, "uint", &si)
        return
   
    VarSetCapacity(rect, 16)
    DllCall("GetClientRect", "uint", hwnd, "uint", &rect)
   
    new_pos := NumGet(si, 20) ; nPos
   
    action := wParam & 0xFFFF
    if action = 0 ; SB_LINEUP
        new_pos -= SCROLL_STEP
    else if action = 1 ; SB_LINEDOWN
        new_pos += SCROLL_STEP
    else if action = 2 ; SB_PAGEUP
        new_pos -= NumGet(rect, 12, "int") - SCROLL_STEP
    else if action = 3 ; SB_PAGEDOWN
        new_pos += NumGet(rect, 12, "int") - SCROLL_STEP
    else if (action = 5 || action = 4) ; SB_THUMBTRACK
        new_pos := wParam>>16 ; nTrackPos
    else if action = 6 ; SB_TOP
        new_pos := NumGet(si, 8, "int") ; nMin
    else if action = 7 ; SB_BOTTOM
        new_pos := NumGet(si, 12, "int") ; nMax
    else
        return
   
    min := NumGet(si, 8, "int") ; nMin
    max := NumGet(si, 12, "int") - NumGet(si, 16) ; nMax-nPage
    new_pos := new_pos > max ? max : new_pos
    new_pos := new_pos < min ? min : new_pos
   
    old_pos := NumGet(si, 20, "int") ; nPos
   
    x := y := 0
    if bar = 0 ; SB_HORZ
        x := old_pos-new_pos
    else
        y := old_pos-new_pos
    ; Scroll contents of window and invalidate uncovered area.
    DllCall("ScrollWindow", "uint", hwnd, "int", x, "int", y, "uint", 0, "uint", 0)
   
    ; Update scroll bar.
    NumPut(new_pos, si, 20, "int") ; nPos
    DllCall("SetScrollInfo", "uint", hwnd, "int", bar, "uint", &si, "int", 1)
}



WheelUp::
WheelDown::
+WheelUp::
+WheelDown::
Up::
Down::
    ; SB_LINEDOWN=1, SB_LINEUP=0, WM_HSCROLL=0x114, WM_VSCROLL=0x115
    OnScroll(InStr(A_ThisHotkey,"Down") ? 1 : 0, 0, GetKeyState("Shift") ? 0x114 : 0x115, WinExist())
return



CleanupAndExit:
    ; May not be necessary; but for good measure...
    if hScrollHook
        DllCall("UnhookWinEvent", "uint", hScrollHook)
ExitApp


ContinueScroll:
    Scroll_Speed *= INERTIA
   
    ; Continue until
    ;   the scroll bar slows to a stop,
    ;   the window is closed,
    ;   or something else moves the scroll bar.

    if (Abs(Scroll_Speed)>0.01
        && GetAbstractScrollInfo(Scroll_Container, Scroll_Type, Scroll_Pos_Int)
        && Scroll_Pos_Int = Last_Pos)
    {
        ; Apply momentum.
        Scroll_Pos += Scroll_Speed
        ; Check if it hit the end.
        if (Scroll_Pos <  Scroll_Min)
            Scroll_Pos := Scroll_Min
        if (Scroll_Pos >  Scroll_Max)
            Scroll_Pos := Scroll_Max
        ; If it has come to a stop, stop the timer.
        if (Scroll_Pos = Last_Pos) {
            SetTimer, ContinueScroll, Off
            return
        }
        ; Move scroll bar.
        if SetAbstractScrollPos(Scroll_Container, Scroll_Type, Round(Scroll_Pos))
        {   ; Update position (to detect if something else moves the bar.)
            GetAbstractScrollInfo(Scroll_Container, Scroll_Type, Last_Pos)
            return
        }
    }
    SetTimer, ContinueScroll, Off
    gosub ReleaseScrollContainerIfNecessary
return

TrackScrollBar:
    ; Update scroll position.
    if GetAbstractScrollInfo(Scroll_Container, Scroll_Type, Scroll_Pos)
    {   ; Recalculate velocity.
        Scroll_Speed := Scroll_Speed*SpeedA + (Scroll_Pos-Last_Pos)*SENSITIVITY
        Last_Pos := Scroll_Pos
    }
    else
    {   ; Error: maybe the window closed?
        SetTimer, TrackScrollBar, Off
        gosub ReleaseScrollContainerIfNecessary
    }
return


ReleaseScrollContainerIfNecessary:
    if Scroll_Type in scrollbarHThumb,scrollbarVThumb
        COM_Release(Scroll_Container)
    Scroll_Container = 0
return
 

[Moderator's note: Edited code to enable word-wrap in several places.]


Last edited by FireGirl on Fri Dec 12, 2008 9:47 pm; edited 3 times in total
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 7299
Location: Australia

PostPosted: Wed Dec 10, 2008 6:13 am    Post subject: Reply with quote

FireGirl wrote:
Can you see what is wrong? Confused
The script is designed to scroll the active control, not the window itself. If there was enough text in the active edit field to enable the scrollbar, it would scroll.
Quote:
BUT HEY, to my surprise (!) when I combined the two scripts together, the thing malfunctions (the insides go wacky).
Where's ScrollInit()???

Btw, Sean has in the past objected to verbatim inclusion of COM.ahk in another script. I would prefer you did not post it here, if only because the code doesn't wrap well (it forces the page to be wider than the browser.) If it is a standard copy of COM.ahk, there is no need to repost it here (and no need to include it directly in your script, but that is less important.)
Back to top
View user's profile Send private message Visit poster's website
FireGirl



Joined: 04 May 2007
Posts: 102

PostPosted: Wed Dec 10, 2008 2:10 pm    Post subject: Reply with quote

Lexikos wrote:
FireGirl wrote:
Can you see what is wrong? Confused
The script is designed to scroll the active control, not the window itself. If there was enough text in the active edit field to enable the scrollbar, it would scroll.


The example GUI included in the last code post actually runs off the bottom of the GUI (is taller), and no matter what you put in there, when you try to throw the scrollbar, it just slips and slides the contents? Confused But, if you try as a test to separate the GUI from Scrollmomemtum, you can see what I mean - it works great then!

Lexikos wrote:
Btw, Sean has in the past objected to verbatim inclusion of COM.ahk in another script. I would prefer you did not post it here, if only because the code doesn't wrap well (it forces the page to be wider than the browser.) If it is a standard copy of COM.ahk, there is no need to repost it here (and no need to include it directly in your script, but that is less important.)


Ah, gotcha~! No worries Smile
Back to top
View user's profile Send private message
FireGirl



Joined: 04 May 2007
Posts: 102

PostPosted: Wed Dec 10, 2008 2:57 pm    Post subject: Reply with quote

I guess one way to better visualize what I see is, combine Scrollable Gui + ScrollMomentum, and change this:

Code:


#NoEnv

OnMessage(0x115, "OnScroll") ; WM_VSCROLL
OnMessage(0x114, "OnScroll") ; WM_HSCROLL

Gui, +Resize +0x300000 ; WS_VSCROLL | WS_HSCROLL

Loop 8
    Gui, Add, Edit, R5 W400, Edit %A_Index%
Gui, Add, Button,, Do absolutely nothing
Gui, Show, W200 H200

Gui, +LastFound
GroupAdd, MyGui, % "ahk_id " . WinExist()

return



to this

Code:


#NoEnv

OnMessage(0x115, "OnScroll") ; WM_VSCROLL
OnMessage(0x114, "OnScroll") ; WM_HSCROLL

Gui, +Resize +0x300000 ; WS_VSCROLL | WS_HSCROLL

Loop 8
Gui, Add, Button,, Do absolutely nothing

Gui, Show, W200 H200

Gui, +LastFound
GroupAdd, MyGui, % "ahk_id " . WinExist()

return



;removed
;Gui, Add, Edit, R5 W400, Edit %A_Index%





btw, ScrollInit() was actually a function from initial iteration of Scrollable Gui by ahklerner Wink Very Happy

The inside edit boxes actually do scroll smoothly when placed in there, it is the outer GUI that malfunctions, unless you run it separately from ScrollMomentum Confused
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 7299
Location: Australia

PostPosted: Wed Dec 10, 2008 9:20 pm    Post subject: Reply with quote

FireGirl wrote:
it is the outer GUI that malfunctions, unless you run it separately from ScrollMomentum Confused
What do you mean, "the outer GUI"? After taking a closer look at your script, it seems to function as it should. The Edit fields are narrower and you've removed the button and one edit field.
Back to top
View user's profile Send private message Visit poster's website
FireGirl



Joined: 04 May 2007
Posts: 102

PostPosted: Wed Dec 10, 2008 11:44 pm    Post subject: Reply with quote

But, try placing a bunch of buttons, or anything other than those edit controls so scrollbars are created in this GUI design, and you'll see what I mean. When you try to scroll around it graphically messes up (in both XP and Vista). But only if the scripts are combined together. Seperately it actually works! Smile

I am so sorry, to clairfy I meant the GUI itself, those scrollbars Smile... outer was a bit misleading, I mean the actual GUI scrollbars. Smile
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 7299
Location: Australia

PostPosted: Thu Dec 11, 2008 7:59 am    Post subject: Reply with quote

FireGirl wrote:
when you try to throw the scrollbar, it just slips and slides the contents
Either I missed that bit, or it worked for me the first time around. In any case, I see what you mean now and I'll look into it.

However, I must question your motivation for combining the scripts. The momentum is applied system-wide, but the GUI part of the script must also be running. There may be better ways to apply momentum only to the GUI. Although hooks may still be required for the edit fields, they could be restricted to the current thread (i.e. the script.)

FYI, I got what you meant by "outer GUI", but wasn't sure since the GUI seemed to be working for me. Smile
Back to top
View user's profile Send private message Visit poster's website
FireGirl



Joined: 04 May 2007
Posts: 102

PostPosted: Thu Dec 11, 2008 1:57 pm    Post subject: Reply with quote

I guess one way to better visualize what I see is, combine Scrollable Gui + ScrollMomentum, and change this:

Code:


#NoEnv

OnMessage(0x115, "OnScroll") ; WM_VSCROLL
OnMessage(0x114, "OnScroll") ; WM_HSCROLL

Gui, +Resize +0x300000 ; WS_VSCROLL | WS_HSCROLL

Loop 8
    Gui, Add, Edit, R5 W400, Edit %A_Index%
Gui, Add, Button,, Do absolutely nothing
Gui, Show, W200 H200

Gui, +LastFound
GroupAdd, MyGui, % "ahk_id " . WinExist()

return



to this

Code:


#NoEnv

OnMessage(0x115, "OnScroll") ; WM_VSCROLL
OnMessage(0x114, "OnScroll") ; WM_HSCROLL

Gui, +Resize +0x300000 ; WS_VSCROLL | WS_HSCROLL

Loop 8
Gui, Add, Button,, Do absolutely nothing

Gui, Show, W200 H200

Gui, +LastFound
GroupAdd, MyGui, % "ahk_id " . WinExist()

return



;removed
;Gui, Add, Edit, R5 W400, Edit %A_Index%





btw, ScrollInit() was actually a function from initial iteration of Scrollable Gui by ahklerner Wink Very Happy

The inside edit boxes actually do scroll smoothly when placed in there, it is the outer GUI that malfunctions, unless you run it separately from ScrollMomentum Confused


Last edited by FireGirl on Fri Dec 12, 2008 9:42 pm; edited 1 time in total
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 7299
Location: Australia

PostPosted: Thu Dec 11, 2008 10:21 pm    Post subject: Reply with quote

FireGirl wrote:
1) Capability to combine these two scripts together so they don't conflict
Remove the following section from SetScrollPos()
Code:
    VarSetCapacity(si, 28, 0) ; SCROLLINFO si
    NumPut(28  , si,  0)    ; si.cbSize := sizeof(SCROLLINFO)
    NumPut(0x4 , si,  4)    ; si.fMask := SIF_POS
    NumPut(nPos, si, 20)    ; si.nPos := nPos
 
    ; Use SetScrollInfo first because it supports 32-bit positions.
    ; If an application supports positions < 0 or > 65535, it most likely
    ; ignores WM_#SCROLL's wParam and uses GetScrollPos or GetScrollInfo
    ; to get the actual scroll position.
    DllCall("SetScrollInfo", "uint", hwnd, "int", fnBar, "uint", &si, "int", 0)
When the script receives the scroll message, it uses GetScrollInfo to determine the old position in order to calculate the distance to move all controls. If SetScrollInfo is used immediately before sending the message, the perceived "old" position is actually the new position, so the script does not move the controls. This only happens if it is called from within the same script. SetScrollInfo does not seem to be necessary for the few applications I tested on.
Quote:
2) Capability to use that KickScrollBar function you made (it actually doesn't work on this GUI design, even with the script separated!!)
As I already pointed out, it is designed to affect the focused control, not the active window itself. Find the following
Code:
    ; Standard Windows scrollbars.
    if !Scroll_Container
    {
        Scroll_Container := hCtl
        if ! GetScrollInfo(Scroll_Container, Scroll_Type, Scroll_Pos, trackpos, Scroll_Min, Scroll_Max, Scroll_Page)
        {
            Scroll_Container:=0, Scroll_Type:="", Scroll_Speed:=0
            return
        }
    }
and replace it with this
Code:
    ; Standard Windows scrollbars.
    if !Scroll_Container
    {
        Scroll_Container := hCtl
        if ! GetScrollInfo(Scroll_Container, Scroll_Type, Scroll_Pos, trackpos, Scroll_Min, Scroll_Max, Scroll_Page)
            || Scroll_Min = Scroll_Max
        {
            Scroll_Container := WinActive("A")
            if ! GetScrollInfo(Scroll_Container, Scroll_Type, Scroll_Pos, trackpos, Scroll_Min, Scroll_Max, Scroll_Page)
            {
                Scroll_Container:=0, Scroll_Type:="", Scroll_Speed:=0
                return
            }
        }
    }
This will allow it to fall back to the active window if the focused control cannot scroll. It does not handle nested controls (i.e. if a parent control also has scroll bars, it will be bypassed.)
Back to top
View user's profile Send private message Visit poster's website
FireGirl



Joined: 04 May 2007
Posts: 102

PostPosted: Thu Dec 11, 2008 11:51 pm    Post subject: Reply with quote

Surprised
Back to top
View user's profile Send private message
Guest






PostPosted: Fri Dec 12, 2008 10:12 pm    Post subject: Reply with quote

hello & Greets group!, i am wondering if anyone knows how to do this >>> with this great C++ GUI control from Lexikos how to do this,

..to be able to control the horizontal & vertical scrollbar anywhere on the screen by holding down the LBUTTON, and then just pointing

it in the general direction I want, anywhere on the screen, UP/DOWN/LEFT/RIGHT. Can this be done?
Back to top
MB777!
Guest





PostPosted: Thu Jan 08, 2009 10:33 pm    Post subject: Scroll Bar - An easier way? Reply with quote

This works great! Thanks Lexikos, - but it seems heck of a lot of code. Is there a shorter easier way just to add a vertical scrollbar?
I tried using VScroll and it put a scrollbar on the window, but it wont scroll!
Back to top
Lexikos



Joined: 17 Oct 2006
Posts: 7299
Location: Australia

PostPosted: Fri Jan 09, 2009 8:27 am    Post subject: Re: Scroll Bar - An easier way? Reply with quote

MB777! wrote:
Is there a shorter easier way just to add a vertical scrollbar?
This has been discussed before. Removing horizontal scrolling would save at most a few lines.
Quote:
I tried using VScroll and it put a scrollbar on the window, but it wont scroll!
Of course, you need to tell the scrollbar what to do. For this script, it moves the child controls, but for controls it would generally "move" the contents, which aren't actually windows but data drawn onto the control.
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Goto page Previous  1, 2, 3, 4  Next
Page 2 of 4

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group