SplitBarGadget - canvas-based splitter (win / linux)

Share your advanced PureBasic knowledge/code with the community.
Julian
Enthusiast
Enthusiast
Posts: 276
Joined: Tue May 24, 2011 1:36 pm

Re: SplitBarGadget - canvas-based splitter

Post by Julian »

eddy wrote:
Julian wrote:Resizing the window seems to cause everything to vanish.
Try to replace this line:

Code: Select all

Protected SmoothMode=Bool(CustomContext\DraggedGadget<>0)
with this line:

Code: Select all

Protected SmoothMode=#False
Same result as above, grey window after resizing
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Re: SplitBarGadget - canvas-based splitter

Post by eddy »

Which OS and Pb version are you using ?

Below the code win=EventWindow(), add these following lines:

Code: Select all

If e=#PB_Event_SizeWindow
            Debug "------ splitter sizes ------------"
            Debug "#Split3 size: " + GadgetX(#Split3) + " " + GadgetY(#Split3) + " " + GadgetWidth(#Split3) + " " + GadgetHeight(#Split3) + " "
            Debug "#Split2 size: " + GadgetX(#Split2) + " " + GadgetY(#Split2) + " " + GadgetWidth(#Split2) + " " + GadgetHeight(#Split2) + " "
            Debug "#Split1 size: " + GadgetX(#Split1) + " " + GadgetY(#Split1) + " " + GadgetWidth(#Split1) + " " + GadgetHeight(#Split1) + " "
EndIf 
Resize your window and send me your splitter sizes.
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
Julian
Enthusiast
Enthusiast
Posts: 276
Joined: Tue May 24, 2011 1:36 pm

Re: SplitBarGadget - canvas-based splitter

Post by Julian »

PB 5.31 x64 on Windows 8.1

Split3 doesnt exist

Could you post another set of test code rather than asking me to change things at certain points?
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Re: SplitBarGadget - canvas-based splitter

Post by eddy »

Here is a modified version of the test code using #PB_Event_SizeWindow explicit event

Code: Select all

CompilerIf #PB_Compiler_IsMainFile
   ;********************
   ; EXAMPLE (modified)
   ;********************
   UseModule SplitBarGadget
   Runtime Enumeration
      #xml : #dialog : #win
      #Split0 : #Split1 : #Split2 : #Split3
      #Left : #Right : #Top : #Bottom : #Center
      
      #ColorContent=$484848
      #ColorBright=$777777
      #ColorDark=$232323
      #ColorGrip=$FFFFFF
   EndEnumeration
   
   Procedure SetGadgetColors(Gadget, BackColor=0, FrontColor=0, LineColor=0, TitleBackColor=0, TitleFrontColor=0)
      SetGadgetColor(Gadget, #PB_Gadget_FrontColor, FrontColor)
      SetGadgetColor(Gadget, #PB_Gadget_BackColor, BackColor)
      SetGadgetColor(Gadget, #PB_Gadget_LineColor, LineColor)
      SetGadgetColor(Gadget, #PB_Gadget_TitleBackColor, TitleBackColor)
      SetGadgetColor(Gadget, #PB_Gadget_TitleFrontColor, TitleFrontColor)
   EndProcedure
   Procedure ResizeSplitters()
      ResizeGadget(#Split3, 0, 0, WindowWidth(#win), WindowHeight(#win))
   EndProcedure
   
   Define xml$="<window id='#win' name='splitter' text='SplitBar Gadgets' width='600' height='300' " + 
               "  flags='#PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget'>" + 
               "" + ;"  <canvas id='#Split3' />" +
               "</window>"
   If CatchXML(#xml, @xml$, StringByteLength(xml$), 0, #PB_Ascii) And XMLStatus(#xml)=#PB_XML_Success And CreateDialog(#dialog) And OpenXMLDialog(#dialog, #xml, "splitter")
      SetWindowColor(#win, #ColorContent)
      ButtonGadget(#Top, 0, 0, 200, 32, "#Top")
      ButtonGadget(#Left, 0, 0, 200, 32, "#Left")
      ButtonGadget(#Right, 0, 0, 200, 32, "#Right")
      ButtonGadget(#Center, 0, 0, 200, 32, "#Center")
      ButtonGadget(#Bottom, 0, 0, 200, 32, "#Bottom")
      SplitBarGadget(#Split0, 0, 0, 0, 0, #Center, #Bottom)
      SplitBarGadget(#Split1, 0, 0, 0, 0, #Left, #Split0, #SplitBar_Vertical | #SplitBar_FixedSize | #SplitBar_Grip)
      SplitBarGadget(#Split2, 0, 0, 0, 0, #Split1, #Right, #SplitBar_Vertical | #SplitBar_FixedSize | #SplitBar_Grip)
      SplitBarGadget(#Split3, 0, 0, 0, 0, #Top, #Split2, #SplitBar_FixedSize | #SplitBar_Locked, 2)
      BindEvent(#PB_Event_SizeWindow, @ResizeSplitters())
      ResizeWindow(#win, #PB_Ignore, #PB_Ignore, #PB_Ignore, 400)
      SetGadgetState(#Split3, 30)
      SetGadgetState(#Split2, -80)
      SetGadgetState(#Split1, 80)
      SetGadgetState(#Split0, -100)
      SetGadgetAttribute(#Split0, #SplitBar_CurrentFirstMinSize, 30)
      SetGadgetAttribute(#Split0, #SplitBar_CurrentSecondMinSize, 50)
      SetGadgetAttribute(#Split1, #SplitBar_CurrentSnapDistance, 80)
      SetGadgetAttribute(#Split2, #SplitBar_CurrentSnapDistance, 80)
      SetGadgetColors(#Split0, #ColorContent, #ColorBright, #ColorGrip)
      SetGadgetColors(#Split1, #ColorContent, #ColorBright, #ColorGrip)
      SetGadgetColors(#Split2, #ColorContent, #ColorBright, #ColorGrip)
      SetGadgetColors(#Split3, #ColorContent, #ColorBright, #ColorGrip)
      Repeat
         e=WaitWindowEvent()
         g=EventGadget()
         t=EventType()
         d=EventData()
         win=EventWindow()
         If t=#PB_EventType_LeftDoubleClick And g=#Split0
            SetGadgetState(g, -100)
            Debug "SplitBar=" + g + " is resetted"
         EndIf
         If t=#PB_EventType_Change
            Debug "SplitBar=" + g + " CurrentStatus=" + d + " State=" + GetGadgetState(g)
         EndIf
      Until e=#PB_Event_CloseWindow
   EndIf
CompilerEndIf
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
User avatar
mk-soft
Always Here
Always Here
Posts: 5335
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: SplitBarGadget - canvas-based splitter

Post by mk-soft »

Very Nice :D

Works fine on Linux. SDK for Mac come on next version of PB :wink:

Code: Select all

DeclareModule SplitBarGadget
  Enumeration
    ;custom Flags
    #SplitBar_Default=0
    #SplitBar_Vertical=1
    #SplitBar_Grip=2
    #SplitBar_Locked=4
    #SplitBar_FixedSize=8
    
    ;custom Statuses
    #SplitBar_IsHighlighted=1
    #SplitBar_IsDragged=2
    #SplitBar_IsSnapped=4
    
    ;custom Attributes
    #SplitBar_CurrentFlags=2000
    #SplitBar_CurrentStatus
    #SplitBar_CurrentThickness
    #SplitBar_CurrentSnapDistance
    #SplitBar_CurrentFirstGadget
    #SplitBar_CurrentSecondGadget
    #SplitBar_CurrentFirstMinSize
    #SplitBar_CurrentSecondMinSize
    #SplitBar_CurrentDrawingFunction
  EndEnumeration
  Declare.i SplitBarGadget(Gadget, x, y, Width, Height, Gadget1=0, Gadget2=0, Flags=#SplitBar_Default, Thickness=6)
EndDeclareModule

Module SplitBarGadget
  EnableExplicit
  CompilerIf #PB_Compiler_OS=#PB_OS_Windows
    ;- PB SDK for Windows
    Structure Gadget
      Gadget.i
      *vt.GadgetVT
      UserData.i
      OldCallback.i
      Daten.i[4]
    EndStructure
    Structure GadgetVT
      GadgetType.l
      SizeOf.l
      *GadgetCallback
      *FreeGadget
      *GetGadgetState
      *SetGadgetState
      *GetGadgetText
      *SetGadgetText
      *AddGadgetItem2
      *AddGadgetItem3
      *RemoveGadgetItem
      *ClearGadgetItemList
      *ResizeGadget
      *CountGadgetItems
      *GetGadgetItemState
      *SetGadgetItemState
      *GetGadgetItemText
      *SetGadgetItemText
      *OpenGadgetList2
      *GadgetX
      *GadgetY
      *GadgetWidth
      *GadgetHeight
      *HideGadget
      *AddGadgetColumn
      *RemoveGadgetColumn
      *GetGadgetAttribute
      *SetGadgetAttribute
      *GetGadgetItemAttribute2
      *SetGadgetItemAttribute2
      *SetGadgetColor
      *GetGadgetColor
      *SetGadgetItemColor2
      *GetGadgetItemColor2
      *SetGadgetItemData
      *GetGadgetItemData
      *GetRequiredSize
      *SetActiveGadget
      *GetGadgetFont
      *SetGadgetFont
      *SetGadgetItemImage
    EndStructure
  CompilerElseIf #PB_Compiler_OS=#PB_OS_Linux
    ;- PB SDK for Linux
    Structure Gadget
      Gadget.i
      GadgetContainer.i
      *vt.GadgetVT
      UserData.i
      Daten.i[4]
    EndStructure
    Structure GadgetVT
      SizeOf.l
      GadgetType.l
      *ActivateGadget
      *FreeGadget
      *GetGadgetState
      *SetGadgetState
      *GetGadgetText
      *SetGadgetText
      *AddGadgetItem2
      *AddGadgetItem3
      *RemoveGadgetItem
      *ClearGadgetItemList
      *ResizeGadget
      *CountGadgetItems
      *GetGadgetItemState
      *SetGadgetItemState
      *GetGadgetItemText
      *SetGadgetItemText
      *SetGadgetFont
      *OpenGadgetList2
      *AddGadgetColumn
      *GetGadgetAttribute
      *SetGadgetAttribute
      *GetGadgetItemAttribute2
      *SetGadgetItemAttribute2
      *RemoveGadgetColumn
      *SetGadgetColor
      *GetGadgetColor
      *SetGadgetItemColor2
      *GetGadgetItemColor2
      *SetGadgetItemData
      *GetGadgetItemData
      *GetGadgetFont
      *SetGadgetItemImage
      *HideGadget ;Mac & Windows only
    EndStructure
    
  CompilerElseIf #PB_Compiler_OS=#PB_OS_MacOS
    ;- PB SDK for MacOs => TODO
  CompilerEndIf
  
  Structure CustomGadget
    vt.GadgetVT          ;new gadget VT
    *originalVT.GadgetVT ;old gadget VT
    
    ;custom properties
    Gadget.i
    Gadget1.i
    Gadget2.i
    Flags.i
    Thickness.i
    x.i : y.i : w.i : h.i
    BackColor.i
    FrontColor.i
    LineColor.i
    State.f
    StatePercent.f
    SnapDistance.i
    FirstMinSize.i
    SecondMinSize.i
    CurrentStatus.i
    DragOffsetX.i
    DragOffsetY.i
    *DrawingFunction
  EndStructure
  Structure CustomContext
    *DraggedGadget.CustomGadget
    DragStartPos.i
  EndStructure
  Global CustomContext.CustomContext        ;Custom global context
  Global NewMap CustomGadget.CustomGadget() ;Custom gadget list
  Declare.i NewCustomGadget(*this.Gadget)
  Declare FreeCustomGadget(*this.Gadget)
  Declare DrawCustomGadget(*this.Gadget)
  Declare UseCustomGadget(*this.Gadget, *CustomGadget.CustomGadget)
  Declare CustomGadgetEvents()
  
  Procedure ResizeGadgetSmoothly(Gadget, x, y, w, h, SmoothMode=#True)
    Protected *this.Gadget=GadgetID(Gadget)
    If SmoothMode ;prevent flickering
      CompilerIf #PB_Compiler_OS=#PB_OS_Windows
        SendMessage_(*this, #WM_SETREDRAW, 0, 0)
      CompilerEndIf
    EndIf
    ResizeGadget(Gadget, x, y, w, h)
    If SmoothMode ;prevent flickering
      CompilerIf #PB_Compiler_OS=#PB_OS_Windows
        SendMessage_(*this, #WM_SETREDRAW, 1, 0)
        InvalidateRect_(*this, 0, 0)
        UpdateWindow_(*this)
      CompilerEndIf
    EndIf      
  EndProcedure   
  
  ; Begin vtFunctions
  
  CompilerIf #PB_Compiler_OS=#PB_OS_Windows
    Macro ProcedureVT
      Procedure
    EndMacro
  CompilerElseIf #PB_Compiler_OS=#PB_OS_Linux
    Macro ProcedureVT
      ProcedureC
    EndMacro
  CompilerElseIf #PB_Compiler_OS=#PB_OS_MacOS
    ;TODO
  CompilerEndIf
  
  ProcedureVT _ResizeGadget(*this.Gadget, x, y, w, h)
    Protected *CustomGadget.CustomGadget=*this\vt
    With *CustomGadget
      If x=#PB_Ignore : x=\x : EndIf
      If y=#PB_Ignore : y=\y : EndIf
      If w=#PB_Ignore : w=\w : EndIf
      If h=#PB_Ignore : h=\h : EndIf
      
      \x=x : \y=y : \w=w : \h=h
      Protected bx=x, by=y, bw.f=w, bh.f=h    ;bar
      Protected fx=x, fy=y, fw.f=w, fh.f=h    ;first gadget
      Protected sx=x, sy=y, sw.f=w, sh.f=h    ;second gadget
      Protected bp, bl.f, fp, fl.f, sp, sl.f  ;generic positions & lengths
      Protected tk=\Thickness, max            ;generic measures
      
      ;convert oriented coordinates into generic coordinates
      If \Flags & #SplitBar_Vertical
        max=w : fp=fx
      Else
        max=h : fp=fy
      EndIf
      ;apply maxsize constraints
      If max<0 Or max>$FFFF : max=0 : EndIf
      If tk>max : tk=max : EndIf
      ;locate 1st gadget
      If \Flags & #SplitBar_FixedSize : fl=\State : Else : fl=\StatePercent * max : EndIf
      If fl<0 : fl=max + fl - tk : EndIf
      ;apply minsize constraints
      If fl<\FirstMinSize : fl=\FirstMinSize : EndIf
      If (fl + tk + \SecondMinSize)>max : fl=max-tk-\SecondMinSize : EndIf
      If fl<0 : fl=0 : EndIf
      ;locate 2nd gadget and bar
      sp=fp + fl + tk : sl=max-fl-tk
      bp=fp + fl : bl=tk
      ;convert generic coordinates into oriented coordinates
      If \Flags & #SplitBar_Vertical
        fw=fl : sx=sp : sw=sl : bx=bp : bw=bl
      Else
        fh=fl : sy=sp : sh=sl : by=bp : bh=bl
      EndIf
      
      ;resize bar (resized original gadget)
      UseCustomGadget(*this, 0)
      ResizeGadget(\Gadget, bx, by, bw, bh)
      UseCustomGadget(*this, *CustomGadget)
      DrawCustomGadget(*this)
      
      ;resize first and second gadgets (if possible)
      Protected SmoothMode=Bool(CustomContext\DraggedGadget<>0)         
      If IsGadget(\Gadget1) : ResizeGadgetSmoothly(\Gadget1, fx, fy, fw, fh, SmoothMode) : EndIf
      If IsGadget(\Gadget2) : ResizeGadgetSmoothly(\Gadget2, sx, sy, sw, sh, SmoothMode) : EndIf
    EndWith
  EndProcedure
  
  ProcedureVT _GetGadgetColor(*this.Gadget, ColorType)
    Protected *CustomGadget.CustomGadget=*this\vt, result
    With *CustomGadget
      Select ColorType
        Case #PB_Gadget_LineColor : result=\LineColor
        Case #PB_Gadget_BackColor : result=\BackColor
        Case #PB_Gadget_FrontColor : result=\FrontColor
      EndSelect
      ProcedureReturn result
    EndWith
  EndProcedure
  
  ProcedureVT _SetGadgetColor(*this.Gadget, ColorType, Color)
    Protected *CustomGadget.CustomGadget=*this\vt
    With *CustomGadget
      Select ColorType
        Case #PB_Gadget_LineColor : \LineColor=Color
        Case #PB_Gadget_BackColor : \BackColor=Color
        Case #PB_Gadget_FrontColor : \FrontColor=Color
      EndSelect
      DrawCustomGadget(*this)
    EndWith
  EndProcedure
  
  ProcedureVT _GetGadgetState(*this.Gadget)
    Protected *CustomGadget.CustomGadget=*this\vt
    With *CustomGadget
      ProcedureReturn \State
    EndWith
  EndProcedure
  
  ProcedureVT _SetGadgetState(*this.Gadget, State.i)
    Protected *CustomGadget.CustomGadget=*this\vt
    With *CustomGadget
      Protected max
      If (\Flags & #SplitBar_Vertical) : max=\w : Else : max=\h : EndIf         
      If (\CurrentStatus & #SplitBar_IsDragged)
        ;Snapped bar constraints
        If \SnapDistance>0
          \CurrentStatus & ~#SplitBar_IsSnapped
          If \StatePercent>=0 And State<\SnapDistance : State=0 : \CurrentStatus | #SplitBar_IsSnapped : EndIf
          If \StatePercent<0 And State>-\SnapDistance : State=0 : \CurrentStatus | #SplitBar_IsSnapped : EndIf
        EndIf
        ;Dragged bar constraints
        If \StatePercent>=0
          If State<1 : State=0 : EndIf
          If State>(max-\Thickness) : State=(max-\Thickness) : EndIf
        Else
          If State>-1 : State=0 : EndIf
          If State<-(max-\Thickness) : State=-(max-\Thickness) : EndIf
        EndIf
      EndIf
      
      If State
        \State=State
        \StatePercent=1e-14*Sign(State)
        If max : \StatePercent=\State / max : EndIf
      Else
        \State=1e-14*Sign(\StatePercent)
        \StatePercent=1e-14*Sign(\StatePercent)
      EndIf         
      _ResizeGadget(*this, #PB_Ignore, #PB_Ignore, #PB_Ignore, #PB_Ignore)
    EndWith
  EndProcedure
  
  ProcedureVT _SetGadgetAttribute(*this.Gadget, Attribute, Value)
    Protected *CustomGadget.CustomGadget=*this\vt
    With *CustomGadget
      Select Attribute
        Case 0 To 1024
          ;Set original gadget attribute
          UseCustomGadget(*this, 0)
          SetGadgetAttribute(\Gadget, Attribute, Value)
          UseCustomGadget(*this, *CustomGadget)
        Case #SplitBar_CurrentFlags : \Flags=Value
        Case #SplitBar_CurrentThickness : \Thickness=Value
        Case #SplitBar_CurrentFirstGadget : \Gadget1=Value
        Case #SplitBar_CurrentSecondGadget : \Gadget2=Value
        Case #SplitBar_CurrentSnapDistance : \SnapDistance=Abs(Value)
        Case #SplitBar_CurrentFirstMinSize : \FirstMinSize=Abs(Value)
        Case #SplitBar_CurrentSecondMinSize : \SecondMinSize=Abs(Value)
        Case #SplitBar_CurrentDrawingFunction : \DrawingFunction=Value
      EndSelect
      _ResizeGadget(*this, #PB_Ignore, #PB_Ignore, #PB_Ignore, #PB_Ignore)
    EndWith
  EndProcedure
  
  ProcedureVT _GetGadgetAttribute(*this.Gadget, Attribute)
    Protected *CustomGadget.CustomGadget=*this\vt, result
    With *CustomGadget
      Select Attribute
        Case 0 To 1024
          ;Get original gadget attribute
          UseCustomGadget(*this, 0)
          result=GetGadgetAttribute(\Gadget, Attribute)
          UseCustomGadget(*this, *CustomGadget)
        Case #SplitBar_CurrentFlags : result=\Flags
        Case #SplitBar_CurrentStatus : result=\CurrentStatus
        Case #SplitBar_CurrentThickness : result=\Thickness
        Case #SplitBar_CurrentFirstGadget : result=\Gadget1
        Case #SplitBar_CurrentSecondGadget : result=\Gadget2
        Case #SplitBar_CurrentSnapDistance : result=\SnapDistance
        Case #SplitBar_CurrentFirstMinSize : result=\FirstMinSize
        Case #SplitBar_CurrentSecondMinSize : result=\SecondMinSize
        Case #SplitBar_CurrentDrawingFunction : result=\DrawingFunction
      EndSelect
      ProcedureReturn result
    EndWith
  EndProcedure
  
  ProcedureVT _FreeGadget(*this.Gadget)
    Protected *CustomGadget.CustomGadget=*this\vt
    With *CustomGadget
      FreeCustomGadget(*this)
    EndWith
  EndProcedure
  
  ; End vtFunctions
  
  Procedure CustomGadgetEvents()
    Protected t=EventType()
    Protected g=EventGadget()
    Protected *this.Gadget=IsGadget(g)
    Protected *CustomGadget.CustomGadget=*this\vt
    With *CustomGadget
      If (\Flags & #SplitBar_Locked)=0
        ;ignore some custom events
        Select t
          Case #PB_EventType_Change
            ProcedureReturn
        EndSelect
        ;handle some custom events
        Protected win=EventWindow()            
        Protected mx=_GetGadgetAttribute(*this, #PB_Canvas_MouseX)
        Protected my=_GetGadgetAttribute(*this, #PB_Canvas_MouseY)
        Protected oldStatus=\CurrentStatus, oldState=\State
        Select t
          Case #PB_EventType_MouseEnter
            \CurrentStatus | #SplitBar_IsHighlighted
            DrawCustomGadget(*this)
          Case #PB_EventType_MouseLeave
            \CurrentStatus & ~#SplitBar_IsHighlighted
            DrawCustomGadget(*this)
            
          Case #PB_EventType_LeftButtonDown
            If CustomContext\DraggedGadget=0
              CustomContext\DraggedGadget=*CustomGadget
              CustomContext\DragStartPos=\State
              \CurrentStatus | #SplitBar_IsDragged
              \DragOffsetX=mx
              \DragOffsetY=my
            EndIf                  
          Case #PB_EventType_LeftButtonUp, #PB_EventType_LeftDoubleClick
            If CustomContext\DraggedGadget
              CustomContext\DraggedGadget=0
              \CurrentStatus & ~#SplitBar_IsDragged
            EndIf
            
          Case #PB_EventType_MouseMove
            If (\CurrentStatus & #SplitBar_IsDragged)                     
              If (\Flags & #SplitBar_Vertical)
                If mx<>\DragOffsetX : _SetGadgetState(*this, \State + (mx-\DragOffsetX)) : EndIf
              Else
                If my<>\DragOffsetY : _SetGadgetState(*this, \State + (my-\DragOffsetY)) : EndIf
              EndIf
            EndIf
            If (\Flags & #SplitBar_Vertical)
              _SetGadgetAttribute(*this, #PB_Canvas_Cursor, #PB_Cursor_LeftRight)
            Else
              _SetGadgetAttribute(*this, #PB_Canvas_Cursor, #PB_Cursor_UpDown)
            EndIf
        EndSelect
        ;post some custom events (new supported events)
        If t<>#PB_EventType_MouseMove And (oldStatus<>\CurrentStatus Or oldState<>\State)
          PostEvent(#PB_Event_Gadget, win, \Gadget, #PB_EventType_Change, \CurrentStatus)
        EndIf            
      EndIf
    EndWith
  EndProcedure
  
  Procedure UseCustomGadget(*this.Gadget, *CustomGadget.CustomGadget)
    If *CustomGadget
      ;use custom gadgetVT
      *this\vt=*CustomGadget
    Else
      ;use original gadgetVT
      *CustomGadget=*this\vt
      *this\vt=*CustomGadget\originalVT
    EndIf
  EndProcedure
  
  Procedure DrawCustomGadget(*this.Gadget)
    Protected *CustomGadget.CustomGadget=*this\vt
    With *CustomGadget
      If \DrawingFunction
        CallFunctionFast(\DrawingFunction, \Gadget)
        ProcedureReturn
      EndIf         
      
      StartDrawing(CanvasOutput(\Gadget))
      Protected color
      If \CurrentStatus & #SplitBar_IsHighlighted
        color=\FrontColor
      Else
        color=\BackColor
      EndIf
      ;draw bar
      Box(0, 0, \w, \h, color)
      ;draw grip (if enabled)
      If \Flags & #SplitBar_Grip
        Protected i, x, y
        If \Flags & #SplitBar_Vertical
          x=0.5*\Thickness -1
          y=0.5*\h -7
          For i=0 To 12 Step 4
            Box(x, y + i, 2, 2, \LineColor)
          Next               
        Else
          x=0.5*\w -7
          y=0.5*\Thickness -1
          For i=0 To 12 Step 4
            Box(x + i, y, 2, 2, \LineColor)
          Next
        EndIf            
      EndIf         
      StopDrawing()
    EndWith
  EndProcedure
  
  Procedure FreeCustomGadget(*this.Gadget)
    ;find custom gadget data
    Protected *CustomGadget.CustomGadget=FindMapElement(CustomGadget(), "ID-" + *this\Gadget)
    With *CustomGadget
      If *CustomGadget
        ;free original gadget
        UseCustomGadget(*this, 0)
        FreeGadget(\Gadget)
        ;delete custom gadget data
        DeleteMapElement(CustomGadget())
      EndIf
    EndWith
  EndProcedure
  
  Procedure.i NewCustomGadget(*this.Gadget)
    ;create custom gadget data
    Protected *CustomGadget.CustomGadget=AddMapElement(CustomGadget(), "ID-" + *this\Gadget)
    If *CustomGadget
      CopyMemory(*this\vt, *CustomGadget\vt, SizeOf(GadgetVT))
      With *CustomGadget\vt
        ;define mandatory custom method
        \FreeGadget=@_FreeGadget()
        
        ;define other custom methods
        \ResizeGadget=@_ResizeGadget()
        \GetGadgetState=@_GetGadgetState()
        \SetGadgetState=@_SetGadgetState()
        \GetGadgetColor=@_GetGadgetColor()
        \SetGadgetColor=@_SetGadgetColor()
        \GetGadgetAttribute=@_GetGadgetAttribute()
        \SetGadgetAttribute=@_SetGadgetAttribute()
      EndWith
      
      *CustomGadget\originalVT=*this\vt   ;save original gadgetVT
      *this\vt=*CustomGadget              ;apply custom gadgetVT
    EndIf
    ProcedureReturn *CustomGadget
  EndProcedure
  
  Procedure.i SplitBarGadget(Gadget, x, y, Width, Height, Gadget1=0, Gadget2=0, Flags=#SplitBar_Default, Thickness=6)
    Protected result=CanvasGadget(Gadget, x, y, Width, Height)
    If result=0 : ProcedureReturn #False : EndIf
    If Gadget=#PB_Any : Gadget=result : EndIf
    Protected *this.Gadget=IsGadget(Gadget)
    Protected *CustomGadget.CustomGadget=NewCustomGadget(*this)
    
    With *CustomGadget
      ;define custom properties
      \x=x : \y=y : \w=Width : \h=Height
      \Gadget=Gadget
      \Gadget1=Gadget1
      \Gadget2=Gadget2
      \Flags=Flags
      \Thickness=Thickness
      If (\Flags & #SplitBar_Vertical)
        _SetGadgetState(*this, \w / 2-\Thickness / 2)
      Else
        _SetGadgetState(*this, \h / 2-\Thickness / 2)
      EndIf
      
      ;define custom events
      BindGadgetEvent(Gadget, @CustomGadgetEvents())         
    EndWith
    ProcedureReturn result
  EndProcedure
EndModule

CompilerIf #PB_Compiler_IsMainFile
  ;********************
  ; EXAMPLE
  ;********************
  UseModule SplitBarGadget
  Runtime Enumeration
    #xml : #dialog : #win
    #Split0 : #Split1 : #Split2 : #Split3
    #Left : #Right : #Top : #Bottom : #Center
    
    #ColorContent=$484848
    #ColorBright=$777777
    #ColorDark=$232323
    #ColorGrip=$FFFFFF
  EndEnumeration
  
  Procedure SetGadgetColors(Gadget, BackColor=0, FrontColor=0, LineColor=0, TitleBackColor=0, TitleFrontColor=0)
    SetGadgetColor(Gadget, #PB_Gadget_FrontColor, FrontColor)
    SetGadgetColor(Gadget, #PB_Gadget_BackColor, BackColor)
    SetGadgetColor(Gadget, #PB_Gadget_LineColor, LineColor)
    SetGadgetColor(Gadget, #PB_Gadget_TitleBackColor, TitleBackColor)
    SetGadgetColor(Gadget, #PB_Gadget_TitleFrontColor, TitleFrontColor)
  EndProcedure
  Procedure DrawingFunction(Gadget)
    StartDrawing(CanvasOutput(Gadget))
    Protected i, x, y, w=OutputWidth(), h=OutputHeight()
    Protected Flags=GetGadgetAttribute(Gadget, #SplitBar_CurrentFlags)
    Protected CurrentStatus=GetGadgetAttribute(Gadget, #SplitBar_CurrentStatus)
    Protected Thickness=GetGadgetAttribute(Gadget, #SplitBar_CurrentThickness)
    Protected FrontColor=GetGadgetColor(Gadget, #PB_Gadget_FrontColor)
    Protected BackColor=GetGadgetColor(Gadget, #PB_Gadget_BackColor)
    Protected LineColor=GetGadgetColor(Gadget, #PB_Gadget_LineColor)
    ;draw bar
    DrawingMode(#PB_2DDrawing_Gradient)
    If CurrentStatus & #SplitBar_IsHighlighted
      BackColor(FrontColor)
      GradientColor(0.4, FrontColor)
      FrontColor(BackColor)
    Else
      BackColor(BackColor)
      GradientColor(0.4, BackColor)
      FrontColor(FrontColor)
    EndIf
    If Flags & #SplitBar_Vertical
      LinearGradient(0, 0, w, 0)
    Else            
      LinearGradient(0, 0, 0, h)
    EndIf         
    Box(0, 0, w, h)
    ;draw grip (if enabled)
    DrawingMode(#PB_2DDrawing_Default)
    If CurrentStatus & #SplitBar_IsSnapped
      FrontColor(RGB(255, 0, 0))
    Else
      FrontColor(LineColor)
    EndIf         
    If Flags & #SplitBar_Grip
      If Flags & #SplitBar_Vertical
        For i=0 To h / 3 Step 5
          Box(w / 3, h / 3 + i, w / 3, 3)
        Next               
      Else
        For i=0 To w / 3 Step 5
          Box(w / 3 + i, h / 3, 3, h / 3)
        Next               
      EndIf
    EndIf
    StopDrawing()      
  EndProcedure
  
  Define xml$="<window id='#win' name='splitter' text='SplitBar Gadgets' width='600' height='300' " + 
              "  flags='#PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget'>" + 
              "  <canvas id='#Split3' />" + 
              "</window>"   
  If CatchXML(#xml, @xml$, StringByteLength(xml$), 0, #PB_Ascii) And XMLStatus(#xml)=#PB_XML_Success And CreateDialog(#dialog) And OpenXMLDialog(#dialog, #xml, "splitter")
    SetWindowColor(#win, #ColorContent)
    ButtonGadget(#Top, 0, 0, 200, 32, "#Top")
    ButtonGadget(#Left, 0, 0, 200, 32, "#Left")
    ButtonGadget(#Right, 0, 0, 200, 32, "#Right")
    ButtonGadget(#Center, 0, 0, 200, 32, "#Center")
    ButtonGadget(#Bottom, 0, 0, 200, 32, "#Bottom")
    SplitBarGadget(#Split0, 0, 0, 0, 0, #Center, #Bottom)
    SplitBarGadget(#Split1, 0, 0, 0, 0, #Left, #Split0, #SplitBar_Vertical | #SplitBar_FixedSize | #SplitBar_Grip)
    SplitBarGadget(#Split2, 0, 0, 0, 0, #Split1, #Right, #SplitBar_Vertical | #SplitBar_FixedSize | #SplitBar_Grip)
    SplitBarGadget(#Split3, 0, 0, 0, 0, #Top, #Split2, #SplitBar_FixedSize | #SplitBar_Locked, 2)
    ResizeWindow(#win, #PB_Ignore, #PB_Ignore, #PB_Ignore, 400)
    SetGadgetState(#Split3, 30)
    SetGadgetState(#Split2, -80)
    SetGadgetState(#Split1, 80)
    SetGadgetState(#Split0, -100)
    SetGadgetAttribute(#Split0, #SplitBar_CurrentFirstMinSize, 30)
    SetGadgetAttribute(#Split0, #SplitBar_CurrentSecondMinSize, 50)
    SetGadgetAttribute(#Split1, #SplitBar_CurrentSnapDistance, 80)
    SetGadgetAttribute(#Split2, #SplitBar_CurrentSnapDistance, 80)
    SetGadgetAttribute(#Split2, #SplitBar_CurrentDrawingFunction, @DrawingFunction())
    SetGadgetColors(#Split0, #ColorContent, #ColorBright, #ColorGrip)
    SetGadgetColors(#Split1, #ColorContent, #ColorBright, #ColorGrip)
    SetGadgetColors(#Split2, #ColorContent, #ColorBright, #ColorGrip)
    SetGadgetColors(#Split3, #ColorContent, #ColorBright, #ColorGrip)
    Repeat
      e=WaitWindowEvent()
      g=EventGadget()
      t=EventType()
      d=EventData()
      win=EventWindow()
      If t=#PB_EventType_LeftDoubleClick And g=#Split0
        ;SetGadgetState(g, -100)
        Debug "SplitBar=" + g + " is resetted"
      EndIf
      If t=#PB_EventType_Change
        Debug "SplitBar=" + g + " CurrentStatus=" + d + " State=" + GetGadgetState(g)
      EndIf
    Until e=#PB_Event_CloseWindow
  EndIf
CompilerEndIf
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Re: SplitBarGadget - canvas-based splitter

Post by eddy »

mk-soft wrote:Very Nice :D
Works fine on Linux. SDK for Mac come on next version of PB :wink:
Hi,
Did you find a way to extract SDK from PB mac package 5.40b ?
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Re: SplitBarGadget - canvas-based splitter

Post by eddy »

[Updated]
- fixed pointer problem for PB 5.60
- added linux support from mk-soft
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
mestnyi
Addict
Addict
Posts: 995
Joined: Mon Nov 25, 2013 6:41 am

Re: SplitBarGadget - canvas-based splitter (win / linux)

Post by mestnyi »

Code: Select all

\StatePercent=1e-14*Sign(State)
Can you explain the following code?
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Re: SplitBarGadget - canvas-based splitter (win / linux)

Post by eddy »

I needed a signed zero value for snapping border.

+0 right border
-0 left border
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
IndigoFuzz

Re: SplitBarGadget - canvas-based splitter (win / linux)

Post by IndigoFuzz »

Any chance of supporting 5.61?

Running the example above this post results in the \Gadget field returning 0 immediately in the _GetGadgetAttribute procedure


Kind regards, and great work :)
Niffo
Enthusiast
Enthusiast
Posts: 500
Joined: Tue Jan 31, 2006 9:43 am
Location: France

Re: SplitBarGadget - canvas-based splitter (win / linux)

Post by Niffo »

Works here with PB 5.61, at least on Windows
Sadly it doesn't work yet on MacOS. Would try to rework the code to not use PB SDK ...
Last edited by Niffo on Tue Nov 21, 2017 11:01 am, edited 1 time in total.
Niffo
IndigoFuzz

Re: SplitBarGadget - canvas-based splitter (win / linux)

Post by IndigoFuzz »

It works for me only if I disable debugger.

If I enable Debugger then it throws the Gadget Not Initialised whenever an operation is performed on the *CustomGadget\Gadget reference (which always returns 0)

:?
Marty2PB
User
User
Posts: 47
Joined: Thu Mar 13, 2014 4:31 pm

Re: SplitBarGadget - canvas-based splitter (win / linux)

Post by Marty2PB »

I use the Module too. Really great and i use 5.42LTS/ Windows7 at time. I managed the Flicker Stuff.
As Buttons, PureCanvas. The other Gui Classes (PureScrollArea etc) need a alternative Flicker Handle.

I use 2 Main Contaner. In this, in the First Container is a ListIcon. In the Second Container Container a collection of ImageGadgets. The #WM_SETREDRAW is uselss. PureContainer and PureScrollArea need only #WS_CLIPCHILDREN. I added this via Select State. this is only for Windows

Code: Select all



   Procedure.s Get_GadgetClass(GadgetObject.i,ShowClassDebug = #False)
       
       Define pszTypeReal$ = Space(1024)
       Define pszTypeName$ = Space(1024)            
       Protected GadgetLongID.l
       If IsGadget(GadgetObject)            
           GadgetLongID = GadgetID(GadgetObject)
       Else
           ;
           ; Try
           If ( GadgetObject >= 1 )
               GadgetLongID = GadgetObject
           Else
               ProcedureReturn ""
           EndIf    
       EndIf
              
       RealGetWindowClass_(GadgetLongID, @pszTypeReal$, Len(pszTypeReal$))
       GetClassName_(GadgetLongID,@pszTypeName$,Len(pszTypeName$))                 
       
       If ( ShowClassDebug = #True )             
           Debug "Klassenamen - Real Window Class: " + pszTypeReal$ + " /GadgetID: " +Str(GadgetObject) + " /GadgteLongID: " +Str(GadgetLongID) 
           If ( pszTypeReal$ <> pszTypeName$)               
               Debug "Klassenamen - Get  Class   Name: " + pszTypeName$ + " /GadgetID: " +Str(GadgetObject) + " /GadgteLongID: " +Str(GadgetLongID) + Chr(13)                
           EndIf            
       EndIf     
       ProcedureReturn pszTypeReal$
   
   ;//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   ;
   ;
   Procedure ResizeGadgetOS_Windows(Class.s, ClassLong.l, Update = #False)
       
       If ( Update = #False )
           Select Class
               Case "PureContainer"
                   SetWindowLongPtr_(ClassLong, #GWL_STYLE, GetWindowLongPtr_(ClassLong, #GWL_STYLE) |#WS_CLIPCHILDREN)                      
               Case "PureScrollArea"
                   SetWindowLongPtr_(ClassLong, #GWL_STYLE, GetWindowLongPtr_(ClassLong, #GWL_STYLE) |#WS_CLIPCHILDREN)                   
               Case "PureCanvas" 
               Case "Button"
                   SendMessage_(ClassLong, #WM_SETREDRAW, 0, 0)
           EndSelect                    
           ProcedureReturn
       EndIf  
       
       If ( Update = #True )      
           Select Class
               Case "PureContainer"                   
               Case "PureScrollArea"                   
                   UpdateWindow_(ClassLong)  
               Case "PureCanvas" 
               Case "Button" 
                   SendMessage_(ClassLong, #WM_SETREDRAW, 1, 0)
                   InvalidateRect_(ClassLong, 0, 0)
                   UpdateWindow_(ClassLong)                     
           EndSelect 
           ProcedureReturn
       EndIf 
   EndProcedure 
   ;//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   ;
   ;   
   Procedure ResizeGadgetSmoothly(Gadget, x, y, w, h, SmoothMode=#True)
      Protected *this.Gadget=GadgetID(Gadget), Gadgetclass.s
 
      If SmoothMode ;prevent flickering
          CompilerIf #PB_Compiler_OS=#PB_OS_Windows 
              ResizeGadgetOS_Windows(Get_GadgetClass(Gadget,#True), *this.Gadget)
         CompilerEndIf
      EndIf
      ResizeGadget(Gadget, x, y, w, h)
      If SmoothMode ;prevent flickering
          CompilerIf #PB_Compiler_OS=#PB_OS_Windows
             ResizeGadgetOS_Windows(Get_GadgetClass(Gadget,#False), *this.Gadget,#True)          
         CompilerEndIf
      EndIf
   EndProcedure
User avatar
❤x1
User
User
Posts: 46
Joined: Thu Jan 10, 2019 5:56 pm

Re: SplitBarGadget - canvas-based splitter (win / linux)

Post by ❤x1 »

I needed the second gadet to have a fixed size, so :
-Replaced #SplitBar_FixedSize with #SplitBar_FirstFixed
-Added #SplitBar_SecondFixed

Code: Select all

DeclareModule SplitBarGadget
	EnumerationBinary   
		;custom Flags
		#SplitBar_Default
		#SplitBar_Vertical
		#SplitBar_Grip
		#SplitBar_Locked
		#SplitBar_FirstFixed
		#SplitBar_SecondFixed
		;custom Statuses
		#SplitBar_IsHighlighted=1
		#SplitBar_IsDragged
		#SplitBar_IsSnapped
	EndEnumeration
	
	Enumeration
		;custom Attributes
		#SplitBar_CurrentFlags=2000
		#SplitBar_CurrentStatus
		#SplitBar_CurrentThickness
		#SplitBar_CurrentSnapDistance
		#SplitBar_CurrentFirstGadget
		#SplitBar_CurrentSecondGadget
		#SplitBar_CurrentFirstMinSize
		#SplitBar_CurrentSecondMinSize
		#SplitBar_CurrentDrawingFunction
	EndEnumeration
	Declare.i SplitBarGadget(Gadget, x, y, Width, Height, Gadget1=0, Gadget2=0, Flags=#SplitBar_Default, Thickness=6)
EndDeclareModule

Module SplitBarGadget
	EnableExplicit
	CompilerIf #PB_Compiler_OS=#PB_OS_Windows
		;- PB SDK for Windows
		Structure Gadget
			Gadget.i
			*vt.GadgetVT
			UserData.i
			OldCallback.i
			Daten.i[4]
		EndStructure
		Structure GadgetVT
			GadgetType.l
			SizeOf.l
			*GadgetCallback
			*FreeGadget
			*GetGadgetState
			*SetGadgetState
			*GetGadgetText
			*SetGadgetText
			*AddGadgetItem2
			*AddGadgetItem3
			*RemoveGadgetItem
			*ClearGadgetItemList
			*ResizeGadget
			*CountGadgetItems
			*GetGadgetItemState
			*SetGadgetItemState
			*GetGadgetItemText
			*SetGadgetItemText
			*OpenGadgetList2
			*GadgetX
			*GadgetY
			*GadgetWidth
			*GadgetHeight
			*HideGadget
			*AddGadgetColumn
			*RemoveGadgetColumn
			*GetGadgetAttribute
			*SetGadgetAttribute
			*GetGadgetItemAttribute2
			*SetGadgetItemAttribute2
			*SetGadgetColor
			*GetGadgetColor
			*SetGadgetItemColor2
			*GetGadgetItemColor2
			*SetGadgetItemData
			*GetGadgetItemData
			*GetRequiredSize
			*SetActiveGadget
			*GetGadgetFont
			*SetGadgetFont
			*SetGadgetItemImage
		EndStructure
	CompilerElseIf #PB_Compiler_OS=#PB_OS_Linux
		;- PB SDK for Linux
		Structure Gadget
			Gadget.i
			GadgetContainer.i
			*vt.GadgetVT
			UserData.i
			Daten.i[4]
		EndStructure
		Structure GadgetVT
			SizeOf.l
			GadgetType.l
			*ActivateGadget
			*FreeGadget
			*GetGadgetState
			*SetGadgetState
			*GetGadgetText
			*SetGadgetText
			*AddGadgetItem2
			*AddGadgetItem3
			*RemoveGadgetItem
			*ClearGadgetItemList
			*ResizeGadget
			*CountGadgetItems
			*GetGadgetItemState
			*SetGadgetItemState
			*GetGadgetItemText
			*SetGadgetItemText
			*SetGadgetFont
			*OpenGadgetList2
			*AddGadgetColumn
			*GetGadgetAttribute
			*SetGadgetAttribute
			*GetGadgetItemAttribute2
			*SetGadgetItemAttribute2
			*RemoveGadgetColumn
			*SetGadgetColor
			*GetGadgetColor
			*SetGadgetItemColor2
			*GetGadgetItemColor2
			*SetGadgetItemData
			*GetGadgetItemData
			*GetGadgetFont
			*SetGadgetItemImage
			*HideGadget ;Mac & Windows only
		EndStructure
	CompilerElseIf #PB_Compiler_OS=#PB_OS_MacOS
		;- PB SDK for MacOs => TODO     
	CompilerEndIf
	
	Structure CustomGadget
		vt.GadgetVT
		vtOld.GadgetVT ;old gadget VT
		isCustom.b	   ;determines if customization is active
		
		;custom properties
		Gadget.i
		Gadget1.i
		Gadget2.i
		Flags.i
		Thickness.i
		x.i : y.i : w.i : h.i
		BackColor.i
		FrontColor.i
		LineColor.i
		State.f
		StatePercent.f
		SnapDistance.i
		FirstMinSize.i
		SecondMinSize.i
		CurrentStatus.i
		DragOffsetX.i
		DragOffsetY.i
		*DrawingFunction
	EndStructure
	Structure CustomContext
		*DraggedGadget.CustomGadget
		DragStartPos.i
	EndStructure
	Global CustomContext.CustomContext        ;Custom global context
	Global NewMap CustomGadget.CustomGadget() ;Custom gadget list
	Declare.i NewCustomGadget(*this.Gadget)
	Declare FreeCustomGadget(*this.Gadget)
	Declare DrawCustomGadget(*this.Gadget)
	Declare UseCustomGadget(*this.Gadget, *CustomGadget.CustomGadget)
	Declare CustomGadgetEvents()
	
	Procedure ResizeGadgetSmoothly(Gadget, x, y, w, h, SmoothMode=#True)
		Protected *this.Gadget=GadgetID(Gadget)
		If SmoothMode ;prevent flickering
			CompilerIf #PB_Compiler_OS=#PB_OS_Windows
				SendMessage_(*this, #WM_SETREDRAW, 0, 0)
			CompilerEndIf
		EndIf
		ResizeGadget(Gadget, x, y, w, h)
		If SmoothMode ;prevent flickering
			CompilerIf #PB_Compiler_OS=#PB_OS_Windows
				SendMessage_(*this, #WM_SETREDRAW, 1, 0)
				InvalidateRect_(*this, 0, 0)
				UpdateWindow_(*this)
			CompilerEndIf
		EndIf
	EndProcedure
	
	Procedure _ResizeGadget(*this.Gadget, x, y, w, h)
		Protected *CustomGadget.CustomGadget=*this\vt
		Protected ps, cs ;positions for SecondFixed

		With *CustomGadget
			
			If x=#PB_Ignore : x=\x : EndIf
			If y=#PB_Ignore : y=\y : EndIf
			If w=#PB_Ignore : w=\w : EndIf
			If h=#PB_Ignore : h=\h : EndIf
			
			Protected bx=x, by=y, bw.f=w, bh.f=h    ;bar
			Protected fx=x, fy=y, fw.f=w, fh.f=h	;first gadget
			Protected sx=x, sy=y, sw.f=w, sh.f=h	;second gadget
			Protected bp, bl.f, fp, fl.f, sp, sl.f	;generic positions & lengths
			Protected tk=\Thickness, max			;generic measures
			
			If \Flags & #SplitBar_Vertical
				cs = w
				ps = \w
			Else
				cs = h
				ps = \h
			EndIf
			
			\x=x : \y=y : \w=w : \h=h
			
			;convert oriented coordinates into generic coordinates
			If \Flags & #SplitBar_Vertical
				max=w : fp=fx
			Else
				max=h : fp=fy
			EndIf
			;apply maxsize constraints
			If max<0 Or max>$FFFF : max=0 : EndIf
			If tk>max : tk=max : EndIf
			;locate 1st gadget
			If \Flags & #SplitBar_FirstFixed : fl=\State : ElseIf \Flags & #SplitBar_SecondFixed : \State = cs-(ps -\State) : \StatePercent=1e-14*Sign(\State) : fl= \State : Else : fl=\StatePercent * max : EndIf
			If fl<0 : fl=max + fl - tk : EndIf
			;apply minsize constraints
			If fl<\FirstMinSize : fl=\FirstMinSize : EndIf
			If (fl + tk + \SecondMinSize)>max : fl=max-tk-\SecondMinSize : EndIf
			If fl<0 : fl=0 : EndIf
			;locate 2nd gadget and bar
			sp=fp + fl + tk : sl=max-fl-tk
			bp=fp + fl : bl=tk
			;convert generic coordinates into oriented coordinates
			If \Flags & #SplitBar_Vertical
				fw=fl : sx=sp : sw=sl : bx=bp : bw=bl
			Else
				fh=fl : sy=sp : sh=sl : by=bp : bh=bl
			EndIf
			
			;resize bar (resized original gadget)
			UseCustomGadget(*this, 0)
			ResizeGadget(\Gadget, bx, by, bw, bh)
			UseCustomGadget(*this, 1)
			DrawCustomGadget(*this)
			
			;resize first and second gadgets (if possible)
			Protected SmoothMode=Bool(CustomContext\DraggedGadget<>0)
			If IsGadget(\Gadget1) : ResizeGadgetSmoothly(\Gadget1, fx, fy, fw, fh, SmoothMode) : EndIf
			If IsGadget(\Gadget2) : ResizeGadgetSmoothly(\Gadget2, sx, sy, sw, sh, SmoothMode) : EndIf
		EndWith
	EndProcedure
	
	Procedure.i _GetGadgetColor(*this.Gadget, ColorType)
		Protected *CustomGadget.CustomGadget=*this\vt, result
		With *CustomGadget
			Select ColorType
				Case #PB_Gadget_LineColor : result=\LineColor
				Case #PB_Gadget_BackColor : result=\BackColor
				Case #PB_Gadget_FrontColor : result=\FrontColor
			EndSelect
			ProcedureReturn result
		EndWith
	EndProcedure
	
	Procedure _SetGadgetColor(*this.Gadget, ColorType, Color)
		Protected *CustomGadget.CustomGadget=*this\vt
		With *CustomGadget
			Select ColorType
				Case #PB_Gadget_LineColor : \LineColor=Color
				Case #PB_Gadget_BackColor : \BackColor=Color
				Case #PB_Gadget_FrontColor : \FrontColor=Color
			EndSelect
			DrawCustomGadget(*this)
		EndWith
	EndProcedure
	
	Procedure.i _GetGadgetState(*this.Gadget)
		Protected *CustomGadget.CustomGadget=*this\vt
		With *CustomGadget
			ProcedureReturn \State
		EndWith
	EndProcedure
	
	Procedure _SetGadgetState(*this.Gadget, State.i)
		Protected *CustomGadget.CustomGadget=*this\vt
		With *CustomGadget
			Protected max
			If (\Flags & #SplitBar_Vertical) : max=\w : Else : max=\h : EndIf
			If (\CurrentStatus & #SplitBar_IsDragged)
				;Snapped bar constraints
				If \SnapDistance>0
					\CurrentStatus & ~#SplitBar_IsSnapped
					If \StatePercent>=0 And State<\SnapDistance : State=0 : \CurrentStatus | #SplitBar_IsSnapped : EndIf
					If \StatePercent<0 And State>-\SnapDistance : State=0 : \CurrentStatus | #SplitBar_IsSnapped : EndIf
				EndIf
				;Dragged bar constraints
				If \StatePercent>=0
					If State<1 : State=0 : EndIf
					If State>(max-\Thickness) : State=(max-\Thickness) : EndIf
				Else
					If State>-1 : State=0 : EndIf
					If State<-(max-\Thickness) : State=-(max-\Thickness) : EndIf
				EndIf
			EndIf
			
			If State
				\State=State
				\StatePercent=1e-14*Sign(State)
				If max : \StatePercent=\State / max : EndIf
			Else
				\State=1e-14*Sign(\StatePercent)
				\StatePercent=1e-14*Sign(\StatePercent)
			EndIf
			
			_ResizeGadget(*this, #PB_Ignore, #PB_Ignore, #PB_Ignore, #PB_Ignore)
		EndWith
	EndProcedure
	
	Procedure _SetGadgetAttribute(*this.Gadget, Attribute, Value)
		Protected *CustomGadget.CustomGadget=*this\vt
		With *CustomGadget
			Select Attribute
				Case 0 To 1024
					;Set original gadget attribute
					UseCustomGadget(*this, 0)
					SetGadgetAttribute(\Gadget, Attribute, Value)
					UseCustomGadget(*this, 1)
				Case #SplitBar_CurrentFlags : \Flags=Value
				Case #SplitBar_CurrentThickness : \Thickness=Value
				Case #SplitBar_CurrentFirstGadget : \Gadget1=Value
				Case #SplitBar_CurrentSecondGadget : \Gadget2=Value
				Case #SplitBar_CurrentSnapDistance : \SnapDistance=Abs(Value)
				Case #SplitBar_CurrentFirstMinSize : \FirstMinSize=Abs(Value)
				Case #SplitBar_CurrentSecondMinSize : \SecondMinSize=Abs(Value)
				Case #SplitBar_CurrentDrawingFunction : \DrawingFunction=Value
			EndSelect
			_ResizeGadget(*this, #PB_Ignore, #PB_Ignore, #PB_Ignore, #PB_Ignore)
		EndWith
	EndProcedure
	
	Procedure.i _GetGadgetAttribute(*this.Gadget, Attribute)
		Protected *CustomGadget.CustomGadget=*this\vt, result
		With *CustomGadget
			Select Attribute
				Case 0 To 1024
					;Get original gadget attribute
					UseCustomGadget(*this, 0)
					result=GetGadgetAttribute(\Gadget, Attribute)
					UseCustomGadget(*this, 1)
				Case #SplitBar_CurrentFlags : result=\Flags
				Case #SplitBar_CurrentStatus : result=\CurrentStatus
				Case #SplitBar_CurrentThickness : result=\Thickness
				Case #SplitBar_CurrentFirstGadget : result=\Gadget1
				Case #SplitBar_CurrentSecondGadget : result=\Gadget2
				Case #SplitBar_CurrentSnapDistance : result=\SnapDistance
				Case #SplitBar_CurrentFirstMinSize : result=\FirstMinSize
				Case #SplitBar_CurrentSecondMinSize : result=\SecondMinSize
				Case #SplitBar_CurrentDrawingFunction : result=\DrawingFunction
			EndSelect
			ProcedureReturn result
		EndWith
	EndProcedure
	
	Procedure _FreeGadget(*this.Gadget)
		Protected *CustomGadget.CustomGadget=*this\vt
		With *CustomGadget
			FreeCustomGadget(*this)
		EndWith
	EndProcedure
	
	Procedure CustomGadgetEvents()
		Protected t=EventType()
		Protected g=EventGadget()
		Protected *this.Gadget=IsGadget(g)
		Protected *CustomGadget.CustomGadget=*this\vt
		With *CustomGadget
			If (\Flags & #SplitBar_Locked)=0
				;ignore some custom events
				Select t
					Case #PB_EventType_Change
						ProcedureReturn
				EndSelect
				;handle some custom events
				Protected win=EventWindow()
				Protected mx=_GetGadgetAttribute(*this, #PB_Canvas_MouseX)
				Protected my=_GetGadgetAttribute(*this, #PB_Canvas_MouseY)
				Protected oldStatus=\CurrentStatus, oldState=\State
				Select t
					Case #PB_EventType_MouseEnter
						\CurrentStatus | #SplitBar_IsHighlighted
						DrawCustomGadget(*this)
					Case #PB_EventType_MouseLeave
						\CurrentStatus & ~#SplitBar_IsHighlighted
						DrawCustomGadget(*this)
						
					Case #PB_EventType_LeftButtonDown
						If CustomContext\DraggedGadget=0
							CustomContext\DraggedGadget=*CustomGadget
							CustomContext\DragStartPos=\State
							\CurrentStatus | #SplitBar_IsDragged
							\DragOffsetX=mx
							\DragOffsetY=my
						EndIf
					Case #PB_EventType_LeftButtonUp, #PB_EventType_LeftDoubleClick
						If CustomContext\DraggedGadget
							CustomContext\DraggedGadget=0
							\CurrentStatus & ~#SplitBar_IsDragged
						EndIf
						
					Case #PB_EventType_MouseMove
						If (\CurrentStatus & #SplitBar_IsDragged)
							If (\Flags & #SplitBar_Vertical)
								If mx<>\DragOffsetX : _SetGadgetState(*this, \State + (mx+\DragOffsetX)) : EndIf
							Else
								If my<>\DragOffsetY : _SetGadgetState(*this, \State + (my-\DragOffsetY)) : EndIf
							EndIf
						EndIf
						If (\Flags & #SplitBar_Vertical)
							_SetGadgetAttribute(*this, #PB_Canvas_Cursor, #PB_Cursor_LeftRight)
						Else
							_SetGadgetAttribute(*this, #PB_Canvas_Cursor, #PB_Cursor_UpDown)
						EndIf
				EndSelect
				;post some custom events (new supported events)
				If t<>#PB_EventType_MouseMove And (oldStatus<>\CurrentStatus Or oldState<>\State)
					PostEvent(#PB_Event_Gadget, win, \Gadget, #PB_EventType_Change, \CurrentStatus)
				EndIf
			EndIf
		EndWith
	EndProcedure
	
	Procedure UseCustomGadget(*this.Gadget, isCustom)
		Protected *CustomGadget.CustomGadget=*this\vt
		Protected vtOld.GadgetVT     
		If Bool(isCustom)<>*CustomGadget\isCustom
			;swap custom gadgetVT and original gadgetVT
			vtOld=*CustomGadget\vtOld
			*CustomGadget\vtOld=*CustomGadget\vt
			*CustomGadget\vt=vtOld
			*CustomGadget\isCustom=Bool(isCustom)
		EndIf
	EndProcedure
	
	Procedure DrawCustomGadget(*this.Gadget)
		Protected *CustomGadget.CustomGadget=*this\vt
		With *CustomGadget
			If \DrawingFunction
				CallFunctionFast(\DrawingFunction, \Gadget)
				ProcedureReturn
			EndIf
			
			StartDrawing(CanvasOutput(\Gadget))
			Protected color
			If \CurrentStatus & #SplitBar_IsHighlighted
				color=\FrontColor
			Else
				color=\BackColor
			EndIf
			;draw bar
			Box(0, 0, \w, \h, color)
			;draw grip (if enabled)
			If \Flags & #SplitBar_Grip
				Protected i, x, y
				If \Flags & #SplitBar_Vertical
					x=0.5*\Thickness -1
					y=0.5*\h -7
					For i=0 To 12 Step 4
						Box(x, y + i, 2, 2, \LineColor)
					Next
				Else
					x=0.5*\w -7
					y=0.5*\Thickness -1
					For i=0 To 12 Step 4
						Box(x + i, y, 2, 2, \LineColor)
					Next
				EndIf
			EndIf
			StopDrawing()
		EndWith
	EndProcedure
	
	Procedure FreeCustomGadget(*this.Gadget)
		;find custom gadget data
		Protected *CustomGadget.CustomGadget=FindMapElement(CustomGadget(), "ID-" + *this\Gadget)
		With *CustomGadget
			If *CustomGadget
				;free original gadget
				UseCustomGadget(*this, 0)
				FreeGadget(\Gadget)
				;delete custom gadget data
				DeleteMapElement(CustomGadget())
			EndIf
		EndWith
	EndProcedure
	
	Procedure.i NewCustomGadget(*this.Gadget)
		;create custom gadget data
		Protected *CustomGadget.CustomGadget=AddMapElement(CustomGadget(), "ID-" + *this\Gadget)
		If *CustomGadget
			*CustomGadget\isCustom=1
			CopyMemory(*this\vt, *CustomGadget\vtOld, SizeOf(GadgetVT))
			CopyMemory(*this\vt, *CustomGadget\vt, SizeOf(GadgetVT))
			With *CustomGadget\vt
				;define mandatory custom method
				\FreeGadget=@_FreeGadget()
				
				;define other custom methods
				\ResizeGadget=@_ResizeGadget()
				\GetGadgetState=@_GetGadgetState()
				\SetGadgetState=@_SetGadgetState()
				\GetGadgetColor=@_GetGadgetColor()
				\SetGadgetColor=@_SetGadgetColor()
				\GetGadgetAttribute=@_GetGadgetAttribute()
				\SetGadgetAttribute=@_SetGadgetAttribute()           
			EndWith
			
			*this\vt=*CustomGadget              ;apply custom gadgetVT
		EndIf
		ProcedureReturn *CustomGadget
	EndProcedure
	
	Procedure.i SplitBarGadget(Gadget, x, y, Width, Height, Gadget1=0, Gadget2=0, Flags=#SplitBar_Default, Thickness=6)
		Protected result=CanvasGadget(Gadget, x, y, Width, Height)
		If result=0 : ProcedureReturn #False : EndIf
		If Gadget=#PB_Any : Gadget=result : EndIf
		Protected *this.Gadget=IsGadget(Gadget)
		Protected *CustomGadget.CustomGadget=NewCustomGadget(*this)
		
		With *CustomGadget
			;define custom properties
			\x=x : \y=y : \w=Width : \h=Height
			\Gadget=Gadget
			\Gadget1=Gadget1
			\Gadget2=Gadget2
			\BackColor=#White
			\FrontColor=$DDDDDD
			\LineColor=#Gray
			\Flags=Flags
			\Thickness=Thickness
			If (\Flags & #SplitBar_Vertical)
				_SetGadgetState(*this, \w / 2-\Thickness / 2)
			Else
				_SetGadgetState(*this, \h / 2-\Thickness / 2)
			EndIf
			
			;define custom events
			BindGadgetEvent(Gadget, @CustomGadgetEvents())
		EndWith
		ProcedureReturn result
	EndProcedure
EndModule
Post Reply