| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- // Copyright 2016 The G3N Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package gui
- type VBoxLayout struct {
- pan IPanel
- spacing float32 // vertical spacing between the children in pixels.
- alignV Align // vertical alignment of the whole block of children
- }
- // Parameters for individual children
- type VBoxLayoutParams struct {
- Expand float32 // item expand vertically factor (0 - no expand)
- AlignH Align // item horizontal alignment
- }
- // NewVBoxLayout creates and returns a pointer to a new horizontal box layout
- func NewVBoxLayout() *VBoxLayout {
- bl := new(VBoxLayout)
- bl.spacing = 0
- bl.alignV = AlignTop
- return bl
- }
- // SetSpacing sets the horizontal spacing between the items in pixels
- // and updates the layout if possible
- func (bl *VBoxLayout) SetSpacing(spacing float32) {
- bl.spacing = spacing
- bl.Recalc(bl.pan)
- }
- // SetAlignH sets the horizontal alignment of the whole group of items
- // inside the parent panel and updates the layout if possible.
- // This only has any effect if there are no expanded items.
- func (bl *VBoxLayout) SetAlignV(align Align) {
- bl.alignV = align
- bl.Recalc(bl.pan)
- }
- // Recalc recalculates and sets the position and sizes of all children
- func (bl *VBoxLayout) Recalc(ipan IPanel) {
- // Saves the received panel
- bl.pan = ipan
- if bl.pan == nil {
- return
- }
- parent := ipan.GetPanel()
- if len(parent.Children()) == 0 {
- return
- }
- // Calculates the total height, expanded height, fixed height and
- // the sum of the expand factor for all items.
- var theight float32 = 0
- var eheight float32 = 0
- var fheight float32 = 0
- var texpand float32 = 0
- ecount := 0
- paramsDef := VBoxLayoutParams{Expand: 0, AlignH: AlignLeft}
- for pos, obj := range parent.Children() {
- pan := obj.(IPanel).GetPanel()
- // Get item layout parameters or use default
- params := paramsDef
- if pan.layoutParams != nil {
- params = *pan.layoutParams.(*VBoxLayoutParams)
- }
- // Calculate total height
- theight += pan.Height()
- if pos > 0 {
- theight += bl.spacing
- }
- // Calculate height of expanded items
- if params.Expand > 0 {
- texpand += params.Expand
- eheight += pan.Height()
- if pos > 0 {
- eheight += bl.spacing
- }
- ecount++
- // Calculate width of fixed items
- } else {
- fheight += pan.Height()
- if pos > 0 {
- fheight += bl.spacing
- }
- }
- }
- // If there is at least on expanded item, all free space will be occupied
- spaceMiddle := bl.spacing
- var posY float32 = 0
- if texpand > 0 {
- // If there is free space, distribute space between expanded items
- totalSpace := parent.ContentHeight() - theight
- if totalSpace > 0 {
- for _, obj := range parent.Children() {
- pan := obj.(IPanel).GetPanel()
- // Get item layout parameters or use default
- params := paramsDef
- if pan.layoutParams != nil {
- params = *pan.layoutParams.(*VBoxLayoutParams)
- }
- if params.Expand > 0 {
- iheight := totalSpace * params.Expand / texpand
- pan.SetHeight(pan.Height() + iheight)
- }
- }
- // No free space: distribute expanded items heights
- } else {
- for _, obj := range parent.Children() {
- pan := obj.(IPanel).GetPanel()
- // Get item layout parameters or use default
- params := paramsDef
- if pan.layoutParams != nil {
- params = *pan.layoutParams.(*VBoxLayoutParams)
- }
- if params.Expand > 0 {
- spacing := bl.spacing * float32(ecount-1)
- iheight := (parent.ContentHeight() - spacing - fheight - bl.spacing) * params.Expand / texpand
- pan.SetHeight(iheight)
- }
- }
- }
- // No expanded items: checks block vertical alignment
- } else {
- // Calculates initial y position which depends
- // on the current horizontal alignment.
- switch bl.alignV {
- case AlignTop:
- posY = 0
- case AlignCenter:
- posY = (parent.ContentHeight() - theight) / 2
- case AlignBottom:
- posY = parent.ContentHeight() - theight
- case AlignHeight:
- space := parent.ContentHeight() - theight + bl.spacing*float32(len(parent.Children())-1)
- if space < 0 {
- space = bl.spacing * float32(len(parent.Children())-1)
- }
- spaceMiddle = space / float32(len(parent.Children())+1)
- posY = spaceMiddle
- default:
- log.Fatal("VBoxLayout: invalid global vertical alignment")
- }
- }
- // Calculates the X position of each item considering
- // it horizontal alignment
- var posX float32
- width := parent.ContentWidth()
- for pos, obj := range parent.Children() {
- pan := obj.(IPanel).GetPanel()
- // Get item layout parameters or use default
- params := paramsDef
- if pan.layoutParams != nil {
- params = *pan.layoutParams.(*VBoxLayoutParams)
- }
- cwidth := pan.Width()
- switch params.AlignH {
- case AlignLeft:
- posX = 0
- case AlignCenter:
- posX = (width - cwidth) / 2
- case AlignRight:
- posX = width - cwidth
- case AlignWidth:
- posX = 0
- pan.SetWidth(width)
- default:
- log.Fatal("VBoxLayout: invalid item horizontal alignment")
- }
- // Sets the child position
- pan.SetPosition(posX, posY)
- // Calculates next position
- posY += pan.Height()
- if pos < len(parent.Children())-1 {
- posY += spaceMiddle
- }
- }
- }
|