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

274 lines
5.5 KiB
Go
Raw Normal View History

2023-07-02 00:52:14 -06:00
package x
2023-07-03 22:04:00 -06:00
import "image"
2023-07-02 00:52:14 -06:00
import "git.tebibyte.media/tomo/tomo"
2023-07-15 22:42:47 -06:00
import "git.tebibyte.media/tomo/tomo/input"
2023-07-03 22:04:00 -06:00
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)
drawBackgroundPart (canvas.Canvas)
2023-09-09 13:05:08 -06:00
captures (eventCategory) bool
2023-07-03 22:04:00 -06:00
}
2023-07-02 00:52:14 -06:00
type anyBox interface {
tomo.Box
canvas.Drawer
doDraw ()
doLayout ()
doMinimumSize ()
contentMinimum () image.Point
setParent (parent)
2023-09-09 13:05:08 -06:00
getParent () parent
flushActionQueue ()
recursiveRedo ()
canBeFocused () bool
2023-09-09 13:05:08 -06:00
boxUnder (image.Point, eventCategory) anyBox
transparent () bool
2023-07-15 22:42:47 -06:00
2023-07-21 21:22:03 -06:00
propagate (func (anyBox) bool) bool
propagateAlt (func (anyBox) bool) bool
2023-07-15 22:54:25 -06:00
handleFocusEnter ()
handleFocusLeave ()
// handleDndEnter ()
// handleDndLeave ()
// handleDndDrop (data.Data)
2023-08-12 10:10:47 -06:00
handleMouseEnter ()
handleMouseLeave ()
2023-08-05 15:56:15 -06:00
handleMouseMove ()
2023-07-15 22:54:25 -06:00
handleMouseDown (input.Button)
handleMouseUp (input.Button)
2023-09-09 13:05:08 -06:00
handleScroll (float64, float64)
2023-07-21 21:22:03 -06:00
handleKeyDown (input.Key, bool)
handleKeyUp (input.Key, bool)
2023-07-02 00:52:14 -06:00
}
2023-07-05 01:25:50 -06:00
func assertAnyBox (unknown tomo.Box) anyBox {
if box, ok := unknown.(anyBox); ok {
return box
} else {
panic("foregin box implementation, i did not make this!")
}
}
2023-07-02 00:52:14 -06:00
func (window *window) SetRoot (root tomo.Object) {
2023-07-04 22:44:56 -06:00
if window.root != nil {
window.root.setParent(nil)
}
if root == nil {
window.root = nil
} else {
2023-08-11 23:03:34 -06:00
box := assertAnyBox(root.GetBox())
2023-07-04 22:44:56 -06:00
box.setParent(window)
box.flushActionQueue()
2023-07-04 22:44:56 -06:00
window.invalidateLayout(box)
window.root = box
}
window.minimumClean = false
2023-07-02 00:52:14 -06:00
}
2023-07-03 22:04:00 -06:00
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)
}
2023-07-03 22:04:00 -06:00
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 }
2023-07-15 22:54:25 -06:00
previous := window.focused
2023-07-03 22:04:00 -06:00
window.focused = box
2023-07-15 22:54:25 -06:00
if previous != nil {
previous.handleFocusLeave()
}
2023-07-21 21:22:03 -06:00
if box != nil && box.canBeFocused() {
2023-07-15 22:54:25 -06:00
box.handleFocusEnter()
}
2023-07-03 22:04:00 -06:00
}
2023-08-12 10:10:47 -06:00
func (window *window) hover (box anyBox) {
if window.hovered == box { return }
2023-08-12 10:10:47 -06:00
previous := window.hovered
window.hovered = box
2023-08-12 10:10:47 -06:00
if previous != nil {
previous.handleMouseLeave()
}
if box != nil {
box.handleMouseEnter()
}
}
2023-07-21 21:22:03 -06:00
func (window *window) anyFocused () bool {
return window.focused != nil
}
2023-09-09 13:05:08 -06:00
type eventCategory int; const (
eventCategoryDND eventCategory = iota
eventCategoryMouse
eventCategoryScroll
eventCategoryKeyboard
)
func (this *window) boxUnder (point image.Point, category eventCategory) anyBox {
2023-07-15 22:42:47 -06:00
if this.root == nil { return nil }
2023-09-09 13:05:08 -06:00
return this.root.boxUnder(point, category)
}
func (this *window) captures (eventCategory) bool {
return false
}
func (this *window) keyboardTarget () anyBox {
focused := this.window().focused
if focused == nil { return nil }
parent := focused.getParent()
for {
parentBox, ok := parent.(anyBox)
if !ok { break }
if parent.captures(eventCategoryKeyboard) {
return parentBox
}
parent = parentBox.getParent()
}
return focused
2023-07-15 22:42:47 -06:00
}
2023-07-21 21:22:03 -06:00
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)
}
2023-07-03 22:04:00 -06:00
func (window *window) afterEvent () {
2023-07-04 22:44:56 -06:00
if window.xCanvas == nil { return }
2023-07-03 22:04:00 -06:00
if window.needRedo {
2023-07-04 22:44:56 -06:00
// set child bounds
childBounds := window.metrics.bounds
childBounds = childBounds.Sub(childBounds.Min)
window.root.SetBounds(childBounds)
// full relayout/redraw
2023-07-03 22:04:00 -06:00
if window.root != nil {
window.root.recursiveRedo()
}
2023-07-04 22:44:56 -06:00
window.pushAll()
window.needRedo = false
2023-07-03 22:04:00 -06:00
return
}
for len(window.needMinimum) > 0 {
window.needMinimum.Pop().doMinimumSize()
}
if !window.minimumClean {
window.doMinimumSize()
}
2023-07-03 22:04:00 -06:00
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())
}
2023-07-04 22:44:56 -06:00
if !toPush.Empty() {
window.pushRegion(toPush)
}
2023-07-02 00:52:14 -06:00
}