AutosizeGadget()

Share your advanced PureBasic knowledge/code with the community.
mdp
Enthusiast
Enthusiast
Posts: 115
Joined: Mon Apr 18, 2005 8:28 pm

AutosizeGadget()

Post by mdp »

To simplify GUI creation, I needed some kind of container gadget which would automatically place and size its children (similarly to the mozilla XUL controls).

This would make several things more comfortable:
- as that container is resized, its children can be automatically resized by the same procedure that first arranges them
- there is no need to define x, y, width and height for the children gadgets (just the order)

This is akin to the SplitterGadget, but:
- it can contain more than two children,
- it can be used when the user does not need to or simply should not change the internal proportions

You can find below the code an example for an AutosizeGadget()

But first, for the Feature Request
I would recommend the implementation of such gadget in the PB core, so that:
- the usage could be akin to the one in the example ( AutosizeGadget(), [children], CloseGadgetList() )
- there would be for the coder no need to call the "AutosizeGadget_Resize()" after the GUI definition, nor after the ResizeGadget(#myautosizegadget,...): calling the ResizeGadget on it should also resize its contents

Do you think this might be useful?

Code: Select all

Enumeration
   #gadget_Autosize_Horizontal
   #gadget_Autosize_Vertical
EndEnumeration

Structure sk_autosizegadget
   num.l             ; #mygadget
   mode.l            ; horizontal: children are side by side | vertical: children are stacked
   children.l[8]     ; #gadgets contained by #mygadget
EndStructure
Global NewList autosizegadgets.sk_autosizegadget()

Procedure AutosizeGadget( gadget_number, x, y, width, height, mode, g0, g1, g2=-1, g3=-1, g4=-1, g5=-1, g6=-1, g7=-1 )
   ContainerGadget(gadget_number,x,y,width,height)
   AddElement( autosizegadgets() )
   autosizegadgets()\num  = gadget_number
   autosizegadgets()\mode = mode
   autosizegadgets()\children[0]=g0
   autosizegadgets()\children[1]=g1
   autosizegadgets()\children[2]=g2
   autosizegadgets()\children[3]=g3
   autosizegadgets()\children[4]=g4
   autosizegadgets()\children[5]=g5
   autosizegadgets()\children[6]=g6
   autosizegadgets()\children[7]=g7
EndProcedure

Procedure AutosizeGadget_Resize()
   ForEach autosizegadgets()
      mode = autosizegadgets()\mode 
      w = GadgetWidth(autosizegadgets()\num)-2
      h = GadgetHeight(autosizegadgets()\num)-2
      totchildren=0 : For a=0 To 7 : If autosizegadgets()\children[a]<>-1 : totchildren+1 : EndIf : Next
      If mode=#gadget_Autosize_Vertical
         childw.f = w*1.0/totchildren : childh.f = h
         For a=0 To 7
            If autosizegadgets()\children[a]<>-1
               ResizeGadget(autosizegadgets()\children[a],Int(a*childw),0,Int(childw),childh)
            EndIf
         Next
      Else
         childh.f = h*1.0/totchildren : childw.f = w
         For a=0 To 7
            If autosizegadgets()\children[a]<>-1
               ResizeGadget(autosizegadgets()\children[a],0,Int(a*childh),childw,Int(childh))
            EndIf
         Next
      EndIf
   Next
EndProcedure

; =======
; EXAMPLE

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

If Not OpenWindow(0, 100, 200, 320, 240, "AutosizeGadget()", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget) : End : EndIf

TextGadget(#g_toplabel,0,0,320,20,"AutosizeGadget test")
AutosizeGadget(#g_autosize2,0,20,320,220,#gadget_autosize_vertical,#g_autosize0,#g_autosize1)
   AutosizeGadget(#g_autosize0,0,0,0,0,#gadget_autosize_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")
   CloseGadgetList()
   AutosizeGadget(#g_autosize1,0,0,0,0,#gadget_autosize_horizontal,#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)
   CloseGadgetList()
CloseGadgetList()

AutosizeGadget_Resize()

Repeat
   EvID = WaitWindowEvent()
   Select EvID
      Case #PB_Event_SizeWindow
         ResizeGadget(#g_autosize2,0,20,WindowWidth(0),WindowHeight(0)-20) 
         AutosizeGadget_Resize()
   EndSelect
Until EvID = #PB_Event_CloseWindow
User avatar
Didelphodon
PureBasic Expert
PureBasic Expert
Posts: 450
Joined: Sat Dec 18, 2004 11:56 am
Location: Vienna - Austria
Contact:

Re: AutosizeGadget()

Post by Didelphodon »

Cool! Reminds me on Java's automatic layout-concept.
Go, tell it on the mountains.
mdp
Enthusiast
Enthusiast
Posts: 115
Joined: Mon Apr 18, 2005 8:28 pm

Re: AutosizeGadget()

Post by mdp »

Update: added proportions. A string before the gadgets list defines the proportional size of each gadget or its constant size.

Procedure AutosizeGadget( gadget_number, x, y, width, height, mode, proportions.s, g0, g1, g2=-1, g3=-1, g4=-1, g5=-1, g6=-1, g7=-1 )

For example,
AutosizeGadget(#g_autosize_main,0,0,WindowWidth(0),WindowHeight(0),#gadget_autosize_vertical,"0120",#g_toplabel,#g_autosize0,#g_autosize1,#g_autosize_bottom)
means
- create a container covering the inner window and layout the contents vertically,
- "0120",#g_toplabel,#g_autosize0,#g_autosize1,#g_autosize_bottom means
-- the #g_toplabel and #g_autosize_bottom will have a constant height ("0"), taken from their gadget definition
-- the #g_autosize0 will have half height of #g_autosize1 ("1","2")

This dramatically simplifies GUI creation. Yep, I push for introduction in the library : ).

BTW: in the former post I swapped horizontal and vertical (sorry)
[EDIT - ...and in the present one I forgot a piece of code...]

@Didelphodon: Thanks! I admit I am not close to Java and I did not know this was common in it

Code: Select all

Enumeration
   #gadget_Autosize_Horizontal
   #gadget_Autosize_Vertical
EndEnumeration

Structure sk_autosizegadget
   num.l             ; #mygadget
   mode.l            ; horizontal: children are stacked | vertical: children are aside
   children.l[8]     ; #gadgets contained by #mygadget
   childprop.l[8]    ; width/height proportion of each child.  0 means constant
EndStructure
Global NewList autosizegadgets.sk_autosizegadget()

Procedure AutosizeGadget( gadget_number, x, y, width, height, mode, proportions.s, g0, g1, g2=-1, g3=-1, g4=-1, g5=-1, g6=-1, g7=-1 )
   ContainerGadget(gadget_number,x,y,width,height)
   AddElement( autosizegadgets() )
   autosizegadgets()\num  = gadget_number
   autosizegadgets()\mode = mode
   autosizegadgets()\children[0]=g0
   autosizegadgets()\children[1]=g1
   autosizegadgets()\children[2]=g2
   autosizegadgets()\children[3]=g3
   autosizegadgets()\children[4]=g4
   autosizegadgets()\children[5]=g5
   autosizegadgets()\children[6]=g6
   autosizegadgets()\children[7]=g7
   proportions=LSet(proportions,8,"0")
   autosizegadgets()\childprop[0]=Val(Mid(proportions,1,1))
   autosizegadgets()\childprop[1]=Val(Mid(proportions,2,1))
   autosizegadgets()\childprop[2]=Val(Mid(proportions,3,1))
   autosizegadgets()\childprop[3]=Val(Mid(proportions,4,1))
   autosizegadgets()\childprop[4]=Val(Mid(proportions,5,1))
   autosizegadgets()\childprop[5]=Val(Mid(proportions,6,1))
   autosizegadgets()\childprop[6]=Val(Mid(proportions,7,1))
   autosizegadgets()\childprop[7]=Val(Mid(proportions,8,1))
EndProcedure

Procedure AutosizeGadget_Resize()
   ForEach autosizegadgets()
      mode = autosizegadgets()\mode 
      w = GadgetWidth(autosizegadgets()\num)-2
      h = GadgetHeight(autosizegadgets()\num)-2
      totchildren=0 : For a=0 To 7 : If autosizegadgets()\children[a]<>-1 : totchildren+1 : Else : Break : EndIf : Next
      totspan=0     : For a=0 To 7 : If autosizegadgets()\children[a]<>-1 : totspan=totspan+autosizegadgets()\childprop[a] : Else : Break : EndIf : Next 
      For a=0 To totchildren-1
         If autosizegadgets()\children[a]<>-1 
            If autosizegadgets()\childprop[a]=0
               If mode=#gadget_Autosize_Horizontal
                  w=w-GadgetWidth(autosizegadgets()\children[a])
               Else
                  h=h-GadgetHeight(autosizegadgets()\children[a])
               EndIf
            EndIf
         EndIf
      Next
      
      If mode=#gadget_Autosize_Horizontal
         childw_base.f = w*1.0/totspan : childh.f = h : pos=0
         For a=0 To totchildren-1
            If autosizegadgets()\children[a]<>-1
               If autosizegadgets()\childprop[a]>0
                  ResizeGadget(autosizegadgets()\children[a], pos, 0, Int(childw_base*autosizegadgets()\childprop[a]), childh)
                  pos=pos+(childw_base*autosizegadgets()\childprop[a])
               Else
                  ResizeGadget(autosizegadgets()\children[a], pos, 0, GadgetWidth(autosizegadgets()\children[a]), childh )
                  pos=pos+GadgetWidth(autosizegadgets()\children[a])
               EndIf
            EndIf
         Next
      Else
         childh_base.f = h*1.0/totspan : childw.f = w : pos=0
         For a=0 To totchildren-1
            If autosizegadgets()\children[a]<>-1
               If autosizegadgets()\childprop[a]>0
                  ResizeGadget(autosizegadgets()\children[a], 0, pos, childw, Int(childh_base*autosizegadgets()\childprop[a]))
                  pos=pos+(childh_base*autosizegadgets()\childprop[a])
               Else
                  ResizeGadget(autosizegadgets()\children[a], 0, pos, childw, GadgetHeight(autosizegadgets()\children[a]))
                  pos=pos+GadgetHeight(autosizegadgets()\children[a])
               EndIf
            EndIf
         Next
      EndIf
   Next
EndProcedure

; =======
; EXAMPLE

Enumeration 
   #g_autosize_main
   #g_toplabel : #g_bottomlabel_left : #g_bottomlabel_right
   #g_autosize_bottom
   #g_autosize1 : #g_label0 : #g_label1
   #g_autosize0 : #g_b0 : #g_b1 : #g_b2
EndEnumeration

If Not OpenWindow(0, 100, 200, 320, 240, "AutosizeGadget()", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget) : End : EndIf


AutosizeGadget(#g_autosize_main,0,0,WindowWidth(0),WindowHeight(0),#gadget_autosize_vertical,"0120",#g_toplabel,#g_autosize0,#g_autosize1,#g_autosize_bottom)
   TextGadget(#g_toplabel,0,0,320,24,"AutosizeGadget test")
   AutosizeGadget(#g_autosize0,0,0,0,0,#gadget_autosize_horizontal,"131",#g_b0,#g_b1,#g_b2)
      ButtonGadget(#g_b0,0,0,0,0,"Button 1")
      ButtonGadget(#g_b1,0,0,0,0,"Button 2")
      ButtonGadget(#g_b2,0,0,0,0,"Button 3")
   CloseGadgetList()
   AutosizeGadget(#g_autosize1,0,0,0,0,#gadget_autosize_horizontal,"41",#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)
   CloseGadgetList()
   AutosizeGadget(#g_autosize_bottom,0,0,0,24,#gadget_Autosize_Horizontal,"11",#g_bottomlabel_left,#g_bottomlabel_right)
      TextGadget(#g_bottomlabel_left,0,0,0,0,"Bottom left")
      TextGadget(#g_bottomlabel_right,0,0,0,0,"Bottom right",#PB_Text_Right)
   CloseGadgetList()
CloseGadgetList()

AutosizeGadget_Resize()

Repeat
   EvID = WaitWindowEvent()
   Select EvID
      Case #PB_Event_SizeWindow
         ResizeGadget(#g_autosize_main,0,0,WindowWidth(0),WindowHeight(0)) 
         AutosizeGadget_Resize()
   EndSelect
Until EvID = #PB_Event_CloseWindow
buddymatkona
Enthusiast
Enthusiast
Posts: 252
Joined: Mon Aug 16, 2010 4:29 am

Re: AutosizeGadget()

Post by buddymatkona »

Very good. I suppose everyone has wanted windows to RESIZE like this but an easy way to manage the details has been missing.
User avatar
OldSkoolGamer
Enthusiast
Enthusiast
Posts: 150
Joined: Mon Dec 15, 2008 11:15 pm
Location: Nashville, TN
Contact:

Re: AutosizeGadget()

Post by OldSkoolGamer »

I was just looking for something like this myself. Thanks a TON for posting this one, will be very useful indeed. 8)
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Re: AutosizeGadget()

Post by blueznl »

How would the container gadget itself then resize? Would that still be a manual process?
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
mdp
Enthusiast
Enthusiast
Posts: 115
Joined: Mon Apr 18, 2005 8:28 pm

Re: AutosizeGadget()

Post by mdp »

Hi blueznl,
yes the rootmost container gadget itself, the one which contains all the other gadgets including other AutosizeGadgets, has to be resized but - there should be no issue about that, since you have the possibility to resize only one gadget. Just nest them, the rest will be automatical.

Meaning: if you build a GUI based on AutosizeGadgets, in your main loop you can simply call some

Code: Select all

If EventType()=#PB_Event_SizeWindow
   ResizeGadget(#my_main_autosize_gadget,0,0,WindowWidth(#my_win),WindowHeight(#my_win))
EndIf
[EDIT: sorry, I forgot one line... Using my code, after the ResizeGadget() you also have to issue a AutosizeGadget_Resize() in order to resize its contents]

And that's all (!) Everything that's inside will resize accordingly to the tree of gadgets you defined. An example (quickly thrown in): ...in the example, you should resize only the Autosize just below 'Win'

Code: Select all

Win
   Autosize (Vert.)
      Autosize (Hor.)
         Button
         Text
         String
      Autosize (Hor.)
         Button
         Text
         String
      Autosize (Hor.)
         Button
         Text
         String
      Splitter (Vert.)
         Autosize (Vert.)
            Autosize (Hor.)
               Calendar
               Text
            Editor
         Web
[...]
Last edited by mdp on Wed Jan 19, 2011 7:07 pm, edited 1 time in total.
mdp
Enthusiast
Enthusiast
Posts: 115
Joined: Mon Apr 18, 2005 8:28 pm

Re: AutosizeGadget()

Post by mdp »

More precisely,the goal would be to provide the minimum number of (computed) data to the code when you are designg GUIs.

Normally I would specify x,y,width and height to every single gadget in the window, those values relative to the 0,0 upper left coner. When you have many, it's a mess and a pain. If you also might need to write the code for resizing, more double pain. If later on you decide you do not need that StringGadget anymore, and you need to move upwards all those that it was on top of... Recalc half of the GUI, recalc half of the values in the resizing procedure. The pain.

With that code you should simply zero the x, y, w and h of your gadgets whenever they do not need to be fixed values.
User avatar
Frarth
Enthusiast
Enthusiast
Posts: 241
Joined: Tue Jul 21, 2009 11:11 am
Location: On the planet
Contact:

Re: AutosizeGadget()

Post by Frarth »

Thanks for sharing mdp!

Frank
PureBasic 5.41 LTS | Xubuntu 16.04 (x32) | Windows 7 (x64)
Post Reply