package x import "image" import "git.tebibyte.media/tomo/tomo" 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 } type anyBox interface { tomo.Box doDraw () doLayout () setParent (parent) recursiveRedo () } 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.Box()) box.setParent(window) window.invalidateLayout(box) window.root = box } } func (window *window) window () *window { return window } func (window *window) canvas () canvas.Canvas { return window.xCanvas } 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 } window.invalidateDraw(window.focused) window.focused = box window.invalidateDraw(box) } 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.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) } }