Autoresize without containergadget

Share your advanced PureBasic knowledge/code with the community.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Autoresize without containergadget

Post by Trond »

When seeing this: http://www.purebasic.fr/english/viewtop ... 12&t=44976 I got inspired and wanted to see if I could make a version without the container gadget and for unlimited children. I used a trick when accessing the parameters of a procedure as an array, if you have 64-bit it may not work, please post your crash if any.

This is the result (there is no proportions like the second code in the topic linked above):

Code: Select all

; Some of this code was by mdp

Enumeration
  #SWidget_Gadget
  #SWidget_Box
  #Horizontal = 0
  #Vertical
EndEnumeration

Structure SWidget
  Type.i
  Number.i
EndStructure

Structure SBox Extends SWidget
  Mode.i
  List Children.SBox()
EndStructure

Structure SIntArray
  i.i[0]
EndStructure

Declare ResizeWidget(*W.SWidget, x, y, w, h)
Procedure ResizeBox(*B.SBox, x, y, w, h)
  Protected cx.d, cy.d
  Protected ItemWidth.d, ItemHeight.d
  Select *B\Mode
    Case #Horizontal
      ItemWidth.d = w/ListSize(*b\children())
      ForEach *b\children()
        ResizeWidget(*b\Children(), x+cx, y, ItemWidth, h)
        cx + ItemWidth
      Next
    Case #Vertical
      ItemHeight = h/ListSize(*b\Children())
      ForEach *b\Children()
        ResizeWidget(*b\Children(), x, y+cy, w, ItemHeight)
        cy + ItemHeight
      Next
  EndSelect
EndProcedure

Procedure ResizeWidget(*W.SWidget, x, y, w, h)
  Select *w\Type
    Case #SWidget_Gadget
      ResizeGadget(*W\Number, x, y, w, h)
    Case #SWidget_Box
      ResizeBox(*W, x, y, w, h)
  EndSelect
EndProcedure

Procedure AddGadgetToBox(*Box.SBox, Gadget)
  AddElement(*box\Children())
  *Box\Children()\Number = Gadget
EndProcedure

Procedure AutosizeGadget(*parent.SBox=0, mode=0, g0=-1, g1=-1, g2=-1, g3=-1, g4=-1, g5=-1, g6=-1, g7=-1, g8=-1)
  If *parent
    AddElement(*parent\Children())
    *parent\Children()\Type = #SWidget_Box
    *Box.SBox = *parent\Children()
  Else
    *Box.SBox = AllocateMemory(SizeOf(SBox))
    InitializeStructure(*Box, SBox)
  EndIf
  *Box\Mode = Mode
  *box\Type = #SWidget_Box
  *Gadgets.SIntArray = @g0
  For I = 0 To 8
    If *gadgets\i[i] <> -1
      AddGadgetToBox(*Box, *Gadgets\i[i])
    EndIf
  Next
  ProcedureReturn *Box
EndProcedure

;- Example
Enumeration 
   #g_toplabel
   #g_autosize2
   #g_autosize1 : #g_label0 : #g_label1
   #g_autosize0 : #g_b0 : #g_b1 : #g_b2
EndEnumeration

#W = 512
#H = 384

OpenWindow(0, 0, 0, #W, #H, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
SmartWindowRefresh(0, 1)

TextGadget(#g_toplabel,0,0,320,20,"AutosizeGadget test")
A = AutosizeGadget(0, #Horizontal)
  B = AutosizeGadget(A, #Vertical, #g_b0, #g_b1, #g_b2)
    ButtonGadget(#g_b0,0,0,0,0,"1")
    ButtonGadget(#g_b1,0,0,0,0,"22")
    ButtonGadget(#g_b2,0,0,0,0,"333")
    For I = 0 To 10
      AddGadgetToBox(B, ButtonGadget(#PB_Any, 0, 0, 0, 0, "Hello " + Str(I)))
    Next
  AutosizeGadget(A, #Vertical, #g_label0, #g_label1)
    TextGadget(#g_label0,0,0,0,0,"Text 1",#PB_Text_Border)
    TextGadget(#g_label1,0,0,0,0,"Text 2",#PB_Text_Border)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_SizeWindow
      ResizeWidget(A, 0, 20, WindowWidth(0), WindowHeight(0)-20)
    Case #PB_Event_CloseWindow
      Break
  EndSelect
ForEver
Last edited by Trond on Sun Jan 16, 2011 12:14 pm, edited 1 time in total.
User avatar
fsw
Addict
Addict
Posts: 1603
Joined: Tue Apr 29, 2003 9:18 pm
Location: North by Northwest

Re: Autoresize without containergadget

Post by fsw »

On my WinXP-32-SP3 laptop it flickers sometimes, got it flickerfree by adding a:

Code: Select all

SmartWindowRefresh(0, #True)
before the repeat/until loop.

Thanks
buddymatkona
Enthusiast
Enthusiast
Posts: 252
Joined: Mon Aug 16, 2010 4:29 am

Re: Autoresize without containergadget

Post by buddymatkona »

It looks great on Win7 64. There was minimal refresh flicker with SmartWindowRefresh and no crashing. The next step might be to associate font sizes with proportion levels.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: Autoresize without containergadget

Post by Trond »

fsw wrote:On my WinXP-32-SP3 laptop it flickers sometimes, got it flickerfree by adding a:

Code: Select all

SmartWindowRefresh(0, #True)
before the repeat/until loop.
Thanks, it looks better. Reducing flicker was one of the goals of not using container gadgets. Because SmartWindowRefresh() doesn't seem to help the flickering of container gadgets.
yrreti
Enthusiast
Enthusiast
Posts: 546
Joined: Tue Oct 31, 2006 4:34 am

Re: Autoresize without containergadget

Post by yrreti »

Hi Trond,

I have always hated the dashed line border that shows on a button after it' s been clicked.
It takes a lot away from the sharpness of your windows layout.
You can easily get rid of it by using an invisible dummy button to set active after clicking on
any button.
Just add the following to your code and see what I mean:

Code: Select all

Enumeration
  #SWidget_Gadget
  #SWidget_Box
  #Horizontal = 0
  #Vertical
  #Button_cdb;<---------------------------------(cdb = clear dash border)
EndEnumeration

Code: Select all

OpenWindow(0, 0, 0, #W, #H, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)

TextGadget(#g_toplabel,0,0,320,20,"AutosizeGadget test")
ButtonGadget(#Button_cdb, 0, 0, 0, 0, "");<-----------------------------------------
A = AutosizeGadget(0, #Horizontal)

Code: Select all

  Select WaitWindowEvent()
    Case #PB_Event_SizeWindow
      ResizeWidget(A, 0, 20, WindowWidth(0), WindowHeight(0)-20)
      SetActiveGadget(#Button_cdb);<---------------------------------------------
User avatar
Vera
Addict
Addict
Posts: 858
Joined: Tue Aug 11, 2009 1:56 pm
Location: Essen (Germany)

Re: Autoresize without containergadget

Post by Vera »

thanks for sharing :)

as for Linux (Suse 11.1) it runs smooth (with a bit of delay)

On start all gadgets are scrambled together on 0x0. This can be avoided by adding:

Code: Select all

ResizeWidget(A, 0, 20, WindowWidth(0), WindowHeight(0)-20)
before the repeat/until loop.

Than you can happily squeeze them down to mere stripes :mrgreen:

As some MAC gadgets will demand a minimum size (e.g. ButtonGadget >=22 (hight)) and a 'minimum-limit-check' would be reasonable to have anyway. Could you / s.o. enhance it in this regard ?


@ yrreti
nice idea - but you could set the focus anywhere to remove it e.g. from a button, and on the whole it doesn't remove these dotted lines for good

Tip: on Linux your 'invisible' button is displayed (~ 10x20px) covering the TextGadget. It's because of the sero-(undefined)-dimension. Setting it to 1x1 will 'hide' it on Linux as well.

Code: Select all

ButtonGadget(#Button_cdb, 0, 0, 1, 1, "");<-------------
p.s.: as this won't work for MAC you might just as well use an ImageGadget to allow the same

greetings ~ Vera
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: Autoresize without containergadget

Post by Trond »

@yrreti: the dotted selection is there for a reason (keyboard navigation), removing it is just annoying.

@vera: I have been working on a version with minimum sizes, but it's not clear to me how to distribute the left-over space nicely.
Let's say I have a container that is 400px wide and four buttons.
Btn A minimum size: 100px
Btn B minimum size: 90px
Btn C minimum size: 50px
Btn D minimum size: 40px
Total: 280px
Leftover: 120px

How do I distribute the leftover pixels? Gtk distributes them evenly (all buttons have 120/4 pixels added to them) but it looks ugly with small children of almost the same sizes, as Btn C and Btn D will have almost the same size, but not exactly the same.
Another alternative is to always give remaining pixels to the smallest child. So we give Btn D 10 pixels so it becomes 50 px, then Btn C and D both gets 40 so the become as big as Btn B, and so on. The problem is that this looks very strange if there are some very large children and some very small.
No matter how I do it, it ends up uglier than manual placement. Any suggestions?
yrreti
Enthusiast
Enthusiast
Posts: 546
Joined: Tue Oct 31, 2006 4:34 am

Re: Autoresize without containergadget

Post by yrreti »

@vera Thanks for those tips with Linux and Mac

@Trond It's just a matter of personal taste I guess :wink:
Still thanks for the interesting code.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: Autoresize without containergadget

Post by Trond »

I made an enchanced version with two modes: #Box_AllSameSize and a default mode which sizes the children proportionally to their minimum sizes. These mode correspond to gtk boxes with and without the "homogenous" property set.

Also I changed to a smarter way of computing child sizes so that everything is now pixel perfect. There isn't any flickering spacing sizes (as with naive double math) nor excess spacing at the end of a box when rounding occurs (as with naive integer math).

What is still missing (and it's rather important) are the packing flags (fill/expand) and spacers (which make no sense without the packing flags).

Required include:

Code: Select all

; gadget_size.pb
; 
;  Calculates the size required to display a Gadget properly.
;  By freak
;
;  Supported Gadgets:
;    Button, Checkbox, Option, Text, String, ComboBox, Image 
;
;  Note:
;    For Gadgets with variable content (String, ComboBox), only the returned height
;    is useful, as the width will only be an absolute minimum value.
;
;  The 'Flags' parameter gives gadget flags to include in the calculation.
;  Currently only #PB_Text_Border makes a difference there.   
;

CompilerIf Defined(MaxI, #PB_Procedure) = 0
  Procedure MaxI(a, b)
    If a > b
      ProcedureReturn a
    Else
      ProcedureReturn b
    EndIf
  EndProcedure
CompilerEndIf

CompilerIf Defined(MinI, #PB_Procedure) = 0
  Procedure MinI(a, b)
    If a < b
      ProcedureReturn a
    Else
      ProcedureReturn b
    EndIf
  EndProcedure
CompilerEndIf

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  Structure PB_Gadget
    *Gadget.GtkWidget
    *Container.GtkWidget
    *VT
    UserData.i
    GadgetData.i[4]
  EndStructure
CompilerEndIf

CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
  Structure OSX_Rect
    top.w
    left.w
    bottom.w
    right.w
  EndStructure
  
  #noErr = 0
CompilerEndIf


; Stores the result in *Width\i and *Height\i

Procedure GetRequiredSize(Gadget, *Width.Integer, *Height.Integer, Flags = 0)

  CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Windows
  
    DC = GetDC_(GadgetID(Gadget))
    oldFont = SelectObject_(DC, GetGadgetFont(Gadget)) 
    Size.SIZE
  
    Select GadgetType(Gadget)
    
      Case #PB_GadgetType_Text
        Text$ = RemoveString(GetGadgetText(Gadget), Chr(10))
        count = CountString(Text$, Chr(13)) + 1
        empty = 0
        maxheight = 0 
        For index = 1 To count 
          Line$ = StringField(Text$, index, Chr(13))
          If Line$ = ""
            empty + 1
          Else 
            GetTextExtentPoint32_(DC, @Line$, Len(Line$), @LineSize.SIZE)
            Size\cx = MaxI(Size\cx, LineSize\cx)
            Size\cy + LineSize\cy
            maxheight = MaxI(maxheight, LineSize\cy)
          EndIf
        Next index            
        Size\cy + empty * maxheight  
        
        If Flags & #PB_Text_Border
          Size\cx + GetSystemMetrics_(#SM_CXEDGE) * 2
          Size\cy + GetSystemMetrics_(#SM_CYEDGE) * 2
        Else           
          Size\cx + 2
          Size\cy + 2
        EndIf

      Case #PB_GadgetType_CheckBox, #PB_GadgetType_Option
        Text$ = GetGadgetText(Gadget)
        GetTextExtentPoint32_(DC, @Text$, Len(Text$), @Size.SIZE)
        Size\cx + 20
        Size\cy = MaxI(Size\cy+2, 20)
        
      Case #PB_GadgetType_Button
        Text$ = GetGadgetText(Gadget)
        GetTextExtentPoint32_(DC, @Text$, Len(Text$), @Size.SIZE)
        Size\cx + GetSystemMetrics_(#SM_CXEDGE)*2
        Size\cy = MaxI(Size\cy+GetSystemMetrics_(#SM_CYEDGE)*2, 24)
        Size\cx + 10
        
      Case #PB_GadgetType_String
        Text$ = GetGadgetText(Gadget) + "Hg" 
        GetTextExtentPoint32_(DC, @Text$, Len(Text$), @Size.SIZE)
        Size\cx = GetSystemMetrics_(#SM_CXEDGE)*2 
        Size\cy = MaxI(Size\cy+GetSystemMetrics_(#SM_CXEDGE)*2, 20)
        
      Case #PB_GadgetType_ComboBox
        GetTextExtentPoint32_(DC, @"Hg", 2, @Size.SIZE)
        Size\cy = MaxI(Size\cy + 8, 21)
        Size\cx = Size\cy  
        
      Case #PB_GadgetType_Image
        Size\cx = GadgetWidth(Gadget)
        Size\cy = GadgetHeight(Gadget)
        
    EndSelect
    
    SelectObject_(DC, oldFont)
    ReleaseDC_(GadgetID(Gadget), DC)
    *Width\i  = Size\cx
    *Height\i = Size\cy
  
  CompilerCase #PB_OS_Linux
  
    Protected RealSize.GtkRequisition
    Protected Size.GtkRequisition
    Protected *Gadget.PB_Gadget
    
    *Gadget.PB_Gadget = IsGadget(Gadget)
    
    If *Gadget And *Gadget\Container And GadgetType(Gadget) <> #PB_GadgetType_ComboBox
      gtk_widget_size_request_(*Gadget\Container, @RealSize.GtkRequisition)
      gtk_widget_set_size_request_(*Gadget\Container, -1, -1)
      gtk_widget_size_request_(*Gadget\Container, @Size.GtkRequisition)      
      gtk_widget_set_size_request_(*Gadget\Container, RealSize\Width, RealSize\Height) 
    Else
      gtk_widget_size_request_(GadgetID(Gadget), @RealSize.GtkRequisition)
      gtk_widget_set_size_request_(GadgetID(Gadget), -1, -1)              
      gtk_widget_size_request_(GadgetID(Gadget), @Size.GtkRequisition)    
      gtk_widget_set_size_request_(GadgetID(Gadget), RealSize\Width, RealSize\Height)
    EndIf
    
    If GadgetType(Gadget) = #PB_GadgetType_ComboBox Or GadgetType(Gadget) = #PB_GadgetType_String
      *Width\i  = 20 
    Else
      *Width\i  = Size\Width
    EndIf
        
    *Height\i = Size\Height    

  CompilerCase #PB_OS_MacOS
  
    Type = GadgetType(Gadget)
    
    If Type = #PB_GadgetType_Image    
      *Width\i = GadgetWidth(Gadget)
      *Height\i = GadgetHeight(Gadget)
      
    ElseIf Type = #PB_GadgetType_Text
      realwidth   = GadgetWidth(Gadget)
      
      *Width\i = 40
      *Height\i = 20      
      
      ResizeGadget(Gadget, #PB_Ignore, #PB_Ignore, 1000, #PB_Ignore) 
      
      If GetBestControlRect_(GadgetID(Gadget), @Rect.OSX_Rect, @BaseLine.w) = #noErr
        Height = Rect\bottom - Rect\top
        If Height > 0
        
          Min = 0
          Max = 1000
          
          While Max > Min+2
            Mid = (Min + Max) / 2
            
            ResizeGadget(Gadget, #PB_Ignore, #PB_Ignore, Mid, #PB_Ignore) 
            
            If GetBestControlRect_(GadgetID(Gadget), @Rect.OSX_Rect, @BaseLine.w) <> #noErr
              ProcedureReturn 
            EndIf
            
            If Rect\bottom - Rect\top > Height
              Min = Mid
            Else
              Max = Mid
            EndIf
          Wend
          
          *Width\i = Rect\right - Rect\left + 2 
          *Height\i = MaxI(Height, 20) 
        EndIf
          
      EndIf 
      
      ResizeGadget(Gadget, #PB_Ignore, #PB_Ignore, realwidth, #PB_Ignore)

    Else 
      If GetBestControlRect_(GadgetID(Gadget), @Rect.OSX_Rect, @BaseLine.w) = #noErr
        *Width\i = Rect\right - Rect\left
        *Height\i = MaxI(Rect\bottom - Rect\top, 20) 
        
        If Type = #PB_GadgetType_Button Or Type = #PB_GadgetType_String
          *Height\i = MaxI(*Height\i, 24)        
        EndIf        
      Else 
        *Width\i = 40
        *Height\i = 20
      EndIf
      
      If Type = #PB_GadgetType_String Or Type  = #PB_GadgetType_ComboBox        
        *Width\i = 30 
      EndIf
    
    EndIf
  
  CompilerEndSelect
  
EndProcedure

Code: Select all

XIncludeFile "gadget_size.pb"

Enumeration
  #SGadget_Gadget
  #SGadget_Box
EndEnumeration

Enumeration 
  #Box_Horizontal  = 0
  #Box_Vertical    = 1
  #Box_AllSameSize = 2
EndEnumeration

Structure SIntArray
  i.i[0]
EndStructure

Structure SSize
  W.i
  H.i
EndStructure

Structure SGadget
  Kind.i
  Number.i
  Padding.i
  MinSize.SSize
EndStructure

Structure SBox Extends SGadget
  BoxOptions.i
  Spacing.i
  List Children.SBox()
EndStructure

Declare   SGadget_UpdateRequiredSize(*G.SGadget)
Procedure SGadget_Box_UpdateRequiredSize(*G.SBox)
  Protected LargestHeight
  Protected LargestWidth
  Protected ChildCount
  Protected SpacingTotal
  
  Protected MinHeight
  Protected MinWidth
  
  ; Calculate child sizes
  ForEach *G\Children()
    SGadget_UpdateRequiredSize(*G\Children())
  Next
  
  ; Fill some variables common to all layout modes
  ChildCount = ListSize(*G\Children())
  ForEach *G\Children()
    LargestWidth = MaxI(*G\Children()\MinSize\W, LargestWidth)
    LargestHeight = MaxI(*G\Children()\MinSize\H, LargestHeight)
  Next
  SpacingTotal = (ChildCount-1) * *G\Spacing
  
  ; Calculate own required size (depending on child sizes)
  If *G\BoxOptions & #Box_Vertical
  
    *G\MinSize\W = LargestWidth
    If *G\BoxOptions & #Box_AllSameSize
      *G\MinSize\H = LargestHeight * ChildCount + SpacingTotal
    Else ; Not all same size
      MinHeight = 0
      ForEach *G\Children()
        MinHeight + *G\Children()\MinSize\H
      Next
      MinHeight + SpacingTotal
      *G\MinSize\H = MinHeight
    EndIf
    
  Else ; Horizontal
  
    *G\MinSize\H = LargestHeight
    
    If *G\BoxOptions & #Box_AllSameSize
      *G\MinSize\W = LargestWidth * ChildCount + SpacingTotal
    Else ; Not all same size
      MinWidth = 0
      ForEach *G\Children()
        MinWidth + *G\Children()\MinSize\W
      Next
      MinWidth + SpacingTotal
      *G\MinSize\W = MinWidth
    EndIf
    
  EndIf
EndProcedure

Declare   SGadget_Resize(*G.SGadget, x, y, w, h)
Procedure SGadget_Box_Resize(*G.SBox, x, y, w, h)
  Protected ChildCount, ChildCountDown
  Protected LargestHeight
  Protected LargestWidth
  Protected SpacingTotal
  
  Protected Leftover
  Protected LeftoverForThis
  Protected cx, cw, cy, ch
  
  ChildCount = ListSize(*G\Children())
  ChildCountDown = ChildCount
  SpacingTotal = (ChildCount-1)**G\Spacing
  
  If *G\BoxOptions & #Box_Vertical
    
    If *G\BoxOptions & #Box_AllSameSize
      ; Find largest
      ForEach *G\Children()
        LargestHeight = MaxI(*G\Children()\MinSize\H, LargestHeight)
      Next
      ; Find leftover space to divide it evenly among children
      Leftover = h - LargestHeight*ChildCount - SpacingTotal
      ForEach *G\Children()
        LeftoverForThis = Leftover / ChildCountDown
        ch = LargestHeight + LeftoverForThis
        SGadget_Resize(*G\Children(), x, y+cy, w, ch)
        Leftover - LeftoverForThis
        ChildCountDown - 1
        cy + ch + *G\Spacing
      Next
    Else ; Not all same size
      ; Find leftover space to divide it evenly among children
      Leftover = h - *G\MinSize\h + *g\Padding*2
      ForEach *G\Children()
        LeftoverForThis = Leftover/ChildCountDown
        ch = *G\Children()\MinSize\H + LeftoverForThis
        SGadget_Resize(*G\Children(), x, y+cy, w, ch)
        Leftover - LeftoverForThis
        ChildCountDown - 1
        cy + ch + *G\Spacing
      Next
    EndIf
    
  Else ; Horizontal
    
    If *G\BoxOptions & #Box_AllSameSize
      ; Find largest
      ForEach *G\Children()
        LargestWidth = MaxI(*G\Children()\MinSize\W, LargestWidth)
      Next
      ; Find leftover space to divide it evenly among children
      Leftover = w - LargestWidth*ChildCount - SpacingTotal
      ForEach *G\Children()
        LeftoverForThis = Leftover/ChildCountDown
        cw = LargestWidth + LeftoverForThis
        SGadget_Resize(*G\Children(), x+cx, y, cw, h)
        Leftover - LeftoverForThis
        ChildCountDown - 1
        cx + cw + *G\Spacing
      Next
    Else ; Not all same size
      ; Find leftover space to divide it evenly among children
      Leftover = w - *G\MinSize\W + *G\Padding*2
      ForEach *G\Children()
        LeftoverForThis = Leftover/ChildCountDown
        cw = *G\Children()\MinSize\W + LeftoverForThis
        SGadget_Resize(*G\Children(), x+cx, y, cw, h)
        Leftover - LeftoverForThis
        ChildCountDown - 1
        cx + cw + *G\Spacing
      Next
    EndIf
  EndIf
EndProcedure

Procedure SGadget_UpdateRequiredSize(*G.SGadget)
  Select *G\Kind
    Case #SGadget_Gadget
      GetRequiredSize(*G\Number, @*g\MinSize\W, @*g\MinSize\H)
      ;Debug Str(*G\Number) + ": " + Str(*g\MinSize\W)
    Case #SGadget_Box
      SGadget_Box_UpdateRequiredSize(*G)
    Default
      CallDebugger
  EndSelect
  *G\MinSize\H + *G\Padding*2
  *G\MinSize\W + *G\Padding*2
EndProcedure

Procedure SGadget_Resize(*G.SGadget, x, y, w, h)
  x + *G\Padding
  y + *G\Padding
  w - *G\Padding*2
  h - *G\Padding*2
  Select *G\Kind
    Case #SGadget_Gadget
      ResizeGadget(*G\Number, x, y, w, h)
    Case #SGadget_Box
      SGadget_Box_Resize(*G, x, y, w, h)
    Default
      CallDebugger
  EndSelect
EndProcedure

Procedure SGadget_SetWindowBounds(*G.SGadget, Window, AddWidth=0, AddHeight=0)
  WindowBounds(Window, *G\MinSize\W+AddWidth, *G\MinSize\H+AddHeight, #PB_Ignore, #PB_Ignore)
EndProcedure

Procedure AddGadgetToBox(*Box.SBox, Gadget)
  AddElement(*box\Children())
  *Box\Children()\Number = Gadget
EndProcedure

Procedure SGadget_Box(*parent.SBox=0, BoxOptions=#Box_Horizontal, g0=-1, g1=-1, g2=-1, g3=-1, g4=-1, g5=-1, g6=-1, g7=-1, g8=-1)
  Protected *Box.SBox
  Protected *Gadgets.SIntArray
  Protected I
  If *parent
    AddElement(*parent\Children())
    *Box = *parent\Children()
  Else
    *Box = AllocateMemory(SizeOf(SBox))
    InitializeStructure(*Box, SBox)
  EndIf
  *Box\Number = -1
  *Box\BoxOptions = BoxOptions
  *box\Kind = #SGadget_Box
  *Gadgets = @g0
  For I = 0 To 8
    If *gadgets\i[i] <> -1
      AddGadgetToBox(*Box, *Gadgets\i[i])
    EndIf
  Next
  ProcedureReturn *Box
EndProcedure

;- EXAMPLE:

Enumeration 
  #g_toplabel
  #g_label0 : #g_label1
  #g_b0 : #g_b1 : #g_b2
  #g_label2
EndEnumeration

#W = 512
#H = 384

OpenWindow(0, 100, 50, #W, #H, "", #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_Invisible)
TextGadget(#g_toplabel, 0, 0, 200, 22, "Adjustable gadgets: ")

Define *A.SBox, *B.SBox, *C.SBox, *D.SBox

*A = SGadget_Box(0, #Box_Horizontal)
  
  ; 3 Horizontally stacked buttons of variable width
  *B = SGadget_Box(*A, #Box_Horizontal, #g_b0, #g_b1, #g_b2)
          ButtonGadget(#g_b0,0,0,0,0,"1")
          ButtonGadget(#g_b1,0,0,0,0,"22")
          ButtonGadget(#g_b2,0,0,0,0,"333 variable width buttons")
  
  ; Multiple vertically stacked buttons and text of variable height
  ; And a child with all same size
  *C = SGadget_Box(*A, #Box_Vertical)
          TextGadget(#g_label2,0,0,0,0, "Testing the variable height")
          For I = 0 To 5
            If i = 3
              AddGadgetToBox(*C, #g_label2)
            EndIf
            AddGadgetToBox(*C, ButtonGadget(#PB_Any, 0, 0, 0, 0, "Hello " + Str(I)))
          Next
  
          ; Child box with all same height
          *C2 = SGadget_Box(*C, #Box_Vertical | #Box_AllSameSize)
          AddGadgetToBox(*C2, TextGadget(#PB_Any, 0, 0, 0, 0, "This text and 6-8 are all same height:"))
          For I = 6 To 8
            AddGadgetToBox(*C2, ButtonGadget(#PB_Any, 0, 0, 0, 0, Str(I)))
          Next
    
  ; 2 Horizontally stacked text of same width
  *D = SGadget_Box(*A, #Box_Horizontal | #Box_AllSameSize, #g_label0, #g_label1)
          TextGadget(#g_label0,0,0,0,0,"Text 1", #PB_Text_Border)
          TextGadget(#g_label1,0,0,0,0,"All same size text", #PB_Text_Border)
          

ForEach *A\Children()
  *a\Children()\Padding = 5
Next

*A\Padding = 10
; *A\Spacing = 7

SGadget_UpdateRequiredSize(*A)
SGadget_Resize(*A, 0, 20, WindowWidth(0), WindowHeight(0)-20)
SGadget_SetWindowBounds(*A, 0, 0, 20)
HideWindow(0, 0)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_SizeWindow
      SGadget_Resize(*A, 0, 20, WindowWidth(0), WindowHeight(0)-20)
    Case #PB_Event_CloseWindow
      Break
  EndSelect
ForEver

Post Reply