This repository has been archived on 2024-06-02. You can view files and clone it, but cannot push or open issues or pull requests.
x/system.go
Sasha Koshka ff8875535d Changed the way minimum sizes are calculated
Boxes that need their minimum size to be updated now use a map like
for layout and drawing. Size set with MinimumSize is now treated as
separate from the content size and the larger size is used.
2023-08-17 23:20:08 -04:00

243 lines
4.8 KiB
Go

package x
import "image"
import "git.tebibyte.media/tomo/tomo"
import "git.tebibyte.media/tomo/tomo/input"
import "git.tebibyte.media/tomo/tomo/canvas"
type boxSet map[anyBox] struct { }
func (set boxSet) Empty () bool {
return set == nil || len(set) == 0
}
func (set boxSet) Has (box anyBox) bool {
if set == nil { return false }
_, ok := set[box]
return ok
}
func (set *boxSet) Add (box anyBox) {
if *set == nil {
*set = make(boxSet)
}
(*set)[box] = struct { } { }
}
func (set *boxSet) Pop () anyBox {
for box := range *set {
delete(*set, box)
return box
}
return nil
}
type parent interface {
window () *window
canvas () canvas.Canvas
notifyMinimumSizeChange (anyBox)
}
type anyBox interface {
tomo.Box
canvas.Drawer
doDraw ()
doLayout ()
doMinimumSize ()
contentMinimum () image.Point
setParent (parent)
flushActionQueue ()
recursiveRedo ()
canBeFocused () bool
boxUnder (image.Point) anyBox
propagate (func (anyBox) bool) bool
propagateAlt (func (anyBox) bool) bool
handleFocusEnter ()
handleFocusLeave ()
// handleDndEnter ()
// handleDndLeave ()
// handleDndDrop (data.Data)
handleMouseEnter ()
handleMouseLeave ()
handleMouseMove ()
handleMouseDown (input.Button)
handleMouseUp (input.Button)
// handleScroll (float64, float64)
handleKeyDown (input.Key, bool)
handleKeyUp (input.Key, bool)
}
func assertAnyBox (unknown tomo.Box) anyBox {
if box, ok := unknown.(anyBox); ok {
return box
} else {
panic("foregin box implementation, i did not make this!")
}
}
func (window *window) SetRoot (root tomo.Object) {
if window.root != nil {
window.root.setParent(nil)
}
if root == nil {
window.root = nil
} else {
box := assertAnyBox(root.GetBox())
box.setParent(window)
box.flushActionQueue()
window.invalidateLayout(box)
window.root = box
}
window.minimumClean = false
}
func (window *window) window () *window {
return window
}
func (window *window) canvas () canvas.Canvas {
return window.xCanvas
}
func (window *window) notifyMinimumSizeChange (anyBox) {
window.minimumClean = false
}
func (window *window) invalidateMinimum (box anyBox) {
window.needMinimum.Add(box)
}
func (window *window) invalidateDraw (box anyBox) {
window.needDraw.Add(box)
}
func (window *window) invalidateLayout (box anyBox) {
window.needLayout.Add(box)
window.invalidateDraw(box)
}
func (window *window) focus (box anyBox) {
if window.focused == box { return }
previous := window.focused
window.focused = box
if previous != nil {
previous.handleFocusLeave()
}
if box != nil && box.canBeFocused() {
box.handleFocusEnter()
}
}
func (window *window) hover (box anyBox) {
if window.hovered == box { return }
previous := window.hovered
window.hovered = box
if previous != nil {
previous.handleMouseLeave()
}
if box != nil {
box.handleMouseEnter()
}
}
func (window *window) anyFocused () bool {
return window.focused != nil
}
func (this *window) boxUnder (point image.Point) anyBox {
if this.root == nil { return nil }
return this.root.boxUnder(point)
}
func (this *window) focusNext () {
found := !this.anyFocused()
focused := false
this.propagateAlt (func (box anyBox) bool {
if found {
// looking for the next box to select
if box.canBeFocused() {
// found it
this.focus(box)
focused = true
return false
}
} else {
// looking for the current focused element
if box == this.focused {
// found it
found = true
}
}
return true
})
if !focused { this.focus(nil) }
}
func (this *window) focusPrevious () {
var behind anyBox
this.propagate (func (box anyBox) bool {
if box == this.focused {
return false
}
if box.canBeFocused() { behind = box }
return true
})
this.focus(behind)
}
func (this *window) propagate (callback func (box anyBox) bool) {
if this.root == nil { return }
this.root.propagate(callback)
}
func (this *window) propagateAlt (callback func (box anyBox) bool) {
if this.root == nil { return }
this.root.propagateAlt(callback)
}
func (window *window) afterEvent () {
if window.xCanvas == nil { return }
if window.needRedo {
// set child bounds
childBounds := window.metrics.bounds
childBounds = childBounds.Sub(childBounds.Min)
window.root.SetBounds(childBounds)
// full relayout/redraw
if window.root != nil {
window.root.recursiveRedo()
}
window.pushAll()
window.needRedo = false
return
}
for len(window.needMinimum) > 0 {
window.needMinimum.Pop().doMinimumSize()
}
if !window.minimumClean {
window.doMinimumSize()
}
for len(window.needLayout) > 0 {
window.needLayout.Pop().doLayout()
}
var toPush image.Rectangle
for len(window.needDraw) > 0 {
box := window.needDraw.Pop()
box.doDraw()
toPush = toPush.Union(box.Bounds())
}
if !toPush.Empty() {
window.pushRegion(toPush)
}
}