Page 1 of 1

AutosizeGadget()

Posted: Sat Jan 15, 2011 1:57 pm
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

Re: AutosizeGadget()

Posted: Sat Jan 15, 2011 2:20 pm
by Didelphodon
Cool! Reminds me on Java's automatic layout-concept.

Re: AutosizeGadget()

Posted: Sat Jan 15, 2011 3:40 pm
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

Re: AutosizeGadget()

Posted: Sat Jan 15, 2011 10:02 pm
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.

Re: AutosizeGadget()

Posted: Wed Jan 19, 2011 2:24 pm
by OldSkoolGamer
I was just looking for something like this myself. Thanks a TON for posting this one, will be very useful indeed. 8)

Re: AutosizeGadget()

Posted: Wed Jan 19, 2011 5:26 pm
by blueznl
How would the container gadget itself then resize? Would that still be a manual process?

Re: AutosizeGadget()

Posted: Wed Jan 19, 2011 6:44 pm
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
[...]

Re: AutosizeGadget()

Posted: Wed Jan 19, 2011 6:56 pm
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.

Re: AutosizeGadget()

Posted: Sun Jan 23, 2011 5:25 am
by Frarth
Thanks for sharing mdp!

Frank