October 28, 2020, 05:35:30 AM

Author Topic: [bmx] MaxGUI Layout by Otus [ 1+ years ago ]  (Read 1292 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
[bmx] MaxGUI Layout by Otus [ 1+ years ago ]
« on: June 29, 2017, 12:28:43 AM »
Title : MaxGUI Layout
Author : Otus
Posted : 1+ years ago

Description : SetGadgetLayout only works for very basic layout needs. Here is more advanced (but still simple) layout management for MaxGUI.

Three layout types are implemented:
- Grid Layout, which makes each gadget fill a cell in a grid
- Box Layout, which stacks gadgets next to each other either vertically or horizontally
- Grid Intersection Layout, which positions gadgets in a grid, but keeps their original size if possible.

Where resizing must be supported, layouts should be associated with either a parent window, or a parent gadget that is laid out (has been added to another layout). Any other gadgets won't produce the necessary events when resized.

sample1.bmx:
Code: [Select]
SuperStrict

Framework MaxGUI.Drivers

Import "layout.bmx"

' Main window
Local flags:Int = WINDOW_CLIENTCOORDS | WINDOW_TITLEBAR | WINDOW_CENTER | WINDOW_RESIZABLE
Local win:TGadget = CreateWindow("Layout Sample 1", 0,0, 400,200, Null, flags)
SetMinWindowSize win, 100,100

' Grid layout for window with two cells and a gap
Local winlay:TGridLayout = TGridLayout.Create(win, 1, 2, 0, 25)

' Upper panel
Local panel1:TGadget = CreatePanel(0,0,0,0,win)
SetGadgetColor panel1, 255,0,0
winlay.AddGadget panel1, 0,0

' Box layout for upper panel: horizontal, centered and a gap
Local pan1lay:TBoxLayout = TBoxLayout.Create(panel1, TBoxLayout.X_AXIS, TBoxLayout.ALIGN_CENTER, 5)

' Buttons for upper panel
For Local i% = 1 To 3
Local b:TGadget = CreateButton(i, 0,0, i*30, i*20, panel1)
pan1lay.AddGadget b
Next

' Lower panel
Local panel2:TGadget = CreatePanel(0,0,0,0,win)
SetGadgetColor panel2, 0,0,255
winlay.AddGadget panel2, 0,1

' Grid intersection layout for lower panel: centers the gadget and restricts its size
Local pan2lay:TGridIntLayout = TGridIntLayout.Create(panel2, 1, 1)

' Button for lower panel
Local ok:TGadget = CreateButton("OK", 0,0,150,25, panel2, BUTTON_OK)
pan2lay.AddGadget ok, 0,0


' Quit after closing window
Global quit:Int
Function Hook:Object(id:Int, data:Object, context:Object)
Local e:TEvent = TEvent(data)
If e.id=EVENT_WINDOWCLOSE Or e.id=EVENT_APPTERMINATE Then quit=True
Return data
End Function
AddHook EmitEventHook, Hook

' Main loop
Repeat
WaitSystem
Until quit


sample2.bmx:
Code: [Select]
SuperStrict

Framework MaxGUI.Drivers

Import "layout.bmx"

' Main window
Local flags:Int = WINDOW_CLIENTCOORDS | WINDOW_TITLEBAR | WINDOW_CENTER | WINDOW_RESIZABLE
Local win:TGadget = CreateWindow("Layout Sample 2", 0,0, 200,300, Null, flags)
SetMinWindowSize win, 150,150

' Vertical layout
Local vlay:TGridLayout = TGridLayout.Create(win, 1, 4, 10, 10, 1)

' Panels
Local panel:TGadget[4]
For Local i% = 0 To 3
panel[i] = CreatePanel(0,0,0,0, win)
vlay.AddGadget panel[i], 0, i
Next

' Form fields:

' Box layouts
Local blay:TBoxLayout[3]
For Local i% = 0 To 2
blay[i] = TBoxLayout.Create(panel[i], TBoxLayout.X_AXIS, TBoxLayout.ALIGN_CENTER, 15)
Next

' Labels
Local names:String[] = ["Name:", "Email:", "Password:"]
For Local i% = 0 To 2
blay[i].AddGadget CreateLabel(names[i], 0,0, 25, 24, panel[i])
Next

' Text fields
For Local i% = 0 To 2
blay[i].AddGadget CreateTextField(0,0, 75, 24, panel[i])
Next

' OK button:

' Grid layout for centering
Local glay:TGridIntLayout = TGridIntLayout.Create(panel[3], 1, 1)
glay.AddGadget CreateButton("OK", 0,0, 80,24, panel[3], BUTTON_OK), 0, 0

' Quit after closing window
Global quit:Int
Function Hook:Object(id:Int, data:Object, context:Object)
Local e:TEvent = TEvent(data)
If e.id=EVENT_WINDOWCLOSE Or e.id=EVENT_APPTERMINATE Then quit=True
Return data
End Function
AddHook EmitEventHook, Hook

' Main loop
Repeat
WaitSystem
Until quit


Layout.bmx: [/i]

Code :
Code: BlitzMax
  1. SuperStrict
  2.  
  3. Import MaxGUI.MaxGUI
  4.  
  5. ' Abstract type that handles resize events
  6. Type TLayout Abstract
  7.        
  8.         Field parent:TGadget
  9.        
  10.         Method Update() Abstract
  11.        
  12.         Method SetParent(g:TGadget)
  13.                 If Not parent Then AddHook EmitEventHook, _Hook, Self
  14.                 parent = g
  15.         End Method
  16.        
  17.         Global resize_event:Int = AllocUserEventId("Layout Resize")
  18.        
  19.         Function _Hook:Object(id:Int, data:Object, context:Object)
  20.                 Local event:TEvent = TEvent(data)
  21.                 If event.id=EVENT_WINDOWSIZE Or event.id=resize_event
  22.                         Local l:TLayout = TLayout(context)
  23.                         If l And event.source=l.parent Then l.Update()
  24.                 End If
  25.                 Return data
  26.         End Function
  27.        
  28. End Type
  29.  
  30. ' Grid layout makes gadget fill cells in a grid
  31. Type TGridLayout Extends TLayout
  32.        
  33.         Field items:TList = New TList
  34.        
  35.         Field rows:Int, cols:Int, hgap:Int, vgap:Int, egap:Int
  36.        
  37.         ' Add a gadget at position
  38.         Method AddGadget(g:TGadget, x:Int, y:Int)
  39.                 Assert (0<=x) And (0<=y) And (x<cols) And (y<rows),..
  40.                         "Gadget position outside grid!"
  41.                 Local i:TGridItem = New TGridItem
  42.                 i.gadget = g
  43.                 i.x = x
  44.                 i.y = y
  45.                 items.AddLast i
  46.                 Update
  47.         End Method
  48.        
  49.         Method Update()
  50.                 Local gw:Float = Float(ClientWidth(parent) - hgap*(cols-1+2*egap)) / cols
  51.                 Local gh:Float = Float(ClientHeight(parent) - vgap*(rows-1+2*egap)) / rows
  52.                 For Local i:TGridItem = EachIn items
  53.                         Local gx:Int = gw*i.x + hgap*(i.x+egap), gy:Int = gh*i.y + vgap*(i.y+egap)
  54.                         SetGadgetShape i.gadget, gx, gy, gw, gh
  55.                         EmitEvent TEvent.Create(TLayout.resize_event, i.gadget)
  56.                 Next
  57.         End Method
  58.        
  59.         ' Create a grid layout. Optional gaps between cells. Setting egap=True also adds gaps outside grid.
  60.         Function Create:TGridLayout(g:TGadget, cols:Int, rows:Int, hgap:Int=0, vgap:Int=0, egap:Int=False)
  61.                 Local l:TGridLayout = New TGridLayout
  62.                 l.SetParent g
  63.                 l.rows = rows
  64.                 l.cols = cols
  65.                 l.hgap = hgap
  66.                 l.vgap = vgap
  67.                 l.egap = egap
  68.                 Return l
  69.         End Function
  70.        
  71. End Type
  72.  
  73. Type TGridItem
  74.        
  75.         Field gadget:TGadget
  76.        
  77.         Field x:Int, y:Int
  78.        
  79. End Type
  80.  
  81. ' Box layout stacks gadgets either vertically or horizontally
  82. Type TBoxLayout Extends TLayout
  83.        
  84.         Const X_AXIS:Int = 0
  85.         Const Y_AXIS:Int = 1
  86.        
  87.         Const ALIGN_LEFT:Int = 0
  88.         Const ALIGN_CENTER:Int = 1
  89.         Const ALIGN_RIGHT:Int = 2
  90.        
  91.         Const ALIGN_TOP:Int = 0
  92.         Const ALIGN_BOTTOM:Int = 2
  93.        
  94.         Field items:TList = New TList
  95.        
  96.         Field axis:Int, align:Int, gap:Int
  97.        
  98.         Field wtot:Int, htot:Int, num:Int
  99.        
  100.         ' Adds a gadget
  101.         Method AddGadget(g:TGadget)
  102.                 Local i:TBoxItem = New TBoxItem
  103.                 i.gadget = g
  104.                 i.w = GadgetWidth(g)
  105.                 i.h = GadgetHeight(g)
  106.                 items.AddLast i
  107.                 UpdateTotals
  108.                 Update
  109.         End Method
  110.        
  111.         Method UpdateTotals()
  112.                 wtot = 0
  113.                 htot = 0
  114.                 num = 0
  115.                 For Local i:TBoxItem = EachIn items
  116.                         wtot :+ i.w
  117.                         htot :+ i.h
  118.                         num :+ 1
  119.                 Next
  120.         End Method
  121.        
  122.         Method Update()
  123.                 Local w:Int = ClientWidth(parent)
  124.                 Local h:Int = ClientHeight(parent)
  125.                 If axis = X_AXIS
  126.                         Local x:Int, n:Int
  127.                         Local factor:Float = Float(w-(num-1)*gap)/wtot
  128.                         For Local i:TBoxItem = EachIn items
  129.                                 Local gx:Int = x*factor
  130.                                 x :+ i.w
  131.                                 Local gw:Int = x*factor - gx
  132.                                 gx :+ n*gap
  133.                                 n :+ 1
  134.                                 Local gy:Int
  135.                                 Local gh:Int = Min(i.h, h)
  136.                                 If align=ALIGN_TOP
  137.                                         gy = 0
  138.                                 Else If align=ALIGN_CENTER
  139.                                         gy = (h-gh)/2
  140.                                 Else
  141.                                         gy = h-gh
  142.                                 End If
  143.                                 SetGadgetShape i.gadget, gx, gy, gw, gh
  144.                         Next
  145.                 Else
  146.                         Local y:Int, n:Int
  147.                         Local factor:Float = Float(h-(num-1)*gap)/htot
  148.                         For Local i:TBoxItem = EachIn items
  149.                                 Local gy:Int = y*factor
  150.                                 y :+ i.h
  151.                                 Local gh:Int = y*factor - gy
  152.                                 gy :+ n*gap
  153.                                 n :+ 1
  154.                                 Local gx:Int
  155.                                 Local gw:Int = Min(i.w, w)
  156.                                 If align=ALIGN_LEFT
  157.                                         gx = 0
  158.                                 Else If align=ALIGN_CENTER
  159.                                         gx = (w-gw)/2
  160.                                 Else
  161.                                         gx = w-gw
  162.                                 End If
  163.                                 SetGadgetShape i.gadget, gx, gy, gw, gh
  164.                         Next
  165.                 End If
  166.         End Method
  167.        
  168.         ' Creates a box layout. See constants above for valid axis and align values.
  169.         Function Create:TBoxLayout(g:TGadget, axis:Int, align:Int, gap:Int=0)
  170.                 Local l:TBoxLayout = New TBoxLayout
  171.                 l.SetParent g
  172.                 l.axis = axis
  173.                 l.align = align
  174.                 l.gap = gap
  175.                 Return l
  176.         End Function
  177.        
  178. End Type
  179.  
  180. Type TBoxItem
  181.        
  182.         Field gadget:TGadget
  183.        
  184.         Field w:Int, h:Int
  185.        
  186. End Type
  187.  
  188. ' Grid intersection layout positions gadgets in a grid, but only resizes when necessary
  189. Type TGridIntLayout Extends TLayout
  190.        
  191.         Field items:TList = New TList
  192.        
  193.         Field rows:Int, cols:Int
  194.        
  195.         ' Adds a gadgt at position
  196.         Method AddGadget(g:TGadget, x:Int, y:Int)
  197.                 Assert (0<=x) And (0<=y) And (x<cols) And (y<rows),..
  198.                         "Gadget position outside grid!"
  199.                 Local i:TGridIntItem = New TGridIntItem
  200.                 i.gadget = g
  201.                 i.x = x
  202.                 i.y = y
  203.                 i.w = GadgetWidth(g)
  204.                 i.h = GadgetHeight(g)
  205.                 items.AddLast i
  206.                 Update
  207.         End Method
  208.        
  209.         Method Update()
  210.                 Local w:Int = ClientWidth(parent) / cols
  211.                 Local h:Int = ClientHeight(parent) / rows
  212.                 For Local i:TGridIntItem = EachIn items
  213.                         Local gw:Int = Min(i.w, w)
  214.                         Local gh:Int = Min(i.h, h)
  215.                         Local gx:Int = (i.x+0.5)*w- gw/2, gy:Int = (i.y+0.5)*h- gh/2
  216.                         SetGadgetShape i.gadget, gx, gy, gw, gh
  217.                         EmitEvent TEvent.Create(TLayout.resize_event, i.gadget)
  218.                 Next
  219.         End Method
  220.        
  221.         ' Creates a layout for gadget, allows optional gaps
  222.         Function Create:TGridIntLayout(g:TGadget, cols:Int, rows:Int)
  223.                 Local l:TGridIntLayout = New TGridIntLayout
  224.                 l.SetParent g
  225.                 l.rows = rows
  226.                 l.cols = cols
  227.                 Return l
  228.         End Function
  229.        
  230. End Type
  231.  
  232. Type TGridIntItem
  233.        
  234.         Field gadget:TGadget
  235.        
  236.         Field x:Int, y:Int, w:Int, h:Int
  237.        
  238. End Type


Comments : none...

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal