2023-04-13 22:25:05 -06:00
|
|
|
package x
|
|
|
|
|
|
|
|
import "image"
|
|
|
|
import "git.tebibyte.media/sashakoshka/tomo"
|
|
|
|
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
2023-04-14 23:14:36 -06:00
|
|
|
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
|
|
|
import "git.tebibyte.media/sashakoshka/tomo/default/config"
|
2023-04-13 22:25:05 -06:00
|
|
|
|
|
|
|
type entitySet map[*entity] struct { }
|
|
|
|
|
|
|
|
func (set entitySet) Empty () bool {
|
|
|
|
return len(set) == 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (set entitySet) Has (entity *entity) bool {
|
|
|
|
_, ok := set[entity]
|
|
|
|
return ok
|
|
|
|
}
|
|
|
|
|
|
|
|
func (set entitySet) Add (entity *entity) {
|
|
|
|
set[entity] = struct { } { }
|
|
|
|
}
|
|
|
|
|
|
|
|
type system struct {
|
|
|
|
child *entity
|
|
|
|
focused *entity
|
|
|
|
canvas canvas.BasicCanvas
|
|
|
|
|
2023-04-14 23:14:36 -06:00
|
|
|
theme theme.Wrapped
|
|
|
|
config config.Wrapped
|
2023-04-13 22:25:05 -06:00
|
|
|
|
|
|
|
invalidateIgnore bool
|
|
|
|
drawingInvalid entitySet
|
|
|
|
anyLayoutInvalid bool
|
2023-04-14 17:08:14 -06:00
|
|
|
|
|
|
|
drags [10]tomo.MouseTarget
|
2023-04-13 22:25:05 -06:00
|
|
|
|
|
|
|
pushFunc func (image.Rectangle)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (system *system) initialize () {
|
|
|
|
system.drawingInvalid = make(entitySet)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (system *system) SetTheme (theme tomo.Theme) {
|
2023-04-14 23:14:36 -06:00
|
|
|
system.theme.Theme = theme
|
2023-04-14 17:08:14 -06:00
|
|
|
system.propagate (func (entity *entity) bool {
|
|
|
|
if child, ok := system.child.element.(tomo.Themeable); ok {
|
|
|
|
child.SetTheme(theme)
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
})
|
2023-04-13 22:25:05 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (system *system) SetConfig (config tomo.Config) {
|
2023-04-14 23:14:36 -06:00
|
|
|
system.config.Config = config
|
2023-04-14 17:08:14 -06:00
|
|
|
system.propagate (func (entity *entity) bool {
|
|
|
|
if child, ok := system.child.element.(tomo.Configurable); ok {
|
|
|
|
child.SetConfig(config)
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (system *system) focusNext () {
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
|
|
|
|
func (system *system) focusPrevious () {
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
|
|
|
|
func (system *system) propagate (callback func (*entity) bool) {
|
2023-04-13 22:25:05 -06:00
|
|
|
if system.child == nil { return }
|
2023-04-14 17:08:14 -06:00
|
|
|
system.child.propagate(callback)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (system *system) childAt (point image.Point) *entity {
|
|
|
|
if system.child == nil { return nil }
|
|
|
|
return system.child.childAt(point)
|
2023-04-13 22:25:05 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (system *system) resizeChildToFit () {
|
|
|
|
system.child.bounds = system.canvas.Bounds()
|
|
|
|
system.child.clippedBounds = system.child.bounds
|
|
|
|
system.child.Invalidate()
|
|
|
|
if system.child.isContainer {
|
|
|
|
system.child.InvalidateLayout()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (system *system) afterEvent () {
|
|
|
|
if system.anyLayoutInvalid {
|
|
|
|
system.layout(system.child, false)
|
|
|
|
system.anyLayoutInvalid = false
|
|
|
|
}
|
|
|
|
system.draw()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (system *system) layout (entity *entity, force bool) {
|
2023-04-15 16:09:49 -06:00
|
|
|
if entity == nil || !entity.isContainer { return }
|
2023-04-13 22:25:05 -06:00
|
|
|
if entity.layoutInvalid == true || force {
|
|
|
|
entity.element.(tomo.Container).Layout()
|
|
|
|
entity.layoutInvalid = false
|
|
|
|
force = true
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, child := range entity.children {
|
|
|
|
system.layout(child, force)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (system *system) draw () {
|
|
|
|
finalBounds := image.Rectangle { }
|
|
|
|
|
|
|
|
// ignore invalidations that result from drawing elements, because if an
|
|
|
|
// element decides to do that it really needs to rethink its life
|
|
|
|
// choices.
|
|
|
|
system.invalidateIgnore = true
|
|
|
|
defer func () { system.invalidateIgnore = false } ()
|
|
|
|
|
|
|
|
for entity := range system.drawingInvalid {
|
|
|
|
entity.element.Draw (canvas.Cut (
|
|
|
|
system.canvas,
|
|
|
|
entity.clippedBounds))
|
|
|
|
finalBounds = finalBounds.Union(entity.clippedBounds)
|
|
|
|
}
|
|
|
|
system.drawingInvalid = make(entitySet)
|
|
|
|
|
|
|
|
// TODO: don't just union all the bounds together, we can definetly
|
|
|
|
// consolidateupdated regions more efficiently than this.
|
|
|
|
if !finalBounds.Empty() {
|
|
|
|
system.pushFunc(finalBounds)
|
|
|
|
}
|
|
|
|
}
|