Page 1 of 1

DockPanel Layout

Posted: Sat Jun 06, 2015 11:49 pm
by eddy
  • Docking panel system
  • Add/Attach/Detach panel
  • Resize layout
  • Detect if mouse hits splitter or panel
  • Capture/Drag splitter
  • Docking Size Units : Pixels or Percent
  • Docking Mode : LEFT,RIGHT,TOP,BOTTOM,FILL
  • Customizable drawing function
  • using OOP Module
  • Coded in PB 5.30+
Image

Code: Select all


CompilerIf Not Defined(OOP, #PB_Module)
   DeclareModule OOP
      Macro _CONCAT(a=, b=) ; helpers used to escape some MACRO variable
         a#b
      EndMacro
      
      Macro _DQUOTE ; helpers used to build MACRO string
         "
      EndMacro
      
      Macro _COLON ; helpers used to construct nested MACRO
         : 
      EndMacro
      
      Macro UseInstanceType(T) ; determine which instance TYPE will be implemented
         Procedure.i DefaultFreeInstance_#T()
            UseInstance(*this.T)
            ClearStructure(*this.T, T)
            ProcedureReturn #Null
         EndProcedure
         UndefineMacro _CONCAT(INSTANCE, _TYPE)
         _COLON#Macro _CONCAT(INSTANCE, _TYPE)_COLON#T#_COLON#EndMacro
      EndMacro
      
      Macro Instanciate(This, ParentType=OOP::OBJECT, InstanciateParent=#Null) ; create NEW instance
         Protected *parent.ParentType=InstanciateParent
         Protected This=AllocateStructure(INSTANCE_TYPE)
         If *parent
            CopyStructure(*parent, This, ParentType)
            This\InstanceParentType$=*parent\InstanceType$
         Else
            This\InstanceParentType$="OBJECT"
         EndIf
         This\InstanceType$=_DQUOTE#INSTANCE_TYPE#_DQUOTE
         This\FreeInstance=@DefaultFreeInstance_#INSTANCE_TYPE()
         This\DefaultFreeInstance=@DefaultFreeInstance_#INSTANCE_TYPE()
      EndMacro
      
      Macro SetInstanceMethod(Method) ; init NEW instance method
         *this\Method=@Method()
      EndMacro
      
      Macro UseInstance(This) ; provide THIS instance to module method
         CompilerIf Not Defined(_CONCAT(*th, is), #PB_Variable)
            Protected This
            CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
               ! MOV [p.p_this], Rbp
            CompilerElse
               ! MOV [p.p_this], Ebp
            CompilerEndIf
         CompilerEndIf
      EndMacro
      
      Prototype.i FreeInstance()
      Structure OBJECT ; instance base TYPE
         InstanceParentType$
         InstanceType$
         FreeInstance.FreeInstance
         DefaultFreeInstance.FreeInstance
      EndStructure
   EndDeclareModule
   Module OOP : EndModule
   Macro FreeInstance(This)
      This=This\OOP::_CONCAT(Free, Instance)()
   EndMacro
CompilerEndIf

CompilerIf Not Defined(DOCKPANEL, #PB_Module)
   DeclareModule DOCKPANEL
      EnableExplicit
      UseModule OOP
      Enumeration
         #DOCK_Fill=0
         #DOCK_Left
         #DOCK_Right
         #DOCK_Top
         #DOCK_Bottom
         
         #HITBOX_None=0
         #HITBOX_Panel
         #HITBOX_PanelSplitter
         #HITBOX_PanelHitBox
      EndEnumeration
      Prototype DrawPanelFunction(*ChildPanel)
      Prototype Draw(*DrawPanelFunction.DrawPanelFunction)
      Prototype Resize(x=#PB_Ignore, y=#PB_Ignore, w=#PB_Ignore, h=#PB_Ignore)
      Prototype AddHitBox(BoxName$, x, y, w, h, IsDefaultBox=#False)
      Prototype.i TestHitBox(MouseX, MouseY, *hitbox, AbsolutePosition=#True)
      Prototype.i ExamineMouseHit(MouseX, MouseY)
      Prototype.i MouseHitBox()
      Prototype.i MouseHitBoxType()
      Prototype.i MouseHitBoxPanel()
      Prototype.i MouseDragSplitter(IsEnabled=#PB_Ignore)
      Prototype.i FindChildPanel(ChildName$)
      Prototype.i RemoveChildPanel(ChildName$)
      Prototype.i DetachChildPanel(ChildName$)
      Prototype.i AddChildPanelTo(ParentName$, ChildName$, DockMode=#DOCK_Left, DockSize.f=100, SplitterThickness=8)
      Prototype.i AttachChildPanelTo(ParentName$, *ChildPanel, DockMode=#DOCK_Left, DockSize.f=100, SplitterThickness=8)
      Prototype.i GetParent()
      Prototype.i GetDockMode()
      Prototype.f GetDockSize()
      
      Structure PANEL_HITBOX
         x.i : y.i : w.i : h.i
         Name$
         Type.i
      EndStructure
      Structure PANEL_SPLITTER
         HitBox.PANEL_HITBOX
         IsVertical.b
         Thickness.i
         Length.i
      EndStructure
      Structure DOCKPANEL Extends OBJECT
         ;public methods
         Draw.Draw
         Resize.Resize
         AddHitBox.AddHitBox
         TestHitBox.TestHitBox
         ExamineMouseHit.ExamineMouseHit
         MouseHitBox.MouseHitBox
         MouseHitBoxType.MouseHitBoxType
         MouseHitBoxPanel.MouseHitBoxPanel
         MouseDragSplitter.MouseDragSplitter
         AddChildPanelTo.AddChildPanelTo
         FindChildPanel.FindChildPanel
         RemoveChildPanel.RemoveChildPanel
         DetachChildPanel.DetachChildPanel
         AttachChildPanelTo.AttachChildPanelTo
         GetDockMode.GetDockMode
         GetDockSize.GetDockSize
         GetParent.GetParent
         ;public properties
         Name$
         HitBox.PANEL_HITBOX
         Splitter.PANEL_SPLITTER
      EndStructure
      ;contructor
      Declare.i InstanciateDOCKPANEL(Name$, x=0, y=0, w=0, h=0)
   EndDeclareModule
   
   Module DOCKPANEL
      UseModule OOP
      Prototype ResizeSplitter(IsVertical, x, y, Length)
      Prototype.i GetSiblingPanel()
      Structure _DOCKPANEL Extends DOCKPANEL
         ;private methods
         GetSiblingPanel.GetSiblingPanel
         ResizeSplitter.ResizeSplitter
         ;private fields
         IsFiller.b
         DockMode.i
         DockSize.f
         *DockArea._DOCKPANEL
         *FillArea._DOCKPANEL
         *Parent._DOCKPANEL
      EndStructure
      Structure MOUSE_CONTROL
         *HitBox.PANEL_HITBOX
         *HitBoxPanel._DOCKPANEL
         *CapturePanel._DOCKPANEL
         CaptureX.i
         CaptureY.i
         x.i : y.i
      EndStructure
      Global MouseControl.MOUSE_CONTROL
      Global NewMap DefaultHitBoxs.PANEL_HITBOX()
      UseInstanceType(_DOCKPANEL)
      
      Procedure AddHitBox(Name$, x, y, w, h, IsDefaultBox=#False)
         UseInstance(*this._DOCKPANEL)
         With *this
            If IsDefaultBox
               AddMapElement(DefaultHitBoxs(), Name$)
               DefaultHitBoxs()\Type=#HITBOX_PanelHitBox
               DefaultHitBoxs()\Name$=Name$
               DefaultHitBoxs()\x=x
               DefaultHitBoxs()\y=y
               DefaultHitBoxs()\w=w
               DefaultHitBoxs()\h=h
            Else
               
            EndIf
         EndWith
      EndProcedure
      
      Procedure.i TestHitBox(MouseX, MouseY, *hitbox.PANEL_HITBOX, AbsolutePosition=#True)
         UseInstance(*this._DOCKPANEL)
         With *this
            If AbsolutePosition
               ProcedureReturn Bool(*hitbox\x<=MouseX And MouseX<(*hitbox\x + *hitbox\w) And *hitbox\y<=MouseY And MouseY<(*hitbox\y + *hitbox\h))
            Else
               MouseX -\HitBox\x : MouseY -\HitBox\y
               Protected testX
               If *hitbox\w<0
                  testX=Bool((\HitBox\w - *hitbox\x + *hitbox\w)<=MouseX And MouseX<(\HitBox\w - *hitbox\x))
               Else
                  testX=Bool(*hitbox\x<=MouseX And MouseX<(*hitbox\x + *hitbox\w))
               EndIf
               If testX
                  If *hitbox\h<0
                     ProcedureReturn Bool((\HitBox\h - *hitbox\y + *hitbox\h)<=MouseY And MouseY<(\HitBox\h - *hitbox\y))
                  Else
                     ProcedureReturn Bool(*hitbox\y<=MouseY And MouseY<(*hitbox\y + *hitbox\h))
                  EndIf
               EndIf
            EndIf
         EndWith
      EndProcedure
      
      Procedure.i ExamineMouseHit(MouseX, MouseY)
         UseInstance(*this._DOCKPANEL)
         With *this
            Static IsExamining
            If Not IsExamining
               IsExamining=1
               MouseControl\x=MouseX
               MouseControl\y=MouseY
               MouseControl\HitBox=0
               MouseControl\HitBoxPanel=0
            EndIf
            If MouseControl\CapturePanel
               MouseControl\HitBoxPanel=MouseControl\CapturePanel
               MouseControl\HitBox=MouseControl\CapturePanel\Splitter\HitBox
            EndIf
            If \TestHitBox(MouseX, MouseY, \HitBox)
               If \Name$
                  ForEach DefaultHitBoxs()
                     Protected *hitBox.PANEL_HITBOX=DefaultHitBoxs()
                     If \TestHitBox(MouseX, MouseY, *hitBox, #False)
                        MouseControl\HitBoxPanel=*this
                        MouseControl\HitBox=DefaultHitBoxs()
                        Break
                     EndIf
                  Next
                  If MouseControl\HitBoxPanel=0
                     MouseControl\HitBoxPanel=*this
                     MouseControl\HitBox=\HitBox
                  EndIf
               Else
                  If MouseControl\HitBoxPanel=0 And \DockArea
                     \DockArea\ExamineMouseHit(MouseX, MouseY)
                  EndIf
                  If MouseControl\HitBoxPanel=0 And \FillArea
                     \FillArea\ExamineMouseHit(MouseX, MouseY)
                  EndIf
                  If \MouseHitBoxType()<>#HITBOX_PanelHitBox And \TestHitBox(MouseX, MouseY, \Splitter\HitBox)
                     MouseControl\HitBoxPanel=*this
                     MouseControl\HitBox=\Splitter\HitBox
                  EndIf
               EndIf
            EndIf
            IsExamining=0
            ProcedureReturn MouseControl\HitBoxPanel
         EndWith
      EndProcedure
      
      Procedure.i MouseHitBoxPanel()
         UseInstance(*this._DOCKPANEL)
         ProcedureReturn MouseControl\HitBoxPanel
      EndProcedure
      
      Procedure.i MouseHitBox()
         UseInstance(*this._DOCKPANEL)
         If *this\MouseHitBoxPanel() : ProcedureReturn MouseControl\HitBox : EndIf
      EndProcedure
      
      Procedure.i MouseHitBoxType()
         UseInstance(*this._DOCKPANEL)
         If *this\MouseHitBox() : ProcedureReturn MouseControl\HitBox\Type : EndIf
      EndProcedure
      
      Procedure.i MouseDragSplitter(IsEnabled=#PB_Ignore)
         UseInstance(*this._DOCKPANEL)
         If IsEnabled=#PB_Ignore
            ;move splitter
            If MouseControl\CapturePanel
               With MouseControl\CapturePanel
                  Protected tw.i=1, th.i=1 ;thickness conversion from pixel to percent
                  If \DockSize<1
                     tw=\HitBox\w
                     th=\HitBox\h
                  EndIf
                  \Splitter\HitBox\x=MouseControl\x + MouseControl\CaptureX + \Splitter\Thickness / 2
                  \Splitter\HitBox\y=MouseControl\y + MouseControl\CaptureY + \Splitter\Thickness / 2
                  Select \DockMode
                     Case #DOCK_Left
                        \DockSize=(\Splitter\HitBox\x-\HitBox\x) / tw
                     Case #DOCK_Right
                        \DockSize=(\HitBox\x + \HitBox\w-\Splitter\HitBox\x) / tw
                     Case #DOCK_Top
                        \DockSize=(\Splitter\HitBox\y-\HitBox\y) / th
                     Case #DOCK_Bottom
                        \DockSize=(\HitBox\y + \HitBox\h-\Splitter\HitBox\y) / th
                  EndSelect
                  \Resize()
               EndWith
            EndIf
         ElseIf IsEnabled
            ;capture splitter
            If *this\MouseHitBoxType()=#HITBOX_PanelSplitter
               With MouseControl
                  \CapturePanel=*this\MouseHitBoxPanel()
                  \CaptureX=\CapturePanel\Splitter\HitBox\x-\x
                  \CaptureY=\CapturePanel\Splitter\HitBox\y-\y
               EndWith
            EndIf
         Else
            ;release splitter
            MouseControl\CapturePanel=0
         EndIf
         ProcedureReturn MouseControl\CapturePanel
      EndProcedure
      
      Procedure ResizeHitBox(*hitbox.PANEL_HITBOX, x=#PB_Ignore, y=#PB_Ignore, w=#PB_Ignore, h=#PB_Ignore)
         With *hitbox
            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
         EndWith
      EndProcedure
      
      Procedure ResizeSplitter(IsVertical, x, y, Length)
         UseInstance(*this._DOCKPANEL)
         With *this\Splitter
            \IsVertical=IsVertical
            \Length=Length
            If IsVertical
               ResizeHitBox(\HitBox, x-\Thickness / 2, y, \Thickness, Length)
            Else
               ResizeHitBox(\HitBox, x, y-\Thickness / 2, Length, \Thickness)
            EndIf
         EndWith
      EndProcedure
      
      Procedure Resize(x=#PB_Ignore, y=#PB_Ignore, w=#PB_Ignore, h=#PB_Ignore)
         UseInstance(*this._DOCKPANEL)
         With *this
            ResizeHitBox(\HitBox, x, y, w, h)
            Protected fx.i=\HitBox\x, fy.i=\HitBox\y, fw.i=\HitBox\w, fh.i=\HitBox\h ;fill area
            Protected dx.i=\HitBox\x, dy.i=\HitBox\y, dw.i=\HitBox\w, dh.i=\HitBox\h ;dock area
            Protected tw.i=1, th.i=1                                                 ;thickness conversion from pixel to percent
            If \DockSize<1
               tw=\HitBox\w
               th=\HitBox\h
            EndIf
            Select \DockMode
               Case #DOCK_Left
                  dw=\DockSize*tw : fw=\HitBox\w-dw : fx + dw
                  \ResizeSplitter(#True, fx, fy, fh)
               Case #DOCK_Right
                  dw=\DockSize*tw : fw=\HitBox\w-dw : dx + fw
                  \ResizeSplitter(#True, dx, dy, dh)
               Case #DOCK_Top
                  dh=\DockSize*th : fh=\HitBox\h-dh : fy + dh
                  \ResizeSplitter(#False, fx, fy, fw)
               Case #DOCK_Bottom
                  dh=\DockSize*th : fh=\HitBox\h-dh : dy + fh
                  \ResizeSplitter(#False, dx, dy, dw)
            EndSelect
            If \DockArea : \DockArea\Resize(dx, dy, dw, dh) : EndIf
            If \FillArea : \FillArea\Resize(fx, fy, fw, fh) : EndIf
         EndWith
      EndProcedure
      
      Procedure Draw(*DrawPanelFunction.DrawPanelFunction)
         UseInstance(*this._DOCKPANEL)
         With *this
            If *DrawPanelFunction
               *DrawPanelFunction(*this)
            EndIf
            ;draw child panels
            If \DockArea : \DockArea\Draw(*DrawPanelFunction) : EndIf
            If \FillArea : \FillArea\Draw(*DrawPanelFunction) : EndIf
         EndWith
      EndProcedure
      
      Procedure.i GetDockMode()
         UseInstance(*this._DOCKPANEL)
         If *this\Parent And Not *this\IsFiller
            ProcedureReturn *this\Parent\DockMode
         EndIf
      EndProcedure
      
      Procedure.f GetDockSize()
         UseInstance(*this._DOCKPANEL)
         If *this\Parent And Not *this\IsFiller
            ProcedureReturn *this\Parent\DockSize
         Else
            ProcedureReturn -1
         EndIf
      EndProcedure
      
      Procedure.i GetParent()
         UseInstance(*this._DOCKPANEL)
         ProcedureReturn *this\Parent
      EndProcedure
      
      Procedure.i GetSiblingPanel()
         UseInstance(*this._DOCKPANEL)
         With *this
            Protected *sibling._DOCKPANEL
            If \Parent
               If \IsFiller
                  *sibling=\Parent\DockArea
               Else
                  *sibling=\Parent\FillArea
               EndIf
            EndIf
            ProcedureReturn *sibling
         EndWith
      EndProcedure
      
      Procedure.i FindChildPanel(Name$)
         UseInstance(*this._DOCKPANEL)
         With *this
            Protected *found=#False
            If \DockArea
               If \DockArea\Name$=Name$
                  *found=\DockArea
               Else
                  *found=\DockArea\FindChildPanel(Name$)
               EndIf
            EndIf
            If Not *found And \FillArea
               If \FillArea\Name$=Name$
                  *found=\FillArea
               Else
                  *found=\FillArea\FindChildPanel(Name$)
               EndIf
            EndIf
            ProcedureReturn *found
         EndWith
      EndProcedure
      
      Procedure.i DetachChildPanel(Name$)
         UseInstance(*this._DOCKPANEL)
         With *this
            Protected *parent._DOCKPANEL
            Protected *sibling._DOCKPANEL
            Protected *detached._DOCKPANEL=\FindChildPanel(Name$)
            If *detached
               ;find sibling of detached panel
               *parent=*detached\Parent
               *sibling=*detached\GetSiblingPanel()
               ;parent panel handles children of sibling panel (but preserve parent size)
               *parent\Name$=*sibling\Name$
               *parent\Splitter=*sibling\Splitter
               *parent\DockMode=*sibling\DockMode
               *parent\DockSize=*sibling\DockSize
               *parent\DockArea=*sibling\DockArea
               *parent\FillArea=*sibling\FillArea
               If *parent\FillArea : *parent\FillArea\Parent=*parent : EndIf
               If *parent\DockArea : *parent\DockArea\Parent=*parent : EndIf
               ;free sibling panel
               *sibling\FillArea=0
               *sibling\DockArea=0
               *sibling\FreeInstance()
               ;retrieve detached panel (as standalone)
               *detached\Parent=0
               *detached\IsFiller=0
               ProcedureReturn *detached
            EndIf
         EndWith
      EndProcedure
      
      Procedure.i RemoveChildPanel(Name$)
         UseInstance(*this._DOCKPANEL)
         With *this
            Protected *removed._DOCKPANEL=DetachChildPanel(Name$)
            If *removed
               *removed\FreeInstance()
               ProcedureReturn #True
            EndIf
         EndWith
      EndProcedure
      
      Procedure.i AttachChildPanelTo(TargetName$, *ChildPanel._DOCKPANEL, DockMode=#DOCK_Left, DockSize.f=100, SplitterThickness=8)
         UseInstance(*this._DOCKPANEL)
         With *this
            Protected *target._DOCKPANEL=\FindChildPanel(TargetName$)
            If *target=0 And \Name$=TargetName$
               *target=*this
            EndIf
         EndWith
         With *target
            ;standalone or detached panels are accepted
            If *target And *ChildPanel And *ChildPanel\Parent=0
               If DockMode<>#DOCK_Fill
                  \DockArea=*ChildPanel
                  \DockArea\Parent=*target
                  \DockArea\IsFiller=0
                  \DockMode=DockMode
                  \DockSize=DockSize
                  \Splitter\Thickness=SplitterThickness
                  
                  \FillArea=InstanciateDOCKPANEL(\Name$)
                  \FillArea\Parent=*target
                  \FillArea\IsFiller=1
                  \Name$=""
                  
                  ProcedureReturn \DockArea
               EndIf
            EndIf
         EndWith
      EndProcedure
      
      Procedure.i AddChildPanelTo(TargetName$, ChildName$, DockMode=#DOCK_Left, DockSize.f=100, SplitterThickness=8)
         UseInstance(*this._DOCKPANEL)
         ;retrieve new docked panel
         ProcedureReturn *this\AttachChildPanelTo(TargetName$, InstanciateDOCKPANEL(ChildName$), DockMode, DockSize, SplitterThickness)
      EndProcedure
      
      Procedure.i FreeInstance()
         UseInstance(*this._DOCKPANEL)
         With *this
            ;remove children
            If \DockArea : \DockArea\FreeInstance() : EndIf
            If \FillArea : \FillArea\FreeInstance() : EndIf
            ProcedureReturn \DefaultFreeInstance()
         EndWith
      EndProcedure
      
      Procedure.i InstanciateDOCKPANEL(Name$, x=0, y=0, w=0, h=0)
         Instanciate(*this._DOCKPANEL)
         SetInstanceMethod(FreeInstance)
         SetInstanceMethod(Draw)
         SetInstanceMethod(Resize)
         SetInstanceMethod(ResizeSplitter)
         SetInstanceMethod(AddHitBox)
         SetInstanceMethod(TestHitBox)
         SetInstanceMethod(ExamineMouseHit)
         SetInstanceMethod(MouseHitBox)
         SetInstanceMethod(MouseHitBoxType)
         SetInstanceMethod(MouseHitBoxPanel)
         SetInstanceMethod(MouseDragSplitter)
         SetInstanceMethod(AddChildPanelTo)
         SetInstanceMethod(RemoveChildPanel)
         SetInstanceMethod(DetachChildPanel)
         SetInstanceMethod(AttachChildPanelTo)
         SetInstanceMethod(FindChildPanel)
         SetInstanceMethod(GetSiblingPanel)
         SetInstanceMethod(GetDockMode)
         SetInstanceMethod(GetDockSize)
         SetInstanceMethod(GetParent)
         With *this
            ResizeHitBox(\HitBox, x, y, w, h)
            \HitBox\Type=#HITBOX_Panel
            \Splitter\HitBox\Type=#HITBOX_PanelSplitter
            \Name$=Name$
         EndWith
         ProcedureReturn *this
      EndProcedure
   EndModule
CompilerEndIf

CompilerIf #PB_Compiler_IsMainFile
   ; ********************
   ; EXAMPLE
   ; ********************
   EnableExplicit
   UseModule DOCKPANEL
   Global *container.DOCKPANEL
   Define *card.DOCKPANEL
   *container.DOCKPANEL=InstanciateDOCKPANEL("content", 0, 0, 800, 600)
   *container\AddHitBox("grip", 0, 0, 10, 20, #True)
   *container\AddChildPanelTo("content", "toolbar", #DOCK_Top, 32)
   *container\AddChildPanelTo("content", "side", #DOCK_Left, 100)
   *container\AddChildPanelTo("side", "props", #DOCK_Bottom, 100)
   *container\AddChildPanelTo("side", "card", #DOCK_Top, 150)
   *card=*container\DetachChildPanel("card")
   *container\AttachChildPanelTo("content", *card, #DOCK_Right, 0.2) ; => 20%
   *card=*container\FindChildPanel("card")
   Debug *card\Name$ + " has been attached"
   *container\AddChildPanelTo("content", "bottom", #DOCK_Bottom, 50)
   ;*container\RemoveChildPanel("bottom")
   
   Runtime Enumeration
      #xml
      #dialog
      #win
      #canvas
      #fnt
   EndEnumeration
   
   Procedure DrawChildPanel(*ChildPanel.DOCKPANEL)
      With *ChildPanel\HitBox
         #ColorBright=$686868
         #ColorDark=$232323
         #ColorContent=$484848
         #ColorGrip=$111111
         #TabsHeight=20
         
         ;draw docking parameter
         Protected Name$=*ChildPanel\Name$
         If Name$
            
            ;draw vertical or horizontal gradient
            DrawingMode(#PB_2DDrawing_Default)
            FrontColor(#ColorContent)
            Box(\x, \y, \w, \h)
            ;draw borders
            FrontColor(#ColorBright)
            Line(\x, \y + #TabsHeight, 1, \h-#TabsHeight)
            Line(\x, \y + #TabsHeight, \w, 1)
            FrontColor(#ColorDark)
            Line(\x + \w-1, \y, 1, \h)
            Line(\x, \y + \h-1, \w, 1)
            ;draw tabs
            Box(\x, \y, \w, #TabsHeight)
            DrawingFont(FontID(#fnt))
            ClipOutput(\x + 20, \y, TextWidth(Name$) + 20, #TabsHeight + 1)
            RoundBox(\x + 20, \y + 2, TextWidth(Name$) + 20, 26, 3, 3, #ColorContent)
            DrawingMode(#PB_2DDrawing_Default | #PB_2DDrawing_Outlined)
            RoundBox(\x + 20, \y + 2, TextWidth(Name$) + 20, 26, 3, 3, #ColorBright)
            ClipOutput(\x + 20 + TextWidth(Name$) + 20-3, \y, 3, #TabsHeight + 1)
            RoundBox(\x + 20, \y + 2, TextWidth(Name$) + 20, 26, 3, 3, #ColorDark)
            UnclipOutput()
            DrawingMode(#PB_2DDrawing_Transparent)
            DrawText(\x + 30, \y + 4, Name$, RGBA(255, 255, 255, 255))
            ;draw grip
            Protected i, j
            For i=1 To 9 Step 3
               For j=0 To 20 Step 3
                  Box(\x + i, \y + j, 2, 2, #ColorGrip)
                  Box(\x + i, \y + j, 1, 1, #ColorContent)
               Next
            Next
            
            If *ChildPanel\GetDockSize()<0
               Protected size$="<Fill>"
            ElseIf *ChildPanel\GetDockSize()<=1
               size$="" + Str(*ChildPanel\GetDockSize()*100) + "%"
            Else
               size$="" + *ChildPanel\GetDockSize() + "px"
            EndIf
            DrawText(\x + 5, \y + 20, size$, RGBA(0, 109, 255, 255))
         EndIf
         
      EndWith
   EndProcedure
   
   Procedure DrawPanels()
      StartDrawing(CanvasOutput(#canvas))
      DrawingMode(#PB_2DDrawing_Default)
      Box(0, 0, OutputWidth(), OutputHeight(), RGB(0, 0, 0))
      *container\Draw(@DrawChildPanel())
      StopDrawing()
   EndProcedure
   
   Procedure ResizePanels()
      *container\Resize(#PB_Ignore, #PB_Ignore, GadgetWidth(#canvas), GadgetHeight(#canvas))
      DrawPanels()
   EndProcedure
   Global *hoverGrip.DOCKPANEL, *dragGrip.DOCKPANEL
   Procedure DropPanels()
      If *hoverGrip
         *hoverGrip=0
         *dragGrip=0
         GadgetToolTip(#canvas, "")
         Debug "drop image"
      EndIf
   EndProcedure
   
   Procedure DropCallback(TargetHandle, State, Format, Action, x, y)
      If State=#PB_Drag_Leave
         ProcedureReturn #False
      EndIf
      If State=#PB_Drag_Enter
         ;EnableGadgetDrop(#canvas, #PB_Drop_Image, #PB_Drag_Move | #PB_Drag_Copy | #PB_Drag_Link)
      EndIf
      If State=#PB_Drag_Update
         DropPanels()
      EndIf
      If State=#PB_Drag_Finish
         ;DropPanels()
      EndIf
      ProcedureReturn #True
   EndProcedure
   SetDropCallback(@DropCallback())
   
   
   Procedure ManagePanels()
      ;mouse hover panel
      Protected mx=GetGadgetAttribute(#canvas, #PB_Canvas_MouseX)
      Protected my=GetGadgetAttribute(#canvas, #PB_Canvas_MouseY)
      Protected *hitPanel.DOCKPANEL=*container\ExamineMouseHit(mx, my)
      Protected *hitbox.PANEL_HITBOX=*container\MouseHitBox()
      Protected hitboxType=*container\MouseHitBoxType()
      
      Select EventType()
         Case #PB_EventType_LeftButtonDown
            *container\MouseDragSplitter(#True)
            
            If hitBoxType=#HITBOX_PanelHitBox
               If *dragGrip<>*hoverGrip
                  *dragGrip=*hoverGrip
                  Debug "drag image"
               EndIf
            EndIf
         Case #PB_EventType_LeftButtonUp
            *container\MouseDragSplitter(#False)
         Case #PB_EventType_MouseMove
            If *container\MouseDragSplitter()
               DrawPanels()
            EndIf
            
            If hitBoxType=#HITBOX_PanelHitBox
               If *hoverGrip<>*hitPanel
                  *hoverGrip=*hitPanel
                  GadgetToolTip(#canvas, "Drag " + *hitPanel\Name$)
               EndIf
               If *dragGrip
                  DragImage(CreateImage(0, 1, 1, 24), #PB_Drag_Move)
               EndIf
            Else
               ;DropPanels()
            EndIf
            
            ;mouse cursor
            Select hitBoxType
               Case #HITBOX_PanelSplitter
                  If *hitPanel\Splitter\IsVertical
                     SetGadgetAttribute(#canvas, #PB_Canvas_Cursor, #PB_Cursor_LeftRight)
                  Else
                     SetGadgetAttribute(#canvas, #PB_Canvas_Cursor, #PB_Cursor_UpDown)
                  EndIf
               Case #HITBOX_PanelHitBox
                  SetGadgetAttribute(#canvas, #PB_Canvas_Cursor, #PB_Cursor_Hand)
               Case #HITBOX_Panel
                  SetGadgetAttribute(#canvas, #PB_Canvas_Cursor, #PB_Cursor_Default)
            EndSelect
      EndSelect
   EndProcedure
   
   Define xml$="<window id='#win' name='test' text='Dock Panel' minwidth='600' minheight='400' width='600' height='400' margin='0' " + 
               "   flags='#PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget'>" + 
               "   <canvas id='#canvas'></canvas>" + 
               "</window>"
   
   If CatchXML(#xml, @xml$, StringByteLength(xml$), 0, #PB_Ascii) And XMLStatus(#xml)=#PB_XML_Success And CreateDialog(#dialog) And OpenXMLDialog(#dialog, #xml, "test")
      LoadFont(#fnt, "Tahoma", 8)
      BindEvent(#PB_Event_SizeWindow, @ResizePanels())
      BindGadgetEvent(#canvas, @ManagePanels())      
      EnableWindowDrop(#win, #PB_Drop_Image, #PB_Drag_Move | #PB_Drag_Copy | #PB_Drag_Link)
      PostEvent(#PB_Event_SizeWindow)
      Repeat: Until WaitWindowEvent()=#PB_Event_CloseWindow
   EndIf
CompilerEndIf

Re: DockPanel Layout

Posted: Sun Jun 07, 2015 12:07 pm
by Zebuddi123
Nice eddy. Works on Linux too :) pb shows "Warning Gtk(CRITICAL):IA_gtk_window_resize: assertion 'width > 0' failed" though cant fond much about the warning

Zebuddi. :)

Re: DockPanel Layout

Posted: Sun Jun 07, 2015 1:20 pm
by eddy
Zebuddi123 wrote:Nice eddy. Works on Linux too :) pb shows "Warning Gtk(CRITICAL):IA_gtk_window_resize: assertion 'width > 0' failed" though cant fond much about the warning
Zebuddi. :)
I think it's because I didn't specify the size of the window in xml$ variable.
You can fix that by adding these attributes in xml$

Code: Select all

width='600' height='400'

Re: DockPanel Layout

Posted: Mon Jun 08, 2015 4:14 pm
by eddy
Updated
- Added: hit panel
- Added: hit splitter
- fixed : detach panel method

Re: DockPanel Layout

Posted: Tue Jun 09, 2015 3:02 pm
by eddy
Updated
- capture/drag splitter
- example updated

Re: DockPanel Layout

Posted: Tue Jun 09, 2015 4:16 pm
by aaaaaaaargh
Wow, I don't understand whats going on but the result looks nice!

Re: DockPanel Layout

Posted: Tue Jun 09, 2015 5:28 pm
by eddy
For the moment, there are two missing features:
- Drag Drop panel
- Multi-Tab panel

Image

Re: DockPanel Layout

Posted: Tue Jun 09, 2015 5:34 pm
by Zebuddi123
Hi eddy when trying your suggestion the other day I had to set the width to 1600 (my laptop screen width) else I just had a window with white content nothing drawn. Below i did a bit of a test to iterate the screen width down from 1600 dec 1, in debug mode and run mode when the width size hits 1588 i get a blank window as before. I`m on linux mint x64

Zebuddi. :)

below is my test: the current width is shoen in the window title: just closing the window iterates to the next window

Code: Select all

  ;-----------------------------------------
  Define ww=1600, i 	;<<<<
  For i=20 To 1 Step -1 ;<<<<
  	Debug "width = "+Str(ww);<<<<
  	Define xml$="<window id='#win' name='test' text='width = "+Str(ww)+"' minwidth='600' minheight='400' width='"+ww+"' height='400' margin='0' " + 
  	            "   flags='#PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_Invisible | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget'>" + 
  	            "   <canvas id='#canvas'></canvas>" + 
  	            "</window>"
  	
  	If CatchXML(#xml, @xml$, StringByteLength(xml$), 0, #PB_Ascii) And XMLStatus(#xml)=#PB_XML_Success And CreateDialog(#dialog) And OpenXMLDialog(#dialog, #xml, "test")
  		LoadFont(#fnt, "Tahoma", 8, #PB_Font_Bold)
  		BindEvent(#PB_Event_SizeWindow, @ResizePanels())
  		BindGadgetEvent(#canvas, @ManagePanels())
  		HideWindow(#win, #False)
  		
  		Repeat: 	Until WaitWindowEvent(16)=#PB_Event_CloseWindow
  		
  	EndIf
  	ww-1 ;<<<<
  Next	 ;<<<<
		 ;----------------------------------------

Re: DockPanel Layout

Posted: Wed Jul 15, 2015 11:45 am
by [blendman]
Hi

It's very interesting :)
Any news ?


To avoid the crash with plot(), you should replace those lines in the procedure DrawChildPanel() :

Code: Select all

;draw grip
Protected i, j
For i=1 To 9 Step 3
  For j=0 To 20 Step 3
    Box(\x + i, \y + j, 2, 2, #ColorGrip)
    Box(\x + i, \y + j, 1, 1, #ColorContent)
    ;Plot(\x + i, \y + j, #ColorContent)
  Next
Next

Re: DockPanel Layout

Posted: Wed Jul 15, 2015 1:54 pm
by falsam
Hello eddy. Thank for sharing this code.

When you hide a panel, the code crash. (Windows 8.1)

Image

Re: DockPanel Layout

Posted: Thu Jul 16, 2015 6:18 pm
by [blendman]
@falsam : To avoid the crash with plot(), you should replace those lines in the procedure DrawChildPanel() :

Code: Select all

;draw grip
Protected i, j
For i=1 To 9 Step 3
  For j=0 To 20 Step 3
    Box(\x + i, \y + j, 2, 2, #ColorGrip)
    Box(\x + i, \y + j, 1, 1, #ColorContent)
    ;Plot(\x + i, \y + j, #ColorContent)
  Next
Next

Re: DockPanel Layout

Posted: Fri Jul 17, 2015 11:05 am
by pwd
I had to add a call of ResizePanels() /directly or via PostEvent(#PB_Event_SizeWindow)/ to avoid showing a blank window on start at Xubuntu.

Code: Select all

      PostEvent(#PB_Event_SizeWindow)
      HideWindow(#win, #False)

Re: DockPanel Layout

Posted: Fri Jul 17, 2015 8:51 pm
by Andre
Nice example! Thank you :D

I also had to use the posted workarounds for the Plot() crash and the missing drawing at the start on my MacBook.

Furthermore I would suggest that there should be implemented a "limit", so that the splitters can't be moved outside the visible area (and can't be get back then). Thanks!

Re: DockPanel Layout

Posted: Sat Jul 18, 2015 4:40 pm
by eddy
pwd wrote:I had to add a call of ResizePanels() /directly or via PostEvent(#PB_Event_SizeWindow)/ to avoid showing a blank window on start at Xubuntu.

Code: Select all

      PostEvent(#PB_Event_SizeWindow)
      HideWindow(#win, #False)
Fixed
falsam wrote:Hello eddy. Thank for sharing this code.

When you hide a panel, the code crash. (Windows 8.1)
Fixed