Add theme setting nonsense

This commit is contained in:
Sasha Koshka 2024-06-11 18:12:47 -04:00
parent 26b69d3e21
commit 995e6fd624
5 changed files with 159 additions and 35 deletions

View File

@ -19,7 +19,10 @@ type box struct {
parent parent parent parent
outer anyBox outer anyBox
role tomo.Role role tomo.Role
styleCookie event.Cookie
lastStyleNonce int
lastIconsNonce int
bounds image.Rectangle bounds image.Rectangle
minSize image.Point minSize image.Point
@ -44,19 +47,21 @@ type box struct {
drawer canvas.Drawer drawer canvas.Drawer
on struct { on struct {
focusEnter event.FuncBroadcaster focusEnter event.FuncBroadcaster
focusLeave event.FuncBroadcaster focusLeave event.FuncBroadcaster
dndEnter event.FuncBroadcaster dndEnter event.FuncBroadcaster
dndLeave event.FuncBroadcaster dndLeave event.FuncBroadcaster
dndDrop event.Broadcaster[func (data.Data)] dndDrop event.Broadcaster[func (data.Data)]
mouseEnter event.FuncBroadcaster mouseEnter event.FuncBroadcaster
mouseLeave event.FuncBroadcaster mouseLeave event.FuncBroadcaster
mouseMove event.FuncBroadcaster mouseMove event.FuncBroadcaster
mouseDown event.Broadcaster[func (input.Button)] mouseDown event.Broadcaster[func (input.Button)]
mouseUp event.Broadcaster[func (input.Button)] mouseUp event.Broadcaster[func (input.Button)]
scroll event.Broadcaster[func (float64, float64)] scroll event.Broadcaster[func (float64, float64)]
keyDown event.Broadcaster[func (input.Key, bool)] keyDown event.Broadcaster[func (input.Key, bool)]
keyUp event.Broadcaster[func (input.Key, bool)] keyUp event.Broadcaster[func (input.Key, bool)]
styleChange event.FuncBroadcaster
iconsChange event.FuncBroadcaster
} }
} }
@ -282,6 +287,12 @@ func (this *box) OnKeyDown (callback func(key input.Key, numberPad bool)) event.
func (this *box) OnKeyUp (callback func(key input.Key, numberPad bool)) event.Cookie { func (this *box) OnKeyUp (callback func(key input.Key, numberPad bool)) event.Cookie {
return this.on.keyUp.Connect(callback) return this.on.keyUp.Connect(callback)
} }
func (this *box) OnStyleChange (callback func()) event.Cookie {
return this.on.styleChange.Connect(callback)
}
func (this *box) OnIconsChange (callback func()) event.Cookie {
return this.on.iconsChange.Connect(callback)
}
func (this *box) handleFocusEnter () { func (this *box) handleFocusEnter () {
this.on.focusEnter.Broadcast() this.on.focusEnter.Broadcast()
} }
@ -451,7 +462,7 @@ func (this *box) doLayout () {
// laycnt ++ // laycnt ++
this.innerClippingBounds = this.borderSum().Apply(this.bounds) this.innerClippingBounds = this.borderSum().Apply(this.bounds)
this.loseCanvas() this.outer.recursiveLoseCanvas()
} }
func (this *box) setParent (parent parent) { func (this *box) setParent (parent parent) {
@ -481,7 +492,7 @@ func (this *box) recursiveRedo () {
this.doDraw() this.doDraw()
} }
func (this *box) loseCanvas () { func (this *box) recursiveLoseCanvas () {
this.canvas.InvalidateTo(nil) this.canvas.InvalidateTo(nil)
} }
@ -506,6 +517,28 @@ func (this *box) invalidateMinimum () {
} }
} }
func (this *box) recursiveReApply () {
// re-apply styling, icons *if needed*
// style
hierarchyStyleNonce := this.getStyleNonce()
if this.lastStyleNonce != hierarchyStyleNonce {
this.lastStyleNonce = hierarchyStyleNonce
if this.styleCookie != nil {
this.styleCookie.Close()
}
this.styleCookie = this.getStyle().Apply(this.outer)
this.on.styleChange.Broadcast()
}
// icons
hierarchyIconsNonce := this.getIconsNonce()
if this.lastIconsNonce != hierarchyIconsNonce {
this.lastIconsNonce = hierarchyIconsNonce
this.on.iconsChange.Broadcast()
}
}
func (this *box) canBeFocused () bool { func (this *box) canBeFocused () bool {
return this.focusable return this.focusable
} }
@ -539,7 +572,23 @@ func (this *box) getWindow () tomo.Window {
return hierarchy.getWindow() return hierarchy.getWindow()
} }
func (this *box) getStyle () tomo.Style {
hierarchy := this.getHierarchy()
if hierarchy == nil { return nil }
return hierarchy.getStyle()
}
func (this *box) getHierarchy () *Hierarchy { func (this *box) getHierarchy () *Hierarchy {
if this.parent == nil { return nil } if this.parent == nil { return nil }
return this.parent.getHierarchy() return this.parent.getHierarchy()
} }
func (this *box) getStyleNonce () int {
// should panic if not in the tree
return this.getHierarchy().getStyleNonce()
}
func (this *box) getIconsNonce () int {
// should panic if not in the tree
return this.getHierarchy().getIconsNonce()
}

View File

@ -335,6 +335,20 @@ func (this *containerBox) recursiveRedo () {
} }
} }
func (this *containerBox) recursiveLoseCanvas () {
this.box.recursiveLoseCanvas()
for _, child := range this.children {
child.(anyBox).recursiveLoseCanvas()
}
}
func (this *containerBox) recursiveReApply () {
this.box.recursiveReApply()
for _, child := range this.children {
child.(anyBox).recursiveReApply()
}
}
func (this *containerBox) boxUnder (point image.Point, category eventCategory) anyBox { func (this *containerBox) boxUnder (point image.Point, category eventCategory) anyBox {
if !point.In(this.bounds) { return nil } if !point.In(this.bounds) { return nil }

View File

@ -12,6 +12,10 @@ type Hierarchy struct {
link WindowLink link WindowLink
system *System system *System
canvas canvas.Canvas canvas canvas.Canvas
style tomo.Style
styleNonce int
iconsNonce int
root anyBox root anyBox
focused anyBox focused anyBox
@ -56,6 +60,7 @@ func (this *System) NewHierarchy (link WindowLink) *Hierarchy {
needLayout: make(util.Set[anyBox]), needLayout: make(util.Set[anyBox]),
needDraw: make(util.Set[anyBox]), needDraw: make(util.Set[anyBox]),
} }
this.hierarchies.Add(hierarchy)
return hierarchy return hierarchy
} }
@ -85,7 +90,7 @@ func (this *Hierarchy) Empty () bool {
// draw to. The Hierarchy will use the canvas.Canvas's bounds to lay itself out. // draw to. The Hierarchy will use the canvas.Canvas's bounds to lay itself out.
func (this *Hierarchy) SetCanvas (can canvas.Canvas) { func (this *Hierarchy) SetCanvas (can canvas.Canvas) {
this.canvas = can this.canvas = can
if this.root != nil { this.root.loseCanvas() } if this.root != nil { this.root.recursiveLoseCanvas() }
this.needRedo = true this.needRedo = true
} }
@ -135,6 +140,23 @@ func (this *Hierarchy) AfterEvent () {
} }
} }
// Close closes the Hierarchy. This should be called when the Window that
// contains it has been closed.
func (this *Hierarchy) Close () {
this.system.removeHierarchy(this)
}
func (this *Hierarchy) setStyle (style tomo.Style) {
this.style = style
this.styleNonce ++
if this.root != nil { this.root.recursiveReApply() }
}
func (this *Hierarchy) setIcons (icons tomo.Icons) {
this.iconsNonce ++
if this.root != nil { this.root.recursiveReApply() }
}
func (this *Hierarchy) getHierarchy () *Hierarchy { func (this *Hierarchy) getHierarchy () *Hierarchy {
return this return this
} }
@ -143,6 +165,18 @@ func (this *Hierarchy) getWindow () tomo.Window {
return this.link.GetWindow() return this.link.GetWindow()
} }
func (this *Hierarchy) getStyle () tomo.Style {
return this.style
}
func (this *Hierarchy) getStyleNonce () int {
return this.styleNonce
}
func (this *Hierarchy) getIconsNonce () int {
return this.iconsNonce
}
func (this *Hierarchy) getCanvas () canvas.Canvas { func (this *Hierarchy) getCanvas () canvas.Canvas {
return this.canvas return this.canvas
} }

View File

@ -51,13 +51,17 @@ type anyBox interface {
// flushActionQueue performs any queued actions, like invalidating the // flushActionQueue performs any queued actions, like invalidating the
// minimum size or grabbing input focus. // minimum size or grabbing input focus.
flushActionQueue () flushActionQueue ()
// recursiveRedo recursively recalculates the minimum size, layout, and // recursiveRedo recursively recalculates the minimum size, layout, and
// re-paints this anyBox and all of its children. // re-paints this anyBox and all of its children.
recursiveRedo () recursiveRedo ()
// loseCanvas causes this anyBox and its children (if applicable) to // loseCanvas causes this anyBox and its children (if applicable) to
// lose their canvases and re-cut them as needed. // lose their canvases and re-cut them as needed.
loseCanvas () recursiveLoseCanvas ()
// recursiveReAppply causes this anyBox and its children (if applicable)
// to check whether they have an outdated style or icon set, and if so,
// update it and trigger the appropriate event broadcasters.
recursiveReApply ()
// contentMinimum returns the minimum dimensions of this box's content // contentMinimum returns the minimum dimensions of this box's content
contentMinimum () image.Point contentMinimum () image.Point
@ -81,19 +85,19 @@ type anyBox interface {
propagate (func (anyBox) bool) bool propagate (func (anyBox) bool) bool
propagateAlt (func (anyBox) bool) bool propagateAlt (func (anyBox) bool) bool
handleFocusEnter () handleFocusEnter ()
handleFocusLeave () handleFocusLeave ()
// handleDndEnter () // handleDndEnter ()
// handleDndLeave () // handleDndLeave ()
// handleDndDrop (data.Data) // handleDndDrop (data.Data)
handleMouseEnter () handleMouseEnter ()
handleMouseLeave () handleMouseLeave ()
handleMouseMove () handleMouseMove ()
handleMouseDown (input.Button) handleMouseDown (input.Button)
handleMouseUp (input.Button) handleMouseUp (input.Button)
handleScroll (float64, float64) handleScroll (float64, float64)
handleKeyDown (input.Key, bool) handleKeyDown (input.Key, bool)
handleKeyUp (input.Key, bool) handleKeyUp (input.Key, bool)
} }
func assertAnyBox (unknown tomo.Box) anyBox { func assertAnyBox (unknown tomo.Box) anyBox {

View File

@ -2,12 +2,15 @@ package system
import "io" import "io"
import "image" import "image"
import "git.tebibyte.media/tomo/tomo"
import "git.tebibyte.media/tomo/tomo/canvas" import "git.tebibyte.media/tomo/tomo/canvas"
import "git.tebibyte.media/tomo/backend/internal/util"
// System is coupled to a tomo.Backend implementation, and manages Hierarchies // System is coupled to a tomo.Backend implementation, and manages Hierarchies
// and Boxes. // and Boxes.
type System struct { type System struct {
link BackendLink link BackendLink
hierarchies util.Set[*Hierarchy]
} }
// BackendLink allows the System to call up into the tomo.Backend implementation // BackendLink allows the System to call up into the tomo.Backend implementation
@ -30,6 +33,26 @@ type SurfaceLink interface {
// New creates a new System. // New creates a new System.
func New (link BackendLink) *System { func New (link BackendLink) *System {
return &System { return &System {
link: link, link: link,
hierarchies: make(util.Set[*Hierarchy]),
} }
} }
// SetStyle sets the tomo.Style that is applied to objects, and notifies them
// that the style has changed.
func (this *System) SetStyle (style tomo.Style) {
for hierarchy := range this.hierarchies {
hierarchy.setStyle(style)
}
}
// SetIcons notifies objects that the icons have changed.
func (this *System) SetIcons (icons tomo.Icons) {
for hierarchy := range this.hierarchies {
hierarchy.setIcons(icons)
}
}
func (this *System) removeHierarchy (hierarchy *Hierarchy) {
delete(this.hierarchies, hierarchy)
}