diff --git a/go.mod b/go.mod index 0498488..a7218c9 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,11 @@ module git.tebibyte.media/tomo/backend -go 1.20 +go 1.21.0 + +toolchain go1.22.2 require ( + git.tebibyte.media/sashakoshka/goutil v0.3.0 git.tebibyte.media/tomo/tomo v0.46.1 git.tebibyte.media/tomo/typeset v0.8.0 git.tebibyte.media/tomo/xgbkb v1.0.1 diff --git a/go.sum b/go.sum index b92a944..12341ad 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +git.tebibyte.media/sashakoshka/goutil v0.3.0 h1:dcZ/9/or7m8eTpf2B1Pu4CscplXh2INTXFartz+ExwE= +git.tebibyte.media/sashakoshka/goutil v0.3.0/go.mod h1:e1OXLa+wX7x/F8n8gyxz2hnfVCEkWzGrZNX8/k/lR/M= git.tebibyte.media/sashakoshka/xgbkb v1.0.0/go.mod h1:pNcE6TRO93vHd6q42SdwLSTTj25L0Yzggz7yLe0JV6Q= git.tebibyte.media/tomo/tomo v0.46.1 h1:/8fT6I9l4TK529zokrThbNDHGRvUsNgif1Zs++0PBSQ= git.tebibyte.media/tomo/tomo v0.46.1/go.mod h1:WrtilgKB1y8O2Yu7X4mYcRiqOlPR8NuUnoA/ynkQWrs= diff --git a/internal/system/attribute.go b/internal/system/attribute.go index aacab29..b583bcc 100644 --- a/internal/system/attribute.go +++ b/internal/system/attribute.go @@ -1,12 +1,12 @@ package system import "git.tebibyte.media/tomo/tomo" -import "git.tebibyte.media/tomo/backend/internal/util" +import "git.tebibyte.media/sashakoshka/goutil/container" type attrHierarchy [T tomo.Attr] struct { fallback T - style util.Optional[T] - user util.Optional[T] + style ucontainer.Optional[T] + user ucontainer.Optional[T] } func (this *attrHierarchy[T]) SetFallback (fallback T) { diff --git a/internal/system/box.go b/internal/system/box.go index 224e9ac..dfe6740 100644 --- a/internal/system/box.go +++ b/internal/system/box.go @@ -7,20 +7,21 @@ import "git.tebibyte.media/tomo/tomo/data" import "git.tebibyte.media/tomo/tomo/input" import "git.tebibyte.media/tomo/tomo/event" import "git.tebibyte.media/tomo/tomo/canvas" -import "git.tebibyte.media/tomo/backend/internal/util" +import "git.tebibyte.media/sashakoshka/goutil/container" +import "git.tebibyte.media/sashakoshka/goutil/image/color" type box struct { system *System parent parent outer anyBox - tags util.Set[string] + tags ucontainer.Set[string] role tomo.Role lastStyleNonce int lastIconSetNonce int styleApplicator *styleApplicator - minSize util.Memo[image.Point] + minSize ucontainer.Memo[image.Point] bounds image.Rectangle innerClippingBounds image.Rectangle @@ -41,7 +42,7 @@ type box struct { focused bool pressed bool - canvas util.Memo[canvas.Canvas] + canvas ucontainer.Memo[canvas.Canvas] drawer canvas.Drawer on struct { @@ -68,10 +69,10 @@ func (this *System) newBox (outer anyBox) *box { system: this, outer: outer, drawer: outer, - tags: make(util.Set[string]), + tags: make(ucontainer.Set[string]), } box.attrColor.SetFallback(tomo.AColor(color.Transparent)) - box.canvas = util.NewMemo (func () canvas.Canvas { + box.canvas = ucontainer.NewMemo (func () canvas.Canvas { if box.parent == nil { return nil } parentCanvas := box.parent.getCanvas() if parentCanvas == nil { return nil } @@ -82,7 +83,7 @@ func (this *System) newBox (outer anyBox) *box { box.drawer = box box.outer = box } - box.minSize = util.NewMemo(box.calculateMinimumSize) + box.minSize = ucontainer.NewMemo(box.calculateMinimumSize) return box } @@ -476,7 +477,7 @@ func (this *box) drawBorders (can canvas.Canvas) { rectangle := func (x0, y0, x1, y1 int, c color.Color) { area := image.Rect(x0, y0, x1, y1) if area.Empty() { return } - if util.Transparent(c) && this.parent != nil { + if ucolor.Transparent(c) && this.parent != nil { this.parent.drawBackgroundPart(can.SubCanvas(area)) } pen.Fill(c) @@ -682,7 +683,7 @@ func (this *box) transparent () bool { // TODO uncomment once we have // a way to detect texture transparency col := this.attrColor.Value().Color - return col == nil || util.Transparent(col) /*&& + return col == nil || ucolor.Transparent(col) /*&& (this.texture == nil || !this.texture.Opaque())*/ } diff --git a/internal/system/containerbox.go b/internal/system/containerbox.go index 58a3ef7..b821df5 100644 --- a/internal/system/containerbox.go +++ b/internal/system/containerbox.go @@ -1,11 +1,11 @@ package system import "image" +import "slices" import "image/color" import "git.tebibyte.media/tomo/tomo" import "git.tebibyte.media/tomo/tomo/event" import "git.tebibyte.media/tomo/tomo/canvas" -import "git.tebibyte.media/tomo/backend/internal/util" type containerBox struct { *box @@ -50,7 +50,7 @@ func (this *containerBox) OnContentBoundsChange (callback func()) event.Cookie { func (this *containerBox) Add (child tomo.Object) { box := assertAnyBox(child.GetBox()) - if util.IndexOf(this.children, box) > -1 { return } + if slices.Index(this.children, box) > -1 { return } box.setParent(this) box.flushActionQueue() @@ -61,26 +61,26 @@ func (this *containerBox) Add (child tomo.Object) { func (this *containerBox) Remove (child tomo.Object) { box := assertAnyBox(child.GetBox()) - index := util.IndexOf(this.children, box) + index := slices.Index(this.children, box) if index < 0 { return } box.setParent(nil) - this.children = util.Remove(this.children, index) + this.children = slices.Delete(this.children, index, index) this.invalidateLayout() this.invalidateMinimum() } func (this *containerBox) Insert (child, before tomo.Object) { box := assertAnyBox(child.GetBox()) - if util.IndexOf(this.children, box) > -1 { return } + if slices.Index(this.children, box) > -1 { return } beforeBox := assertAnyBox(before.GetBox()) - index := util.IndexOf(this.children, beforeBox) + index := slices.Index(this.children, beforeBox) if index < 0 { this.children = append(this.children, box) } else { - this.children = util.Insert(this.children, index, box) + this.children = slices.Insert(this.children, index, box) } box.setParent(this) diff --git a/internal/system/hierarchy.go b/internal/system/hierarchy.go index 5a45116..a3e05a5 100644 --- a/internal/system/hierarchy.go +++ b/internal/system/hierarchy.go @@ -5,7 +5,7 @@ import "git.tebibyte.media/tomo/tomo" import "git.tebibyte.media/tomo/tomo/input" import "git.tebibyte.media/tomo/tomo/canvas" import "git.tebibyte.media/tomo/backend/style" -import "git.tebibyte.media/tomo/backend/internal/util" +import "git.tebibyte.media/sashakoshka/goutil/container" // Hierarchy is coupled to a tomo.Window implementation, and manages a tree of // Boxes. @@ -25,9 +25,9 @@ type Hierarchy struct { drags [10][]anyBox minimumSize image.Point - needStyle util.Set[anyBox] - needLayout util.Set[anyBox] - needDraw util.Set[anyBox] + needStyle ucontainer.Set[anyBox] + needLayout ucontainer.Set[anyBox] + needDraw ucontainer.Set[anyBox] needRedo bool minimumClean bool } @@ -53,9 +53,9 @@ func (this *System) NewHierarchy (link WindowLink) *Hierarchy { hierarchy := &Hierarchy { system: this, link: link, - needStyle: make(util.Set[anyBox]), - needLayout: make(util.Set[anyBox]), - needDraw: make(util.Set[anyBox]), + needStyle: make(ucontainer.Set[anyBox]), + needLayout: make(ucontainer.Set[anyBox]), + needDraw: make(ucontainer.Set[anyBox]), } this.hierarchies.Add(hierarchy) return hierarchy diff --git a/internal/system/system.go b/internal/system/system.go index 0ea9bb9..9e9da1d 100644 --- a/internal/system/system.go +++ b/internal/system/system.go @@ -4,7 +4,7 @@ import "io" import "image" import "git.tebibyte.media/tomo/tomo/canvas" import "git.tebibyte.media/tomo/backend/style" -import "git.tebibyte.media/tomo/backend/internal/util" +import "git.tebibyte.media/sashakoshka/goutil/container" // System is coupled to a tomo.Backend implementation, and manages Hierarchies // and Boxes. @@ -17,7 +17,7 @@ type System struct { styleNonce int iconSetNonce int - hierarchies util.Set[*Hierarchy] + hierarchies ucontainer.Set[*Hierarchy] } // BackendLink allows the System to call up into the tomo.Backend implementation @@ -41,7 +41,7 @@ type SurfaceLink interface { func New (link BackendLink) *System { return &System { link: link, - hierarchies: make(util.Set[*Hierarchy]), + hierarchies: make(ucontainer.Set[*Hierarchy]), } } diff --git a/internal/system/textbox.go b/internal/system/textbox.go index 1093093..67318a0 100644 --- a/internal/system/textbox.go +++ b/internal/system/textbox.go @@ -12,6 +12,7 @@ import "git.tebibyte.media/tomo/tomo/input" import "git.tebibyte.media/tomo/tomo/event" import "git.tebibyte.media/tomo/tomo/canvas" import "git.tebibyte.media/tomo/backend/internal/util" +import "git.tebibyte.media/sashakoshka/goutil/container" type textBox struct { *box @@ -36,7 +37,7 @@ type textBox struct { drawer typeset.Drawer face util.Cycler[font.Face] - lineHeight util.Memo[fixed.Int26_6] + lineHeight ucontainer.Memo[fixed.Int26_6] on struct { contentBoundsChange event.FuncBroadcaster @@ -49,7 +50,7 @@ func (this *System) NewTextBox () tomo.TextBox { box.box = this.newBox(box) box.attrTextColor.SetFallback(tomo.ATextColor(color.Black)) box.attrDotColor.SetFallback(tomo.ADotColor(color.RGBA { G: 255, B: 255, A: 255})) - box.lineHeight = util.NewMemo(func () fixed.Int26_6 { + box.lineHeight = ucontainer.NewMemo(func () fixed.Int26_6 { face := box.face.Value() if face == nil { return 0 } metrics := face.Metrics() diff --git a/internal/util/util.go b/internal/util/util.go index a13ac27..a222e80 100644 --- a/internal/util/util.go +++ b/internal/util/util.go @@ -1,100 +1,6 @@ package util import "io" -import "image/color" - -// IndexOf returns the index of needle within haystack. If needle does not exist -// within haystack, it returns -1. -func IndexOf[T comparable] (haystack []T, needle T) int { - for index, test := range haystack { - if test == needle { - return index - } - } - return -1 -} - -// Remove removes an element from slice at index. -func Remove[T any] (slice []T, index int) []T { - return append(slice[:index], slice[index + 1:]...) -} - -// Insert inserts an element into slice at index. -func Insert[T any] (slice []T, index int, element T) []T { - slice = append(slice[:index + 1], slice[index:]...) - slice[index] = element - return slice -} - -// Transparent returns whether or not a color has transparency. -func Transparent (c color.Color) bool { - _, _, _, a := c.RGBA() - return a != 0xFFFF -} - -// Set is a set of unique items, built on top of map. -type Set[T comparable] map[T] struct { } - -// Empty returns true if there are no items in the set. -func (set Set[T]) Empty () bool { - return set == nil || len(set) == 0 -} - -// Has returns true if the set contains item. -func (set Set[T]) Has (item T) bool { - if set == nil { - return false - } - _, ok := set[item] - return ok -} - -// Add adds an item to the set. -func (set Set[T]) Add (item T) { - set[item] = struct { } { } -} - -// Pop removes the first accessible item from the set and returns it. -func (set Set[T]) Pop () (item T) { - for item := range set { - delete(set, item) - return item - } - return -} - -// Memo holds a cached value. -type Memo[T any] struct { - cache T - valid bool - update func () T -} - -// NewMemo creates a new Memo which will take its value from the specified -// update callback. -func NewMemo[T any] (update func () T) Memo[T] { - return Memo[T] { - update: update, - } -} - -// Value returns the Memo's value, updating it if the current cached value is -// invalid. -func (this *Memo[T]) Value () T { - if !this.valid { - this.cache = this.update() - this.valid = true - } - return this.cache -} - -// Invalidate marks the Memo's value as invalid, which will cause it to be -// updated the next time Value is called. -func (this *Memo[T]) Invalidate () { - var zero T - this.cache = zero - this.valid = false -} // Cycler stores a value and an accompanying io.Closer. When the value is set, // the closer associated with the previous value is closed. @@ -124,33 +30,3 @@ func (this *Cycler[T]) Close () error { this.closer = nil return err } - -// Optional is an optional value. -type Optional[T any] struct { - value T - exists bool -} - -// Value returns the value and true if the value exists. If not, it returns the -// last set value and false. -func (this *Optional[T]) Value () (T, bool) { - return this.value, this.exists -} - -// Set sets the value. -func (this *Optional[T]) Set (value T) { - this.value = value - this.exists = true -} - -// Unset unsets the value. -func (this *Optional[T]) Unset () { - var zero T - this.value = zero - this.exists = false -} - -// Exists returns if the value is currently set. -func (this *Optional[T]) Exists () bool { - return this.exists -}