AutosizeGadget 2 (building GUI easier)

Share your advanced PureBasic knowledge/code with the community.
said
Enthusiast
Enthusiast
Posts: 342
Joined: Thu Apr 14, 2011 6:07 pm

AutosizeGadget 2 (building GUI easier)

Post by said »

Below is a revised work of the original and appreciated AutosizeGadget of mdp (http://www.purebasic.fr/english/viewtop ... t=autosize)

Added:
Possibility to include custom gadgets (such as canvas-based gadgets)
Margins and spacing between child-gadgets
Many top levels autosize-containers

For testing, i have included the nice canvas toggle button of einander (http://www.purebasic.fr/english/viewtop ... nvasbutton) with few modifications ...

Hope this will be useful to someone ...

Code: Select all

;{ added for testing a custom (canvas-based) gadget
;===================================================================
;Canvas Toggle Buttons
;by einander - PureBasic 4.60 Beta 3
EnableExplicit
Enumeration ; 6 CanvasButton states
  #Normal=0 
  #Selected
  #Pressed
  #HoverSelected
  #HoverUnSelected
  #Disabled
EndEnumeration
Global Dim _Stat$(6)
_Stat$(2)="Pressed"
_Stat$(3)="HoverSelected"
_Stat$(4)="HoverUnSelected"
_Stat$(5)="Disabled"
Global _Myfont10=FontID(LoadFont(#PB_Any,"arial",10))
Global _Myfont12=FontID(LoadFont(#PB_Any,"times new roman",12))
Global _Myfont14=FontID(LoadFont(#PB_Any,"georgia",14))
Global _Myfont16=FontID(LoadFont(#PB_Any,"impact",16))
;
Structure BtnColors
  TextRGB.L
  BackRGB.L
EndStructure
;
Structure CanvasButton
  Indx.I
  gNum.I
  FontID.I
  Text.S
  Selected.I
  Stat.I
  RGB.BtnColors[6] ; Colors :\L1=TextColor, \L2=BackColor
EndStructure
;
Procedure CenterTxt(X,Y,Wi,He,Text.S)
  Protected TextWidth=TextWidth(Text),TextHeight=TextHeight(Text)
  Protected X1=X+Wi,Y1=Y+He
  If TextWidth>Wi :  DrawText(X,(Y+Y1)/2-TextHeight/2 , Text)
  Else            :  DrawText((X+X1)/2-TextWidth/2, (Y1+Y)/2-TextHeight/2 , Text)
  EndIf
EndProcedure     

Procedure CBDraw(*CB.CanvasButton)
  With *Cb
    Protected Wi=GadgetWidth(*Cb\gNum)
    Protected He=GadgetHeight(*Cb\gNum)
    ;Protected Img=CreateImage(#PB_Any,Wi,He)
    
    ;StartDrawing(ImageOutput(Img))   ;background Color, Gradient with #White
    StartDrawing(CanvasOutput(*Cb\gNum))   ; mdified by said as an image cant be created with 0 width/ 0 height
    DrawingMode(#PB_2DDrawing_Gradient)
    FrontColor(\RGB[\Stat]\BackRGB)
    BackColor(#White)
    LinearGradient(Wi/2,0, Wi/2,He)    ; try  (0,0,Wi,He) to diagonal Gradient
    ;LinearGradient(0,0, Wi,He)    ; try  (0,0,Wi,He) to diagonal Gradient
    Box(0,0,Wi,He)
    DrawingMode(#PB_2DDrawing_Transparent) ; Button Text
    DrawingFont(\Fontid)
    FrontColor(\RGB[\Stat]\TextRGB)
    CenterTxt(0,0,Wi,He,\Text)
    StopDrawing()
    ;SetGadgetAttribute(*Cb\gNum,#PB_Canvas_Image,ImageID(Img))
    ;FreeImage(Img)
  EndWith 
EndProcedure
;
Procedure CanvasButton(CBNum,X,Y,Wi,He,Text.S,Fontid,Indx,*Cb.CanvasButton,Flags=-1)
  Protected I
  With *Cb
    If Flags=-1:Flags=#PB_Canvas_Keyboard
    Else       :Flags|#PB_Canvas_Keyboard
    EndIf
    \Text=Text
    \gNum =CanvasGadget(CBNum,X,Y,Wi,He,Flags) 
    If CBNum<>#PB_Any:\gNum=CBNum:EndIf
    SetGadgetAttribute(\gNum,#PB_Canvas_Cursor,#PB_Cursor_Hand)
    \Fontid=Fontid
    \Indx=Indx
    Restore BtnColors
    For I=0 To 5
      Read.I \RGB[I]\TextRGB
      Read.I \RGB[I]\BackRGB
    Next
    CBDraw(*Cb) 
    SetGadgetData(\gNum, *Cb) ; added by said
  EndWith
EndProcedure
;
Procedure  GetCanvasState(*Cb.CanvasButton)
  With *Cb
    Select EventType()
      Case  #PB_EventType_LeftButtonDown 
        \Selected!1   :\Stat=#Pressed         : CBDraw(*Cb)
      Case #PB_EventType_MouseEnter,#PB_EventType_LeftButtonUp
        If \Selected  :\Stat=#HoverSelected   : CBDraw(*Cb)
        Else          :\Stat=#HoverUnSelected : CBDraw(*Cb)
        EndIf
      Case #PB_EventType_MouseLeave
        If \Selected  :\Stat=#Selected        : CBDraw(*Cb)
        Else          :\Stat=#Normal          : CBDraw(*Cb)   
        EndIf
    EndSelect
    If \Stat>1: ProcedureReturn \Stat:EndIf
  EndWith 
EndProcedure

; had to add a custom-resize as per prototype _CustomResize (said)
Procedure ResizeCanvasButton(Gadget, X, Y, Width, Height)
   ResizeGadget(Gadget, X, Y, Width, Height)
   CBDraw(GetGadgetData(Gadget))
EndProcedure

DataSection   ; try here other color pairs <<<<<<<<<<<<<
  BtnColors:
  Data.I $464646 , $888888   ;Normal           : DarkGray, LightGray
  Data.I $0000FF , $6666FF   ;Selected         : Red, Light Red
  Data.I $000000 , $0082FF   ;Pressed          : Black, Dark Orange
  Data.I $FF00FF , $00A5FF   ;HoverSelected    : Magenta, Orange
  Data.I $000000 , $00A5FF   ;HoverUnSelected  : Black, Orange
  Data.I $888888 , $CECECE   ;Disabled         : Light Gray , Pale Gray
EndDataSection

Define CB1.CanvasButton
Define CB2.CanvasButton


;===================== end of einander's cnavas-button ========================
;}

EnableExplicit

Enumeration
   #AutosizeGadget_Horizontal
   #AutosizeGadget_Vertical
EndEnumeration
Prototype _CustomResize(Gadget.i, X.i, Y.i, Width.i, Height.i)

Structure AS_Child_Struc
   Gadget.i
   Proportion.f
   CustomResize._CustomResize
EndStructure
Structure AS_Container_Struc
   IsParent.i     ; true/false
   Gadget.i
   Mode.i
   HMargin.i      ; horizontal margin left and right
   VMargin.i      ; vertical   margin top and bottom
   Spacing.i      ; spacing btweenn childs hor or ver
   
   List Childs.AS_Child_Struc()
EndStructure
Global NewList AS_Containers.AS_Container_Struc()

Procedure AS_StartParent( Gadget, x, y, width, height, mode=#AutosizeGadget_Horizontal, hMargin=0, vMargin=0, spacing=0)
   ContainerGadget(Gadget,x,y,width,height)
   
   AddElement( AS_Containers() )
   AS_Containers()\IsParent= #True
   AS_Containers()\Gadget  = Gadget
   AS_Containers()\Mode    = mode
   AS_Containers()\HMargin = hMargin
   AS_Containers()\VMargin = vMargin
   AS_Containers()\Spacing = spacing
EndProcedure
Procedure AS_StopParent()
   ; closes current main resizable parent and moves to previous parent if any
   CloseGadgetList()
   Protected nn
   Repeat
      If AS_Containers()\IsParent : nn+1 : EndIf
      If Not PreviousElement(AS_Containers()) 
         ResetList(AS_Containers())
         Break 
      EndIf
      If nn >= 1 : Break : EndIf
   ForEver
   
EndProcedure

Procedure AS_StartGrouping(Proportion.f=1.0, mode=#AutosizeGadget_Horizontal, hMargin=0, vMargin=0, spacing=0)
   ; Group is a dynamic container Hor or Ver
   ; param Proportion has 2 usages if >= 0 => actual proportion
   ;                                  <  0 => fised width/height
   Protected gadget_number, fixedSize
   
   If Proportion >= 0
      gadget_number = ContainerGadget(#PB_Any,0,0,0,0)
   Else
      fixedSize = Int(-Proportion)
      If mode=#AutosizeGadget_Horizontal
         gadget_number = ContainerGadget(#PB_Any,0,0,0,fixedSize)
      Else
         gadget_number = ContainerGadget(#PB_Any,0,0,fixedSize,0)
      EndIf
      Proportion = 0
   EndIf
   
   AddElement(AS_Containers()\Childs())
   AS_Containers()\Childs()\Gadget = gadget_number
   AS_Containers()\Childs()\Proportion = Proportion
   AS_Containers()\Childs()\CustomResize = 0
   
   SetGadgetColor(gadget_number, #PB_Gadget_BackColor, GetGadgetColor(AS_Containers()\Gadget, #PB_Gadget_BackColor))

   AddElement( AS_Containers() )
   AS_Containers()\IsParent= #False
   AS_Containers()\Gadget  = gadget_number
   AS_Containers()\Mode    = mode
   AS_Containers()\HMargin = hMargin
   AS_Containers()\VMargin = vMargin
   AS_Containers()\Spacing = spacing
   
EndProcedure
Procedure AS_StopGrouping()
   ; closes current group
   CloseGadgetList()
   PreviousElement(AS_Containers())
EndProcedure

Procedure AS_AddChild(Gadget, Proportion.f, *CustomResizeFunc = 0)
   
   ;LastElement(AS_Containers())
   ;LastElement(AS_Containers()\Childs())
   AddElement(AS_Containers()\Childs())
   
   AS_Containers()\Childs()\Gadget = Gadget
   AS_Containers()\Childs()\Proportion = Proportion
   AS_Containers()\Childs()\CustomResize = *CustomResizeFunc
   
EndProcedure

Procedure AS_ResizeParent(Gadget = -1)
   Protected   mode,w,h,pos,gdt,hm,vm,ss,nn
   Protected.f prop,totspan,childw_base,childh,childh_base,childw
   
   FirstElement(AS_Containers())
   If Gadget <> -1 ; resize s[ecific parent (-1 => all parents)
      Repeat
         If AS_Containers()\IsParent And AS_Containers()\Gadget = Gadget   : Break : EndIf
         If Not NextElement(AS_Containers())                               : Break : EndIf
      ForEver
   EndIf
   
   Repeat 
      mode  = AS_Containers()\Mode
      hm    = AS_Containers()\HMargin
      vm    = AS_Containers()\VMargin
      ss    = AS_Containers()\Spacing
      
      w     = GadgetWidth(AS_Containers()\Gadget)
      h     = GadgetHeight(AS_Containers()\Gadget)
      nn    = ListSize(AS_Containers()\Childs())
      
      totspan = 0
      ForEach AS_Containers()\Childs()
         If AS_Containers()\Childs()\Proportion > 0
            totspan = totspan + AS_Containers()\Childs()\Proportion
         Else
            If mode=#AutosizeGadget_Horizontal
               w = w - GadgetWidth(AS_Containers()\Childs()\Gadget)
            Else
               h = h - GadgetHeight(AS_Containers()\Childs()\Gadget)
            EndIf
         EndIf
      Next
      w = w - (2*hm)
      h = h - (2*vm)
      If nn > 1 
         If mode=#AutosizeGadget_Horizontal
            w = w - ((nn-1)*ss)
         Else
            h = h - ((nn-1)*ss)
         EndIf
      EndIf
      If w < 0 : w = 0 : EndIf
      If h < 0 : h = 0 : EndIf
      
      If mode=#AutosizeGadget_Horizontal
         childh = h : pos = hm : If totspan > 0 : childw_base = w*1.0/totspan : EndIf
         ForEach AS_Containers()\Childs()
            prop = AS_Containers()\Childs()\Proportion
            gdt  = AS_Containers()\Childs()\Gadget
            If prop > 0
               If AS_Containers()\Childs()\CustomResize = 0
                  ResizeGadget(gdt, pos, vm, Int(childw_base * prop), childh)
               Else
                  AS_Containers()\Childs()\CustomResize(gdt, pos, vm, Int(childw_base * prop), childh)
               EndIf
            Else
               If AS_Containers()\Childs()\CustomResize = 0
                  ResizeGadget(gdt, pos, vm, GadgetWidth(gdt), childh)
               Else
                  AS_Containers()\Childs()\CustomResize(gdt, pos, vm, GadgetWidth(gdt), childh)
               EndIf
            EndIf
            pos = pos + GadgetWidth(gdt) + ss
         Next
         
      Else
         
         childw = w : pos = vm : If totspan > 0 : childh_base = h*1.0/totspan : EndIf
         ForEach AS_Containers()\Childs()
            prop = AS_Containers()\Childs()\Proportion
            gdt  = AS_Containers()\Childs()\Gadget
            If prop > 0
               If AS_Containers()\Childs()\CustomResize = 0
                  ResizeGadget(gdt, hm, pos, childw, Int(childh_base * prop))
               Else
                  AS_Containers()\Childs()\CustomResize(gdt, hm, pos, childw, Int(childh_base * prop))
               EndIf
            Else
               If AS_Containers()\Childs()\CustomResize = 0
                  ResizeGadget(gdt, hm, pos, childw, GadgetHeight(gdt))
               Else
                  AS_Containers()\Childs()\CustomResize(gdt, hm, pos, childw, GadgetHeight(gdt))
               EndIf
            EndIf
            pos = pos + GadgetHeight(gdt) + ss
         Next
      EndIf
      
      If Not NextElement(AS_Containers()) : Break : EndIf
      If (Gadget <> -1) And AS_Containers()\IsParent And (AS_Containers()\Gadget <> Gadget) : Break : EndIf
   ForEver
   
EndProcedure

; =======
; EXAMPLE
Enumeration
   #g_autosize_main
   #g_toplabel : #g_bottomlabel_left : #g_bottomlabel_right
   #g_label0 : #g_label1
   #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

AS_StartParent(#g_autosize_main,0,0,WindowWidth(0),WindowHeight(0),#AutosizeGadget_Vertical,0,0,10) ;,"0120",#g_toplabel,#g_autosize0,#g_autosize1,#g_autosize_bottom)
   SetGadgetColor(#g_autosize_main, #PB_Gadget_BackColor, 0)
   AS_AddChild(#g_toplabel, 0)

   TextGadget(#g_toplabel,0,0,320,24,"AutosizeGadget test")
   
   AS_StartGrouping(1.5, #AutosizeGadget_Horizontal,2,0,10)
      CanvasButton(#g_b0,0,0,0,0,"Button 1",_Myfont10,1,@Cb1) : AS_AddChild(#g_b0, 1, @ResizeCanvasButton())
      CanvasButton(#g_b1,0,0,0,0,"Button 2",_Myfont12,2,@Cb2) : AS_AddChild(#g_b1, 3, @ResizeCanvasButton())
      ButtonGadget(#g_b2,0,0,0,0,"Button 3") : AS_AddChild(#g_b2, 1)
   AS_StopGrouping()
   
   AS_StartGrouping(3,#AutosizeGadget_Horizontal,2,25,2)
      AS_AddChild(#g_label0, 4)
      AS_AddChild(#g_label1, 1)
      TextGadget(#g_label0,0,0,0,0,"Text 1",#PB_Text_Border)
      TextGadget(#g_label1,0,0,0,0,"Text 2",#PB_Text_Border)
   AS_StopGrouping()
   
   AS_StartGrouping(-24, #AutosizeGadget_Horizontal,0,0,30)
      AS_AddChild(#g_bottomlabel_left, 1)
      AS_AddChild(#g_bottomlabel_right, 1)
      TextGadget(#g_bottomlabel_left,0,0,0,0,"Bottom left",#PB_Text_Border)
      TextGadget(#g_bottomlabel_right,0,0,0,0,"Bottom right",#PB_Text_Border|#PB_Text_Right)
   AS_StopGrouping()
   
AS_StopParent()

Define EvID
Repeat
   EvID = WaitWindowEvent()
   Select EvID
      Case #PB_Event_SizeWindow
         ResizeGadget(#g_autosize_main,0,0,WindowWidth(0),WindowHeight(0))
         AS_ResizeParent()
      Case #PB_Event_Gadget
         Select EventGadget()
            Case #g_b0 : GetCanvasState(@CB1)
            Case #g_b1 : GetCanvasState(@CB2)
         EndSelect
         
   EndSelect
Until EvID = #PB_Event_CloseWindow



Last edited by said on Sat Nov 10, 2012 12:19 pm, edited 1 time in total.
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: AutosizeGadget 2

Post by rsts »

Very interesting. Thanks for sharing the code with us.
Post Reply