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
outer anyBox
role tomo.Role
role tomo.Role
styleCookie event.Cookie
lastStyleNonce int
lastIconsNonce int
bounds image.Rectangle
minSize image.Point
@ -44,19 +47,21 @@ type box struct {
drawer canvas.Drawer
on struct {
focusEnter event.FuncBroadcaster
focusLeave event.FuncBroadcaster
dndEnter event.FuncBroadcaster
dndLeave event.FuncBroadcaster
dndDrop event.Broadcaster[func (data.Data)]
mouseEnter event.FuncBroadcaster
mouseLeave event.FuncBroadcaster
mouseMove event.FuncBroadcaster
mouseDown event.Broadcaster[func (input.Button)]
mouseUp event.Broadcaster[func (input.Button)]
scroll event.Broadcaster[func (float64, float64)]
keyDown event.Broadcaster[func (input.Key, bool)]
keyUp event.Broadcaster[func (input.Key, bool)]
focusEnter event.FuncBroadcaster
focusLeave event.FuncBroadcaster
dndEnter event.FuncBroadcaster
dndLeave event.FuncBroadcaster
dndDrop event.Broadcaster[func (data.Data)]
mouseEnter event.FuncBroadcaster
mouseLeave event.FuncBroadcaster
mouseMove event.FuncBroadcaster
mouseDown event.Broadcaster[func (input.Button)]
mouseUp event.Broadcaster[func (input.Button)]
scroll event.Broadcaster[func (float64, float64)]
keyDown 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 {
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 () {
this.on.focusEnter.Broadcast()
}
@ -451,7 +462,7 @@ func (this *box) doLayout () {
// laycnt ++
this.innerClippingBounds = this.borderSum().Apply(this.bounds)
this.loseCanvas()
this.outer.recursiveLoseCanvas()
}
func (this *box) setParent (parent parent) {
@ -481,7 +492,7 @@ func (this *box) recursiveRedo () {
this.doDraw()
}
func (this *box) loseCanvas () {
func (this *box) recursiveLoseCanvas () {
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 {
return this.focusable
}
@ -539,7 +572,23 @@ func (this *box) getWindow () tomo.Window {
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 {
if this.parent == nil { return nil }
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 {
if !point.In(this.bounds) { return nil }

View File

@ -12,6 +12,10 @@ type Hierarchy struct {
link WindowLink
system *System
canvas canvas.Canvas
style tomo.Style
styleNonce int
iconsNonce int
root anyBox
focused anyBox
@ -56,6 +60,7 @@ func (this *System) NewHierarchy (link WindowLink) *Hierarchy {
needLayout: make(util.Set[anyBox]),
needDraw: make(util.Set[anyBox]),
}
this.hierarchies.Add(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.
func (this *Hierarchy) SetCanvas (can canvas.Canvas) {
this.canvas = can
if this.root != nil { this.root.loseCanvas() }
if this.root != nil { this.root.recursiveLoseCanvas() }
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 {
return this
}
@ -143,6 +165,18 @@ func (this *Hierarchy) getWindow () tomo.Window {
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 {
return this.canvas
}

View File

@ -51,13 +51,17 @@ type anyBox interface {
// flushActionQueue performs any queued actions, like invalidating the
// minimum size or grabbing input focus.
flushActionQueue ()
flushActionQueue ()
// recursiveRedo recursively recalculates the minimum size, layout, and
// re-paints this anyBox and all of its children.
recursiveRedo ()
recursiveRedo ()
// loseCanvas causes this anyBox and its children (if applicable) to
// 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 () image.Point
@ -81,19 +85,19 @@ type anyBox interface {
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)
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 {

View File

@ -2,12 +2,15 @@ package system
import "io"
import "image"
import "git.tebibyte.media/tomo/tomo"
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
// and Boxes.
type System struct {
link BackendLink
link BackendLink
hierarchies util.Set[*Hierarchy]
}
// BackendLink allows the System to call up into the tomo.Backend implementation
@ -30,6 +33,26 @@ type SurfaceLink interface {
// New creates a new System.
func New (link BackendLink) *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)
}