Containers now share a bunch of code

This commit is contained in:
Sasha Koshka 2023-04-19 00:29:25 -04:00
parent ac58a43220
commit afdecc2c8b
4 changed files with 95 additions and 202 deletions

View File

@ -21,19 +21,12 @@ func (space Space) Includes (sub Space) bool {
return (space & sub) > 0 return (space & sub) > 0
} }
type scratchEntry struct {
expand bool
minSize float64
minBreadth float64
}
// Box is a container that lays out its children horizontally or vertically. // Box is a container that lays out its children horizontally or vertically.
// Child elements can be set to contract to their minimum size, or expand to // Child elements can be set to contract to their minimum size, or expand to
// fill remaining space. Boxes can be nested and used together to create more // fill remaining space. Boxes can be nested and used together to create more
// complex layouts. // complex layouts.
type Box struct { type Box struct {
entity tomo.ContainerEntity container
scratch map[tomo.Element] scratchEntry
theme theme.Wrapped theme theme.Wrapped
padding bool padding bool
margin bool margin bool
@ -46,9 +39,10 @@ func NewHBox (space Space, children ...tomo.Element) (element *Box) {
padding: space.Includes(SpacePadding), padding: space.Includes(SpacePadding),
margin: space.Includes(SpaceMargin), margin: space.Includes(SpaceMargin),
} }
element.scratch = make(map[tomo.Element] scratchEntry)
element.theme.Case = tomo.C("tomo", "box")
element.entity = tomo.NewEntity(element).(tomo.ContainerEntity) element.entity = tomo.NewEntity(element).(tomo.ContainerEntity)
element.minimumSize = element.updateMinimumSize
element.init()
element.theme.Case = tomo.C("tomo", "box")
element.Adopt(children...) element.Adopt(children...)
return return
} }
@ -60,17 +54,14 @@ func NewVBox (space Space, children ...tomo.Element) (element *Box) {
margin: space.Includes(SpaceMargin), margin: space.Includes(SpaceMargin),
vertical: true, vertical: true,
} }
element.scratch = make(map[tomo.Element] scratchEntry)
element.theme.Case = tomo.C("tomo", "box")
element.entity = tomo.NewEntity(element).(tomo.ContainerEntity) element.entity = tomo.NewEntity(element).(tomo.ContainerEntity)
element.minimumSize = element.updateMinimumSize
element.init()
element.theme.Case = tomo.C("tomo", "box")
element.Adopt(children...) element.Adopt(children...)
return return
} }
func (element *Box) Entity () tomo.Entity {
return element.entity
}
func (element *Box) Draw (destination canvas.Canvas) { func (element *Box) Draw (destination canvas.Canvas) {
rocks := make([]image.Rectangle, element.entity.CountChildren()) rocks := make([]image.Rectangle, element.entity.CountChildren())
for index := 0; index < element.entity.CountChildren(); index ++ { for index := 0; index < element.entity.CountChildren(); index ++ {
@ -127,64 +118,8 @@ func (element *Box) Layout () {
} }
} }
func (element *Box) Adopt (children ...tomo.Element) {
for _, child := range children {
element.entity.Adopt(child)
element.scratch[child] = scratchEntry { expand: false }
}
element.updateMinimumSize()
element.entity.Invalidate()
element.entity.InvalidateLayout()
}
func (element *Box) AdoptExpand (children ...tomo.Element) { func (element *Box) AdoptExpand (children ...tomo.Element) {
for _, child := range children { element.adopt(true, children...)
element.entity.Adopt(child)
element.scratch[child] = scratchEntry { expand: true }
}
element.updateMinimumSize()
element.entity.Invalidate()
element.entity.InvalidateLayout()
}
func (element *Box) Disown (children ...tomo.Element) {
for _, child := range children {
index := element.entity.IndexOf(child)
if index < 0 { continue }
element.entity.Disown(index)
delete(element.scratch, child)
}
element.updateMinimumSize()
element.entity.Invalidate()
element.entity.InvalidateLayout()
}
func (element *Box) 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 *Box) Child (index int) tomo.Element {
if index < 0 || index >= element.entity.CountChildren() { return nil }
return element.entity.Child(index)
}
func (element *Box) CountChildren () int {
return element.entity.CountChildren()
}
func (element *Box) HandleChildMinimumSizeChange (child tomo.Element) {
element.updateMinimumSize()
element.entity.Invalidate()
element.entity.InvalidateLayout()
} }
func (element *Box) DrawBackground (destination canvas.Canvas) { func (element *Box) DrawBackground (destination canvas.Canvas) {

77
elements/container.go Normal file
View File

@ -0,0 +1,77 @@
package elements
import "git.tebibyte.media/sashakoshka/tomo"
type scratchEntry struct {
expand bool
minSize float64
minBreadth float64
}
type container struct {
entity tomo.ContainerEntity
scratch map[tomo.Element] scratchEntry
minimumSize func ()
}
func (container *container) Entity () tomo.Entity {
return container.entity
}
func (container *container) Adopt (children ...tomo.Element) {
container.adopt(false, children...)
}
func (container *container) init () {
container.scratch = make(map[tomo.Element] scratchEntry)
}
func (container *container) adopt (expand bool, children ...tomo.Element) {
for _, child := range children {
container.entity.Adopt(child)
container.scratch[child] = scratchEntry { expand: expand }
}
container.minimumSize()
container.entity.Invalidate()
container.entity.InvalidateLayout()
}
func (container *container) Disown (children ...tomo.Element) {
for _, child := range children {
index := container.entity.IndexOf(child)
if index < 0 { continue }
container.entity.Disown(index)
delete(container.scratch, child)
}
container.minimumSize()
container.entity.Invalidate()
container.entity.InvalidateLayout()
}
func (container *container) DisownAll () {
func () {
for index := 0; index < container.entity.CountChildren(); index ++ {
index := index
defer container.entity.Disown(index)
}
} ()
container.scratch = make(map[tomo.Element] scratchEntry)
container.minimumSize()
container.entity.Invalidate()
container.entity.InvalidateLayout()
}
func (container *container) Child (index int) tomo.Element {
if index < 0 || index >= container.entity.CountChildren() { return nil }
return container.entity.Child(index)
}
func (container *container) CountChildren () int {
return container.entity.CountChildren()
}
func (container *container) HandleChildMinimumSizeChange (child tomo.Element) {
container.minimumSize()
container.entity.Invalidate()
container.entity.InvalidateLayout()
}

View File

@ -12,9 +12,9 @@ type documentEntity interface {
} }
type Document struct { type Document struct {
container
entity documentEntity entity documentEntity
scratch map[tomo.Element] scratchEntry
scroll image.Point scroll image.Point
contentBounds image.Rectangle contentBounds image.Rectangle
@ -25,17 +25,15 @@ type Document struct {
func NewDocument (children ...tomo.Element) (element *Document) { func NewDocument (children ...tomo.Element) (element *Document) {
element = &Document { } element = &Document { }
element.scratch = make(map[tomo.Element] scratchEntry)
element.theme.Case = tomo.C("tomo", "document") element.theme.Case = tomo.C("tomo", "document")
element.entity = tomo.NewEntity(element).(documentEntity) element.entity = tomo.NewEntity(element).(documentEntity)
element.container.entity = element.entity
element.minimumSize = element.updateMinimumSize
element.init()
element.Adopt(children...) element.Adopt(children...)
return return
} }
func (element *Document) Entity () tomo.Entity {
return element.entity
}
func (element *Document) Draw (destination canvas.Canvas) { func (element *Document) Draw (destination canvas.Canvas) {
rocks := make([]image.Rectangle, element.entity.CountChildren()) rocks := make([]image.Rectangle, element.entity.CountChildren())
for index := 0; index < element.entity.CountChildren(); index ++ { for index := 0; index < element.entity.CountChildren(); index ++ {
@ -111,63 +109,11 @@ func (element *Document) Layout () {
} }
func (element *Document) Adopt (children ...tomo.Element) { func (element *Document) Adopt (children ...tomo.Element) {
for _, child := range children { element.adopt(true, children...)
element.entity.Adopt(child)
element.scratch[child] = scratchEntry { expand: true }
}
element.updateMinimumSize()
element.entity.Invalidate()
element.entity.InvalidateLayout()
} }
func (element *Document) AdoptInline (children ...tomo.Element) { func (element *Document) AdoptInline (children ...tomo.Element) {
for _, child := range children { element.adopt(false, children...)
element.entity.Adopt(child)
element.scratch[child] = scratchEntry { expand: false }
}
element.updateMinimumSize()
element.entity.Invalidate()
element.entity.InvalidateLayout()
}
func (element *Document) Disown (children ...tomo.Element) {
for _, child := range children {
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 *Document) 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 *Document) Child (index int) tomo.Element {
if index < 0 || index >= element.entity.CountChildren() { return nil }
return element.entity.Child(index)
}
func (element *Document) CountChildren () int {
return element.entity.CountChildren()
}
func (element *Document) HandleChildMinimumSizeChange (child tomo.Element) {
element.updateMinimumSize()
element.entity.Invalidate()
element.entity.InvalidateLayout()
} }
func (element *Document) HandleChildFlexibleHeightChange (child tomo.Flexible) { func (element *Document) HandleChildFlexibleHeightChange (child tomo.Flexible) {

View File

@ -7,24 +7,15 @@ import "git.tebibyte.media/sashakoshka/tomo/canvas"
import "git.tebibyte.media/sashakoshka/tomo/artist" import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/default/theme" import "git.tebibyte.media/sashakoshka/tomo/default/theme"
// TODO: make hidden variants:
// vertical: one column.
// flow: acts like DocumentContainer with all inline elements.
// create wrapper elements for making a plain version of each of these, but keep
// the implementations private (but with public methods) so they can be included
// in other elements.
// have table be a very tabular thing with named columns that can be sorted,
// resized, etc.
type listEntity interface { type listEntity interface {
tomo.ContainerEntity tomo.ContainerEntity
tomo.ScrollableEntity tomo.ScrollableEntity
} }
type List struct { type List struct {
container
entity listEntity entity listEntity
scratch map[tomo.Element] scratchEntry
scroll image.Point scroll image.Point
contentBounds image.Rectangle contentBounds image.Rectangle
columnSizes []int columnSizes []int
@ -41,18 +32,16 @@ type List struct {
func NewList (columns int, children ...tomo.Element) (element *List) { func NewList (columns int, children ...tomo.Element) (element *List) {
if columns < 1 { columns = 1 } if columns < 1 { columns = 1 }
element = &List { selected: -1 } element = &List { selected: -1 }
element.scratch = make(map[tomo.Element] scratchEntry)
element.columnSizes = make([]int, columns) element.columnSizes = make([]int, columns)
element.theme.Case = tomo.C("tomo", "list") element.theme.Case = tomo.C("tomo", "list")
element.entity = tomo.NewEntity(element).(listEntity) element.entity = tomo.NewEntity(element).(listEntity)
element.container.entity = element.entity
element.minimumSize = element.updateMinimumSize
element.init()
element.Adopt(children...) element.Adopt(children...)
return return
} }
func (element *List) Entity () tomo.Entity {
return element.entity
}
func (element *List) Draw (destination canvas.Canvas) { func (element *List) Draw (destination canvas.Canvas) {
rocks := make([]image.Rectangle, element.entity.CountChildren()) rocks := make([]image.Rectangle, element.entity.CountChildren())
for index := 0; index < element.entity.CountChildren(); index ++ { for index := 0; index < element.entity.CountChildren(); index ++ {
@ -123,54 +112,6 @@ func (element *List) Layout () {
} }
} }
func (element *List) Adopt (children ...tomo.Element) {
for _, child := range children {
element.entity.Adopt(child)
element.scratch[child] = scratchEntry { }
}
element.updateMinimumSize()
element.entity.Invalidate()
element.entity.InvalidateLayout()
}
func (element *List) Disown (children ...tomo.Element) {
for _, child := range children {
index := element.entity.IndexOf(child)
if index < 0 { return }
if index == element.selected {
element.selected = -1
element.entity.SelectChild(index, false)
}
element.entity.Disown(index)
delete(element.scratch, child)
}
element.updateMinimumSize()
element.entity.Invalidate()
element.entity.InvalidateLayout()
}
func (element *List) 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 *List) Child (index int) tomo.Element {
if index < 0 || index >= element.entity.CountChildren() { return nil }
return element.entity.Child(index)
}
func (element *List) CountChildren () int {
return element.entity.CountChildren()
}
func (element *List) HandleChildMouseDown (x, y int, button input.Button, child tomo.Element) { func (element *List) HandleChildMouseDown (x, y int, button input.Button, child tomo.Element) {
if child, ok := child.(tomo.Selectable); ok { if child, ok := child.(tomo.Selectable); ok {
index := element.entity.IndexOf(child) index := element.entity.IndexOf(child)
@ -185,12 +126,6 @@ func (element *List) HandleChildMouseDown (x, y int, button input.Button, child
func (element *List) HandleChildMouseUp (int, int, input.Button, tomo.Element) { } func (element *List) HandleChildMouseUp (int, int, input.Button, tomo.Element) { }
func (element *List) HandleChildMinimumSizeChange (child tomo.Element) {
element.updateMinimumSize()
element.entity.Invalidate()
element.entity.InvalidateLayout()
}
func (element *List) HandleChildFlexibleHeightChange (child tomo.Flexible) { func (element *List) HandleChildFlexibleHeightChange (child tomo.Flexible) {
element.updateMinimumSize() element.updateMinimumSize()
element.entity.Invalidate() element.entity.Invalidate()