Gadget+ AutoResize, Docking, Anchors, Margins

Share your advanced PureBasic knowledge/code with the community.
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Gadget+ AutoResize, Docking, Anchors, Margins

Post by eddy »

For PB4.20 & PB4.30
- automatic resize gadgets
- set gadget docking mode
- set gadget anchors
- refresh gadget docking
- macro for FreeGadget (to refresh gadget docking)
- get gadget docking mode

Image


Code: Select all

;{ Utils
Structure GadgetAnchor
   ;gadget ID
   ID.i
   
   ;gadget container
   Parent.i
   
   ;for gadget layout calculation
   a.i
   b.i
   c.i
   d.i
   
   ;anchor status
   Left.b
   Top.b
   Right.b
   Bottom.b
   
   ;margin distance for docking
   MarginLeft.i
   MarginTop.i
   MarginRight.i
   MarginBottom.i
   
   ;docking parameters
   GadgetDocking.i
   DockMode.b
   DockPriority.i
EndStructure
Structure GadgetDocking
   ;gadget container
   Parent.i
   
   ;for client size calculation
   a.i
   b.i
   c.i
   d.i
EndStructure
Global NewList GadgetAnchor.GadgetAnchor()
Global NewList GadgetDocking.GadgetDocking()
DeclareDLL AutoDockGadgets()
;}

;{ Functions for GadgetDock & GadgetAnchor
Enumeration 0
   #Dock_None
   #Dock_Left
   #Dock_Right
   #Dock_Top
   #Dock_Bottom
   #Dock_Fill
EndEnumeration
ProcedureDLL.l GetGadgetDock(ID) ;get gadget docking mode
   ForEach GadgetAnchor()
      With GadgetAnchor()
         If \ID=ID
            Protected DockMode=\DockMode
         EndIf
      EndWith
   Next
   ProcedureReturn DockMode
EndProcedure
ProcedureDLL SetGadgetAnchor(ID, Left.b, Top.b, Right.b, Bottom.b) ;set gadget border anchor
   ;find anchor if exists
   Protected GadgetAnchor
   ForEach GadgetAnchor()
      If GadgetAnchor()\ID=ID
         GadgetAnchor=@GadgetAnchor()
         Break
      EndIf
   Next
   ;create anchor if necessary
   If Not GadgetAnchor
      AddElement(GadgetAnchor())
   EndIf
   
   ;delete anchor if standard
   If Left And Top And Not Right And Not Bottom
      DeleteElement(GadgetAnchor())
      ProcedureReturn
   EndIf
   
   With GadgetAnchor()
      \ID=ID
      \Left=Left
      \Top=Top
      \Right=Right
      \Bottom=Bottom
      \Parent=GetParent_(GadgetID(ID))
      \GadgetDocking=0
      \DockMode=0
      \DockPriority=0
      
      ;remove docking behaviour if necessary
      Shared GadgetDocking
      If Not GadgetDocking And \DockMode
         AutoDockGadgets()
      EndIf
      
      \a=#PB_Ignore
      \b=#PB_Ignore
      \c=#PB_Ignore
      \d=#PB_Ignore
      
      GetClientRect_(\parent, rc.RECT)
      Protected parentW=rc\right
      Protected parentH=rc\bottom
      Protected parentCenterX=rc\right/2
      Protected parentCenterY=rc\bottom/2
      If Left
      ElseIf Right
         \a=rc\right-GadgetX(ID)
      Else
         \a=parentCenterX-GadgetX(ID)
      EndIf
      
      If Right
         \c=parentW-(GadgetX(ID)+GadgetWidth(ID))
      EndIf
      
      If Top
      ElseIf Bottom
         \b=parentH-GadgetY(ID)
      Else
         \b=parentCenterY-GadgetY(ID)
      EndIf
      
      If Bottom
         \d=parentH-(GadgetY(ID)+GadgetHeight(ID))
      EndIf
   EndWith
EndProcedure
ProcedureDLL SetGadgetDock(ID, DockMode, MarginLeft=#PB_Ignore, MarginTop=#PB_Ignore, MarginRight=#PB_Ignore, MarginBottom=#PB_Ignore) ;set gadget docking mode
   Protected parent=GetParent_(GadgetID(ID))
   GetClientRect_(parent, rc.RECT)
   Protected parentW=rc\right
   Protected parentH=rc\bottom
   Protected parentCenterX=rc\right/2
   Protected parentCenterY=rc\bottom/2
   
   Protected a, b, c, d
   Protected x, y, w, h
   
   If DockMode=#Dock_None
      SetGadgetAnchor(ID, 1, 1, 0, 0)
      AutoDockGadgets()
      ProcedureReturn
   EndIf
   
   ForEach GadgetDocking()
      With GadgetDocking()
         If \parent=parent
            a=\a
            b=\b
            c=\c
            d=\d
            DeleteElement(GadgetDocking())
            Break
         EndIf
      EndWith
   Next
   AddElement(GadgetDocking())
   
   With GadgetAnchor()
      ForEach GadgetAnchor()
         If \ID=ID
            If MarginLeft=#PB_Ignore : MarginLeft=\MarginLeft : EndIf
            If MarginTop=#PB_Ignore : MarginTop=\MarginTop : EndIf
            If MarginRight=#PB_Ignore : MarginRight=\MarginRight : EndIf
            If MarginBottom=#PB_Ignore : MarginBottom=\MarginBottom : EndIf
            Break
         EndIf
      Next
      If MarginLeft=#PB_Ignore : MarginLeft=0 : EndIf
      If MarginTop=#PB_Ignore : MarginTop=0 : EndIf
      If MarginRight=#PB_Ignore : MarginRight=0 : EndIf
      If MarginBottom=#PB_Ignore : MarginBottom=0 : EndIf
      
      Shared GadgetDocking
      GadgetDocking=1
      Select DockMode
         Case #Dock_Left
            x=a+MarginLeft
            y=b+MarginTop
            h=parentH-d-b-MarginTop-MarginBottom
            ResizeGadget(ID, x, y, #PB_Ignore, h)
            SetGadgetAnchor(ID, 1, 1, 0, 1)
            a+GadgetWidth(ID)+MarginLeft+MarginRight
         Case #Dock_Right
            x=parentW-c-GadgetWidth(ID)-MarginRight
            y=b+MarginTop
            h=parentH-d-b-MarginTop-MarginBottom
            ResizeGadget(ID, x, y, #PB_Ignore, h)
            SetGadgetAnchor(ID, 0, 1, 1, 1)
            c+GadgetWidth(ID)+MarginLeft+MarginRight
         Case #Dock_Top
            x=a+MarginLeft
            y=b+MarginTop
            w=parentW-c-a-MarginLeft-MarginRight
            ResizeGadget(ID, x, y, w, #PB_Ignore)
            SetGadgetAnchor(ID, 1, 1, 1, 0)
            b+GadgetHeight(ID)+MarginTop+MarginBottom
         Case #Dock_Bottom
            x=a+MarginLeft
            y=parentH-d-GadgetHeight(ID)-MarginBottom
            w=parentW-c-a-MarginLeft-MarginRight
            ResizeGadget(ID, x, y, w, #PB_Ignore)
            SetGadgetAnchor(ID, 1, 0, 1, 1)
            d+GadgetHeight(ID)+MarginTop+MarginBottom
         Case #Dock_Fill
            x=a+MarginLeft
            y=b+MarginTop
            w=parentW-c-a-MarginLeft-MarginRight
            h=parentH-d-b-MarginTop-MarginBottom
            ResizeGadget(ID, x, y, w, h)
            SetGadgetAnchor(ID, 1, 1, 1, 1)
      EndSelect
      GadgetDocking=0
      
      ;update docking client size
      GadgetDocking()\parent=parent
      GadgetDocking()\a=a
      GadgetDocking()\b=b
      GadgetDocking()\c=c
      GadgetDocking()\d=d
      
      ;update docking margins
      \MarginLeft=MarginLeft
      \MarginTop=MarginTop
      \MarginRight=MarginRight
      \MarginBottom=MarginBottom
      
      If \DockMode<>DockMode : AutoDockGadgetsNeeded=1 : EndIf            
      \GadgetDocking=@GadgetDocking()
      \DockMode=DockMode
            
      ;update docked gadgets if necessary
      If AutoDockGadgetsNeeded
         AutoDockGadgets()
      EndIf
   EndWith
   
EndProcedure
ProcedureDLL AutoResizeGadgets() ;update gadget sizes
   Shared AutoResizeGadgets
   If Not AutoResizeGadgets
      AutoResizeGadgets=1
      ;{/// UPDATE GADGET SIZES
      ForEach GadgetAnchor()         
         If Not IsGadget(GadgetAnchor()\ID)
            DeleteElement(GadgetAnchor())
            Continue
         EndIf
         
         Protected x, y, w, h
         Protected gx, gy
         With GadgetAnchor()
            GetClientRect_(\parent, rc.RECT)
            Protected parentW=rc\right
            Protected parentH=rc\bottom
            Protected parentCenterX=rc\right/2
            Protected parentCenterY=rc\bottom/2
            If \Left
               x=\a
               gx=GadgetX(\ID)
            ElseIf \c<>#PB_Ignore
               x=parentW-\a
               gx=x
            Else
               x=parentCenterX-\a
            EndIf
            If \Right
               w=parentW-gx-\c
            Else
               w=\c
            EndIf
            
            If \Top
               y=\b
               gy=GadgetY(\ID)
            ElseIf \d<>#PB_Ignore
               y=parentH-\b
               gy=y
            Else
               y=parentCenterY-\b
            EndIf
            If \Bottom
               h=parentH-gy-\d
            Else
               h=\d
            EndIf
            
            ResizeGadget(\ID, x, y, w, h)
         EndWith
      Next
      ;}/// UPDATE GADGET SIZES
      AutoResizeGadgets=0
   EndIf
EndProcedure
ProcedureDLL AutoDockGadgets() ;update docked gadgets
   Shared AutoDockGadgets
   If Not AutoDockGadgets
      AutoDockGadgets=1
      ;{/// UPDATE DOCKED GADGETS
      ForEach GadgetDocking()
         With GadgetDocking()
            If Not IsWindow(\parent)
               DeleteElement(GadgetDocking())
               Continue
            EndIf
            
            \a=0
            \b=0
            \c=0
            \d=0
         EndWith
      Next
      
      ;update docking priority (#Dock_Fill = low priority)
      ForEach GadgetAnchor()
         With GadgetAnchor()
            If \DockMode=#Dock_Fill
               CompilerIf #PB_Compiler_Version<430
                  \DockPriority=CountList(GadgetAnchor())
               CompilerElse
                  \DockPriority=ListSize(GadgetAnchor())
               CompilerEndIf               
            Else
               \DockPriority=ListIndex(GadgetAnchor())
            EndIf
         EndWith 
      Next
      SortStructuredList(GadgetAnchor(), #PB_Sort_Ascending, OffsetOf(GadgetAnchor\DockPriority), #PB_Sort_Integer)
            
      ForEach GadgetAnchor()
         With GadgetAnchor()
            If Not IsGadget(\ID)
               DeleteElement(GadgetAnchor())
               Continue
            EndIf
            
            If Not \DockMode
               Continue
            EndIf
            
            SetGadgetDock(\ID, \DockMode)
         EndWith
      Next
      ;}/// UPDATE DOCKED GADGETS
      AutoDockGadgets=0
   EndIf 
EndProcedure
Macro FreeGadget(ID, FreeGadgetFunction=FreeGadget)
   FreeGadgetFunction(ID)
   If GetGadgetDock(ID)
      AutoDockGadgets()
   EndIf
EndMacro
;}

; ********************
; EXAMPLE
; ********************

If OpenWindow(1, 200, 200, 230, 220, "Docking by Eddy", #PB_Window_SizeGadget | #PB_Window_SystemMenu)
   CompilerIf #PB_Compiler_Version < 430
      CreateGadgetList(WindowID(1))
   CompilerElse
      WindowBounds(1, 220, 170, 500, 500)
   CompilerEndif
   SmartWindowRefresh(1, 1)
   
   ButtonGadget(50, 0, 0, 20, 20, "D")
   SetGadgetDock(50, #Dock_Right, 0, 0, 5, 0)
   
   ButtonGadget(60, 0, 0, 20, 20, "Remove Me!")
   SetGadgetDock(60, #Dock_top, 5, 5, 5, 5)
   
   ButtonGadget(70, 0, 0, 20, 20, "Clone Me!")
   SetGadgetDock(70, #Dock_Bottom, 5, 5, 5, 5)
   
   ButtonGadget(80, 0, 0, 20, 20, "D")
   SetGadgetDock(80, #Dock_Left, 0, 5, 0, 5)
   ButtonGadget(90, 0, 0, 20, 20, "D")
   SetGadgetDock(90, #Dock_Left)
   
   If ContainerGadget(10, 50, 50, 0, 0, #PB_Container_Single)
      SetGadgetColor(10, #PB_Gadget_BackColor, RGB(255, 255, 0))
      SetGadgetDock(10, #Dock_Fill)
      
      ButtonGadget(11, 130, 10, 20, 20, "1")
      SetGadgetAnchor(11, 0, 1, 1, 0)
      
      ButtonGadget(12, 130, 90, 20, 20, "2")
      SetGadgetAnchor(12, 0, 0, 1, 1)
      
      ButtonGadget(13, 10, 50, 20, 20, "3")
      SetGadgetAnchor(13, 1, 0, 0, 0)
      
      ButtonGadget(14, 70, 50, 20, 20, "4")
      SetGadgetAnchor(14, 0, 0, 0, 0)
      
      CloseGadgetList()
   EndIf
EndIf

Repeat
   e=WaitWindowEvent()
   If e=#PB_Event_SizeWindow
      AutoResizeGadgets()
   EndIf
   If e=#PB_Event_Gadget And EventGadget()=70 And EventType()=#PB_EventType_LeftClick
      ;//// HOW TO ADD NEW DOCKED GADGET
      ButtonGadget(190, 0, 0, 20, 20, "Clone Me!")
      SetGadgetDock(190, #Dock_Bottom, 5, 5, 5, 0)
   EndIf
   If e=#PB_Event_Gadget And EventGadget()=60 And EventType()=#PB_EventType_LeftClick
      
      ;//// HOW TO REMOVE DOCKED GADGET (3 ways)
      #HowToRemoveDockedGadget=1
      CompilerSelect #HowToRemoveDockedGadget
         CompilerCase 1
            FreeGadget(60)
            ;If GetGadgetDock(ID)<>#Dock_None : AutoDockGadgets() : EndIf
         CompilerCase 2
            SetGadgetAnchor(60, 0, 0, 0, 0)
         CompilerCase 3
            SetGadgetDock(60, #Dock_None)            
      CompilerEndSelect
   EndIf
Until e=#PB_Event_CloseWindow
Last edited by eddy on Mon Oct 06, 2008 2:34 am, edited 23 times in total.
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
User avatar
Demivec
Addict
Addict
Posts: 4267
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

I noticed when I tested your sample code that it doesn't add a System Menu to the window so that it can be closed, even though you check for it in the event loop. :(
milan1612
Addict
Addict
Posts: 894
Joined: Thu Apr 05, 2007 12:15 am
Location: Nuremberg, Germany
Contact:

Post by milan1612 »

Cool, I wrote a docking system myself but never published it here.

http://www.purebasic.fr/german/viewtopi ... =10#196583
The first code is the include, the second one is an example...

You can do almost the same than with your code, but mine doesn't flicker that much :P
Last edited by milan1612 on Sun Sep 28, 2008 5:52 pm, edited 1 time in total.
Windows 7 & PureBasic 4.4
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Post by eddy »

Demivec wrote:I noticed when I tested your sample code that it doesn't add a System Menu to the window so that it can be closed, even though you check for it in the event loop.
You can add a system menu.
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
User avatar
Demivec
Addict
Addict
Posts: 4267
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

eddy wrote:
Demivec wrote:I noticed when I tested your sample code that it doesn't add a System Menu to the window so that it can be closed, even though you check for it in the event loop.
You can add a system menu.
Great code.

I made the comment because it seemed that is what you intended to do but didn't. I noticed you made the change to the original post.
Last edited by Demivec on Sun Sep 28, 2008 5:53 pm, edited 1 time in total.
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Post by eddy »

Code: Select all

Cool, I wrote a docking system myself but never published it here. 
There are interesting idea in your dock library.
But there are too much API.
You can do almost the same than with your code, but mine doesn't flicker that much
You can reduce the fickering by using SmartWindowRefresh
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

Post by eddy »

- ADDED : GetGadgetDock(ID)
- ADDED : macro for freegadget
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

Post by eddy »

- ADDED : margin parameters for docking

e.g:
- marginLeft=#PB_Ignore => don't change margin left
- marginLeft=33 => margin left distance = 33
Last edited by eddy on Mon Sep 29, 2008 11:23 am, edited 1 time in total.
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
Intrigued
Enthusiast
Enthusiast
Posts: 501
Joined: Thu Jun 02, 2005 3:55 am
Location: U.S.A.

Re: Gadget : Anchor, Dock, Margin, AutoResize

Post by Intrigued »

Thanks!
Intrigued - Registered PureBasic, lifetime updates user
ABBKlaus
Addict
Addict
Posts: 1143
Joined: Sat Apr 10, 2004 1:20 pm
Location: Germany

Post by ABBKlaus »

I can´t get it to work :
Line 333: WindowBounds() is not a function, array, macro or linked list
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Post by eddy »

ABBKlaus wrote:I can´t get it to work :
Line 333: WindowBounds() is not a function, array, macro or linked list
This code is optimized for PB4.30 :wink:
Comment this line if you use PB4.20

Code: Select all

From PB4.30 manual 
WindowBounds : set min / max window size
Last edited by eddy on Mon Sep 29, 2008 11:41 am, edited 1 time in total.
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
ABBKlaus
Addict
Addict
Posts: 1143
Joined: Sat Apr 10, 2004 1:20 pm
Location: Germany

Post by ABBKlaus »

ah ok :o (would be better you mentioned it in the first line of your code)
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Post by eddy »

I added some CompilerIf directives
- PB 4.20
- PB 4.30
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
ABBKlaus
Addict
Addict
Posts: 1143
Joined: Sat Apr 10, 2004 1:20 pm
Location: Germany

Post by ABBKlaus »

cool 8) works now. Thanks eddy.
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Post by eddy »

- FIXED : function recursive call
- FIXED : problem of dock process priority (#Dock_Fill has a low priority)
- FIXED : it supports docking negativ margins
- UPDATED : example - add docked gadget & remove docked gadget

- edit - PB430 & PB420
Imagewin10 x64 5.72 | IDE | PB plugin | Tools | Sprite | JSON | visual tool
Post Reply