This is something I had to throw together for work and I thought it might be useful. It displays a simple bar with labels and allows the user to make a selection with the mouse. I use dates in my example but it should be able to be whatever you want. Please note that this was built specifically for work and could use some major cleaning up for production work.
Save this as "trackselect.pb"
Code: Select all
;-
EnableExplicit
;-
Structure s_TrackSelect_Settings
; Structure used to pass initial settings of the control. The user fills this structure with information and passes to the gadget.
BackColor.l
; The background color of the control itself.
SelectedColor.l
; The color used to draw a selection.
Labels.s
; String of labels used in the selection. Broken up by the | (pipe) character.
EventCallback.l
; Pointer to procedure to return information when a selection is made.
DisplayCount.l
; The number of items to display at one time.
SelectedBegin.l
; Either 0 for no starting selection or non-zero for a starting selection.
SelectedEnd.l
; Either 0 for no ending selection or non-zero for an ending selection.
IndexBegin.l
; Either 0 or 1 for the first label to be visible or the first label to be visible.
EndStructure
Structure _s_TrackSelect_Main
;
Gadget.l
Handle.l
X.l
Y.l
Width.l
Height.l
;
BackColor.l
; The color used to draw the background for the control.
SelectedColor.l
; The color used to draw the selection.
Labels.s
; String list of labels, divided by the | (pipe) character.
Dimensions.RECT
;
DisplayCount.l
; The number of items to display at one time.
ItemCount.l
; The total number of items in the gadget.
TickPosition.l
; Block of memory storing dividing line positions.
SizeTickPosition.l
; The size of the TickPosition array.
Callback.l
; The callback used for handling Windows events.
Image.l
;
SelectedBegin.l
;
SelectedEnd.l
;
LastX.l
;
HalfWidth.l
;
EventCallback.l
;
IsRedrawing.l
; Flag used to determine whether the control is being redrawn.
IndexBegin.l
; The 1 based index of the first displayed label.
Clicked.l
; True if the user clicked within the track select.
EndStructure
;-
Procedure FreePBString(*Address)
; Procedure and method of removing structure strings from memory from freak @ http://www.purebasic.fr/english/viewtopic.php?t=23099&start=0
Protected String.String
; The String Structure contains one String element, which is initialized to 0 on procedure start
PokeL(@String, *Address)
; Poke the string's address into the structure. When returning, PB's string free routine for the local structure will actually free the passed string.
EndProcedure
Procedure _TrackSelect_Draw(*HoldSelect._s_TrackSelect_Main)
;
Protected hdc.l
;
Protected iLoop.l
;
Protected hFont.l
;
Protected HoldPen.l
;
Protected HoldBrush.l
;
Protected hBrushButton.l
;
Protected HoldRect.RECT
;
Protected HoldSize.SIZE
; Generic size structure.
Protected MaxSize.SIZE
;
Protected HoldString.s
;
Protected HoldWidth.l
;
Protected EachWidth.l
;
Protected HalfWidth.l
;
Protected CurrentLeft.l
;
Protected SelectedBegin.l
;
Protected SelectedEnd.l
;
Protected *PositionTick.Long
; Pointer to tick location in memory.
Protected Padding.l
; The amount of pixels to pad the left and right.
Protected Dim ArrayName.s(*HoldSelect\DisplayCount - 1)
Protected Dim ArrayLength.l(*HoldSelect\DisplayCount - 1)
Protected Dim ArrayTick.l(*HoldSelect\DisplayCount - 1)
Protected Dim ArraySize.SIZE(*HoldSelect\DisplayCount - 1)
; Create temporary arrays for calculating strings.
hdc = StartDrawing(ImageOutput(*HoldSelect\Image))
; Start drawing the control.
SetBkMode_(hdc, #TRANSPARENT)
; Enable transparent text drawing mode.
HoldPen = CreatePen_(#PS_SOLID, 1, #Black)
; Create a generic black pen.
SelectObject_(hdc, HoldPen)
; Select the pen into the drawing.
;/
;{ Draw the panning buttons.
hBrushButton = CreateSolidBrush_(RGB(245, 245, 245))
; Create the brush used to draw the left and right panning buttons.
SetRect_(@HoldRect, 0, 0, 15, *HoldSelect\Dimensions\Bottom)
; Set the area used by the left panning button.
FillRect_(hdc, @HoldRect, hBrushButton)
; Fill the area used by the left panning button.
MoveToEx_(hdc, 16, 0, #Null) : LineTo_(hdc, 16, *HoldSelect\Dimensions\Bottom + 1)
; Draw the dividing line for the left panning button.
SetRect_(@HoldRect, *HoldSelect\Dimensions\Right + 1, 0, *HoldSelect\Dimensions\Right + 1 + 15, *HoldSelect\Dimensions\Bottom)
; Set the area used by the right panning button.
FillRect_(hdc, @HoldRect, hBrushButton)
; Fill the area used by the right panning button.
MoveToEx_(hdc, *HoldSelect\Dimensions\Right, 0, #Null) : LineTo_(hdc, *HoldSelect\Dimensions\Right, *HoldSelect\Dimensions\Bottom + 1)
; Draw the dividing line for the right panning button.
;/
hFont = CreateFont_(-MulDiv_(8, GetDeviceCaps_(hdc, #LOGPIXELSY), 72), 0, 0, 0, #FW_BOLD, #False, #False, #False, #DEFAULT_CHARSET, #OUT_DEFAULT_PRECIS, #CLIP_DEFAULT_PRECIS, #DEFAULT_QUALITY, #FF_DONTCARE, @"Arial Unicode MS")
; Create the font used to write the labels.
SelectObject_(hdc, hFont)
; Select the font into drawing.
;/
HoldString = "<"
; Store the text used to draw the left panning button.
GetTextExtentPoint32_(hdc, @HoldString, 1, @HoldSize)
; Get the size of the text.
SetRect_(@HoldRect, 0, *HoldSelect\Dimensions\Top, 15, *HoldSelect\Dimensions\Bottom)
;
MoveToEx_(hdc, (15 - HoldSize\cx) >> 1, ((*HoldSelect\Dimensions\Bottom - *HoldSelect\Dimensions\Top) - HoldSize\cy) >> 1, #Null)
;
DrawText_(hdc, @HoldString, 1, @HoldRect, #DT_LEFT | #DT_TOP | #DT_SINGLELINE)
;/
HoldString = ">"
; Store the text used to draw the left panning button.
GetTextExtentPoint32_(hdc, @HoldString, 1, @HoldSize)
; Get the size of the text.
SetRect_(@HoldRect, *HoldSelect\Dimensions\Right + 1, *HoldSelect\Dimensions\Top, *HoldSelect\Dimensions\Right + 1 + 15, *HoldSelect\Dimensions\Bottom)
;
MoveToEx_(hdc, (*HoldSelect\Dimensions\Right + 1) + ((15 - HoldSize\cx) >> 1), ((*HoldSelect\Dimensions\Bottom - *HoldSelect\Dimensions\Top) - HoldSize\cy) >> 1, #Null)
;
DrawText_(hdc, @HoldString, 1, @HoldRect, #DT_LEFT | #DT_TOP | #DT_SINGLELINE)
;
DeleteObject_(hFont)
;}
;/
hFont = CreateFont_(-MulDiv_(8, GetDeviceCaps_(hdc, #LOGPIXELSY), 72), 0, 0, 0, #FW_NORMAL, #False, #False, #False, #DEFAULT_CHARSET, #OUT_DEFAULT_PRECIS, #CLIP_DEFAULT_PRECIS, #DEFAULT_QUALITY, #FF_DONTCARE, @"Arial Unicode MS")
; Create the font used to write the labels.
SelectObject_(hdc, hFont)
; Select the font into drawing.
For iLoop = 1 To *HoldSelect\DisplayCount
;
HoldString = StringField(*HoldSelect\Labels, *HoldSelect\IndexBegin + iLoop - 1, "|")
;
ArrayName(iLoop - 1) = HoldString
ArrayLength(iLoop - 1) = Len(HoldString)
;
GetTextExtentPoint32_(hdc, @ArrayName(iLoop - 1), ArrayLength(iLoop - 1), @HoldSize)
;
ArraySize(iLoop - 1)\cx = HoldSize\cx
ArraySize(iLoop - 1)\cy = HoldSize\cy
;
If HoldSize\cx > MaxSize\cx : MaxSize\cx = HoldSize\cx : EndIf
;
If HoldSize\cy > MaxSize\cy : MaxSize\cy = HoldSize\cy : EndIf
;
Next iLoop
;
EachWidth = ((*HoldSelect\Dimensions\Right - *HoldSelect\Dimensions\Left) / *HoldSelect\DisplayCount)
;
Padding = ((*HoldSelect\Dimensions\Right - *HoldSelect\Dimensions\Left) - (EachWidth * *HoldSelect\DisplayCount)) >> 1
; Store the amount to pad the left
HalfWidth = EachWidth >> 1
;
*HoldSelect\HalfWidth = EachWidth
;
CurrentLeft = *HoldSelect\Dimensions\Left + Padding + HalfWidth
;
If *HoldSelect\TickPosition : FreeMemory(*HoldSelect\TickPosition) : *HoldSelect\TickPosition = 0 : EndIf
; Free any existing tick location values.
*HoldSelect\SizeTickPosition = *HoldSelect\DisplayCount << 2
; Store the size of the tick position array.
*HoldSelect\TickPosition = AllocateMemory(*HoldSelect\SizeTickPosition)
; Allocate space to store the tick positions.
*PositionTick = *HoldSelect\TickPosition
; Store a pointer to the first tick position location.
For iLoop = 1 To *HoldSelect\DisplayCount
;
ArrayTick(iLoop - 1) = CurrentLeft
;
If *HoldSelect\SelectedBegin = iLoop + (*HoldSelect\IndexBegin - 1) : SelectedBegin = ArrayTick(iLoop - 1) : EndIf
;
If *HoldSelect\SelectedEnd = iLoop + (*HoldSelect\IndexBegin - 1) : SelectedEnd = ArrayTick(iLoop - 1) : EndIf
;
CurrentLeft = CurrentLeft + EachWidth
; Update the current left position.
*PositionTick\l = ArrayTick(iLoop - 1)
; Store the tick position.
*PositionTick + 4
; Seek to the next tick position.
Next iLoop
;
If *HoldSelect\SelectedBegin = 1 Or *HoldSelect\SelectedBegin < *HoldSelect\IndexBegin : SelectedBegin = *HoldSelect\Dimensions\Left : EndIf
;
If *HoldSelect\SelectedEnd = *HoldSelect\ItemCount Or *HoldSelect\SelectedEnd > ((*HoldSelect\IndexBegin - 1) + *HoldSelect\DisplayCount) : SelectedEnd = *HoldSelect\Dimensions\Right : EndIf
;
If *HoldSelect\BackColor = -1
HoldBrush = CreateSolidBrush_(GetSysColor_(#COLOR_3DFACE))
Else
HoldBrush = CreateSolidBrush_(*HoldSelect\BackColor)
EndIf
;
SelectObject_(hdc, HoldBrush)
;
If *HoldSelect\SelectedBegin <> *HoldSelect\SelectedEnd And *HoldSelect\SelectedBegin <> -1 And *HoldSelect\SelectedEnd <> -1
;
If SelectedBegin > 0 And SelectedEnd > 0
;
If *HoldSelect\SelectedBegin <> -1
;
SetRect_(@HoldRect, *HoldSelect\Dimensions\Left, *HoldSelect\Dimensions\Top, SelectedBegin - 1, *HoldSelect\Dimensions\Bottom)
;
FillRect_(hdc, @HoldRect, HoldBrush)
;
EndIf
;
If *HoldSelect\SelectedEnd <> -1 ; < *HoldSelect\DisplayCount
;
SetRect_(@HoldRect, SelectedEnd + 1, *HoldSelect\Dimensions\Top, *HoldSelect\Dimensions\Right, *HoldSelect\Dimensions\Bottom)
;
FillRect_(hdc, @HoldRect, HoldBrush)
;
EndIf
;
If HoldBrush : DeleteObject_(HoldBrush) : HoldBrush = 0 : EndIf
;
HoldBrush = CreateSolidBrush_(*HoldSelect\SelectedColor)
;
SetRect_(@HoldRect, SelectedBegin + 1, *HoldSelect\Dimensions\Top, SelectedEnd - 1, *HoldSelect\Dimensions\Bottom)
;
SelectObject_(hdc, HoldBrush)
;
FillRect_(hdc, @HoldRect, HoldBrush)
;
DeleteObject_(HoldBrush) : HoldBrush = 0
;
Else
;
FillRect_(hdc, @*HoldSelect\Dimensions, HoldBrush)
;
EndIf
;
Else
;
FillRect_(hdc, @*HoldSelect\Dimensions, HoldBrush)
;
If *HoldSelect\SelectedBegin = *HoldSelect\SelectedEnd And *HoldSelect\SelectedBegin <> -1 And *HoldSelect\SelectedEnd <> -1
; One item selected.
If HoldBrush : DeleteObject_(HoldBrush) : HoldBrush = 0 : EndIf
;
HoldBrush = CreateSolidBrush_(*HoldSelect\SelectedColor)
;
SetRect_(@HoldRect, SelectedBegin - (HalfWidth >> 1), *HoldSelect\Dimensions\Top, SelectedBegin + (HalfWidth >> 1), *HoldSelect\Dimensions\Bottom)
;
SelectObject_(hdc, HoldBrush)
;
FillRect_(hdc, @HoldRect, HoldBrush)
;
DeleteObject_(HoldBrush) : HoldBrush = 0
;
EndIf
;
EndIf
;
If HoldBrush : DeleteObject_(HoldBrush) : HoldBrush = 0 : EndIf
;
CurrentLeft = *HoldSelect\Dimensions\Left + Padding
;
For iLoop = 1 To *HoldSelect\DisplayCount
;
MoveToEx_(hdc, ArrayTick(iLoop - 1), *HoldSelect\Dimensions\Top, #Null) : LineTo_(hdc, ArrayTick(iLoop - 1), *HoldSelect\Dimensions\Top + (((*HoldSelect\Dimensions\Bottom - *HoldSelect\Dimensions\Top) - MaxSize\cy) >> 1))
;
MoveToEx_(hdc, ArrayTick(iLoop - 1), *HoldSelect\Dimensions\Bottom, #Null) : LineTo_(hdc, ArrayTick(iLoop - 1), *HoldSelect\Dimensions\Bottom - (((*HoldSelect\Dimensions\Bottom - *HoldSelect\Dimensions\Top) - MaxSize\cy) >> 1))
;
MoveToEx_(hdc, CurrentLeft + (EachWidth - ArraySize(iLoop - 1)\cx) >> 1, ((*HoldSelect\Dimensions\Bottom - *HoldSelect\Dimensions\Top) - ArraySize(iLoop - 1)\cy) >> 1, #Null)
;
SetRect_(@HoldRect, CurrentLeft, *HoldSelect\Dimensions\Top, CurrentLeft + EachWidth, *HoldSelect\Dimensions\Bottom)
;
DrawText_(hdc, @ArrayName(iLoop - 1), ArrayLength(iLoop - 1), @HoldRect, #DT_LEFT | #DT_TOP | #DT_SINGLELINE)
;
CurrentLeft = CurrentLeft + EachWidth
;
Next iLoop
;
DeleteObject_(hFont)
; Delete the font from the drawing.
DeleteObject_(HoldPen)
; Delete the black pen.
DeleteObject_(hBrushButton)
; Delete the brush used to draw the panning buttons.
StopDrawing()
;
*HoldSelect\IsRedrawing = #True
SetGadgetState(*HoldSelect\Gadget, ImageID(*HoldSelect\Image))
*HoldSelect\IsRedrawing = #False
; Refresh the display and notify the event that we're redrawing so the size event is not called.
EndProcedure
Procedure TrackSelectSetSelection(Gadget.l, NewBegin.l, NewEnd.l, EnsureVisible.l = #False)
;
Protected *HoldSelect._s_TrackSelect_Main
; Pointer to track select information.
*HoldSelect = GetWindowLong_(GadgetID(Gadget), #GWL_USERDATA)
; Load track select information.
If *HoldSelect = 0 : ProcedureReturn : EndIf
;
If NewBegin > 0 And NewEnd > 0
; Initial selection indexes are passed.
*HoldSelect\SelectedBegin = NewBegin : *HoldSelect\SelectedEnd = NewEnd
;
If *HoldSelect\SelectedBegin < 1 : *HoldSelect\SelectedBegin = 1 : EndIf
;
If *HoldSelect\SelectedBegin > *HoldSelect\ItemCount : *HoldSelect\SelectedBegin = *HoldSelect\ItemCount : EndIf
;
If *HoldSelect\SelectedEnd < 1 : *HoldSelect\SelectedEnd = 1 : EndIf
;
If *HoldSelect\SelectedEnd > *HoldSelect\ItemCount : *HoldSelect\SelectedEnd = *HoldSelect\ItemCount : EndIf
;
If *HoldSelect\SelectedEnd < *HoldSelect\SelectedBegin : *HoldSelect\SelectedEnd = *HoldSelect\SelectedBegin : EndIf
;
ElseIf NewBegin < 0 And NewEnd = -1
; Special case selection.
*HoldSelect\SelectedEnd = *HoldSelect\ItemCount
; Select the last item.
*HoldSelect\SelectedBegin = *HoldSelect\SelectedEnd + NewBegin
; Select x number of items before the last item.
Else
; Nothing selected.
*HoldSelect\SelectedBegin = -1 : *HoldSelect\SelectedEnd = -1
; Nothing is currently selected.
EndIf
;
If EnsureVisible
; The user wants to see the selection.
*HoldSelect\IndexBegin = *HoldSelect\SelectedBegin - 1
;
If *HoldSelect\IndexBegin < 1 : *HoldSelect\IndexBegin = 1 : EndIf
;
If *HoldSelect\IndexBegin > (*HoldSelect\ItemCount - *HoldSelect\DisplayCount) + 1 : *HoldSelect\IndexBegin = (*HoldSelect\ItemCount - *HoldSelect\DisplayCount) + 1 : EndIf
; Set the maximum allowed starting index.
EndIf
;
_TrackSelect_Draw(*HoldSelect)
; Redraw the gadget.
EndProcedure
Procedure TrackSelectSetStartIndex(Gadget.l, Index.l)
;
Protected *HoldSelect._s_TrackSelect_Main
; Pointer to track select information.
*HoldSelect = GetWindowLong_(GadgetID(Gadget), #GWL_USERDATA)
; Load track select information.
If *HoldSelect And SizeOf(*HoldSelect) <> SizeOf(_s_TrackSelect_Main) : ProcedureReturn : EndIf
;
If Index < 1 Or Index > *HoldSelect\ItemCount : ProcedureReturn : EndIf
;
*HoldSelect\IndexBegin = Index
; Set the new selection.
If *HoldSelect\IndexBegin > (*HoldSelect\ItemCount - *HoldSelect\DisplayCount) + 1 : *HoldSelect\IndexBegin = (*HoldSelect\ItemCount - *HoldSelect\DisplayCount) + 1 : EndIf
; Set the maximum allowed starting index.
_TrackSelect_Draw(*HoldSelect)
; Redraw the gadget.
EndProcedure
Procedure _TrackSelect_Callback(Handle.l, Message.l, wParam.l, lParam.l)
;
Protected Index.l
;
Protected lResult.l
;
Protected HoldMessage.l
;
Protected HoldPoint.POINT
;
Protected Callback.l
;
Protected HoldValue.l
;
Protected HoldBegin.l, HoldEnd.l
;
Protected SwitchBegin.l
;
Protected *HoldSelect._s_TrackSelect_Main
;
Protected HoldRect.RECT
; Temporary rectangular storage.
Protected *PositionTick.Long
; Pointer to tick positions.
*HoldSelect = GetWindowLong_(Handle, #GWL_USERDATA)
;
Callback = *HoldSelect\Callback
;
If Message = #WM_DESTROY
;
If *HoldSelect\Image And IsImage(*HoldSelect\Image) : FreeImage(*HoldSelect\Image) : *HoldSelect\Image = 0 : EndIf
;
FreePBString(@*HoldSelect\Labels)
;
If *HoldSelect\TickPosition : FreeMemory(*HoldSelect\TickPosition) : *HoldSelect\TickPosition = 0 : EndIf
;
FreeMemory(*HoldSelect)
;
ElseIf Message = #WM_SIZE
;
If *HoldSelect\IsRedrawing = #False
;
GetClientRect_(Handle, @HoldRect)
; Get the dimensions of the control.
*HoldSelect\Width = HoldRect\Right : *HoldSelect\Height = HoldRect\Bottom
;
*HoldSelect\Dimensions\Right = HoldRect\Right - 16 : *HoldSelect\Dimensions\Bottom = HoldRect\Bottom
; Store the usable drawing dimensions of the item. Offset both sides by 16 for the panning buttons.
If *HoldSelect\Image : FreeImage(*HoldSelect\Image) : *HoldSelect\Image = 0 : EndIf
;
*HoldSelect\Image = CreateImage(#PB_Any, HoldRect\Right, HoldRect\Bottom)
;
_TrackSelect_Draw(*HoldSelect)
;
EndIf
;
ElseIf Message = #WM_SETCURSOR
;
HoldMessage = (lParam >> 16) & $FFFF
; Get the cursor message.
GetCursorPos_(@HoldPoint)
; Get the cursor position in desktop coordinates.
MapWindowPoints_(#Null, wParam, @HoldPoint, 1)
; Map the cursor from the desktop to the window.
If HoldMessage = #WM_LBUTTONDOWN
; The user left-clicked in the track select.
If HoldPoint\X < 16
; Clicked in the left panning button.
If *HoldSelect\IndexBegin > 1
; The first label is not visible.
While GetAsyncKeyState_(#VK_LBUTTON) & $FFFE = 32768 : Delay(10) : Wend
; Loop until the user releases the "button".
*HoldSelect\IndexBegin - 1
; Pan left in the track select.
_TrackSelect_Draw(*HoldSelect)
; Redraw the track select.
EndIf
;
ElseIf HoldPoint\X > *HoldSelect\Dimensions\Right + 1
; Clicked in the right panning button.
If *HoldSelect\IndexBegin <= *HoldSelect\ItemCount - *HoldSelect\DisplayCount
; The last label is not visible.
While GetAsyncKeyState_(#VK_LBUTTON) & $FFFE = 32768 : Delay(10) : Wend
; Loop until the user releases the "button".
*HoldSelect\IndexBegin + 1
; Pan right in the track select.
_TrackSelect_Draw(*HoldSelect)
; Redraw the track select.
EndIf
;
Else
; The user clicked in the track select area.
*HoldSelect\Clicked = #True
; The user clicked in the track select.
EndIf
;
EndIf
;
If *HoldSelect\Clicked
; The user clicked within the track select.
HoldEnd = *HoldSelect\SelectedEnd : HoldBegin = *HoldSelect\SelectedBegin
;
*HoldSelect\SelectedEnd = -1 : *HoldSelect\SelectedBegin = -1
;
While GetAsyncKeyState_(#VK_LBUTTON) & $FFFE = 32768
; The user is making a selection while the mouse cursor is down.
GetCursorPos_(@HoldPoint)
; Store the position of the cursor relative to the desktop.
MapWindowPoints_(#Null, wParam, @HoldPoint, 1)
; Convert the mouse position to the window coordinates.
If HoldPoint\X < 16
; The mouse is over the left panning button.
If *HoldSelect\IndexBegin > 1
; The first label is not visible.
*HoldSelect\IndexBegin - 1
; Pan left in the track select.
*HoldSelect\SelectedBegin - 1
;
_TrackSelect_Draw(*HoldSelect)
; Redraw the track select.
EndIf
;
Delay(250)
; Delay for reaction time.
ElseIf HoldPoint\X > *HoldSelect\Dimensions\Right + 1
; The mouse is over the right panning button while making a selection.
If *HoldSelect\IndexBegin <= *HoldSelect\ItemCount - *HoldSelect\DisplayCount
; The last label is not visible.
*HoldSelect\IndexBegin + 1
; Pan right in the track select.
*HoldSelect\SelectedEnd + 1
;
_TrackSelect_Draw(*HoldSelect)
; Redraw the track select.
EndIf
;
Delay(250)
; Delay for reaction time.
Else
; The mouse is within the track select area.
Index = 1
; Reset the index.
*PositionTick = *HoldSelect\TickPosition
While *PositionTick - *HoldSelect\TickPosition < *HoldSelect\SizeTickPosition
; Loop through all ticks.
If HoldPoint\X >= *PositionTick\l - 8 And HoldPoint\X <= *PositionTick\l + 8
;
If *HoldSelect\SelectedBegin = -1
;
HoldBegin = Index + (*HoldSelect\IndexBegin - 1)
;
*HoldSelect\SelectedBegin = HoldBegin
;
EndIf
;
If SwitchBegin = #False And Index + (*HoldSelect\IndexBegin - 1) <= *HoldSelect\SelectedBegin
SwitchBegin = #True ; *holdselect\SelectedBegin
*HoldSelect\SelectedEnd = *HoldSelect\SelectedBegin
*HoldSelect\SelectedBegin = Index + (*HoldSelect\IndexBegin - 1)
ElseIf SwitchBegin And Index + (*HoldSelect\IndexBegin - 1) <= *HoldSelect\SelectedBegin
*HoldSelect\SelectedBegin = Index + (*HoldSelect\IndexBegin - 1)
ElseIf SwitchBegin And Index + (*HoldSelect\IndexBegin - 1) >=*HoldSelect\SelectedBegin
SwitchBegin = #False
*HoldSelect\SelectedBegin = *HoldSelect\SelectedEnd
*HoldSelect\SelectedEnd = Index + (*HoldSelect\IndexBegin - 1)
Else
*HoldSelect\SelectedEnd = Index + (*HoldSelect\IndexBegin - 1)
EndIf
;
Break
;
EndIf
;
Index + 1
; Increment to the next index.
*PositionTick + 4
; Cycle to the next tick.
Wend
;
EndIf
;
If HoldBegin <> *HoldSelect\SelectedBegin Or HoldEnd <> *HoldSelect\SelectedEnd : _TrackSelect_Draw(*HoldSelect) : EndIf
; Redraw the new selection.
HoldEnd = *HoldSelect\SelectedEnd : HoldBegin = *HoldSelect\SelectedBegin
; Store the updated beginning and ending selection indexes.
Wend
;
*HoldSelect\Clicked = #False
; The mouse button is no longer down.
_TrackSelect_Draw(*HoldSelect)
; Redraw the track select.
If *HoldSelect\EventCallback : CallFunctionFast(*HoldSelect\EventCallback, 0, HoldBegin, HoldEnd) : EndIf
; Call the user defined event function if it exists.
EndIf
;
EndIf
;
lResult = CallWindowProc_(Callback, Handle, Message, wParam, lParam)
;
ProcedureReturn lResult
;
EndProcedure
Procedure TrackSelectGadget(Gadget.l, X.l, Y.l, Width.l, Height.l, *Settings.s_TrackSelect_Settings)
; The procedure used to create the track select control.
Protected HoldRect.RECT
; General purpose rect structure.
Protected *HoldSelect._s_TrackSelect_Main
; Structure for information on the track select.
If IsGadget(Gadget) : ProcedureReturn : EndIf
; Do not use an existing gadget number.
*HoldSelect = AllocateMemory(SizeOf(_s_TrackSelect_Main))
; Allocate space for the track select structure.
With *HoldSelect
;
\Gadget = Gadget
; Store the PB gadget id.
ImageGadget(Gadget, X, Y, Width, Height, #Null, #PB_Image_Border)
; Create the image that stores the track select display.
\Handle = GadgetID(Gadget)
; Store the handle to the control.
\X = X
\Y = Y
\Width = Width
\Height = Height
; Store standard control information.
\BackColor = *Settings\BackColor
; Store information on the back color used in drawing the control. Use a -1 to use the default gray color.
\SelectedColor = *Settings\SelectedColor
; Store the color used to draw the selection color.
\Labels = *Settings\Labels
; Store the labels used in drawing the item.
GetClientRect_(\Handle, @HoldRect)
; Get the rectangular area available for drawing.
\Dimensions\Left = 16 : \Dimensions\Top = 0 : \Dimensions\Right = HoldRect\Right - 16 : \Dimensions\Bottom = HoldRect\Bottom
; Store the usable drawing dimensions of the item. Offset both sides by 16 for the panning buttons.
\ItemCount = CountString(*Settings\Labels, "|") + 1
; Store the number of items in the control.
\DisplayCount = *Settings\DisplayCount
; Store the number of displayed items.
If \DisplayCount = 0 : \DisplayCount = \ItemCount : EndIf
; Store the number of items to display at one time, or the maximum.
If \DisplayCount > \ItemCount : \DisplayCount = \ItemCount : EndIf
; Cannot display more than the store items.
If *Settings\IndexBegin > 0
; A starting index was specified.
\IndexBegin = *Settings\IndexBegin
; The first label is displayed by default.
If \IndexBegin < 1 : \IndexBegin = 1 : EndIf
;
If \IndexBegin > (\ItemCount - \DisplayCount) + 1 : \IndexBegin = (\ItemCount - \DisplayCount) + 1 : EndIf
; Set the maximum allowed starting index.
ElseIf *Settings\IndexBegin = -1
; Special case starting index - seek to the last visible item.
\IndexBegin = (\ItemCount - \DisplayCount) + 1
; Set the maximum allowed starting index.
Else
; No starting index specified.
\IndexBegin = 1
;
EndIf
;
If *Settings\SelectedBegin > 0 And *Settings\SelectedEnd > 0
; Initial selection indexes are passed.
\SelectedBegin = *Settings\SelectedBegin : \SelectedEnd = *Settings\SelectedEnd
; Set the initial selections.
If \SelectedBegin < 1 : \SelectedBegin = 1 : EndIf
;
If \SelectedBegin > \ItemCount : \SelectedBegin = \ItemCount : EndIf
;
If \SelectedEnd < 1 : \SelectedEnd = 1 : EndIf
;
If \SelectedEnd > \ItemCount : \SelectedEnd = \ItemCount : EndIf
;
If \SelectedEnd < \SelectedBegin : \SelectedEnd = \SelectedBegin : EndIf
;
ElseIf *Settings\SelectedBegin < 0 And *Settings\SelectedEnd = -1
; Special case selection.
\SelectedEnd = \ItemCount
; Select the last item.
\SelectedBegin = \SelectedEnd + *Settings\SelectedBegin
; Select x number of items before the last item.
Else
; Nothing selected.
\SelectedBegin = -1 : \SelectedEnd = -1
; Nothing is currently selected.
EndIf
;
\EventCallback = *Settings\EventCallback
; Store the user event procedure, if any.
\Image = CreateImage(#PB_Any, HoldRect\Right, HoldRect\Bottom)
; Create the image for the track select control.
SetWindowLong_(\Handle, #GWL_USERDATA, *HoldSelect)
; Store the pointer to the track select memory address.
SetWindowLong_(\Handle, #GWL_STYLE, GetWindowLong_(\Handle, #GWL_STYLE) | #SS_NOTIFY)
; Enable advanced events for the control.
\Callback = SetWindowLong_(\Handle, #GWL_WNDPROC, @_TrackSelect_Callback())
; Hook into the callback for the control.
_TrackSelect_Draw(*HoldSelect)
; Draw the track select.
EndWith
;
EndProcedure
;-Good luck and you can pass on bug reports but it'll take a little bit of time before I can get to them.


