Page 1 of 2

ScrollBarEx : Custom ScrollBar Gadget [CrossPlatform]

Posted: Tue Oct 04, 2016 10:50 am
by Peyman
main idea is for have a same looking ScrollBar in All OSs and ScrollBar Events so here is my ScrollBar Gadget

for run example u need some images for scrollbar(Up, Down, Left, Right And Knob), i use Images for Win 10 Theme.

just say for adding any futures, report Bugs or anything.

Enjoy,
Peyman.

Code: Select all

; ====================================
; Name:             ScrollBarEx
; Version:          1.40
; Author:           Peyman
; Date:             04th Oct 2016
; Update:           08th Nov 2016
; OS:               All
; Compiler Option : ThreadSafe
; PB ver.:          5.20+
; License:          Free
;
; Thanks :          
;                   infratec - For fixing thread problem in linux and mac
;                   And all of you that use it and send good comments
;
; ====================================
;{ Release info...
; 1.00 First release version
;
; 1.10  Fixed Drawing ScrollBar
;       Added CompilerError for threadsafe option
;       Fixed a problem in BindScrollBarExEvent
;       Images embeded in Example
;       Changed CanvasCallback to ScrollBarExCallback
;       Changed UpdateCallback to UpdateScrollBarEx
;
; 1.20  Fixed problem in linux with image drawings
;       Fixed thread problem with linux (thx to infratec)
;
; 1.30  Fixed a bug in move knob and show over button for arrows
;       Fixed a bug in state event
;       Added Command procedure
;       Added UnbindEvent procedure
;       Changed all procedures to SBEx_*
;       Changed all ScrollBarEx_ constants to SBEx_*
;       Changed Callback system now each gadget can have many callbacks
;       Removed SBEx_SetAttribute and SBEx_GetAttribute (all attributes now is in command)
;       Removed SBEx_SetData and SBEx_GetData (integrated in command)
;       Removed SetScrollBarExState and SetScrollBarExState (integrated in command)
;       Removed SBEx_Event (integrated in command)
;       Removed SBEx_Wheel (integrated in command)
;
; 1.40  Fixed the moving slider system, now its move by State instead of width and height
;       Added continues slider moving when click and hold left button on gadget
;       Fixed a problem in knob resizing when Max number of ScrollBar is too high
;       Fixed a bug in Wheel command (#SBEx_Command_Wheel)
;       Some cleanup in SBEx_Resize
;}


;- START OF MODULE
DeclareModule ScrollBarEx  
  ; Flags
  Enumeration 1
    #SBEx_Vertical
    #SBEx_Horizontal
  EndEnumeration
  
  ; Events
  CompilerIf #PB_Compiler_Version >= 540
    EnumerationBinary 1
      #SBEx_Event_State
      #SBEx_Event_WheelUp
      #SBEx_Event_WheelDown
      #SBEx_Event_WheelLeft
      #SBEx_Event_WheelRight
    EndEnumeration
  CompilerElse
    Enumeration
      #SBEx_Event_State      = 1
      #SBEx_Event_WheelUp    = 2
      #SBEx_Event_WheelDown  = 4
      #SBEx_Event_WheelLeft  = 8
      #SBEx_Event_WheelRight = 16
    EndEnumeration
  CompilerEndIf
  
  ; Commands
  Enumeration
    #SBEx_Command_Minimum
    #SBEx_Command_Maximum
    #SBEx_Command_PageLength
    #SBEx_Command_Wheel_Step
    #SBEx_Command_Arrow_Step
    #SBEx_Command_Background_Step
    
    #SBEx_Command_LastEvent
    #SBEx_Command_Wheel
    #SBEx_Command_Data
    #SBEx_Command_State
  EndEnumeration
  
  ; Wheels for #SBEx_Command_Wheel command
  Enumeration 1
    #SBEx_Wheel_Up
    #SBEx_Wheel_Down
    #SBEx_Wheel_Left
    #SBEx_Wheel_Right
  EndEnumeration
  
  Structure SBEx_Settings
    Up_Left_Image.i
    Up_Left_Over_Image.i
    Up_Left_Click_Image.i
    Down_Right_Image.i
    Down_Right_Over_Image.i
    Down_Right_Click_Image.i
    Knob_Image.i
    Knob_Over_Image.i
    Knob_Click_Image.i
    BackColor.i
  EndStructure
  
  Declare SBEx_Create(Gadget, X, Y, Width, Height, Min, Max, PageLength, *Settings.SBEx_Settings, Flags = #SBEx_Horizontal)
  Declare SBEx_Free(Gadget)
  Declare SBEx_Command(Gadget, Command, Param = #PB_Ignore, lParam = #PB_Ignore)
  Declare SBEx_Resize(Gadget, X, Y, Width, Height)
  Declare SBEx_BindEvent(Gadget, *Callback, EventType = #PB_All)
  Declare SBEx_UnbindEvent(Gadget, *Callback, EventType = #PB_All)
EndDeclareModule


Module ScrollBarEx
  EnableExplicit
  
  CompilerIf #PB_Compiler_Thread = #False
    CompilerError "ThreadSafe option must be enabled in Compiler Option"
  CompilerEndIf
  

  Enumeration #PB_EventType_FirstCustomValue
    #SBEx_EventType_Arrow_Thread
    #SBEx_EventType_Background_Thread
  EndEnumeration
  
  
  Prototype Callback(Gadget)
  
  Enumeration 1
    #STEP_UP
    #STEP_DOWN
    #STEP_LEFT
    #STEP_RIGHT
  EndEnumeration
  
  Enumeration 1
    #_THREAD_ARROWS
    #_THREAD_BACKGROUND
  EndEnumeration
  
  Structure Callback_desc
    *Callback
    CEvents.b
  EndStructure
  
  Structure Thread_desc
    hThread.i
    Type.b
    *_Data
    _Continue.b
  EndStructure
  
  Structure ScrollBarExdesc
    Gadget.i
    Type.b
    StructureUnion
      Up.i
      Left.i
    EndStructureUnion
    StructureUnion
      Up_Over.i
      Left_Over.i
    EndStructureUnion
    StructureUnion
      Up_Click.i
      Left_Click.i
    EndStructureUnion
    StructureUnion
      Down.i
      Right.i
    EndStructureUnion
    StructureUnion
      Down_Over.i
      Right_Over.i
    EndStructureUnion
    StructureUnion
      Down_Click.i
      Right_Click.i
    EndStructureUnion
    Knob.i
    Knob_Over.i
    Knob_Click.i
    Knob_Min_Size.b
    Thread.Thread_desc
    LBtnDown.b
    LastX.i
    LastY.i
    Min.i
    Max.i
    PageLength.i
    State.l
    Drag.b
    KnobSize.i
    KnobPos.i
    BackColor.l
    *_Data
    List Callbacks.Callback_desc()
    LEvent.b
    WheelStep.w
    ArrowStep.w
    BackStep.w
  EndStructure
  
  ;- Internal Procedures
  Procedure IsInRegion(x, y, width, height, xcur, ycur)
    If xcur >= x And xcur <= x + width
      If ycur >= y And ycur <= y + height
        ProcedureReturn #True
      EndIf
    EndIf
  EndProcedure
  
  
  Procedure DispatchEvents(*ScrollBarExdesc.ScrollBarExdesc, _Event)
    Protected Callback.Callback
    Static LastState.l
    
    With *ScrollBarExdesc
      If _Event = #SBEx_Event_State
        If LastState <> \State
          LastState = \State
        Else
          ProcedureReturn
        EndIf
      EndIf
      
      ForEach \Callbacks()
        If \Callbacks()\CEvents & _Event
          Callback = \Callbacks()\Callback
          \LEvent = _Event
          Callback(\Gadget)
        EndIf
      Next
    EndWith
  EndProcedure
  
  Procedure UpdateState(*ScrollBarExdesc.ScrollBarExdesc)
    With *ScrollBarExdesc
      If \Type = #SBEx_Vertical
        \State = Round((\KnobPos - ImageHeight(\Up)) / ((GadgetHeight(\Gadget) - ImageHeight(\Up) - ImageHeight(\Down)) / (\Max - \Min)), #PB_Round_Nearest)
      Else
        \State = Round((\KnobPos - ImageWidth(\Left)) / ((GadgetWidth(\Gadget) - ImageWidth(\Left) - ImageWidth(\Right)) / (\Max - \Min)), #PB_Round_Nearest)
      EndIf
      DispatchEvents(*ScrollBarExdesc, #SBEx_Event_State)
    EndWith
  EndProcedure
  
  
  Procedure ReCalcKnob(*ScrollBarExdesc.ScrollBarExdesc, State = #PB_Ignore)
    Protected KnobArea
    
    With *ScrollBarExdesc
      
      If State = #PB_Ignore
        State = \State
      EndIf
      
      If \Type = #SBEx_Vertical
        KnobArea = GadgetHeight(\Gadget) - ImageHeight(\Up) - ImageHeight(\Down)
        \KnobPos = ImageHeight(\Up) + Round(State * (KnobArea / (\Max - \Min)), #PB_Round_Nearest)
        \KnobSize = Round(KnobArea - (KnobArea / (\Max - \Min)) * ((\Max - \Min) - \PageLength), #PB_Round_Down)
        If \KnobSize < \Knob_Min_Size
          \KnobSize = \Knob_Min_Size
        EndIf
        ResizeImage(\Knob, #PB_Ignore, \KnobSize)
        ResizeImage(\Knob_Over, #PB_Ignore, \KnobSize)
        ResizeImage(\Knob_Click, #PB_Ignore, \KnobSize)
      Else
        KnobArea = GadgetWidth(\Gadget) - ImageWidth(\Left) - ImageWidth(\Right)
        \KnobPos = ImageWidth(\Left) + Round(State * (KnobArea / (\Max - \Min)), #PB_Round_Nearest)
        \KnobSize = Round(KnobArea - (KnobArea / (\Max - \Min)) * ((\Max - \Min) - \PageLength), #PB_Round_Down)
        If \KnobSize < \Knob_Min_Size
          \KnobSize = \Knob_Min_Size
        EndIf
        ResizeImage(\Knob, \KnobSize, #PB_Ignore)
        ResizeImage(\Knob_Over, \KnobSize, #PB_Ignore)
        ResizeImage(\Knob_Click, \KnobSize, #PB_Ignore)
      EndIf
    EndWith
    
  EndProcedure
  
  
  Procedure UpdateScrollBarEx(*ScrollBarExdesc.ScrollBarExdesc, X = #PB_Ignore, Y = #PB_Ignore)
    
    With *ScrollBarExdesc
      If X = #PB_Ignore
        X = GetGadgetAttribute(\Gadget, #PB_Canvas_MouseX)
      EndIf
      If Y = #PB_Ignore
        Y = GetGadgetAttribute(\Gadget, #PB_Canvas_MouseY)
      EndIf
      
      If \Type = #SBEx_Vertical
        
        StartDrawing(CanvasOutput(\Gadget))
        Box(0, 0, OutputWidth(), OutputHeight(), \BackColor)
        If IsInRegion(0, 0, ImageWidth(\Up), ImageHeight(\Up), X, Y) And Not \Drag
          If \LBtnDown
            DrawImage(ImageID(\Up_Click), 0, 0)
          Else
            DrawImage(ImageID(\Up_Over), 0, 0)
          EndIf
        Else
          DrawImage(ImageID(\Up), 0, 0)
        EndIf
        
        If IsInRegion(0, \KnobPos + 1, ImageWidth(\Knob), \KnobSize - 1, X, Y) Or \Drag
          If \LBtnDown
            DrawImage(ImageID(\Knob_Click), 0, \KnobPos)
          Else
            DrawImage(ImageID(\Knob_Over), 0, \KnobPos)
          EndIf
        Else
          DrawImage(ImageID(\Knob), 0, \KnobPos)
        EndIf
        
        If IsInRegion(0, OutputHeight() - ImageHeight(\Down) + 1, ImageWidth(\Down), ImageHeight(\Down), X, Y) And Not \Drag
          If \LBtnDown
            DrawImage(ImageID(\Down_Click), 0, OutputHeight() - ImageHeight(\Down_Click))
          Else
            DrawImage(ImageID(\Down_Over), 0, OutputHeight() - ImageHeight(\Down_Over))
          EndIf
        Else
          DrawImage(ImageID(\Down), 0, OutputHeight() - ImageHeight(\Down))
        EndIf
        StopDrawing()
        
      Else
        
        StartDrawing(CanvasOutput(\Gadget))
        Box(0, 0, OutputWidth(), OutputHeight(), \BackColor)
        If IsInRegion(0, 0, ImageWidth(\Left), ImageHeight(\Left), X, Y) And Not \Drag
          If \LBtnDown
            DrawImage(ImageID(\Left_Click), 0, 0)
          Else
            DrawImage(ImageID(\Left_Over), 0, 0)
          EndIf
        Else
          DrawImage(ImageID(\Left), 0, 0)
        EndIf
        
        If IsInRegion(\KnobPos + 1, 0, \KnobSize - 1, ImageHeight(\Knob), X, Y) Or \Drag
          If \LBtnDown
            DrawImage(ImageID(\Knob_Click), \KnobPos, 0)
          Else
            DrawImage(ImageID(\Knob_Over), \KnobPos, 0)
          EndIf
        Else
          DrawImage(ImageID(\Knob), \KnobPos, 0)
        EndIf
        
        If IsInRegion(OutputWidth() - ImageWidth(\Right) + 1, 0, ImageWidth(\Right), ImageHeight(\Right), X, Y) And Not \Drag
          If \LBtnDown
            DrawImage(ImageID(\Right_Click), OutputWidth() - ImageWidth(\Right), 0)
          Else
            DrawImage(ImageID(\Right_Over), OutputWidth() - ImageWidth(\Right), 0)
          EndIf
        Else
          DrawImage(ImageID(\Right), OutputWidth() - ImageWidth(\Right), 0)
        EndIf
        StopDrawing()
        
      EndIf
      
    EndWith
    
  EndProcedure
  
  
  Procedure StepScrollBarEx(*ScrollBarExdesc.ScrollBarExdesc, WheelType.b, Steps.w)
    Protected Max_State
    
    With *ScrollBarExdesc
      StartDrawing(CanvasOutput(\Gadget))
      Select WheelType
        Case #STEP_UP, #STEP_LEFT
          \State - Steps
          If \State < 0
            \State = 0
          EndIf
          
        Case #STEP_DOWN, #STEP_RIGHT
          Max_State = Round(((OutputHeight() - ImageHeight(\Down) - \KnobSize) - ImageHeight(\Up)) / ((GadgetHeight(\Gadget) - ImageHeight(\Up) - ImageHeight(\Down)) / (\Max - \Min)), #PB_Round_Nearest)
          \State + Steps
          If \State > Max_State
            \State = Max_State
          EndIf
      EndSelect
      StopDrawing()
      ReCalcKnob(*ScrollBarExdesc)
    EndWith
    
    DispatchEvents(*ScrollBarExdesc, #SBEx_Event_State)
  EndProcedure
  
  
  Procedure ScrollBarExThread(*ScrollBarExdesc.ScrollBarExdesc)
    
    With *ScrollBarExdesc
      While \Thread\_Continue
        If \Thread\Type = #_THREAD_ARROWS
          PostEvent(#PB_Event_Gadget, GetActiveWindow(), \Gadget, #SBEx_EventType_Arrow_Thread, \Thread\_Data)
        Else
          PostEvent(#PB_Event_Gadget, GetActiveWindow(), \Gadget, #SBEx_EventType_Background_Thread, \Thread\_Data)
        EndIf
        Delay(100)
      Wend
    EndWith
  EndProcedure
  
  
  Procedure ScrollBarExCallback()
    Protected *ScrollBarExdesc.ScrollBarExdesc
    Protected X, Y, GX, GY, update.b
    
    *ScrollBarExdesc = GetGadgetData(EventGadget())
    
    With *ScrollBarExdesc
      Select EventType()
        Case #SBEx_EventType_Background_Thread
          X = DesktopMouseX()
          Y = DesktopMouseY()
          GX = GadgetX(\Gadget, #PB_Gadget_ScreenCoordinate)
          GY = GadgetY(\Gadget, #PB_Gadget_ScreenCoordinate)
          
          Select EventData()
            Case #STEP_UP
              If IsInRegion(GX, GY + ImageHeight(\Up) + 1, ImageWidth(\Up), \KnobPos - ImageHeight(\Up), X, Y)
                StepScrollBarEx(*ScrollBarExdesc, #STEP_UP, \BackStep)
              EndIf
              
            Case #STEP_DOWN
              If IsInRegion(GX, GY + \KnobPos + \KnobSize + 1, ImageWidth(\Up), GadgetHeight(\Gadget) - ImageHeight(\Down) - \KnobPos - \KnobSize, X, Y)
                StepScrollBarEx(*ScrollBarExdesc, #STEP_DOWN, \BackStep)
              EndIf
              
            Case #STEP_LEFT
              If IsInRegion(GX + ImageWidth(\Left) + 1, GY, \KnobPos - ImageWidth(\Left), ImageHeight(\Left), X, Y)
                StepScrollBarEx(*ScrollBarExdesc, #STEP_LEFT, \BackStep)
              EndIf
              
            Case #STEP_RIGHT
              If IsInRegion(GX + \KnobPos + \KnobSize + 1, GY, GadgetWidth(\Gadget) - ImageWidth(\Right) - \KnobPos - \KnobSize, ImageHeight(\Left), X, Y)
                StepScrollBarEx(*ScrollBarExdesc, #STEP_RIGHT, \BackStep)
              EndIf
              
          EndSelect
          UpdateScrollBarEx(*ScrollBarExdesc, X - GX, Y - GY)
          
          
        Case #SBEx_EventType_Arrow_Thread
          X = DesktopMouseX()
          Y = DesktopMouseY()
          GX = GadgetX(\Gadget, #PB_Gadget_ScreenCoordinate)
          GY = GadgetY(\Gadget, #PB_Gadget_ScreenCoordinate)
          
          Select EventData()
            Case #STEP_UP
              If IsInRegion(GX, GY, ImageWidth(\Up), ImageHeight(\Up), X, Y)
                StepScrollBarEx(*ScrollBarExdesc, #STEP_UP, \ArrowStep)
              EndIf
              
            Case #STEP_DOWN
              If IsInRegion(GX, GY + GadgetHeight(\Gadget) - ImageHeight(\Down), ImageWidth(\Down), ImageHeight(\Down), X, Y)
                StepScrollBarEx(*ScrollBarExdesc, #STEP_DOWN, \ArrowStep)
              EndIf
              
            Case #STEP_LEFT
              If IsInRegion(GX, GY, ImageWidth(\Left), ImageHeight(\Left), X, Y)
                StepScrollBarEx(*ScrollBarExdesc, #STEP_LEFT, \ArrowStep)
              EndIf
              
            Case #STEP_RIGHT
              If IsInRegion(GX + GadgetWidth(\Gadget) - ImageWidth(\Right), GY, ImageWidth(\Right), ImageHeight(\Right), X, Y)
                StepScrollBarEx(*ScrollBarExdesc, #STEP_RIGHT, \ArrowStep)
              EndIf
              
          EndSelect
          UpdateScrollBarEx(*ScrollBarExdesc, X - GX, Y - GY)
          
        Case #PB_EventType_MouseEnter
          update = #True
          
          
        Case #PB_EventType_MouseLeave
          If Not \Drag
            UpdateScrollBarEx(*ScrollBarExdesc, -1)
          EndIf
          
          
        Case #PB_EventType_LeftButtonDown
          \LastX = GetGadgetAttribute(\Gadget, #PB_Canvas_MouseX)
          \LastY = GetGadgetAttribute(\Gadget, #PB_Canvas_MouseY)
          \LBtnDown = #True
          
          If \Type = #SBEx_Vertical
            If \LastY >= 0 And \LastY < ImageHeight(\Up) ; UP Button
              \Thread\_Data = #STEP_UP
              \Thread\Type = #_THREAD_ARROWS
            ElseIf \LastY > ImageHeight(\Up) And \LastY < \KnobPos ; Between UP Button and Knob Button
              \Thread\_Data = #STEP_UP
              \Thread\Type = #_THREAD_BACKGROUND
            ElseIf \LastY > \KnobPos + \KnobSize And \LastY < (GadgetHeight(\Gadget) - ImageHeight(\Down)) ; Between Knob Button and Down Button
              \Thread\_Data = #STEP_DOWN
              \Thread\Type = #_THREAD_BACKGROUND
            ElseIf \LastY > (GadgetHeight(\Gadget) - ImageHeight(\Down)) And \LastY <= GadgetHeight(\Gadget) ; Down Button
              \Thread\_Data = #STEP_DOWN
              \Thread\Type = #_THREAD_ARROWS
            ElseIf \LastY > \KnobPos And \LastY < \KnobPos + \KnobSize
              \Drag = #True
            EndIf
          Else
            If \LastX >= 0 And \LastX < ImageWidth(\Left) ; Left Button
              \Thread\_Data = #STEP_LEFT
              \Thread\Type = #_THREAD_ARROWS
            ElseIf \LastX > ImageWidth(\Left) And \LastX < \KnobPos ; Between Left Button and Knob Button
              \Thread\_Data = #STEP_LEFT
              \Thread\Type = #_THREAD_BACKGROUND
            ElseIf \LastX > \KnobPos + \KnobSize And \LastX < (GadgetWidth(\Gadget) - ImageWidth(\Right)) ; Between Knob Button and Right Button
              \Thread\_Data = #STEP_RIGHT
              \Thread\Type = #_THREAD_BACKGROUND
            ElseIf \LastX > (GadgetWidth(\Gadget) - ImageWidth(\Right)) And \LastX <= GadgetWidth(\Gadget) ; Right Button
              \Thread\_Data = #STEP_RIGHT
              \Thread\Type = #_THREAD_ARROWS
            ElseIf \LastX > \KnobPos And \LastX < \KnobPos + \KnobSize
              \Drag = #True
            EndIf
          EndIf
          
          If \Thread\Type
            \Thread\_Continue = #True
            \Thread\hThread = CreateThread(@ScrollBarExThread(), *ScrollBarExdesc)
          EndIf
          
          update = #True
          
          
        Case #PB_EventType_LeftButtonUp
          \Drag = #False
          \LBtnDown = #False
          If IsThread(\Thread\hThread)
            \Thread\_Continue = #False
            WaitThread(\Thread\hThread)
            \Thread\hThread = #Null
            \Thread\Type = #Null
          EndIf
          
          update = #True
          
          
        Case #PB_EventType_MouseMove
          If \Drag
            X = GetGadgetAttribute(\Gadget, #PB_Canvas_MouseX)
            Y = GetGadgetAttribute(\Gadget, #PB_Canvas_MouseY)
            If \Type = #SBEx_Vertical
              If IsInRegion(-100, ImageHeight(\Up), 100 * 2 + ImageWidth(\Knob), GadgetHeight(\Gadget) - ImageHeight(\Up) - ImageHeight(\Down), X, Y)
                If \KnobPos + Y - \LastY <= ImageHeight(\Up)
                  \KnobPos = ImageHeight(\Up)
                ElseIf \KnobPos + Y - \LastY + \KnobSize >= GadgetHeight(\Gadget) - ImageHeight(\Down)
                  \KnobPos = GadgetHeight(\Gadget) - ImageHeight(\Down) - \KnobSize
                Else
                  \KnobPos + Y - \LastY
                EndIf
                UpdateState(*ScrollBarExdesc)
              EndIf
            Else
              If IsInRegion(ImageWidth(\Left), -100, GadgetWidth(\Gadget) - ImageWidth(\Left) - ImageWidth(\Right), 100 * 2 + ImageWidth(\Knob), X, Y)
                If \KnobPos + X - \LastX <= ImageWidth(\Left)
                  \KnobPos = ImageWidth(\Left)
                ElseIf \KnobPos + X - \LastX + \KnobSize >= GadgetWidth(\Gadget) - ImageWidth(\Right)
                  \KnobPos = GadgetWidth(\Gadget) - ImageWidth(\Right) - \KnobSize
                Else
                  \KnobPos + X - \LastX
                EndIf
                UpdateState(*ScrollBarExdesc)
              EndIf
            EndIf
            
            \LastX = X
            \LastY = Y           
          EndIf
          
          update = #True
          
          
        Case #PB_EventType_MouseWheel
          If \Type = #SBEx_Vertical
            If GetGadgetAttribute(\Gadget, #PB_Canvas_WheelDelta) > 0
              StepScrollBarEx(*ScrollBarExdesc, #STEP_UP, \WheelStep)
              DispatchEvents(*ScrollBarExdesc, #SBEx_Event_WheelUp)
            Else
              StepScrollBarEx(*ScrollBarExdesc, #STEP_DOWN, \WheelStep)
              DispatchEvents(*ScrollBarExdesc, #SBEx_Event_WheelDown)
            EndIf
          Else
            If GetGadgetAttribute(\Gadget, #PB_Canvas_WheelDelta) > 0
              StepScrollBarEx(*ScrollBarExdesc, #STEP_LEFT, \WheelStep)
              DispatchEvents(*ScrollBarExdesc, #SBEx_Event_WheelLeft)
            Else
              StepScrollBarEx(*ScrollBarExdesc, #STEP_RIGHT, \WheelStep)
              DispatchEvents(*ScrollBarExdesc, #SBEx_Event_WheelRight)
            EndIf
          EndIf
          
          update = #True
          
      EndSelect
    EndWith
    
    If update
      UpdateScrollBarEx(*ScrollBarExdesc)
    EndIf
    
  EndProcedure
  
  
  ;- External Procedures
  Procedure SBEx_Create(Gadget, X, Y, Width, Height, Min, Max, PageLength, *Settings.SBEx_Settings, Flags = #SBEx_Horizontal)
    Protected Result
    Protected *ScrollBarExdesc.ScrollBarExdesc
    
    Result = CanvasGadget(Gadget, X, Y, Width, Height)
    
    If Result
      If Gadget = #PB_Any
        Gadget = Result
      EndIf
      
      *ScrollBarExdesc = AllocateMemory(SizeOf(ScrollBarExdesc))
      InitializeStructure(*ScrollBarExdesc, ScrollBarExdesc)
      SetGadgetData(Gadget, *ScrollBarExdesc)
      
      With *ScrollBarExdesc
        \Gadget = Gadget
        \BackColor = *Settings\BackColor
        \Up = *Settings\Up_Left_Image
        \Up_Over = *Settings\Up_Left_Over_Image
        \Up_Click = *Settings\Up_Left_Click_Image
        
        \Down = *Settings\Down_Right_Image
        \Down_Over = *Settings\Down_Right_Over_Image
        \Down_Click = *Settings\Down_Right_Click_Image
        
        \Knob = CopyImage(*Settings\Knob_Image, #PB_Any)
        \Knob_Over = CopyImage(*Settings\Knob_Over_Image, #PB_Any)
        \Knob_Click = CopyImage(*Settings\Knob_Click_Image, #PB_Any)
        
        \ArrowStep = 5
        \WheelStep = 10
        \BackStep = 60
        
        \Min = Min
        If Max < \Min
          \Max = \Min + 1
        Else
          \Max = Max
        EndIf
        
        If PageLength > \Max - \Min
          \PageLength = Max - Min
        Else
          \PageLength = PageLength
        EndIf
        
        If Flags = #SBEx_Vertical
          \Knob_Min_Size = ImageHeight(\Knob)
          \Type = #SBEx_Vertical
        Else
          \Knob_Min_Size = ImageWidth(\Knob)
          \Type = #SBEx_Horizontal
        EndIf
        
        ReCalcKnob(*ScrollBarExdesc, 0)
        
      EndWith     
      
      UpdateScrollBarEx(*ScrollBarExdesc, -1)
      BindGadgetEvent(Gadget, @ScrollBarExCallback())
    EndIf
    
    ProcedureReturn Result
  EndProcedure
  
  
  Procedure SBEx_Free(Gadget)
    Protected *ScrollBarExdesc.ScrollBarExdesc
    
    If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas
      *ScrollBarExdesc = GetGadgetData(Gadget)
      
      With *ScrollBarExdesc
        If IsThread(\Thread\hThread)
          \Thread\_Continue = #False
          WaitThread(\Thread\hThread)
        EndIf
        FreeImage(\Knob)
        FreeImage(\Knob_Over)
        FreeImage(\Knob_Click)
      EndWith
      
      FreeStructure(*ScrollBarExdesc)
      FreeGadget(Gadget)
    EndIf
  EndProcedure
  
  
  Procedure SBEx_Command(Gadget, Command, Param = #PB_Ignore, lParam = #PB_Ignore)
    Protected *ScrollBarExdesc.ScrollBarExdesc
    Protected KnobArea, Update.b
    
    If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas
      *ScrollBarExdesc = GetGadgetData(Gadget)
      
      With *ScrollBarExdesc
        Select Command
          Case #SBEx_Command_Data
            If Param = #PB_Ignore
              ProcedureReturn \_Data
            Else
              \_Data = Param
            EndIf
            
          Case #SBEx_Command_Wheel_Step
            If Param = #PB_Ignore
              ProcedureReturn \WheelStep
            Else
              \WheelStep = Param
            EndIf
            
          Case #SBEx_Command_Arrow_Step
            If Param = #PB_Ignore
              ProcedureReturn \ArrowStep
            Else
              \ArrowStep = Param
            EndIf
            
          Case #SBEx_Command_Background_Step
            If Param = #PB_Ignore
              ProcedureReturn \BackStep
            Else
              \BackStep = Param
            EndIf
            
          Case #SBEx_Command_Minimum
            If Param = #PB_Ignore
              ProcedureReturn \Min
            Else
              If \Min <> Param
                \Min = Param
                ReCalcKnob(*ScrollBarExdesc)
                Update = #True
              EndIf
            EndIf
            
          Case #SBEx_Command_Maximum
            If Param = #PB_Ignore
              ProcedureReturn \Max
            Else
              If \Max <> Param
                If Param < \Min
                  \Max = \Min + 1
                Else
                  \Max = Param
                EndIf
                ReCalcKnob(*ScrollBarExdesc)
                Update = #True
              EndIf
            EndIf
            
          Case #SBEx_Command_PageLength
            If Param = #PB_Ignore
              ProcedureReturn \PageLength
            Else  
              If \PageLength <> Param
                If Param > \Max - \Min
                  \PageLength = \Max - \Min
                Else
                  \PageLength = Param
                EndIf
                ReCalcKnob(*ScrollBarExdesc)
                Update = #True
              EndIf
            EndIf
            
          Case #SBEx_Command_LastEvent
            ProcedureReturn \LEvent
            
          Case #SBEx_Command_Wheel
            Select Param
              Case #SBEx_Wheel_Up, #SBEx_Wheel_Left
                StepScrollBarEx(*ScrollBarExdesc, #STEP_UP, \WheelStep)
            
              Case #SBEx_Wheel_Down, #SBEx_Wheel_Right
                StepScrollBarEx(*ScrollBarExdesc, #STEP_DOWN, \WheelStep)
            EndSelect
            Update = #True
            
          Case #SBEx_Command_State
            If Param = #PB_Ignore
              ProcedureReturn \State
            Else
              If \State <> Param
                If \Type = #SBEx_Vertical
                  KnobArea = GadgetHeight(Gadget) - ImageHeight(\Up) - ImageHeight(\Down)
                  \KnobPos = ImageHeight(\Up) + Round(Param * (KnobArea / (\Max - \Min)), #PB_Round_Nearest)
                  If \KnobPos + \KnobSize > GadgetHeight(Gadget) - ImageHeight(\Down)
                    \KnobPos = GadgetHeight(Gadget) - ImageHeight(\Down) - \KnobSize
                    UpdateState(*ScrollBarExdesc)
                  Else
                    \State = Param
                  EndIf
                Else
                  KnobArea = GadgetWidth(Gadget) - ImageWidth(\Left) - ImageWidth(\Right)
                  \KnobPos = ImageWidth(\Left) + Round(Param * (KnobArea / (\Max - \Min)), #PB_Round_Nearest)
                  If \KnobPos + \KnobSize > GadgetWidth(Gadget) - ImageWidth(\Right)
                    \KnobPos = GadgetWidth(Gadget) - ImageWidth(\Right) - \KnobSize
                    UpdateState(*ScrollBarExdesc)
                  Else
                    \State = Param
                  EndIf
                EndIf
                UpdateScrollBarEx(*ScrollBarExdesc, -1, -1)
                DispatchEvents(*ScrollBarExdesc, #SBEx_Event_State)
              EndIf
            EndIf
            
        EndSelect
        If Update
          UpdateScrollBarEx(*ScrollBarExdesc, -1, -1)
        EndIf
      EndWith
    EndIf
  EndProcedure
  
  
  Procedure SBEx_Resize(Gadget, X, Y, Width, Height)
    If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas
      ResizeGadget(Gadget, X, Y, Width, Height)
      ReCalcKnob(GetGadgetData(Gadget))
    EndIf
  EndProcedure
  
  
  Procedure SBEx_BindEvent(Gadget, *Callback, EventType = #PB_All)
    Protected *ScrollBarExdesc.ScrollBarExdesc, finded.b
    
    If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas And *Callback
      *ScrollBarExdesc = GetGadgetData(Gadget)
      With *ScrollBarExdesc
        If EventType = #PB_All
          If \Type = #SBEx_Vertical
            EventType = #SBEx_Event_State | #SBEx_Event_WheelUp | #SBEx_Event_WheelDown
          Else
            EventType = #SBEx_Event_State | #SBEx_Event_WheelLeft | #SBEx_Event_WheelRight
          EndIf
        EndIf
        
        ForEach \Callbacks()
          If \Callbacks()\Callback = *Callback
            \Callbacks()\CEvents | EventType
            finded = #True
            Break
          EndIf
        Next
        
        If Not finded
          AddElement(\Callbacks())
          \Callbacks()\Callback = *Callback
          \Callbacks()\CEvents = EventType
        EndIf
        
      EndWith
    EndIf
  EndProcedure
  
  
  Procedure SBEx_UnbindEvent(Gadget, *Callback, EventType = #PB_All)
    Protected *ScrollBarExdesc.ScrollBarExdesc, finded.b
    
    If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Canvas And *Callback
      *ScrollBarExdesc = GetGadgetData(Gadget)
      With *ScrollBarExdesc
        If EventType = #PB_All
          If \Type = #SBEx_Vertical
            EventType = #SBEx_Event_State | #SBEx_Event_WheelUp | #SBEx_Event_WheelDown
          Else
            EventType = #SBEx_Event_State | #SBEx_Event_WheelLeft | #SBEx_Event_WheelRight
          EndIf
        EndIf
        
        ForEach \Callbacks()
          If \Callbacks()\Callback = *Callback
            \Callbacks()\CEvents ! EventType
            finded = #True
            Break
          EndIf
        Next
        
        If finded And \Callbacks()\CEvents = #Null
          DeleteElement(\Callbacks())
        EndIf
      EndWith
    EndIf
  EndProcedure
EndModule
;- END OF MODULE



;- START OF EXAMPLE
CompilerIf #PB_Compiler_IsMainFile
  UsePNGImageDecoder()
  UseModule ScrollBarEx
  
  CompilerIf Not Defined(White, #PB_Constant)
    #White = $FFFFFF
  CompilerEndIf
  
  Enumeration
    #HSCROLL
    #VSCROLL
    #ImageGadget
  EndEnumeration
  
  
  Enumeration
    #UP_IMAGE
    #UP_OVER_IMAGE
    #UP_CLICK_IMAGE
    #DOWN_IMAGE
    #DOWN_OVER_IMAGE
    #DOWN_CLICK_IMAGE
    #LEFT_IMAGE
    #LEFT_OVER_IMAGE
    #LEFT_CLICK_IMAGE
    #RIGHT_IMAGE
    #RIGHT_OVER_IMAGE
    #RIGHT_CLICK_IMAGE
    #KNOB_IMAGE
    #KNOB_OVER_IMAGE
    #KNOB_CLICK_IMAGE
    #Image
  EndEnumeration
  
  
  Procedure VerticalEvents(Gadget)
    Select SBEx_Command(Gadget, #SBEx_Command_LastEvent)
      Case #SBEx_Event_WheelUp
        Debug "Vertical Wheel Up"
        
      Case #SBEx_Event_WheelDown
        Debug "Vertical Wheel Down"
        
      Case #SBEx_Event_State
        Debug "Vertical State Changed : " + Str(SBEx_Command(Gadget, #SBEx_Command_State))
        
        StartDrawing(CanvasOutput(#ImageGadget))
        Box(0, 0, GadgetWidth(#ImageGadget), GadgetHeight(#ImageGadget), #White)
        DrawImage(ImageID(#Image), (-1)*SBEx_Command(#HSCROLL, #SBEx_Command_State), (-1)*SBEx_Command(#VSCROLL, #SBEx_Command_State))
        StopDrawing()
        
    EndSelect
  EndProcedure
  
  
  Procedure HorizontalEvents(Gadget)
    Select SBEx_Command(Gadget, #SBEx_Command_LastEvent)
      Case #SBEx_Event_WheelLeft
        Debug "Horizontal Wheel Left"
        
      Case #SBEx_Event_WheelRight
        Debug "Horizontal Wheel Right"
        
      Case #SBEx_Event_State
        Debug "Horizontal State Changed : " + Str(SBEx_Command(Gadget, #SBEx_Command_State))
        
        StartDrawing(CanvasOutput(#ImageGadget))
        Box(0, 0, GadgetWidth(#ImageGadget), GadgetHeight(#ImageGadget), #White)
        DrawImage(ImageID(#Image), (-1)*SBEx_Command(#HSCROLL, #SBEx_Command_State), (-1)*SBEx_Command(#VSCROLL, #SBEx_Command_State))
        StopDrawing()
        
    EndSelect
  EndProcedure
  
  Procedure CanvasCallback()
    If EventType() = #PB_EventType_MouseWheel
      If GetGadgetAttribute(EventGadget(), #PB_Canvas_WheelDelta) > 0
        SBEx_Command(#VSCROLL, #SBEx_Command_Wheel, #SBEx_Wheel_Up)
      Else
        SBEx_Command(#VSCROLL, #SBEx_Command_Wheel, #SBEx_Wheel_Down)
      EndIf
    EndIf
  EndProcedure
  
  Procedure WindowSizeHandler()
    SBEx_Resize(#VSCROLL, WindowWidth(0) - GadgetWidth(#VSCROLL), #PB_Ignore, #PB_Ignore, WindowHeight(0) - GadgetHeight(#HSCROLL))
    SBEx_Resize(#HSCROLL, #PB_Ignore, WindowHeight(0) - GadgetHeight(#HSCROLL), WindowWidth(0) - GadgetWidth(#VSCROLL), #PB_Ignore)
    ResizeGadget(#ImageGadget, #PB_Ignore, #PB_Ignore, WindowWidth(0) - GadgetWidth(#VSCROLL), WindowHeight(0) - GadgetHeight(#HSCROLL))
    SBEx_Command(#VSCROLL, #SBEx_Command_PageLength, GadgetHeight(#ImageGadget))
    SBEx_Command(#HSCROLL, #SBEx_Command_PageLength, GadgetWidth(#ImageGadget))
    StartDrawing(CanvasOutput(#ImageGadget))
      Box(0, 0, OutputWidth(), OutputHeight(), #White)
      DrawImage(ImageID(#Image), (-1)*SBEx_Command(#HSCROLL, #SBEx_Command_State), (-1)*SBEx_Command(#VSCROLL, #SBEx_Command_State))
    StopDrawing()
  EndProcedure
  
  
  File$ = OpenFileRequester("open a PNG File", "", "PNG File (*.png)|*.png", 0)
  If File$
    If OpenWindow(0, 0, 0, 300, 200, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
      
      ;LoadImage(#Image, #PB_Compiler_Home + "/examples/3D/Data/Water/Foam.png")
      LoadImage(#Image, File$)
      
      WindowBounds(0, 100, 100, ImageWidth(#Image) + 17, ImageHeight(#Image) + 17)
      
      CanvasGadget(#ImageGadget, 0, 0, WindowWidth(0) - 17, WindowHeight(0) - 17)
      StartDrawing(CanvasOutput(#ImageGadget))
      DrawImage(ImageID(#Image), 0, 0)
      StopDrawing()
      
      BindGadgetEvent(#ImageGadget, @CanvasCallback())
      
      CatchImage(#UP_IMAGE, ?Up)
      CatchImage(#UP_OVER_IMAGE, ?Up_Over)
      CatchImage(#UP_CLICK_IMAGE, ?Up_Click)
      CatchImage(#DOWN_IMAGE, ?Down)
      CatchImage(#DOWN_OVER_IMAGE, ?Down_Over)
      CatchImage(#DOWN_CLICK_IMAGE, ?Down_Click)
      CatchImage(#LEFT_IMAGE, ?Left)
      CatchImage(#LEFT_OVER_IMAGE, ?Left_Over)
      CatchImage(#LEFT_CLICK_IMAGE, ?Left_Click)
      CatchImage(#RIGHT_IMAGE, ?Right)
      CatchImage(#RIGHT_OVER_IMAGE, ?Right_Over)
      CatchImage(#RIGHT_CLICK_IMAGE, ?Right_Click)
      CatchImage(#KNOB_IMAGE, ?Knob)
      CatchImage(#KNOB_OVER_IMAGE, ?Knob_Over)
      CatchImage(#KNOB_CLICK_IMAGE, ?Knob_Click)
      
      Settings.SBEx_Settings
      With Settings
        \Up_Left_Image = #UP_IMAGE
        \Up_Left_Over_Image = #UP_OVER_IMAGE
        \Up_Left_Click_Image = #UP_CLICK_IMAGE
        \Down_Right_Image = #DOWN_IMAGE
        \Down_Right_Over_Image = #DOWN_OVER_IMAGE
        \Down_Right_Click_Image = #DOWN_CLICK_IMAGE
        \Knob_Image = #KNOB_IMAGE
        \Knob_Over_Image = #KNOB_OVER_IMAGE
        \Knob_Click_Image = #KNOB_CLICK_IMAGE
        \BackColor = RGB(240, 240, 240)
        SBEx_Create(#VSCROLL, WindowWidth(0) - 17, 0, 17, WindowHeight(0) - 17, 0, ImageHeight(#Image), GadgetHeight(#ImageGadget), Settings, #SBEx_Vertical)
        
        
        \Up_Left_Image = #LEFT_IMAGE
        \Up_Left_Over_Image = #LEFT_OVER_IMAGE
        \Up_Left_Click_Image = #LEFT_CLICK_IMAGE
        \Down_Right_Image = #RIGHT_IMAGE
        \Down_Right_Over_Image = #RIGHT_OVER_IMAGE
        \Down_Right_Click_Image = #RIGHT_CLICK_IMAGE
        \Knob_Image = #KNOB_IMAGE
        \Knob_Over_Image = #KNOB_OVER_IMAGE
        \Knob_Click_Image = #KNOB_CLICK_IMAGE
        \BackColor = RGB(240, 240, 240)
        SBEx_Create(#HSCROLL, 0, WindowHeight(0) - 17, WindowWidth(0) - 17, 17, 0, ImageWidth(#Image), GadgetWidth(#ImageGadget), Settings, #SBEx_Horizontal)
      EndWith
      
      SBEx_BindEvent(#VSCROLL, @VerticalEvents())
      SBEx_BindEvent(#HSCROLL, @HorizontalEvents())
      BindEvent(#PB_Event_SizeWindow, @WindowSizeHandler())
      
      Repeat
        Event = WaitWindowEvent()
      Until Event = #PB_Event_CloseWindow
    EndIf
  EndIf
  
  DataSection
    Up:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1100000011000000,$476D3B0000000608,$59487009000000FA,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$2E9FC8043216020A,$58457407000000A2,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $00000027D2EEA800,$638D385441444948,$010A067FC3E1F0FC,$21A6421A8C06A513,$8033021994050505,$CF88D7410D384190,$6130986B2086AC20
    Data.q $0066077AF0834102,$9F11AE82192441B2,$0086368779A38C41,$A9F5185F19F1F400,$4E45490000000018
    Data.b $44,$AE,$42,$60,$82
    
    Up_Over:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1100000011000000,$476D3B0000000608,$59487009000000FA,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$CA9CF4203216020A,$5845740700000073,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $00000027D2EEA800,$638D385441444948,$010A067FD6EB75BC,$21A6421A8C06A513,$80330219946A6A6A,$CF88D7410D384190,$EB75B86B2086AC20
    Data.q $0066077AF0834116,$9F11AE82192441B2,$0086368779A38C41,$FC2A901F17336A00,$4E4549000000009C
    Data.b $44,$AE,$42,$60,$82
    
    Up_Click:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1100000011000000,$476D3B0000000608,$59487009000000FA,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$C7DDF02C0709030A,$58457407000000C6,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $00000027D2EEA800,$638D385441444947,$602140CFF848484C,$6434C8435180D4A2,$8033021994F9FCFE,$CF88D7410D384190,$4C4C486B2086AC20
    Data.q $400CC0EF5E106824,$33E235D043248836,$0010C6D0EF347188,$683F387F1917716E,$444E454900000000
    Data.b $AE,$42,$60,$82
    
    Down:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1100000011000000,$476D3B0000000608,$59487009000000FA,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$D80F5B333116020A,$584574070000006E,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $00000027D2EEA800,$ED8D385441444954,$C0040820000A41D2,$EA0FEA9F14FB17B5,$51E43A87482ED11A,$6AC38ECCCB4141DC,$876FBB880A47C0A7
    Data.q $91201806B26E9F59,$BB6CF6300000A839,$900C035936D44460,$D4A9CE2000541CC8,$1D0B26190576CFE3,$000000B208383D2D,$6042AE444E454900
    Data.b $82
    
    Down_Over:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1100000011000000,$476D3B0000000608,$59487009000000FA,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$4299AB193216020A,$584574070000007B,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $00000027D2EEA800,$ED8D38544144494F,$40030820000DC1CE,$97E8CBA79FF61875,$7A1B3C8CFE315A10,$E05B8DE5DB300769,$A72CCFA599880723
    Data.q $0545F1120181624B,$25A5E7C0BA400450,$B602A2F88900C0B1,$590C7B9521280548,$9E2ABAB6AF18DF4D,$444E454900000000
    Data.b $AE,$42,$60,$82
    
    Down_Click:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1100000011000000,$476D3B0000000608,$59487009000000FA,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$E7B3CB0C0709030A,$584574070000000E,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $00000027D2EEA800,$ED8D385441444953,$C0040820000A41D2,$235D6A7CCBEA97B5,$3B8A3C8750E905DA,$14ED5871DEEE6828,$EB30EDCCC90148F8
    Data.q $0732240300D64DD3,$8C176D9EC6000015,$991201806B26DA88,$FC7A9539C4000A83,$3719367C0320AED9,$00000000F154F3D6,$826042AE444E4549
    
    Left:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1100000011000000,$476D3B0000000608,$59487009000000FA,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$B0B80D232117020A,$584574070000006C,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $00000027D2EEA800,$638D385441444948,$010A067FC3E1F0FC,$085843430C06A513,$4C27B38028282829,$AF0031884BBA4098,$0C5210D3801AC421
    Data.q $49036446B20869C0,$B12C06F083548432,$0218DA1DE68E3106,$054AC4C11CBC1400,$4E45490000000031
    Data.b $44,$AE,$42,$60,$82
    
    Left_Over:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1100000011000000,$476D3B0000000608,$59487009000000FA,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$FCD0551E2117020A,$584574070000007D,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $00000027D2EEA800,$638D38544144494C,$010A067FD6EB75BC,$085843430C06A513,$DD6FB38353535029,$AF0031884BBA45BA,$0C5210D3801AC421
    Data.q $49036446B20869C0,$B12C06F083548432,$5484C3B2628C1106,$1B64E200010CCC30,$000000E8531A9A41,$6042AE444E454900
    Data.b $82
    
    Left_Click:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1100000011000000,$476D3B0000000608,$59487009000000FA,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$2E600D01240C030A,$5845740700000039,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $00000027D2EEA800,$638D385441444947,$602140CFF848484C,$210B08686180D4A2,$1313B387CFE7F305,$35E0063109774913,$018A421A70035884
    Data.q $49206C88D6410D38,$D62580DE106A9086,$00431B43BCD1C620,$7DE797886119E21F,$444E454900000000
    Data.b $AE,$42,$60,$82
    
    Right:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1100000011000000,$476D3B0000000608,$59487009000000FA,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$440C2C172117020A,$58457407000000D9,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $00000027D2EEA800,$638D385441444948,$010A067FC3E1F0FC,$705843430C06A513,$2613D9C014141449,$0D911AC825CF204C,$2618220C5210C924
    Data.q $06C26210D04418C4,$48434E2E06C421AF,$431B43BCD1C61D89,$616AFFC11CADE400,$4E45490000000079
    Data.b $44,$AE,$42,$60,$82
    
    Right_Over:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1100000011000000,$476D3B0000000608,$59487009000000FA,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$D168B2102117020A,$584574070000007A,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $00000027D2EEA800,$638D38544144494E,$010A067FD6EB75BC,$705843430C06A513,$6EB7D9C1A9A9A849,$0D911AC825CF22DD,$2618220C5210C924
    Data.q $06C26210D04418C4,$48434E2E06C421AF,$5123484C519C1D89,$C60043330C05212E,$00185CAAD4411BD4,$AE444E4549000000
    Data.b $42,$60,$82
    
    Right_Click:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1100000011000000,$476D3B0000000608,$59487009000000FA,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$42666E1C240C030A,$58457407000000E0,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $00000027D2EEA800,$638D385441444948,$602140CFF848484C,$2E0B08686180D4A2,$8989D9C3E7F3F989,$81B2235904B9E489,$84C304418A421924
    Data.q $E0D84C421A088318,$290869C5C0D88435,$086368779A38C3B1,$1191BE6119D3EF00,$4E45490000000029
    Data.b $44,$AE,$42,$60,$82
    
    Knob:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1100000011000000,$476D3B0000000608,$59487009000000FA,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$2B3293082317020A,$58457407000000AE,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $00000027D2EEA800,$638D38544144491E,$010A067FC0E0703C,$C86A321A8C06A513,$2A00014086A321A8,$00298E74FA61038A,$AE444E4549000000
    Data.b $42,$60,$82
    
    Knob_Over:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1100000011000000,$476D3B0000000608,$59487009000000FA,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$7BF9353B2217020A,$58457407000000F9,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $00000027D2EEA800,$638D38544144491E,$010A067FD96CB65C,$C86A321A8C06A513,$C500014086A321A8,$007E99691D1303A2,$AE444E4549000000
    Data.b $42,$60,$82
    
    Knob_Click:
    Data.q $0A1A0A0D474E5089,$524448490D000000,$1100000011000000,$476D3B0000000608,$59487009000000FA,$0E0000C40E000073,$00001B0E2B9501C4
    Data.q $E007454D49740700,$7EF8CF1B0809030A,$5845740700000006,$00726F6874754174,$0C00000048CCAEA9,$6373654474584574,$006E6F6974706972
    Data.q $0A00000023210913,$79706F4374584574,$0FAC007468676972,$45740E0000003ACC,$6974616572437458,$00656D6974206E6F,$09000000090FF735
    Data.q $74666F5374584574,$FF705D0065726177,$5845740B0000003A,$69616C6373694474,$8FB4C0B70072656D,$7458457408000000,$00676E696E726157
    Data.q $0700000087E61BC0,$72756F5374584574,$00EB83FFF5006563,$4374584574080000,$F600746E656D6D6F,$7406000000BF96CC,$656C746954745845
    Data.q $00000027D2EEA800,$638D38544144491E,$602140CFF848484C,$190D46435180D4A2,$0400002810D46435,$00473A9F964102DF,$AE444E4549000000
    Data.b $42,$60,$82
    
    
  EndDataSection
CompilerEndIf
;- END OF EXAMPLE

Re: ScrollBarEx : Custom ScrollBar Gadget [CrossPlatform]

Posted: Tue Oct 18, 2016 9:51 pm
by Peyman
new update with some bug fixes and images now embed in example.

Code: Select all

; 1.10  Fixed Drawing ScrollBar
;       Added CompilerError for threadsafe option
;       Fixed a problem in BindScrollBarExEvent
;       Images embeded in Example
;       Changed CanvasCallback to ScrollBarExCallback
;       Changed UpdateCallback to UpdateScrollBarEx

Re: ScrollBarEx : Custom ScrollBar Gadget [CrossPlatform]

Posted: Wed Oct 19, 2016 8:01 am
by Kukulkan
Nice scrollbars, thanks.

Scrolling itself seem to work using the bars, but using the arrow buttons it crashes immediately. I'm on Ubuntu 16.04 using PB 5.43 LTS (x64, threadsave, unicode).

Re: ScrollBarEx : Custom ScrollBar Gadget [CrossPlatform]

Posted: Wed Oct 19, 2016 12:52 pm
by Peyman
Kukulkan wrote:Nice scrollbars, thanks.

Scrolling itself seem to work using the bars, but using the arrow buttons it crashes immediately. I'm on Ubuntu 16.04 using PB 5.43 LTS (x64, threadsave, unicode).
your welcome

its crash without any error ?!
please change ScrollBarExCallback with below code and test its works or not ?

EDIT :
code on first topic updated to work on linux

Re: ScrollBarEx : Custom ScrollBar Gadget [CrossPlatform]

Posted: Wed Oct 19, 2016 1:20 pm
by Kukulkan
Ok, for the crash there is a small window coming up saying "The debugged executable quit unexpectedly." :-)

Yes, it works fine with the new callback function. Great!

BTW, I have to define the constant for #White all the time:

Code: Select all

#White = $ffffff
These color constants are IMHO a Windows only thing...

Re: ScrollBarEx : Custom ScrollBar Gadget [CrossPlatform]

Posted: Wed Oct 19, 2016 2:00 pm
by Peyman
so its have a problem with my thread, i try to install ubuntu on virtual box to solve problem with thread.

really i didn't know the color constants are just defined in windows :shock:, thx for say this for my other sources.

Re: ScrollBarEx : Custom ScrollBar Gadget [CrossPlatform]

Posted: Wed Oct 19, 2016 8:49 pm
by davido
@Peyman,

Very nice. Thank you for sharing. :D

Works on my MacBook Pro, but only when the references to #white were changed to $ffffff.

Re: ScrollBarEx : Custom ScrollBar Gadget [CrossPlatform]

Posted: Wed Oct 19, 2016 9:04 pm
by Peyman
@davido
your welcome, so you run code from the first topic without crash or it crashs on your mac too as Kukulkan said for linux ?

Re: ScrollBarEx : Custom ScrollBar Gadget [CrossPlatform]

Posted: Thu Oct 20, 2016 6:59 am
by infratec
The problem on Linux is:
You can not (safe) access GUI elements from a thread.
You have to use PostEvent() and do the drawing in the main event loop
or you can trigger an event which is used by a BindEvent()
Then you don't need to modify the main program.

I sent you a pm.

Bernd

Re: ScrollBarEx : Custom ScrollBar Gadget [CrossPlatform]

Posted: Fri Oct 21, 2016 1:44 pm
by Peyman
with thx to the infratec for code & netmaestro for tips new version works well on linux too.

Code: Select all

;{ Release info...
; 1.00 First release version
;
; 1.10  Fixed Drawing ScrollBar
;       Added CompilerError for threadsafe option
;       Fixed a problem in BindScrollBarExEvent
;       Images embeded in Example
;       Changed CanvasCallback to ScrollBarExCallback
;       Changed UpdateCallback to UpdateScrollBarEx
;
; 1.20  Fixed problem in linux with image drawings
;       Fixed thread problem with linux (thx to infratec)
;}

Re: ScrollBarEx : Custom ScrollBar Gadget [CrossPlatform]

Posted: Fri Nov 04, 2016 3:56 am
by Peyman
new version 1.30 with very changes released, check first post

Code: Select all

; 1.30  Fixed a bug in move knob and show over button for arrows
;       Fixed a bug in state event
;       Added Command procedure
;       Added UnbindEvent procedure
;       Changed all procedures to SBEx_*
;       Changed all ScrollBarEx_ constants to SBEx_*
;       Changed Callback system now each gadget can have many callbacks
;       Removed SBEx_SetAttribute and SBEx_GetAttribute (all attributes now is in command)
;       Removed SBEx_SetData and SBEx_GetData (integrated in command)
;       Removed SetScrollBarExState and SetScrollBarExState (integrated in command)
;       Removed SBEx_Event (integrated in command)
;       Removed SBEx_Wheel (integrated in command)

Re: ScrollBarEx : Custom ScrollBar Gadget [CrossPlatform]

Posted: Fri Nov 04, 2016 7:48 am
by infratec
An idea...

I know this from many programs:
If you press and hold the middle button inside of the area, you can move the area.

Bernd

Re: ScrollBarEx : Custom ScrollBar Gadget [CrossPlatform]

Posted: Fri Nov 04, 2016 10:05 pm
by Peyman
infratec wrote:An idea...

I know this from many programs:
If you press and hold the middle button inside of the area, you can move the area.

Bernd
so its just like move the knob with the left click or something else you say ?

Re: ScrollBarEx : Custom ScrollBar Gadget [CrossPlatform]

Posted: Sat Nov 05, 2016 11:30 pm
by Demivec
Great work. Thanks for this code.

A small request:

When the left mouse button is clicked and held over one of the scrollbar arrows the scrollbar moves repeatedly by single increments.
When the left mouse button is clicked and held over the open scrollbar (where the 'bar' isn't) it moves only one page and stops.

Can the behavior of repeating the scrolling action be included for the open part of the scrollbar?

Re: ScrollBarEx : Custom ScrollBar Gadget [CrossPlatform]

Posted: Sun Nov 06, 2016 12:32 pm
by Michael Vogel
When loading a large image in your example, the scroll bar indicator will be smaller than one pixel, which should be avoided. If not, resizing the windows may lead to an error in the following line of the UpdateScrollBarEx procedure:

Code: Select all

	:
	If IsInRegion(0, \KnobPos + 1, ImageWidth(\Knob), \KnobSize - 1, X, Y) Or \Drag
					If \LBtnDown
						DrawImage(ImageID(\Knob_Click), 0, \KnobPos)
					Else
						DrawImage(ImageID(\Knob_Over), 0, \KnobPos)
					EndIf
				Else
					DrawImage(ImageID(\Knob), 0, \KnobPos)  <---- The specified ImageID is null
				EndIf
	:
A quick and (absolute) dirty workaround is to change all lines containing "\KnobSize = " to "\KnobSize = 1+"...