diff --git a/ui/cache.go b/ui/cache.go new file mode 100644 index 0000000..9f6ad98 --- /dev/null +++ b/ui/cache.go @@ -0,0 +1,38 @@ +package ui + +type CacheHashFn func(interface{}) string +type CacheHashContextFn func(Context) string + +func (c CacheHashContextFn) Fn() CacheHashFn { + return func(state interface{}) string { return c(state.(Context)) } +} + +type CacheUpdateFn func(interface{}) interface{} +type CacheUpdateContextFn func(Context) interface{} + +func (c CacheUpdateContextFn) Fn() CacheUpdateFn { + return func(state interface{}) interface{} { return c(state.(Context)) } +} + +type Cache struct { + value interface{} + hash string + + updateFn CacheUpdateFn + hashFn CacheHashFn +} + +func NewCache(update CacheUpdateFn, hash CacheHashFn) *Cache { + return &Cache{updateFn: update, hashFn: hash} +} + +func NewCacheContext(update CacheUpdateContextFn, hash CacheHashContextFn) *Cache { + return NewCache(update.Fn(), hash.Fn()) +} + +func (c *Cache) Get(state interface{}) interface{} { + if c.hashFn(state) != c.hash { + c.value = c.updateFn(state) + } + return c.value +} diff --git a/ui/desiredsizecache.go b/ui/desiredsizecache.go deleted file mode 100644 index 314fdc7..0000000 --- a/ui/desiredsizecache.go +++ /dev/null @@ -1,21 +0,0 @@ -package ui - -import ( - "github.com/minio/highwayhash" - "opslag.de/schobers/geom" -) - -type desiredSizeCache struct { - sum [32]byte - size geom.PointF32 -} - -func (c *desiredSizeCache) Update(ctx Context, data string, calcFn func(Context) geom.PointF32) geom.PointF32 { - var key = [32]byte{} - sum := highwayhash.Sum([]byte(data), key[:]) - if c.sum != sum { - c.size = calcFn(ctx) - c.sum = sum - } - return c.size -} diff --git a/ui/label.go b/ui/label.go index 4d17d8c..4077799 100644 --- a/ui/label.go +++ b/ui/label.go @@ -9,7 +9,8 @@ type Label struct { Text string - size desiredSizeCache + init bool + size *Cache } func BuildLabel(text string, fn func(*Label)) *Label { @@ -20,23 +21,38 @@ func BuildLabel(text string, fn func(*Label)) *Label { return l } +func (l *Label) initialize() { + if l.init { + return + } + l.size = NewCacheContext(l.desiredSize, l.hashContent) + l.init = true +} + +func (l *Label) hashContent(ctx Context) string { + return l.FontName(ctx) + l.Text +} + +func (l *Label) desiredSize(ctx Context) interface{} { + fontName := l.FontName(ctx) + font := ctx.Renderer().Font(fontName) + width := font.WidthOf(l.Text) + height := font.Height() + pad := ctx.Style().Dimensions.TextPadding + return geom.PtF32(width+pad*2, height+pad*2) +} + func (l *Label) DesiredSize(ctx Context) geom.PointF32 { - var fontName = l.FontName(ctx) - return l.size.Update(ctx, fontName+l.Text, func(ctx Context) geom.PointF32 { - var font = ctx.Renderer().Font(fontName) - var width = font.WidthOf(l.Text) - var height = font.Height() - var pad = ctx.Style().Dimensions.TextPadding - return geom.PtF32(width+pad*2, height+pad*2) - }) + l.initialize() + return l.size.Get(ctx).(geom.PointF32) } func (l *Label) Render(ctx Context) { l.RenderBackground(ctx) - var c = l.FontColor(ctx) - var f = l.FontName(ctx) - var pad = ctx.Style().Dimensions.TextPadding - var bounds = l.bounds.Inset(pad) + c := l.FontColor(ctx) + f := l.FontName(ctx) + pad := ctx.Style().Dimensions.TextPadding + bounds := l.bounds.Inset(pad) switch l.TextAlignment { case AlignLeft: ctx.Renderer().TextAlign(bounds.Min, f, c, l.Text, l.TextAlignment)