Long Scrollbar Control
Posted: Wed Jan 04, 2006 10:02 pm
This is code based on some of Sparkie's original code here...
viewtopic.php?t=11689
And before you ask "Why do you need a scrollbar with a maximum of more than 50,000 (or whatever)?" Well, sometimes I work with virtual widths that are quite large so I need something that can scroll through that.
Also, this does more than add a large scroll. It will fire your custom event procedure as it is scrolling so you don't have to wait for the user to let go of the mouse. This work with thumb tracking so you get events while the user drags the scrollbar. When I say "events" I mean like most of my code here. When you create the LongScrollbar() you pass the address of an "event procedure" that you want executed every time the position changes. You can have a different event for each scrollbar or you can use one event and some select/endselect or if/endif statements to branch through the different scrollbars.
When you set up the custom procedure (if you're using my stock code) you must have three parameters. The first will be the gadget (long), the second the old position (long) and the third will be the new position (long). So like this.
This procedure will be called every time the position changes in the scrollbar.
Even if you don't need the ability to have a maximum of more than 50,000 whatever then you might be interested in it's ability to return an "event" continuously.
Also, I've included some procedures that let you get the x, y, width, height and current position. There are also procedures that let you change the min, max, page and position during runtime.
This is the test form I used. I called it "Main.pb"
And this is the code for the Long Scrollbar itself. Saved as "LongScroll.pb" for my test form.
Let me know if you spot any mistakes on this. Enjoy it or not but at least have a good day 
viewtopic.php?t=11689
And before you ask "Why do you need a scrollbar with a maximum of more than 50,000 (or whatever)?" Well, sometimes I work with virtual widths that are quite large so I need something that can scroll through that.
Also, this does more than add a large scroll. It will fire your custom event procedure as it is scrolling so you don't have to wait for the user to let go of the mouse. This work with thumb tracking so you get events while the user drags the scrollbar. When I say "events" I mean like most of my code here. When you create the LongScrollbar() you pass the address of an "event procedure" that you want executed every time the position changes. You can have a different event for each scrollbar or you can use one event and some select/endselect or if/endif statements to branch through the different scrollbars.
When you set up the custom procedure (if you're using my stock code) you must have three parameters. The first will be the gadget (long), the second the old position (long) and the third will be the new position (long). So like this.
Code: Select all
Procedure TestScroll(Gadget.l, OldPosition.l, NewPosition.l)
;
Debug "Old Position: "+Str(OldPosition)+" : "+Str(NewPosition)
;
EndProcedure
Even if you don't need the ability to have a maximum of more than 50,000 whatever then you might be interested in it's ability to return an "event" continuously.
Also, I've included some procedures that let you get the x, y, width, height and current position. There are also procedures that let you change the min, max, page and position during runtime.
This is the test form I used. I called it "Main.pb"
Code: Select all
; By Xombie - 01/04/2006
Enumeration ; Window List
#WindowMain
EndEnumeration
Enumeration ; Menu List
#MenuMain
EndEnumeration
Enumeration ; Control List
#ButtonTest
#ScrollTest
#Contain01
#Contain02
#Contain03
EndEnumeration
;- Includes
XIncludeFile "LongScroll.pb"
;-
Procedure TestScroll(Gadget.l, OldPosition.l, NewPosition.l)
;
Debug "Old Position: "+Str(OldPosition)+" : "+Str(NewPosition)
;
EndProcedure
;- Main Program
DoQuit.b
;
If OpenWindow(#WindowMain, 100, 300, 300, 200, #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget, "Test")
;
If CreateGadgetList(WindowID())
;
AdvancedGadgetEvents(#True)
;
ContainerGadget(#Contain01, 0, 0, WindowWidth(), WindowHeight())
LongScrollBar(#ScrollTest, GadgetID(#Contain01), 0, 0, WindowWidth() - 2, 15, 0, 1000000, 15, #False, @TestScroll())
ButtonGadget(#ButtonTest, 0, 16, 100, 20, "Test")
CloseGadgetList()
;
EndIf
;
Repeat
;
EventID.l = WaitWindowEvent()
;
If EventID = #PB_Event_CloseWindow ; If the user has pressed on the close button
;
DoQuit = #True
;
ElseIf EventID = #PB_Event_Gadget
;
If EventGadgetID() = #ButtonTest
;
If EventType() = #PB_EventType_LeftClick
;
Debug LongScrollGetPos(#ScrollTest)
;
FreeLongScroll(#ScrollTest)
;
EndIf
;
EndIf
;
EndIf
;
Until DoQuit = #True
EndIf
;
LongScroll_DestroyAll()
;
End
;
Code: Select all
; By Xombie: 1-4-2006 based on original code by Sparkie ( http://forums.purebasic.com/english/viewtopic.php?t=11689 )
Structure s_LongScroll
;
Gadget.l
;
Handle.l
;
HandleParent.l
;
X.l
Y.l
;
Width.l
Height.l
;
Min.l
Max.l
;
Page.l
;
Position.l
;
EventNotify.l
;
EndStructure
Structure s_LongScrollParent
;
Handle.l
;
CallBack.l
;
EndStructure
;-
NewList _LongScroll.s_LongScroll()
NewList _LongScrollParent.s_LongScrollParent()
;-
Procedure.l LongScroll_HandleEvents(HandleWindow, Message, wParam, lParam)
; Main form callback procedure.
lResult.l
;
lResult = -1
;
ScrollCode.l
;
HoldPosition.l
;
HandledScroll.b
;
HoldScroll.SCROLLINFO
;
ResetList(_LongScrollParent())
While NextElement(_LongScrollParent())
;
If _LongScrollParent()\Handle = HandleWindow : Break : EndIf
;
Wend
;
If Message = #WM_HSCROLL
;
ScrollCode = wParam & $FFFF
;
ResetList(_LongScroll())
While NextElement(_LongScroll())
;
If _LongScroll()\Handle = lParam
;
HoldScroll\cbSize = SizeOf(SCROLLINFO)
;
HoldScroll\fMask = #SIF_ALL
;
GetScrollInfo_(_LongScroll()\Handle, #SB_CTL, @HoldScroll)
;
HoldPosition = HoldScroll\nPos
;
If ScrollCode = #SB_LINELEFT
;
HoldPosition - 1
;
HandledScroll = #True
;
ElseIf ScrollCode = #SB_LINERIGHT
;
HoldPosition + 1
;
HandledScroll = #True
;
ElseIf ScrollCode = #SB_PAGELEFT
;
HoldPosition - HoldScroll\nPage
;
HandledScroll = #True
;
ElseIf ScrollCode = #SB_PAGERIGHT
;
HoldPosition + _LongScroll()\Page
;
HandledScroll = #True
;
ElseIf ScrollCode = #SB_THUMBPOSITION Or ScrollCode = #SB_THUMBTRACK
;
HoldPosition = HoldScroll\nTrackPos
;
HandledScroll = #True
;
EndIf
;
If HandledScroll
;
HoldScroll\fMask = #SIF_POS
;
HoldScroll\nPos = HoldPosition
;
HoldPosition = SetScrollInfo_(_LongScroll()\Handle, #SB_CTL, @HoldScroll, #True)
;
If _LongScroll()\Position <> HoldPosition
;
CallFunctionFast(_LongScroll()\EventNotify, _LongScroll()\Gadget, _LongScroll()\Position, HoldPosition)
; Call the custom event function for the scrollbar.
_LongScroll()\Position = HoldPosition
;
EndIf
;
lResult = 0
;
EndIf
;
Break
;
EndIf
;
Wend
;
If HandledScroll = #False : lResult = CallWindowProc_(_LongScrollParent()\CallBack, HandleWindow, Message, wParam, lParam) : EndIf
;
ElseIf Message = #WM_VSCROLL
;
;
ScrollCode = wParam & $FFFF
;
ResetList(_LongScroll())
While NextElement(_LongScroll())
;
If _LongScroll()\Handle = lParam
;
HoldScroll\cbSize = SizeOf(SCROLLINFO)
;
HoldScroll\fMask = #SIF_ALL
;
GetScrollInfo_(_LongScroll()\Handle, #SB_CTL, @HoldScroll)
;
HoldPosition = HoldScroll\nPos
;
If ScrollCode = #SB_LINEUP
;
HoldPosition - 1
;
HandledScroll = #True
;
ElseIf ScrollCode = #SB_LINEDOWN
;
HoldPosition + 1
;
HandledScroll = #True
;
ElseIf ScrollCode = #SB_PAGEUP
;
HoldPosition - HoldScroll\nPage
;
HandledScroll = #True
;
ElseIf ScrollCode = #SB_PAGEDOWN
;
HoldPosition + _LongScroll()\Page
;
HandledScroll = #True
;
ElseIf ScrollCode = #SB_THUMBPOSITION Or ScrollCode = #SB_THUMBTRACK
;
HoldPosition = HoldScroll\nTrackPos
;
HandledScroll = #True
;
EndIf
;
If HandledScroll
;
HoldScroll\fMask = #SIF_POS
;
HoldScroll\nPos = HoldPosition
;
HoldPosition = SetScrollInfo_(_LongScroll()\Handle, #SB_CTL, @HoldScroll, #True)
;
If _LongScroll()\Position <> HoldPosition
;
CallFunctionFast(_LongScroll()\EventNotify, _LongScroll()\Gadget, _LongScroll()\Position, HoldPosition)
; Call the custom event function for the scrollbar.
_LongScroll()\Position = HoldPosition
;
EndIf
;
lResult = 0
;
EndIf
;
Break
;
EndIf
;
Wend
;
If HandledScroll = #False : lResult = CallWindowProc_(_LongScrollParent()\CallBack, HandleWindow, Message, wParam, lParam) : EndIf
;
Else
;
lResult = CallWindowProc_(_LongScrollParent()\CallBack, HandleWindow, Message, wParam, lParam)
;
EndIf
;
ProcedureReturn lResult
;
EndProcedure
;-
Procedure _LongScroll_AddParent(HandleParent.l)
;
ResetList(_LongScrollParent())
While NextElement(_LongScrollParent())
;
If _LongScrollParent()\Handle = HandleParent
;
ProcedureReturn
;
EndIf
;
Wend
;
AddElement(_LongScrollParent())
_LongScrollParent()\Handle = HandleParent
_LongScrollParent()\CallBack = SetWindowLong_(_LongScrollParent()\Handle, #GWL_WNDPROC, @LongScroll_HandleEvents())
;
EndProcedure
;-
Procedure LongScrollBar(Gadget.l, HandleParent.l, X.l, Y.l, Width.l, Height.l, Min.l, Max.l, Page.l, Vertical.b, EventNotify.l)
;
Handle.l
;
HandleParent.l
;
HoldScroll.SCROLLINFO
;
ResetList(_LongScroll())
While NextElement(_LongScroll())
;
If _LongScroll()\Gadget = Gadget : ProcedureReturn : EndIf
;
Wend
;
If Vertical
Handle = CreateWindowEx_(0, "SCROLLBAR", "", #WS_CHILD | #WS_VISIBLE | #SBS_VERT, X, Y, Width, Height, HandleParent, Gadget, GetModuleHandle_(0), 0)
Else
Handle = CreateWindowEx_(0, "SCROLLBAR", "", #WS_CHILD | #WS_VISIBLE | #SBS_HORZ, X, Y, Width, Height, HandleParent, Gadget, GetModuleHandle_(0), 0)
EndIf
;
AddElement(_LongScroll())
;
_LongScroll()\Gadget = Gadget
_LongScroll()\Handle = Handle
_LongScroll()\HandleParent = HandleParent
_LongScroll()\X = X
_LongScroll()\Y = Y
_LongScroll()\Width = Width
_LongScroll()\Height = Height
_LongScroll()\Min = Min
_LongScroll()\Max = Max
_LongScroll()\Page = Page
_LongScroll()\Position = Min
_LongScroll()\EventNotify = EventNotify
;
HoldScroll\cbSize = SizeOf(SCROLLINFO)
HoldScroll\fMask = #SIF_ALL
HoldScroll\nMin = Min
HoldScroll\nPage = Page
HoldScroll\nMax = Max - (Page - 1)
HoldScroll\nPos = 0
; Maximum value for Max is 2147483647 or $7FFFFFFF
SetScrollInfo_(Handle, #SB_CTL, @HoldScroll, #True)
;
_LongScroll_AddParent(HandleParent)
;
ProcedureReturn Handle
;
EndProcedure
Procedure.l LongScrollX(Gadget.l)
;
ResetList(_LongScroll())
While NextElement(_LongScroll())
;
If _LongScroll()\Gadget = Gadget : ProcedureReturn _LongScroll()\X : EndIf
;
Wend
;
EndProcedure
Procedure.l LongScrollY(Gadget.l)
;
ResetList(_LongScroll())
While NextElement(_LongScroll())
;
If _LongScroll()\Gadget = Gadget : ProcedureReturn _LongScroll()\Y : EndIf
;
Wend
;
EndProcedure
Procedure.l LongScrollWidth(Gadget.l)
;
ResetList(_LongScroll())
While NextElement(_LongScroll())
;
If _LongScroll()\Gadget = Gadget : ProcedureReturn _LongScroll()\Width : EndIf
;
Wend
;
EndProcedure
Procedure.l LongScrollHeight(Gadget.l)
;
ResetList(_LongScroll())
While NextElement(_LongScroll())
;
If _LongScroll()\Gadget = Gadget : ProcedureReturn _LongScroll()\Height : EndIf
;
Wend
;
EndProcedure
Procedure.l LongScrollGetPos(Gadget.l)
;
ResetList(_LongScroll())
While NextElement(_LongScroll())
;
If _LongScroll()\Gadget = Gadget : ProcedureReturn _LongScroll()\Position : EndIf
;
Wend
;
EndProcedure
Procedure ResizeLongScroll(Gadget.l, X.l, Y.l, Width.l, Height.l)
;
ResetList(_LongScroll())
While NextElement(_LongScroll())
;
If _LongScroll()\Gadget = Gadget
;
If X = -1 : X = _LongScroll()\X : EndIf
If Y = -1 : Y = _LongScroll()\Y : EndIf
If Width = -1 : Width = _LongScroll()\Width : EndIf
If Height = -1 : Height = _LongScroll()\Height : EndIf
;
_LongScroll()\X = X
_LongScroll()\Y = Y
_LongScroll()\Width = Width
_LongScroll()\Height = Height
;
MoveWindow_(_LongScroll()\Handle, X, Y, Width, Height, #True)
;
Break
;
EndIf
;
Wend
;
EndProcedure
Procedure LongScrollSetMax(Gadget.l, Max.l)
;
HoldScroll.SCROLLINFO
;
ResetList(_LongScroll())
While NextElement(_LongScroll())
;
If _LongScroll()\Gadget = Gadget
;
If _LongScroll()\Min > Max : _LongScroll()\Min = Max : EndIf
;
If _LongScroll()\Position > Max : _LongScroll()\Position = Max : EndIf
;
HoldScroll\cbSize = SizeOf(SCROLLINFO)
HoldScroll\fMask = #SIF_ALL
HoldScroll\nPos = _LongScroll()\Position
HoldScroll\nMax = Max - (_LongScroll()\Page - 1)
HoldScroll\nMin = _LongScroll()\Min
;
_LongScroll()\Position = HoldScroll\nPos
_LongScroll()\Max = HoldScroll\nMax
_LongScroll()\Min = HoldScroll\nMin
;
SetScrollInfo_(_LongScroll()\Handle, #SB_CTL, @HoldScroll, #True)
;
Break
;
EndIf
;
Wend
;
EndProcedure
Procedure LongScrollSetMin(Gadget.l, Min.l)
;
HoldScroll.SCROLLINFO
;
ResetList(_LongScroll())
While NextElement(_LongScroll())
;
If _LongScroll()\Gadget = Gadget
;
If _LongScroll()\Max < Min : _LongScroll()\Max = Min : EndIf
;
If _LongScroll()\Position < Min : _LongScroll()\Position = Min : EndIf
;
HoldScroll\cbSize = SizeOf(SCROLLINFO)
HoldScroll\fMask = #SIF_ALL
HoldScroll\nPos = _LongScroll()\Position
HoldScroll\nMax = _LongScroll()\Max - (_LongScroll()\Page - 1)
HoldScroll\nMin = Min
;
_LongScroll()\Position = HoldScroll\nPos
_LongScroll()\Max = HoldScroll\nMax
_LongScroll()\Min = HoldScroll\nMin
;
SetScrollInfo_(_LongScroll()\Handle, #SB_CTL, @HoldScroll, #True)
;
Break
;
EndIf
;
Wend
;
EndProcedure
Procedure LongScrollSetPage(Gadget.l, Page.l)
;
HoldScroll.SCROLLINFO
;
ResetList(_LongScroll())
While NextElement(_LongScroll())
;
If _LongScroll()\Gadget = Gadget
;
HoldScroll\cbSize = SizeOf(SCROLLINFO)
HoldScroll\fMask = #SIF_PAGE
HoldScroll\nPage = Page
;
_LongScroll()\Page = HoldScroll\nPage
;
SetScrollInfo_(_LongScroll()\Handle, #SB_CTL, @HoldScroll, #True)
;
Break
;
EndIf
;
Wend
;
EndProcedure
Procedure LongScrollSetPos(Gadget.l, Position.l)
;
HoldScroll.SCROLLINFO
;
ResetList(_LongScroll())
While NextElement(_LongScroll())
;
If _LongScroll()\Gadget = Gadget
;
If Position < _LongScroll()\Min : Position = _LongScroll()\Min : EndIf
;
If Position > _LongScroll()\Max : Position = _LongScroll()\Max : EndIf
;
HoldScroll\cbSize = SizeOf(SCROLLINFO)
HoldScroll\fMask = #SIF_POS
HoldScroll\nPos = Position
;
_LongScroll()\Position = HoldScroll\nPos
;
SetScrollInfo_(_LongScroll()\Handle, #SB_CTL, @HoldScroll, #True)
;
Break
;
EndIf
;
Wend
;
EndProcedure
;-
Procedure FreeLongScroll(Gadget.l)
;
Handle.l
;
Index.l
;
ResetList(_LongScroll())
While NextElement(_LongScroll())
;
If Gadget = _LongScroll()\Gadget
;
Handle = _LongScroll()\HandleParent
;
DestroyWindow_(_LongScroll()\Handle)
;
DeleteElement(_LongScroll())
;
Break
;
EndIf
;
Wend
;
If Handle
;
ResetList(_LongScrollParent())
While NextElement(_LongScrollParent())
;
If _LongScrollParent()\Handle = Handle
;
If Index : ProcedureReturn : EndIf
;
Index = ListIndex(_LongScrollParent())
;
EndIf
;
Wend
;
SelectElement(_LongScrollParent(), Index)
;
SetWindowLong_(_LongScrollParent()\Handle, #GWL_WNDPROC, _LongScrollParent()\CallBack)
;
DeleteElement(_LongScrollParent(), 1)
;
EndIf
;
EndProcedure
Procedure LongScroll_DestroyAll()
;
ResetList(_LongScroll())
While NextElement(_LongScroll())
;
DestroyWindow_(_LongScroll()\Handle)
;
DeleteElement(_LongScroll(), 1)
;
Wend
;
ResetList(_LongScrollParent())
While NextElement(_LongScrollParent())
;
SetWindowLong_(_LongScrollParent()\Handle, #GWL_WNDPROC, _LongScrollParent()\CallBack)
;
DeleteElement(_LongScrollParent(), 1)
;
Wend
;
EndProcedure
;-
