179 lines
4.6 KiB
Go
179 lines
4.6 KiB
Go
package containers
|
|
|
|
import "image"
|
|
import "git.tebibyte.media/sashakoshka/tomo"
|
|
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
|
import "git.tebibyte.media/sashakoshka/tomo/shatter"
|
|
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
|
|
|
type scratchEntry struct {
|
|
expand bool
|
|
minimum float64
|
|
}
|
|
|
|
type VBox struct {
|
|
entity tomo.ContainerEntity
|
|
scratch map[tomo.Element] scratchEntry
|
|
theme theme.Wrapped
|
|
padding bool
|
|
margin bool
|
|
}
|
|
|
|
func NewVBox (padding, margin bool) (element *VBox) {
|
|
element = &VBox { padding: padding, margin: margin }
|
|
element.scratch = make(map[tomo.Element] scratchEntry)
|
|
element.theme.Case = tomo.C("tomo", "vBox")
|
|
element.entity = tomo.NewEntity(element).(tomo.ContainerEntity)
|
|
return
|
|
}
|
|
|
|
func (element *VBox) Entity () tomo.Entity {
|
|
return element.entity
|
|
}
|
|
|
|
func (element *VBox) Draw (destination canvas.Canvas) {
|
|
rocks := make([]image.Rectangle, element.entity.CountChildren())
|
|
for index := 0; index < element.entity.CountChildren(); index ++ {
|
|
rocks[index] = element.entity.Child(index).Entity().Bounds()
|
|
}
|
|
|
|
tiles := shatter.Shatter(element.entity.Bounds(), rocks...)
|
|
for _, tile := range tiles {
|
|
element.entity.DrawBackground(canvas.Cut(destination, tile))
|
|
}
|
|
}
|
|
|
|
func (element *VBox) Layout () {
|
|
margin := element.theme.Margin(tomo.PatternBackground)
|
|
padding := element.theme.Padding(tomo.PatternBackground)
|
|
bounds := element.entity.Bounds()
|
|
if element.padding { bounds = padding.Apply(bounds) }
|
|
|
|
freeSpace, nExpanding := element.freeSpace()
|
|
expandingElementHeight := freeSpace / nExpanding
|
|
|
|
// set the size and position of each element
|
|
x := float64(bounds.Min.X)
|
|
y := float64(bounds.Min.Y)
|
|
for index := 0; index < element.entity.CountChildren(); index ++ {
|
|
entry := element.scratch[element.entity.Child(index)]
|
|
|
|
var height float64; if entry.expand {
|
|
height = expandingElementHeight
|
|
} else {
|
|
height = entry.minimum
|
|
}
|
|
|
|
element.entity.PlaceChild (index, tomo.Bounds (
|
|
int(x), int(y),
|
|
bounds.Dx(), int(height)))
|
|
|
|
y += height
|
|
if element.margin { y += float64(margin.Y) }
|
|
}
|
|
|
|
}
|
|
|
|
func (element *VBox) Adopt (child tomo.Element, expand bool) {
|
|
element.entity.Adopt(child)
|
|
element.scratch[child] = scratchEntry { expand: expand }
|
|
element.updateMinimumSize()
|
|
element.entity.Invalidate()
|
|
element.entity.InvalidateLayout()
|
|
}
|
|
|
|
func (element *VBox) Disown (child tomo.Element) {
|
|
index := element.entity.IndexOf(child)
|
|
if index < 0 { return }
|
|
element.entity.Disown(index)
|
|
delete(element.scratch, child)
|
|
element.updateMinimumSize()
|
|
element.entity.Invalidate()
|
|
element.entity.InvalidateLayout()
|
|
}
|
|
|
|
func (element *VBox) DisownAll () {
|
|
func () {
|
|
for index := 0; index < element.entity.CountChildren(); index ++ {
|
|
index := index
|
|
defer element.entity.Disown(index)
|
|
}
|
|
} ()
|
|
element.scratch = make(map[tomo.Element] scratchEntry)
|
|
element.updateMinimumSize()
|
|
element.entity.Invalidate()
|
|
element.entity.InvalidateLayout()
|
|
}
|
|
|
|
func (element *VBox) HandleChildMinimumSizeChange (child tomo.Element) {
|
|
element.updateMinimumSize()
|
|
element.entity.Invalidate()
|
|
element.entity.InvalidateLayout()
|
|
}
|
|
|
|
func (element *VBox) DrawBackground (destination canvas.Canvas) {
|
|
element.entity.DrawBackground(destination)
|
|
}
|
|
|
|
// SetTheme sets the element's theme.
|
|
func (element *VBox) SetTheme (theme tomo.Theme) {
|
|
if theme == element.theme.Theme { return }
|
|
element.theme.Theme = theme
|
|
element.updateMinimumSize()
|
|
element.entity.Invalidate()
|
|
element.entity.InvalidateLayout()
|
|
}
|
|
|
|
func (element *VBox) freeSpace () (space float64, nExpanding float64) {
|
|
margin := element.theme.Margin(tomo.PatternBackground)
|
|
padding := element.theme.Padding(tomo.PatternBackground)
|
|
space = float64(element.entity.Bounds().Dy())
|
|
|
|
for _, entry := range element.scratch {
|
|
if entry.expand {
|
|
nExpanding ++;
|
|
} else {
|
|
space -= float64(entry.minimum)
|
|
}
|
|
}
|
|
|
|
if element.padding {
|
|
space -= float64(padding.Vertical())
|
|
}
|
|
if element.margin {
|
|
space -= float64(margin.Y * (len(element.scratch) - 1))
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (element *VBox) updateMinimumSize () {
|
|
margin := element.theme.Margin(tomo.PatternBackground)
|
|
padding := element.theme.Padding(tomo.PatternBackground)
|
|
var width, height int
|
|
|
|
for index := 0; index < element.entity.CountChildren(); index ++ {
|
|
childWidth, childHeight := element.entity.ChildMinimumSize(index)
|
|
|
|
key := element.entity.Child(index)
|
|
entry := element.scratch[key]
|
|
entry.minimum = float64(childHeight)
|
|
element.scratch[key] = entry
|
|
|
|
if childWidth > width {
|
|
width = childWidth
|
|
}
|
|
height += childHeight
|
|
if element.margin && index > 0 {
|
|
height += margin.Y
|
|
}
|
|
}
|
|
|
|
if element.padding {
|
|
width += padding.Horizontal()
|
|
height += padding.Vertical()
|
|
}
|
|
|
|
element.entity.SetMinimumSize(width, height)
|
|
}
|