...

Source file src/code.rocket9labs.com/tslocum/etk/frame.go

Documentation: code.rocket9labs.com/tslocum/etk

     1  package etk
     2  
     3  import (
     4  	"image"
     5  )
     6  
     7  // Frame is a widget container. All children are displayed at once. Children are
     8  // not repositioned by default. Repositioning may be enabled via SetPositionChildren.
     9  type Frame struct {
    10  	*Box
    11  	padding          int
    12  	positionChildren bool
    13  	maxWidth         int
    14  	maxHeight        int
    15  	horizontal       Alignment
    16  	vertical         Alignment
    17  }
    18  
    19  // NewFrame returns a new Frame widget.
    20  func NewFrame(w ...Widget) *Frame {
    21  	f := &Frame{
    22  		Box: NewBox(),
    23  	}
    24  	f.AddChild(w...)
    25  	return f
    26  }
    27  
    28  // SetPadding sets the amount of padding around widgets in the frame.
    29  func (f *Frame) SetPadding(padding int) {
    30  	f.Lock()
    31  	defer f.Unlock()
    32  
    33  	f.padding = padding
    34  	f.repositionAll()
    35  }
    36  
    37  // SetRect sets the position and size of the widget.
    38  func (f *Frame) SetRect(r image.Rectangle) {
    39  	f.Lock()
    40  	defer f.Unlock()
    41  
    42  	f.rect = r
    43  	f.repositionAll()
    44  }
    45  
    46  // SetPositionChildren sets a flag that determines whether child widgets are
    47  // repositioned when the Frame is repositioned.
    48  func (f *Frame) SetPositionChildren(position bool) {
    49  	f.Lock()
    50  	defer f.Unlock()
    51  
    52  	f.positionChildren = position
    53  	f.repositionAll()
    54  }
    55  
    56  // SetMaxWidth sets the maximum width of widgets within the frame. This will
    57  // only have an effect after SetPositionChildren(true) is called. 0 to disable.
    58  func (f *Frame) SetMaxWidth(w int) {
    59  	f.Lock()
    60  	defer f.Unlock()
    61  
    62  	f.maxWidth = w
    63  	f.repositionAll()
    64  }
    65  
    66  // SetMaxHeight sets the maximum height of widgets within the frame. This will
    67  // only have an effect after SetPositionChildren(true) is called. 0 to disable.
    68  func (f *Frame) SetMaxHeight(h int) {
    69  	f.Lock()
    70  	defer f.Unlock()
    71  
    72  	f.maxHeight = h
    73  	f.repositionAll()
    74  }
    75  
    76  // SetHorizontal sets the horizontal alignment of widgets within the Frame. This
    77  // will only have an effect when a max width is set and there is extra space.
    78  func (f *Frame) SetHorizontal(h Alignment) {
    79  	f.Lock()
    80  	defer f.Unlock()
    81  
    82  	f.horizontal = h
    83  }
    84  
    85  // SetVertical sets the vertical alignment ofwidgets within the Frame. This
    86  // will only have an effect when a max height is set and there is extra space.
    87  func (f *Frame) SetVertical(v Alignment) {
    88  	f.Lock()
    89  	defer f.Unlock()
    90  
    91  	f.vertical = v
    92  }
    93  
    94  // AddChild adds a child to the widget.
    95  func (f *Frame) AddChild(w ...Widget) {
    96  	f.Lock()
    97  	defer f.Unlock()
    98  
    99  	f.children = append(f.children, w...)
   100  
   101  	if !f.positionChildren {
   102  		return
   103  	}
   104  	for _, child := range w {
   105  		f.repositionChild(child)
   106  	}
   107  }
   108  
   109  func (f *Frame) repositionChild(w Widget) {
   110  	r := f.rect
   111  	if f.maxWidth > 0 {
   112  		if r.Dx() > f.maxWidth {
   113  			r.Max.X = r.Min.X + f.maxWidth
   114  		}
   115  		if f.horizontal == AlignCenter {
   116  			extraSpace := f.rect.Dx() - r.Dx()
   117  			if extraSpace > 0 {
   118  				r = image.Rectangle{image.Point{f.rect.Min.X + extraSpace/2, r.Min.Y}, image.Point{f.rect.Max.X - extraSpace/2, r.Max.Y}}
   119  			}
   120  		}
   121  		// TODO Handle AlignEnd
   122  	}
   123  	if f.maxHeight > 0 {
   124  		if r.Dy() > f.maxHeight {
   125  			r.Max.Y = r.Min.Y + f.maxHeight
   126  		}
   127  		if f.vertical == AlignCenter {
   128  			extraSpace := f.rect.Dy() - r.Dy()
   129  			if extraSpace > 0 {
   130  				r = image.Rectangle{image.Point{r.Min.X, f.rect.Min.Y + extraSpace/2}, image.Point{r.Max.X, f.rect.Max.Y - extraSpace/2}}
   131  			}
   132  		}
   133  		// TODO Handle AlignEnd
   134  	}
   135  	r = r.Inset(f.padding)
   136  	w.SetRect(r)
   137  }
   138  
   139  func (f *Frame) repositionAll() {
   140  	if !f.positionChildren {
   141  		return
   142  	}
   143  	for _, w := range f.children {
   144  		f.repositionChild(w)
   145  	}
   146  }
   147  

View as plain text