Page 1 of 1

SplitterGadget+ dashed bar, border snap, thickness,grip,swap

Posted: Thu Aug 29, 2013 6:51 am
by eddy
  • Customizations supported
    - grip size(disable If 0)
    - bar thickness
    - grip images
    - border snapping distances (disable If 0)
    - enable auto snapping by double-click(disable If #False)
    - lock splitter bar(unlock If #False)
  • Methods
    -SwapSplitter : Swap gadgets with options
    -SplitterLocked : returns #True If the splitter is locked
    -SplitterSnapped : returns 1 or 2 if left or right boder snapped (returns 0 if none of them)
  • Events supported:
    -event type: #PB_EventType_LeftDoubleClick
    -event type: #PB_EventType_Change

Code: Select all

;:=============================================================================
;:- SplitterPlus.pbi
;:- Author          : Eddy
;:- Date            : August 29, 2013
;:- Compiler        : PureBasic 5.20 LTS
;:- Target OS       : Windows
;:- Source --------------------------------------------------------------------
;:- http://www.purebasic.fr/english/viewtopic.php?f=40&t=56290
;:=============================================================================
EnableExplicit

Enumeration
   ;splitter gadget events (for internal use)
   #WM_SPLITTER_POSITION_GRIP_AND_GADGETS=#WM_USER
   #WM_SPLITTER_REDRAW_GRIP_IMAGES
   #WM_SPLITTER_CHECK_GRIP_FOCUS
   #WM_SPLITTER_CHECK_LINE_CAPTURE
   #WM_SPLITTER_UPDATE_GRIP_FOCUS
   #WM_SPLITTER_UPDATE_GRIP_CURSOR
   #WM_SPLITTER_UPDATE_SNAP_ZONE
   #WM_SPLITTER_UPDATE_UNSNAPPOS
   #WM_SPLITTER_POSTEVENT_CHANGE
   #WM_SPLITTER_POSTEVENT_DBLCLICK
   #WM_SPLITTER_RELEASE_SPLITBAR_CAPTURE
   #WM_SPLITTER_MOVE_SPLITBAR
   
   ;dashed bar events (for internal use)
   #WM_SPLITTER_RELEASE_LINE_CAPTURE
   #WM_SPLITTER_MOVE_LINE
   #WM_SPLITTER_SHOW_LINE
   #WM_SPLITTER_HIDE_LINE
   #WM_SPLITTER_UPDATE_LINE_CURSOR
EndEnumeration

Procedure SplitterCustomCallback(hWnd, message, wParam, lParam)
   Static cursorArrow, cursorV, cursorH
   If cursorArrow=0
      cursorArrow=LoadCursor_(0, #IDC_ARROW)
      cursorV=LoadCursor_(0, #IDC_SIZENS)
      cursorH=LoadCursor_(0, #IDC_SIZEWE)
   EndIf
   
   If GetProp_(hWnd, "PurebasicCustomSplitterCB")
      Protected Splitter=GetProp_(hWnd, "PB_ID")
      Protected *SplitterID=GadgetID(Splitter)
      
      ;{ Get parameters
      Protected a=GetGadgetAttribute(Splitter, #PB_Splitter_FirstGadget)
      Protected b=GetGadgetAttribute(Splitter, #PB_Splitter_SecondGadget)
      Protected verticalBar=GetProp_(*SplitterID, "VerticalBar")
      Protected grip=GetProp_(*SplitterID, "Grip")
      Protected gripVisible=GetProp_(*SplitterID, "GripVisible")
      Protected gripWidth=GetProp_(*SplitterID, "GripWidth")
      Protected gripFocus=GetProp_(*SplitterID, "GripFocus")
      Protected gripNormal=GetProp_(*SplitterID, "GripNormal")
      Protected thickness=GetProp_(*SplitterID, "Thickness")
      Protected snapFirst=GetProp_(*SplitterID, "SnapFirst")
      Protected snapSecond=GetProp_(*SplitterID, "SnapSecond")
      Protected dblClickToSnap=GetProp_(*SplitterID, "DblClickToSnap")
      Protected locked=GetProp_(*SplitterID, "Locked")
      Protected focused=GetProp_(*SplitterID, "Focused")
      Protected *snap.RECT=GetProp_(*SplitterID, "Snap")
      Protected *limit.RECT=GetProp_(*SplitterID, "Limit")
      Protected lastPos=GetProp_(*SplitterID, "LastPos")
      Protected parentWindow=GetProp_(GetAncestor_(*SplitterID, #GA_ROOT), "PB_WindowID")-1
      Protected lx=GadgetX(Splitter, #PB_Gadget_ScreenCoordinate)
      Protected ly=GadgetY(Splitter, #PB_Gadget_ScreenCoordinate)
      Protected line=GetProp_(*SplitterID, "Line")
      If IsWindow(line) : Protected *lineID=WindowID(line) : EndIf
      ;}
      
      If locked
         Select message
            Case #WM_MOUSEMOVE, #WM_LBUTTONDOWN, #WM_LBUTTONUP, #WM_LBUTTONDBLCLK
               ;{ Locked splitter
               SetCursor_(cursorArrow) ;default cursor
               ProcedureReturn 1       ;disable normal behaviour
                                       ;}
         EndSelect
      EndIf
      
      If gripVisible
         Select message
            Case #WM_SPLITTER_POSITION_GRIP_AND_GADGETS
               ;{ Position grip and gadgets
               If verticalBar
                  Protected x=GadgetWidth(a) + thickness
                  ResizeGadget(b, x, #PB_Ignore, GadgetWidth(Splitter)-x, #PB_Ignore)
                  ResizeGadget(grip, GetGadgetState(Splitter), (GadgetHeight(Splitter)-gripWidth) / 2, #PB_Ignore, #PB_Ignore)
               Else
                  Protected y=GadgetHeight(a) + thickness
                  ResizeGadget(b, #PB_Ignore, y, #PB_Ignore, GadgetHeight(Splitter)-y)
                  ResizeGadget(grip, (GadgetWidth(Splitter)-gripWidth) / 2, GetGadgetState(Splitter), #PB_Ignore, #PB_Ignore)
               EndIf
               ;}
               
            Case #WM_SPLITTER_REDRAW_GRIP_IMAGES
               ;{ Redraw grip images
               Protected gripImage=wParam
               If StartDrawing(ImageOutput(gripImage))
                  Protected dot
                  Protected f1=RGB(189, 204, 254)
                  Protected f2=GetSysColor_(#COLOR_BTNFACE)
                  Protected c1=GetSysColor_(#COLOR_BTNSHADOW)
                  Protected c2=GetSysColor_(#COLOR_BTNHILIGHT)
                  Protected w=ImageWidth(gripImage)
                  Protected h=ImageHeight(gripImage)
                  
                  ;background rectangle
                  If gripImage=gripFocus
                     Box(0, 0, w, h, f1)
                  Else
                     Box(0, 0, w, h, f2)
                  EndIf
                  
                  If verticalBar
                     ;borders
                     Line(0, 0, w, 1, c1)
                     Line(0, 1, w, 1, c2)
                     Line(0, h-2, w, 1, c1)
                     Line(0, h-1, w, 1, c2)
                     
                     ;dots
                     For dot=10 To h-10 Step 3
                        Line(w / 2-1, dot, 2, 1, c1)
                     Next
                  Else
                     ;borders
                     Line(0, 0, 1, h, c1)
                     Line(1, 0, 1, h, c2)
                     Line(w-2, 0, 1, h, c1)
                     Line(w-1, 0, 1, h, c2)
                     
                     ;dots
                     For dot=10 To w-10 Step 3
                        Line(dot, h / 2-1, 1, 2, c1)
                        Line(dot, h / 2 + 1, 1, 1, c2)
                     Next
                  EndIf
                  StopDrawing()
               EndIf
               ;}
               
            Case #WM_SPLITTER_CHECK_GRIP_FOCUS
               ;{ Check if grip has focus
               If DesktopMouseX()>=GadgetX(grip, #PB_Gadget_ScreenCoordinate) And
                  DesktopMouseX()<(GadgetX(grip, #PB_Gadget_ScreenCoordinate) + GadgetWidth(grip)) And
                  DesktopMouseY()>=GadgetY(grip, #PB_Gadget_ScreenCoordinate) And
                  DesktopMouseY()<(GadgetY(grip, #PB_Gadget_ScreenCoordinate) + GadgetHeight(grip))
                  If focused=0
                     SetProp_(*SplitterID, "Focused", 1)
                     ;use timer to check grip automaticly
                     SetTimer_(*SplitterID, 2000, 100, 0)
                     SendMessage_(*SplitterID, #WM_SPLITTER_UPDATE_GRIP_FOCUS, 0, 0)
                  EndIf
               Else
                  If focused=1
                     SetProp_(*SplitterID, "Focused", 0)
                     ;stop grip checking (because mouse pointer is out of area)
                     KillTimer_(*SplitterID, 2000)
                     SendMessage_(*SplitterID, #WM_SPLITTER_UPDATE_GRIP_FOCUS, 0, 0)
                  EndIf
               EndIf
               ;}
               
            Case #WM_SPLITTER_UPDATE_GRIP_FOCUS
               ;{ Show or Hide grip focus
               If focused
                  If GetGadgetState(grip)<>ImageID(gripFocus)
                     SetGadgetState(grip, ImageID(gripFocus))
                  EndIf
               Else
                  If GetGadgetState(grip)<>ImageID(gripNormal)
                     SetGadgetState(grip, ImageID(gripNormal))
                  EndIf
               EndIf
               ;}
               
            Case #WM_SPLITTER_UPDATE_GRIP_CURSOR
               ;{ Show cursor if grip focused or not
               If Not focused
                  SetCursor_(cursorArrow)
               ElseIf verticalBar
                  SetCursor_(cursorH)
               Else
                  SetCursor_(cursorV)
               EndIf
               ;}
         EndSelect
      Else
         Select message
            Case #WM_SPLITTER_RELEASE_SPLITBAR_CAPTURE
               ;{ Release splitter bar (and snap it if possible)
               If GetCapture_()=*SplitterID
                  If GetProp_(*lineID, "LineVisible")
                     SendMessage_(*lineID, #WM_SPLITTER_RELEASE_LINE_CAPTURE, 0, 0)
                  Else
                     SendMessage_(*SplitterID, #WM_SPLITTER_UPDATE_UNSNAPPOS, 0, GetGadgetState(Splitter))
                     PostMessage_(*SplitterID, #WM_SPLITTER_POSTEVENT_CHANGE, 0, 0)
                  EndIf
               EndIf
               ;}
               
            Case #WM_SPLITTER_MOVE_SPLITBAR
               ;{ Move splitter bar
               If GetCapture_()=*SplitterID
                  Protected Hide.b=1
                  
                  ;snap auto
                  If verticalBar
                     x=GetGadgetState(Splitter)
                     If x<*snap\Left : x=*limit\Left : Hide=0 : EndIf
                     If x>*snap\Right : x=*limit\Right : Hide=0 : EndIf
                     ResizeWindow(line, lx + x, #PB_Ignore, #PB_Ignore, #PB_Ignore)
                  Else
                     y=GetGadgetState(Splitter)
                     If y<*snap\Top : y=*limit\Top : Hide=0 : EndIf
                     If y>*snap\Bottom : y=*limit\Bottom : Hide=0 : EndIf
                     ResizeWindow(line, #PB_Ignore, ly + y, #PB_Ignore, #PB_Ignore)
                  EndIf
                  
                  ;show or hide snap position preview
                  If Hide
                     If GetProp_(*lineID, "LineVisible")
                        PostMessage_(*lineID, #WM_SPLITTER_HIDE_LINE, 0, 0)
                     EndIf
                  Else
                     If GetProp_(*lineID, "LineVisible")=0
                        PostMessage_(*lineID, #WM_SPLITTER_SHOW_LINE, 0, 0)
                     EndIf
                  EndIf
               EndIf
               ;}
               
         EndSelect
         
      EndIf
      
      Select message
         Case #WM_SPLITTER_CHECK_LINE_CAPTURE
            ;{ Position line and drag line if possible
            SetProp_(*SplitterID, "LastPos", GetGadgetState(Splitter))
            
            SetProp_(*lineID, "Splitter", Splitter)
            If verticalBar
               SetProp_(*lineID, "LineDragX", DesktopMouseX())
               ResizeWindow(line, lx + GetGadgetState(Splitter), ly, Thickness, GadgetHeight(Splitter))
            Else
               SetProp_(*lineID, "LineDragY", DesktopMouseY())
               ResizeWindow(line, lx, ly + GetGadgetState(Splitter), GadgetWidth(Splitter), Thickness)
            EndIf
            
            If gripVisible
               If GetProp_(*lineID, "LineVisible")=0 And focused
                  SendMessage_(*lineID, #WM_SPLITTER_SHOW_LINE, 0, 0)
                  SetCapture_(*lineID)
               EndIf
               ProcedureReturn 1
            Else
               If GetProp_(*lineID, "LineVisible")=0
                  SendMessage_(*lineID, #WM_SPLITTER_SHOW_LINE, 0, 0)
               EndIf
            EndIf
            ;}
            
         Case #WM_SPLITTER_UPDATE_SNAP_ZONE
            ;{ Update splitterbar limit and snap area
            *limit\Left=GetGadgetAttribute(Splitter, #PB_Splitter_FirstMinimumSize)
            *limit\Top=GetGadgetAttribute(Splitter, #PB_Splitter_FirstMinimumSize)
            *limit\Right=GadgetWidth(Splitter)-thickness-GetGadgetAttribute(Splitter, #PB_Splitter_SecondMinimumSize)
            *limit\Bottom=GadgetHeight(Splitter)-thickness-GetGadgetAttribute(Splitter, #PB_Splitter_SecondMinimumSize)
            
            CopyStructure(*limit, *snap, RECT)
            *snap\Left + snapFirst
            *snap\Top + snapFirst
            *snap\Right-snapSecond
            *snap\Bottom-snapSecond
            ;}
            
         Case #WM_SPLITTER_UPDATE_UNSNAPPOS
            ;{ Update unsnap position
            Protected LinePos=lParam
            If verticalBar
               If (LinePos=*Limit\Right Or LinePos=*Limit\Left) And LinePos<>lastPos
                  SetProp_(*SplitterID, "UnsnapPos", lastPos)
               EndIf
            Else
               If (LinePos=*Limit\top Or LinePos=*Limit\right) And LinePos<>lastPos
                  SetProp_(*SplitterID, "UnsnapPos", lastPos)
               EndIf
            EndIf
            ;}
            
         Case #WM_SPLITTER_POSTEVENT_CHANGE
            ;{ Event CHANGE
            PostEvent(#PB_Event_Gadget, parentWindow, Splitter, #PB_EventType_Change)
            ;}
            
         Case #WM_SPLITTER_POSTEVENT_DBLCLICK
            ;{ Event DBLCLICK
            PostEvent(#PB_Event_Gadget, parentWindow, Splitter, #PB_EventType_LeftDoubleClick)
            ;}
            
      EndSelect
      
      Select message
         Case #WM_DESTROY
            FreeMemory(*snap)
            FreeMemory(*limit)
            FreeGadget(grip)
            FreeImage(gripFocus)
            FreeImage(gripNormal)
            
         Case #WM_PAINT
            PostMessage_(*SplitterID, #WM_SPLITTER_POSITION_GRIP_AND_GADGETS, 0, 0)
            PostMessage_(*SplitterID, #WM_SPLITTER_UPDATE_GRIP_FOCUS, 0, 0)
            
         Case #WM_LBUTTONDOWN
            SendMessage_(*SplitterID, #WM_SPLITTER_UPDATE_GRIP_CURSOR, 0, 0)
            SendMessage_(*SplitterID, #WM_SPLITTER_UPDATE_SNAP_ZONE, 0, 0)
            If SendMessage_(*SplitterID, #WM_SPLITTER_CHECK_LINE_CAPTURE, 0, 0)
               ProcedureReturn 1
            EndIf
            
         Case #WM_MOUSEMOVE
            SendMessage_(*SplitterID, #WM_SPLITTER_UPDATE_GRIP_CURSOR, 0, 0)
            SendMessage_(*SplitterID, #WM_SPLITTER_MOVE_SPLITBAR, 0, 0)
            SendMessage_(*SplitterID, #WM_SPLITTER_CHECK_GRIP_FOCUS, 0, 0)
            
         Case #WM_LBUTTONUP
            SendMessage_(*SplitterID, #WM_SPLITTER_UPDATE_GRIP_CURSOR, 0, 0)
            SendMessage_(*SplitterID, #WM_SPLITTER_RELEASE_SPLITBAR_CAPTURE, 0, 0)
            
         Case #WM_LBUTTONDBLCLK
            SendMessage_(*SplitterID, #WM_SPLITTER_UPDATE_GRIP_CURSOR, 0, 0)
            
            Protected Pos=lastPos
            Protected SnapAction$=""
            Protected Snap1, Snap2
            
            If verticalBar
               Snap1=*Limit\Left
               Snap2=*Limit\Right
            Else
               Snap1=*Limit\Top
               Snap2=*Limit\Bottom
            EndIf
            
            ;fix pixel slide
            If gripVisible=0 And Abs(Pos-Snap1)<2 : Pos=Snap1 : EndIf
            If gripVisible=0 And Abs(Pos-Snap2)<2 : Pos=Snap2 : EndIf
            
            ;determine snap action
            If gripVisible And Not focused
               SnapAction$=""
            ElseIf(Pos=Snap1 Or Pos=Snap2)
               SnapAction$="UNSNAP_ACTION"
            Else
               SnapAction$="SNAP_ACTION"
            EndIf
            
            Select SnapAction$
               Case "SNAP_ACTION"
                  Select dblClickToSnap
                     Case 1
                        SetGadgetState(Splitter, Snap1)
                        SetProp_(*SplitterID, "Focused", 0)
                        SetProp_(*SplitterID, "UnsnapPos", lastPos)
                     Case 2
                        SetGadgetState(Splitter, Snap2)
                        SetProp_(*SplitterID, "Focused", 0)
                        SetProp_(*SplitterID, "UnsnapPos", lastPos)
                     Default
                  EndSelect
               Case "UNSNAP_ACTION"
                  PostMessage_(*lineID, #WM_SPLITTER_HIDE_LINE, 0, 0)
                  SetGadgetState(Splitter, GetProp_(*SplitterID, "UnsnapPos"))
                  SetProp_(*SplitterID, "Focused", 0)
            EndSelect
            
            PostMessage_(*SplitterID, #WM_SPLITTER_POSTEVENT_CHANGE, 0, 0)
            PostMessage_(*SplitterID, #WM_SPLITTER_POSTEVENT_DBLCLICK, 0, 0)
            
         Case #WM_TIMER
            SendMessage_(*SplitterID, #WM_SPLITTER_CHECK_GRIP_FOCUS, 0, 0)
      EndSelect
      
      ProcedureReturn CallWindowProc_(GetProp_(hWnd, "PurebasicCustomSplitterCB"), hWnd, message, wParam, lParam)
   EndIf
   
   If GetProp_(hWnd, "PurebasicCustomSplitterLineCB")
      line=GetProp_(hWnd, "PB_WindowID")-1
      *lineID=WindowID(line)
      Splitter=GetProp_(*lineID, "Splitter")
      If IsGadget(Splitter)
         *SplitterID=GadgetID(Splitter)
         verticalBar=GetProp_(*SplitterID, "VerticalBar")
         thickness=GetProp_(*SplitterID, "Thickness")
         lx=GadgetX(Splitter, #PB_Gadget_ScreenCoordinate)
         ly=GadgetY(Splitter, #PB_Gadget_ScreenCoordinate)
      EndIf
      
      Select message
         Case #WM_SPLITTER_UPDATE_LINE_CURSOR
            ;{ Show cursor (for vertical or horizontal scrolling)
            If verticalBar
               SetCursor_(cursorH)
            Else
               SetCursor_(cursorV)
            EndIf
            ;}
            
         Case #WM_SPLITTER_SHOW_LINE
            ;{ Show line (transparency, resize)
            SetProp_(*lineID, "LineVisible", 1)
            SetLayeredWindowAttributes_(*lineID, 0, GetProp_(*lineID, "LineAlpha"), #LWA_ALPHA)
            If verticalBar
               ResizeWindow(Line, #PB_Ignore, #PB_Ignore, Thickness, GadgetHeight(Splitter))
            Else
               ResizeWindow(Line, #PB_Ignore, #PB_Ignore, GadgetWidth(Splitter), Thickness)
            EndIf
            ;}
            
         Case #WM_SPLITTER_HIDE_LINE
            ;{ Hide line (full transparency, no size)
            SetProp_(*lineID, "LineVisible", 0)
            SetLayeredWindowAttributes_(*lineID, 0, 0, #LWA_ALPHA)
            ResizeWindow(line, #PB_Ignore, #PB_Ignore, 0, 0)
            ;}
            
         Case #WM_SPLITTER_MOVE_LINE
            ;{ Move line
            *snap.RECT=GetProp_(*SplitterID, "Snap")
            *limit.RECT=GetProp_(*SplitterID, "Limit")
            
            If verticalBar
               x=(GetGadgetState(Splitter)) + (DesktopMouseX()-GetProp_(*lineID, "LineDragX"))
               ;snap auto
               If x<*snap\Left : x=*limit\Left : EndIf
               If x>*snap\Right : x=*limit\Right : EndIf
               ;move limits
               If x<*limit\Left : x=*limit\Left : EndIf
               If x>*limit\Right : x=*limit\Right : EndIf
               
               ResizeWindow(Line, lx + x, #PB_Ignore, #PB_Ignore, #PB_Ignore)
            Else
               y=(GetGadgetState(Splitter)) + (DesktopMouseY()-GetProp_(*lineID, "LineDragY"))
               ;snap auto
               If y<*snap\Top : y=*limit\Top : EndIf
               If y>*snap\Bottom : y=*limit\Bottom : EndIf
               ;move limits
               If y<*limit\Top : y=*limit\Top : EndIf
               If y>*limit\Bottom : y=*limit\Bottom : EndIf
               
               ResizeWindow(Line, #PB_Ignore, ly + y, #PB_Ignore, #PB_Ignore)
            EndIf
            ;}
            
         Case #WM_SPLITTER_RELEASE_LINE_CAPTURE
            ;{ Release line capture
            If GetProp_(*lineID, "LineVisible")
               If verticalBar
                  LinePos=WindowX(Line)-GadgetX(Splitter, #PB_Gadget_ScreenCoordinate)
               Else
                  LinePos=WindowY(Line)-GadgetY(Splitter, #PB_Gadget_ScreenCoordinate)
               EndIf
               
               PostMessage_(*lineID, #WM_SPLITTER_HIDE_LINE, 0, 0)
               PostMessage_(*SplitterID, #WM_SPLITTER_UPDATE_UNSNAPPOS, 0, LinePos)
               SetGadgetState(Splitter, LinePos)
               
               PostMessage_(*SplitterID, #WM_SPLITTER_POSTEVENT_CHANGE, 0, 0)
            EndIf
            ;release captured line
            ReleaseCapture_()
            ;}
            
         Case #WM_MOUSEMOVE
            PostMessage_(*lineID, #WM_SPLITTER_MOVE_LINE, 0, 0)
            PostMessage_(*lineID, #WM_SPLITTER_UPDATE_LINE_CURSOR, 0, 0)
            
         Case #WM_LBUTTONUP
            PostMessage_(*lineID, #WM_SPLITTER_RELEASE_LINE_CAPTURE, 0, 0)
            
      EndSelect
      
      ProcedureReturn CallWindowProc_(GetProp_(hWnd, "PurebasicCustomSplitterLineCB"), hWnd, message, wParam, lParam)
   EndIf
   
EndProcedure

Procedure SetSplitterEffects(Splitter, Thickness=8, GripWidth=100, SnapFirst=100, SnapSecond=100, DblClickToSnap=1, Locked=#False)
   Protected *SplitterID=GadgetID(Splitter)
   
   Static line
   If Not line
      Protected colorRGBA=$1E000000
      
      ;create line windows
      Protected parent=OpenWindow(#PB_Any, 0, 0, 0, 0, "", #PB_Window_NoGadgets | #PB_Window_Invisible | #PB_Window_NoActivate)
      line=OpenWindow(#PB_Any, 0, 0, 0, 0, "", #PB_Window_NoGadgets | #PB_Window_Invisible | #PB_Window_BorderLess, WindowID(parent))
      SetWindowColor(line, RGB(Red(colorRGBA), Green(colorRGBA), Blue(colorRGBA)))
      DisableWindow(line, 1)
      StickyWindow(line, 1)
      HideWindow(line, 0, #PB_Window_NoActivate)
      
      ;enable transparent fx
      Protected *lineID=WindowID(line)
      SetWindowLongPtr_(*lineID, #GWL_EXSTYLE, GetWindowLongPtr_(*lineID, #GWL_EXSTYLE) | #WS_EX_LAYERED)
      SetLayeredWindowAttributes_(*lineID, 0, Alpha(colorRGBA), #LWA_ALPHA)
      SetProp_(*lineID, "LineAlpha", Alpha(colorRGBA))
      
      ;enable line custom effects
      SetProp_(*lineID, "PurebasicCustomSplitterLineCB", SetWindowLong_(*lineID, #GWL_WNDPROC, @SplitterCustomCallback()))
   EndIf
   
   If GetProp_(*SplitterID, "PurebasicCustomSplitterCB")=0
      ;enable double-click detection
      SetClassLongPtr_(*SplitterID, #GCL_STYLE, GetClassLongPtr_(*SplitterID, #GCL_STYLE) | #CS_DBLCLKS)
      
      ;enable splitter custom effects
      SetProp_(*SplitterID, "PurebasicCustomSplitterCB", SetWindowLong_(*SplitterID, #GWL_WNDPROC, @SplitterCustomCallback()))
      
      ;init snapping
      Protected *snap.RECT=AllocateMemory(SizeOf(RECT))
      Protected *limit.RECT=AllocateMemory(SizeOf(RECT))
      SetProp_(*SplitterID, "Snap", *snap)
      SetProp_(*SplitterID, "Limit", *limit)
      SetProp_(*SplitterID, "Line", line)
      
      ;init grip images and gadget
      Protected previousGadgetList=UseGadgetList(*SplitterID)
      If previousGadgetList
         Protected gripNormal=CreateImage(#PB_Any, 2, 2, 32, RGB(255, 0, 0))
         Protected gripFocus=CreateImage(#PB_Any, 2, 2, 32, RGB(255, 0, 0))
         Protected grip=ImageGadget(#PB_Any, 0, 0, 0, 0, 0)
         HideGadget(grip, 1)
         DisableGadget(grip, 1)
         UseGadgetList(previousGadgetList)
         SetProp_(*SplitterID, "GripNormal", gripNormal)
         SetProp_(*SplitterID, "GripFocus", gripFocus)
         SetProp_(*SplitterID, "Grip", grip)
      EndIf
      
      ;init orientation and default thickness
      Protected a=GetGadgetAttribute(Splitter, #PB_Splitter_FirstGadget)
      Protected b=GetGadgetAttribute(Splitter, #PB_Splitter_SecondGadget)
      Protected verticalBar=Bool(GadgetX(b)<>GadgetX(a))
      Protected defaultThickness=Bool(verticalBar=1)*Abs(GadgetX(b)-GadgetX(a)-GadgetWidth(a)) + Bool(verticalBar=0)*Abs(GadgetY(b)-GadgetY(a)-GadgetHeight(a))
      Debug defaultThickness
      SetProp_(*SplitterID, "VerticalBar", verticalBar)
      SetProp_(*SplitterID, "Thickness", defaultThickness)
      SetProp_(*SplitterID, "DefaultThickness", defaultThickness)
   EndIf
   
   ;save splitter parameters
   If DblClickToSnap<>#PB_Ignore
      SetProp_(*SplitterID, "DblClickToSnap", DblClickToSnap)
   EndIf
   If SnapFirst<>#PB_Ignore
      SetProp_(*SplitterID, "SnapFirst", SnapFirst)
   EndIf
   If SnapSecond<>#PB_Ignore
      SetProp_(*SplitterID, "SnapSecond", SnapSecond)
   EndIf
   If GripWidth<>#PB_Ignore
      SetProp_(*SplitterID, "GripWidth", GripWidth)
   EndIf
   If Thickness<>#PB_Ignore
      If Thickness>=0 And Thickness<4 : Thickness=4 : EndIf
      SetProp_(*SplitterID, "Thickness", Thickness)
   EndIf
   If Locked<>#PB_Ignore
      SetProp_(*SplitterID, "Locked", Locked)
   EndIf
   
   Thickness=GetProp_(*SplitterID, "Thickness")
   GripWidth=GetProp_(*SplitterID, "GripWidth")
   grip=GetProp_(*SplitterID, "Grip")
   gripFocus=GetProp_(*SplitterID, "GripFocus")
   gripNormal=GetProp_(*SplitterID, "GripNormal")
   If Thickness>0 And GripWidth>0
      ;enable grip & dashed bar
      SetProp_(*SplitterID, "GripVisible", #True)
      Protected w=GripWidth, h=Thickness
      If verticalBar : Swap w, h : EndIf
      ResizeImage(gripNormal, w, h, #PB_Image_Raw)
      ResizeImage(gripFocus, w, h, #PB_Image_Raw)
      SendMessage_(*SplitterID, #WM_SPLITTER_REDRAW_GRIP_IMAGES, gripNormal, 0)
      SendMessage_(*SplitterID, #WM_SPLITTER_REDRAW_GRIP_IMAGES, gripFocus, 0)
      SetGadgetState(grip, ImageID(gripNormal))
      HideGadget(grip, 0)
      
      ;position grip & gadgets
      SendMessage_(*SplitterID, #WM_SPLITTER_POSITION_GRIP_AND_GADGETS, 0, 0)
   Else
      ;disable grip & dashed bar
      SetProp_(*SplitterID, "GripVisible", #False)
      SetGadgetState(grip, #Null)
      HideGadget(grip, 1)
      
      ;restore default thickness
      SetProp_(*SplitterID, "Thickness", GetProp_(*SplitterID, "DefaultThickness"))
   EndIf
EndProcedure

Procedure.i SplitterLocked(Splitter) ;Returns #True if splitter is locked
   Protected *SplitterID=GadgetID(Splitter)
   ProcedureReturn Bool(GetProp_(*SplitterID, "Locked"))
EndProcedure

Procedure.i SplitterSnapped(Splitter) ;Returns 1 or 2 if splitter snapped border 1 or 2  is snapped (not snapped if ZERO)
   Protected *SplitterID=GadgetID(Splitter)
   Protected verticalBar=GetProp_(*SplitterID, "VerticalBar")
   Protected thickness=GetProp_(*SplitterID, "Thickness")
   Protected snapFirst=GetProp_(*SplitterID, "SnapFirst")
   Protected snapSecond=GetProp_(*SplitterID, "SnapSecond")
   Protected snapPos1=GetGadgetAttribute(Splitter, #PB_Splitter_FirstMinimumSize)
   Protected snapPos2
   If verticalBar
      snapPos2=GadgetWidth(Splitter)-GetGadgetAttribute(Splitter, #PB_Splitter_FirstMinimumSize)-thickness
   Else
      snapPos2=GadgetHeight(Splitter)-GetGadgetAttribute(Splitter, #PB_Splitter_SecondMinimumSize)-thickness
   EndIf
   If snapFirst And GetGadgetState(Splitter)=snapPos1
      ProcedureReturn 1
   ElseIf snapSecond And GetGadgetState(Splitter)=snapPos2
      ProcedureReturn 2
   EndIf
EndProcedure

Procedure SwapSplitter(Splitter, SwapBarPosition=#True, SwapSnapping=#True, SwapMinimumSize=#True, SwapGadgets=#True) ; swap gadgets and other options
   SetSplitterEffects(Splitter, #PB_Ignore, #PB_Ignore, #PB_Ignore, #PB_Ignore, #PB_Ignore, #PB_Ignore)
   
   Protected *SplitterID=GadgetID(Splitter)
   Protected verticalBar=GetProp_(*SplitterID, "VerticalBar")
   Protected thickness=GetProp_(*SplitterID, "Thickness")
   Protected gripWidth=GetProp_(*SplitterID, "GripWidth")
   Protected dblClickToSnap=GetProp_(*SplitterID, "DblClickToSnap")
   Protected locked=GetProp_(*SplitterID, "Locked")
   Protected flags=Bool(GetProp_(*SplitterID, "DefaultThickness")>4)*#PB_Splitter_Separator
   
   Protected snapFirst=GetProp_(*SplitterID, "SnapFirst")
   Protected snapSecond=GetProp_(*SplitterID, "SnapSecond")
   If SwapSnapping
      Swap SnapFirst, SnapSecond
   EndIf
   
   Protected Min1=GetGadgetAttribute(Splitter, #PB_Splitter_FirstMinimumSize)
   Protected Min2=GetGadgetAttribute(Splitter, #PB_Splitter_SecondMinimumSize)
   If SwapMinimumSize
      Swap Min1, Min2
   EndIf
   
   Protected Gadget1=GetGadgetAttribute(Splitter, #PB_Splitter_FirstGadget)
   Protected Gadget2=GetGadgetAttribute(Splitter, #PB_Splitter_SecondGadget)
   If SwapGadgets
      Swap Gadget1, Gadget2
   EndIf
   
   Protected Pos=GetGadgetState(Splitter)
   Protected PosOpposite=Pos + (Bool(verticalBar=1)*GadgetWidth(Splitter) + 
                                Bool(verticalBar=0)*GadgetHeight(Splitter) + 
                                (-2*Pos)-Thickness)
   If SwapBarPosition
      Swap Pos, PosOpposite
   EndIf
   
   Protected x=GadgetX(Splitter), y=GadgetY(Splitter)
   Protected w=GadgetWidth(Splitter), h=GadgetHeight(Splitter)
   Protected previousGadgetList=UseGadgetList(GetParent_(*SplitterID))
   Static dummy
   If Not dummy : dummy=TextGadget(#PB_Any, 0, 0, 0, 0, "") : HideGadget(dummy, 1) : EndIf
   SetGadgetAttribute(Splitter, #PB_Splitter_SecondGadget, dummy)
   SetGadgetAttribute(Splitter, #PB_Splitter_FirstGadget, Gadget1)
   SetGadgetAttribute(Splitter, #PB_Splitter_SecondGadget, Gadget2)
   SetGadgetAttribute(Splitter, #PB_Splitter_FirstMinimumSize, Min1)
   SetGadgetAttribute(Splitter, #PB_Splitter_SecondMinimumSize, Min2)
   SetGadgetState(Splitter, Pos)
   SetSplitterEffects(Splitter, thickness, gripWidth, snapFirst, snapSecond, dblClickToSnap, locked)
EndProcedure

; ***************************
; EXAMPLE
; ***************************
CompilerIf #PB_Compiler_IsMainFile
   DisableExplicit
   firstWin=OpenWindow(#PB_Any, 0, 0, 0, 0, "Dashed SplitterGadget And Auto Snap-To-Border", #PB_Window_SizeGadget | #PB_Window_SystemMenu)
   If firstWin
      WindowBounds(firstWin, 410, 440, #PB_Ignore, #PB_Ignore)
      SmartWindowRefresh(firstWin, 1)
      
      panel=PanelGadget(#PB_Any, 0, 0, 0, 0)
      AddGadgetItem(panel, -1, "Tab 1")
      panelButton=ButtonGadget(#PB_Any, 0, 0, 100, 30, "CLICK!")
      CloseGadgetList()
      otherButton=ButtonGadget(#PB_Any, 0, 0, 0, 0, "BIG CLICK!")
      swapButton=ButtonGadget(#PB_Any, 5, 5, 100, 30, "SWAP")
      
      splitter1=SplitterGadget(#PB_Any, 50, 50, 110, 110, panel, otherButton, #PB_Splitter_SecondFixed)
      SetSplitterEffects(splitter1, 8, 100, 50, 100, 1)
      SetGadgetAttribute(splitter1, #PB_Splitter_FirstMinimumSize, 60)
      SetGadgetAttribute(splitter1, #PB_Splitter_SecondMinimumSize, 15)
      SetGadgetState(splitter1, 20)
   EndIf
   
   SecondWin=OpenWindow(#PB_Any, 220, 220, 0, 0, "SplitterGadget : enable / disable options", #PB_Window_SizeGadget | #PB_Window_SystemMenu)
   If SecondWin
      WindowBounds(SecondWin, 410, 410, #PB_Ignore, #PB_Ignore)
      SmartWindowRefresh(SecondWin, 1)
      CheckBoxGadget(100, 5, 5, 80, 20, "LOCKED")
      CheckBoxGadget(101, 100, 5, 130, 20, "DOUBLE-CLICK SNAP")
      CheckBoxGadget(102, 250, 5, 120, 20, "SNAP-TO-BORDER")
      SetGadgetState(101, #True)
      SetGadgetState(102, #True)
      
      ContainerGadget(800, 0, 0, 0, 0) : CloseGadgetList()
      ContainerGadget(900, 0, 0, 0, 0) : CloseGadgetList()
      SetGadgetColor(800, #PB_Gadget_BackColor, $C9C9E3)
      SetGadgetColor(900, #PB_Gadget_BackColor, $ACACAC)
      splitter2=SplitterGadget(#PB_Any, 50, 50, 0, 0, 800, 900, #PB_Splitter_Vertical | #PB_Splitter_FirstFixed | #PB_Splitter_Separator)
      SetSplitterEffects(splitter2, 0, 0, 90, 30, 2)
   EndIf
   
   Repeat
      e=WaitWindowEvent()
      g=EventGadget()
      t=EventType()
      w=EventWindow()
      
      Select e
         Case #PB_Event_CloseWindow
            CloseWindow(w)
            If Not IsWindow(firstWin) And Not IsWindow(SecondWin) : End : EndIf
            
         Case #PB_Event_SizeWindow
            Select w
               Case firstWin
                  ResizeGadget(splitter1, #PB_Ignore, #PB_Ignore, WindowWidth(w)-110, WindowHeight(w)-120)
               Case SecondWin
                  ResizeGadget(splitter2, #PB_Ignore, #PB_Ignore, WindowWidth(w)-110, WindowHeight(w)-120)
            EndSelect
         Case #PB_Event_Gadget
            Select g
               Case Splitter1
                  If t=#PB_EventType_LeftDoubleClick
                     Debug "Double-Click : #Splitter1"
                  ElseIf t=#PB_EventType_Change
                     Debug "Splitter1 : pos=" + GetGadgetState(g)
                     Debug "Splitter1 Snapped=" + SplitterSnapped(g)
                  EndIf
               Case Splitter2
                  If t=#PB_EventType_LeftDoubleClick
                     Debug "Double-Click : #Splitter2"
                  ElseIf t=#PB_EventType_Change
                     Debug "Splitter2 : pos=" + GetGadgetState(g)
                     Debug "Splitter2 Snapped=" + SplitterSnapped(g)
                  EndIf
                  
               Case swapButton
                  SwapSplitter(Splitter1)
                  
               Case 100
                  SetSplitterEffects(Splitter2, #PB_Ignore, #PB_Ignore, #PB_Ignore, #PB_Ignore, #PB_Ignore, GetGadgetState(100))
                  Debug "Splitter2 Locked=" + SplitterLocked(splitter2)
               Case 101
                  SetSplitterEffects(Splitter2, #PB_Ignore, #PB_Ignore, #PB_Ignore, #PB_Ignore, GetGadgetState(101), #PB_Ignore)
               Case 102
                  SetSplitterEffects(Splitter2, #PB_Ignore, #PB_Ignore, 90*GetGadgetState(102), 30*GetGadgetState(102), #PB_Ignore, #PB_Ignore)
            EndSelect
         Default
      EndSelect
   ForEver
   CompilerEndIf

Re: SplitterGadget+ dashed bar, border snap, thickness,grip,

Posted: Fri Aug 30, 2013 8:01 pm
by eddy
Updated
- I upgraded the last function: SwapSplitter