- 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+

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