The following is the complete source (WIP) for the ScrollBar widget (a deceptively fairly complicated widget), using all of the framework API (with a few direct pointer/structure access). Hopefully should give you a good idea of how you create your own custom widgets:
Code: Select all
XIncludeFile "ProGUI_Core.pbi"
XIncludeFile "ProGUI_Widget.pbi"
;- Constants
#_ScrollBar_ThumbSize = 17 ; GetSystemMetrics_(#SM_CXHTHUMB)
#_ScrollBar_ScrollDelay = 300
#_ScrollBar_ScrollFPS = 20
#_ScrollBar_HorizontalHeight = 17 ; GetSystemMetrics_(#SM_CYHSCROLL)
#_ScrollBar_VerticalWidth = 17 ; GetSystemMetrics_(SM_CXVSCROLL)
; ScrollBar state flags
EnumerationBinary
#_ScrollBar_TrackBarDrag
#_ScrollBar_LeftTopThumbDown
#_ScrollBar_RightBottomThumbDown
#_ScrollBar_LeftTopPageDown
#_ScrollBar_RightBottomPageDown
#_ScrollBar_TrackBarHover
#_ScrollBar_LeftTopThumbHover
#_ScrollBar_RightBottomThumbHover
EndEnumeration
; ScrollBar animation IDs
Enumeration
#_ScrollBar_AnimateScroll
EndEnumeration
;- Structures
Structure ScrollBarWidget
min.i
max.i
pageSize.i
pos.i
lastPos.i
flags.i
thumbSize.i
thumbDownScrollDelay.i
thumbDownScrollFPS.i
state.i
dragDelta.i
trackBarPos.d
lastTrackBarPos.d
mouseX.d
mouseY.d
EndStructure
;- Macros
Macro CalculateTrackAreaSize(diminsionSize, thumbSize)
trackAreaSize.d = diminsionSize - (thumbSize * 2)
EndMacro
Macro CalculateTrackBarSize(min, max, pageSize, trackAreaSize, thumbSize, trackBarSize)
trackBarSize.d = (pageSize / (max - min)) * trackAreaSize
If trackBarSize < thumbSize
trackAreaSize - (thumbSize - trackBarSize)
trackBarSize = thumbSize
EndIf
EndMacro
Macro CalculateTrackBarPos(min, max, pos, trackAreaSize, thumbSize)
trackBarPos.d = thumbSize + (((pos - min) / (max - min)) * trackAreaSize)
EndMacro
Macro CalculateTrackBarVisible(diminsionSize, thumbSize)
trackBarVisible = #True
If diminsionSize < thumbSize * 3
trackBarVisible = #False
EndIf
EndMacro
;-
;- *** Internal Functions ***
Procedure eventHandler_ScrollBarDraw(*widget.Widget, EventType, *event.PG_EventData, *userData)
Define width.d, height.d, size.d, trackAreaSize.d, trackBarSize.d, trackBarPos.d
Define min, max, pageSize, pos, thumbSize, trackBarVisible
*scrollbar.ScrollBarWidget = *widget\userData
width.d = *event\width
height.d = *event\height
min = *scrollbar\min
max = *scrollbar\max + 1
pageSize = *scrollbar\pageSize
pos = *scrollbar\pos
thumbSize = *scrollbar\thumbSize
If *scrollbar\flags & #PG_ScrollBar_Vertical
CalculateTrackAreaSize(height, thumbSize)
size = height
Else
CalculateTrackAreaSize(width, thumbSize)
size = width
EndIf
CalculateTrackBarSize(min, max, pageSize, trackAreaSize, thumbSize, trackBarSize)
If *scrollbar\state & #_ScrollBar_TrackBarDrag And *scrollbar\trackBarPos
trackBarPos.d = *scrollbar\trackBarPos
Else
CalculateTrackBarPos(min, max, pos, trackAreaSize, thumbSize)
EndIf
CalculateTrackBarVisible(size, thumbSize)
backColor = RGB(23, 23, 23)
thumbColor = RGB(23, 23, 23)
trackBarColor = RGB(77, 77, 77)
leftTopThumbColor = thumbColor
rightBottomThumbColor = thumbColor
trackBarHoverColor = RGB(122, 122, 122)
trackBarDownColor = RGB(166, 166, 166)
thumbHoverColor = RGB(55, 55, 55)
thumbDownColor = RGB(166, 166, 166)
; Set colors based on state
If *scrollbar\state & #_ScrollBar_TrackBarDrag
trackBarColor = trackBarDownColor
ElseIf *scrollbar\state & #_ScrollBar_TrackBarHover
trackBarColor = trackBarHoverColor
EndIf
If *scrollbar\state & #_ScrollBar_LeftTopThumbDown
leftTopThumbColor = thumbDownColor
If Not *scrollbar\state & #_ScrollBar_LeftTopThumbHover
leftTopThumbColor = thumbHoverColor
EndIf
ElseIf *scrollbar\state & #_ScrollBar_LeftTopThumbHover
leftTopThumbColor = thumbHoverColor
EndIf
If *scrollbar\state & #_ScrollBar_RightBottomThumbDown
rightBottomThumbColor = thumbDownColor
If Not *scrollbar\state & #_ScrollBar_RightBottomThumbHover
rightBottomThumbColor = thumbHoverColor
EndIf
ElseIf *scrollbar\state & #_ScrollBar_RightBottomThumbHover
rightBottomThumbColor = thumbHoverColor
EndIf
; Draw vertical scrollbar
If *scrollbar\flags & #PG_ScrollBar_Vertical
; draw background
DrawBox(0, 0, width, height, backColor, 0.7)
; draw top thumb
DrawBox(0, 0, width, thumbSize, leftTopThumbColor, 1)
; draw bottom thumb
DrawBox(0, height - thumbSize, width, thumbSize, rightBottomThumbColor, 1)
; draw trackbar
If trackBarVisible
DrawBox(0, trackBarPos, width, trackBarSize, trackBarColor, 1)
EndIf
; Draw horizontal scrollbar
Else
; draw background
DrawBox(0, 0, width, height, backColor, 0.7)
; draw left thumb
DrawBox(0, 0, thumbSize, height, leftTopThumbColor, 1)
; draw right thumb
DrawBox(width - thumbSize, 0, thumbSize, height, rightBottomThumbColor, 1)
; draw trackbar
If trackBarVisible
DrawBox(trackBarPos, 0, trackBarSize, height, trackBarColor, 1)
EndIf
EndIf
EndProcedure
Procedure eventHandler_ScrollBarMouse(*widget.Widget, EventType, *event.PG_EventData, *userData)
Define x.d, y.d, width.d, height.d, mousePos.d, mousePos2.d, size.d, size2.d, trackAreaSize.d, trackBarSize.d, trackBarPos.d
Define min, max, pageSize, pos, thumbSize, trackBarVisible
*scrollbar.ScrollBarWidget = *widget\userData
If EventType = #PG_Event_MouseLeave
If *scrollbar\state & #_ScrollBar_TrackBarHover Or *scrollbar\state & #_ScrollBar_LeftTopThumbHover Or *scrollbar\state & #_ScrollBar_RightBottomThumbHover
*scrollbar\state &~ #_ScrollBar_TrackBarHover &~ #_ScrollBar_LeftTopThumbHover &~ #_ScrollBar_RightBottomThumbHover
WidgetRedraw(*widget)
EndIf
ProcedureReturn 0
EndIf
x.d = *event\x
y.d = *event\y
width.d = *widget\parentLayoutItem\width ;-*needs changing event to handle width height
height.d = *widget\parentLayoutItem\height
min = *scrollbar\min
max = *scrollbar\max + 1
pageSize = *scrollbar\pageSize
pos = *scrollbar\pos
thumbSize = *scrollbar\thumbSize
If *scrollbar\flags & #PG_ScrollBar_Vertical
CalculateTrackAreaSize(height, thumbSize)
mousePos.d = y
mousePos2.d = x
size.d = height
size2.d = width
Else
CalculateTrackAreaSize(width, thumbSize)
mousePos.d = x
mousePos2.d = y
size.d = width
size2.d = height
EndIf
CalculateTrackBarSize(min, max, pageSize, trackAreaSize, thumbSize, trackBarSize)
CalculateTrackBarPos(min, max, pos, trackAreaSize, thumbSize)
trackBarPos = Round(trackBarPos, #PB_Round_Nearest)
trackBarSize = Round(trackBarSize, #PB_Round_Nearest)
CalculateTrackBarVisible(size, thumbSize)
Select EventType
Case #PG_Event_MouseMove
*scrollbar\mouseX = x
*scrollbar\mouseY = y
; handle trackbar drag
If trackBarVisible And *scrollbar\state & #_ScrollBar_TrackBarDrag
*scrollbar\trackBarPos = mousePos - *scrollbar\dragDelta
If *scrollbar\trackBarPos <= thumbSize
*scrollbar\trackBarPos = thumbSize
ElseIf *scrollbar\trackBarPos >= size - (thumbSize + trackBarSize)
*scrollbar\trackBarPos = size - (thumbSize + trackBarSize)
EndIf
If *scrollbar\trackBarPos <> *scrollbar\lastTrackBarPos
*scrollbar\pos = (*scrollbar\trackBarPos - thumbSize) * (max - min) / trackAreaSize + min
If *scrollbar\pos <> *scrollbar\lastPos
DispatchEvent(*widget, #PG_Event_Action, *scrollbar\pos)
EndIf
*scrollbar\lastPos = *scrollbar\pos
WidgetRedraw(*widget)
EndIf
*scrollbar\lastTrackBarPos = *scrollbar\trackBarPos
EndIf
; handle hovering
; don't process hovering if page scrolling
If *scrollbar\state & #_ScrollBar_LeftTopPageDown Or *scrollbar\state & #_ScrollBar_RightBottomPageDown
ProcedureReturn 0
EndIf
; trackBar hovering
If Not *scrollbar\state & #_ScrollBar_LeftTopThumbDown And Not *scrollbar\state & #_ScrollBar_RightBottomThumbDown
If trackBarVisible And mousePos >= trackBarPos And mousePos < trackBarPos + trackBarSize
If Not *scrollbar\state & #_ScrollBar_TrackBarHover
*scrollbar\state | #_ScrollBar_TrackBarHover
WidgetRedraw(*widget)
EndIf
Else
If *scrollbar\state & #_ScrollBar_TrackBarHover
*scrollbar\state &~ #_ScrollBar_TrackBarHover
WidgetRedraw(*widget)
EndIf
EndIf
EndIf
; thumb button hovering
If Not *scrollbar\state & #_ScrollBar_TrackBarDrag
; left / top thumb
If Not *scrollbar\state & #_ScrollBar_RightBottomThumbDown
If mousePos >= 0 And mousePos <= thumbSize And mousePos2 >= 0 And mousePos2 <= size2
If Not *scrollbar\state & #_ScrollBar_LeftTopThumbHover
*scrollbar\state | #_ScrollBar_LeftTopThumbHover
WidgetRedraw(*widget)
EndIf
Else
If *scrollbar\state & #_ScrollBar_LeftTopThumbHover
*scrollbar\state &~ #_ScrollBar_LeftTopThumbHover
WidgetRedraw(*widget)
EndIf
EndIf
EndIf
; right / bottom thumb
If Not *scrollbar\state & #_ScrollBar_LeftTopThumbDown
If mousePos >= size - thumbSize And mousePos <= size And mousePos2 >= 0 And mousePos2 <= size2
If Not *scrollbar\state & #_ScrollBar_RightBottomThumbHover
*scrollbar\state | #_ScrollBar_RightBottomThumbHover
WidgetRedraw(*widget)
EndIf
Else
If *scrollbar\state & #_ScrollBar_RightBottomThumbHover
*scrollbar\state &~ #_ScrollBar_RightBottomThumbHover
WidgetRedraw(*widget)
EndIf
EndIf
EndIf
EndIf
Case #PG_Event_MouseLeftButtonDown, #PG_Event_MouseLeftDoubleClick
; trackBar
If trackBarVisible And mousePos >= trackBarPos And mousePos < trackBarPos + trackBarSize
*scrollbar\state | #_ScrollBar_TrackBarDrag
*scrollbar\dragDelta = mousePos - trackBarPos
*scrollbar\trackBarPos = mousePos - *scrollbar\dragDelta
If *scrollbar\trackBarPos <= thumbSize
*scrollbar\trackBarPos = thumbSize
ElseIf *scrollbar\trackBarPos >= size - (thumbSize + trackBarSize)
*scrollbar\trackBarPos = size - (thumbSize + trackBarSize)
EndIf
WidgetRedraw(*widget)
WidgetSetMouseCapture(*widget)
; left / top thumb
ElseIf mousePos >= 0 And mousePos <= thumbSize
*scrollbar\state | #_ScrollBar_LeftTopThumbDown
If pos > min
pos - 1
updatePos = #True
EndIf
update = #True
; right / bottom thumb
ElseIf mousePos >= size - thumbSize And mousePos <= size
*scrollbar\state | #_ScrollBar_RightBottomThumbDown
If pos < max - pageSize
pos + 1
updatePos = #True
EndIf
update = #True
; left / top of trackbar background
ElseIf trackBarVisible And mousePos > thumbSize And mousePos < trackBarPos
*scrollbar\state | #_ScrollBar_LeftTopPageDown
pos - pageSize
If pos < min
pos = min
EndIf
updatePos = #True
update = #True
; right / bottom of trackbar background
ElseIf trackBarVisible And mousePos > trackBarPos And mousePos < size - thumbSize
*scrollbar\state | #_ScrollBar_RightBottomPageDown
pos + pageSize
If pos > max - pageSize
pos = max - pageSize
EndIf
updatePos = #True
update = #True
EndIf
If update
StartAnimation(*widget, #_ScrollBar_AnimateScroll, 0, *scrollBar\thumbDownScrollFPS)
If updatePos
*scrollbar\pos = pos
*scrollbar\lastPos = pos
DispatchEvent(*widget, #PG_Event_Action, pos)
EndIf
WidgetRedraw(*widget)
WidgetSetMouseCapture(*widget)
EndIf
Case #PG_Event_MouseLeftButtonUp
If *scrollbar\state & #_ScrollBar_TrackBarDrag
If trackBarVisible
*scrollbar\pos = (*scrollbar\trackBarPos - thumbSize) * (max - min) / trackAreaSize + min
If *scrollbar\pos <> *scrollbar\lastPos
DispatchEvent(*widget, #PG_Event_Action, *scrollbar\pos)
EndIf
*scrollbar\lastPos = *scrollbar\pos
EndIf
Else
StopAnimation(*widget, #_ScrollBar_AnimateScroll)
EndIf
WidgetReleaseMouseCapture()
*scrollbar\state = #Null
WidgetRedraw(*widget)
EndSelect
EndProcedure
Procedure eventHandler_ScrollBarAnimate(*widget.Widget, EventType, *eventData.PG_EventAnimate)
Define x.d, y.d, width.d, height.d, mousePos.d, size.d, trackAreaSize.d, trackBarSize.d, trackBarPos.d
Define min, max, pageSize, pos, thumbSize, trackBarVisible
Select *eventData\id
Case #_ScrollBar_AnimateScroll
*scrollBar.ScrollBarWidget = *widget\userData
x.d = *scrollBar\mouseX
y.d = *scrollBar\mouseY
width.d = *eventData\width
height.d = *eventData\height
min = *scrollbar\min
max = *scrollbar\max + 1
pageSize = *scrollbar\pageSize
pos = *scrollbar\pos
thumbSize = *scrollbar\thumbSize
If *scrollbar\flags & #PG_ScrollBar_Vertical
CalculateTrackAreaSize(height, thumbSize)
size = height
mousePos = y
Else
CalculateTrackAreaSize(width, thumbSize)
size = width
mousePos = x
EndIf
CalculateTrackBarSize(min, max, pageSize, trackAreaSize, thumbSize, trackBarSize)
CalculateTrackBarPos(min, max, pos, trackAreaSize, thumbSize)
trackBarPos = Round(trackBarPos, #PB_Round_Nearest)
trackBarSize = Round(trackBarSize, #PB_Round_Nearest)
If *eventData\currentTime >= *scrollBar\thumbDownScrollDelay
If x >= 0 And x <= width And y >= 0 And y <= height ; mouse is inside the widget
If *scrollBar\state & #_ScrollBar_LeftTopThumbDown
If mousePos <= thumbSize And pos > min
pos - 1
update = #True
EndIf
ElseIf *scrollBar\state & #_ScrollBar_RightBottomThumbDown
If mousePos >= size - thumbSize And pos < max - pageSize
pos + 1
update = #True
EndIf
ElseIf *scrollBar\state & #_ScrollBar_LeftTopPageDown
If mousePos > thumbSize And trackBarPos > mousePos
pos - pageSize
If pos < min
pos = min
EndIf
update = #True
EndIf
ElseIf *scrollBar\state & #_ScrollBar_RightBottomPageDown
If mousePos < size - thumbSize And trackBarPos + trackBarSize < mousePos
pos + pageSize
If pos > max - pageSize
pos = max - pageSize
EndIf
update = #True
EndIf
EndIf
If update
*scrollbar\pos = pos
*scrollbar\lastPos = pos
DispatchEvent(*widget, #PG_Event_Action, pos)
WidgetRedraw(*widget)
EndIf
EndIf
EndIf
EndSelect
EndProcedure
;-
;- *** Public Functions ***
ProcedureDLL CreateScrollBar(x, y, Width, Height, Minimum, Maximum, PageSize, Flags = #Null)
If Minimum < 0
Minimum = 0
EndIf
If Maximum < Minimum
Maximum = Minimum + 1
EndIf
If PageSize > Maximum
PageSize = Maximum
EndIf
If Width < 0
Width = 0
EndIf
If Height < 0
Height = 0
EndIf
*scrollBar.ScrollBarWidget = AllocateStructure(ScrollBarWidget)
*scrollBar\thumbSize = #_ScrollBar_ThumbSize
*scrollBar\thumbDownScrollDelay = #_ScrollBar_ScrollDelay
*scrollBar\thumbDownScrollFPS = #_ScrollBar_ScrollFPS
*scrollBar\min = Minimum
*scrollBar\max = Maximum
*scrollBar\pageSize = PageSize
*scrollBar\pos = *scrollBar\min
If Flags & #PG_ScrollBar_Vertical
*scrollBar\flags | #PG_ScrollBar_Vertical
If Not Width
Width = #_ScrollBar_VerticalWidth
EndIf
Else
If Not Height
Height = #_ScrollBar_HorizontalHeight
EndIf
EndIf
*widget.Widget = CreateWidget(x, y, Width, Height, *scrollBar, flags | #PG_Widget_Hide)
AddEventHandler(*widget, #PG_Event_Draw, @eventHandler_ScrollBarDraw())
AddEventHandler(*widget, #PG_Event_MouseMove, @eventHandler_ScrollBarMouse())
AddEventHandler(*widget, #PG_Event_MouseLeave, @eventHandler_ScrollBarMouse())
AddEventHandler(*widget, #PG_Event_MouseLeftButtonDown, @eventHandler_ScrollBarMouse())
AddEventHandler(*widget, #PG_Event_MouseLeftButtonUp, @eventHandler_ScrollBarMouse())
AddEventHandler(*widget, #PG_Event_MouseLeftDoubleClick, @eventHandler_ScrollBarMouse())
AddEventHandler(*widget, #PG_Event_Animate, @eventHandler_ScrollBarAnimate())
If Not flags & #PG_Widget_Hide And Not flags & #PG_Widget_NoDraw
WidgetShow(*widget)
EndIf
ProcedureReturn *widget
EndProcedure
Notice how there is absolutelty no DPI logic, that's because ProGUI handles everything automatically (all based on Device Independent Pixels)