aboutsummaryrefslogtreecommitdiffstats
path: root/scroller.go
diff options
context:
space:
mode:
Diffstat (limited to 'scroller.go')
-rw-r--r--scroller.go127
1 files changed, 127 insertions, 0 deletions
diff --git a/scroller.go b/scroller.go
new file mode 100644
index 0000000..fe411f3
--- /dev/null
+++ b/scroller.go
@@ -0,0 +1,127 @@
+package gui
+
+import (
+ "image"
+ "image/color"
+ "image/draw"
+
+ "git.samanthony.xyz/share"
+)
+
+var _ Scheme = Scroller{}
+
+type Scroller struct {
+ Background color.Color
+ Length int
+ ChildHeight int
+ Offset int
+ Gap int
+ Vertical bool
+}
+
+func (s Scroller) redraw(drw draw.Image, bounds image.Rectangle) {
+ col := s.Background
+ if col == nil {
+ col = image.Black
+ }
+ draw.Draw(drw, bounds, image.NewUniform(col), image.ZP, draw.Src)
+}
+
+func clamp(val, a, b int) int {
+ if a > b {
+ if val < b {
+ return b
+ }
+ if val > a {
+ return a
+ }
+ } else {
+ if val > b {
+ return b
+ }
+ if val < a {
+ return a
+ }
+ }
+ return val
+}
+
+func (s Scroller) Partition(bounds image.Rectangle) []image.Rectangle {
+ items := s.Length
+ ch := s.ChildHeight
+ gap := s.Gap
+
+ ret := make([]image.Rectangle, items)
+ Y := bounds.Min.Y + s.Offset + gap
+ for i := 0; i < items; i++ {
+ r := image.Rect(bounds.Min.X+gap, Y, bounds.Max.X-gap, Y+ch)
+ ret[i] = r
+ Y += ch + gap
+ }
+ return ret
+}
+
+func (s Scroller) Intercept(parent Env) Env {
+ lastResize := share.NewVal[image.Rectangle]()
+ img := share.NewVal[draw.Image]()
+ mouseOver := share.NewVal[bool]()
+
+ lastResize.Set <- image.Rectangle{}
+ img.Set <- image.NewRGBA(image.Rectangle{})
+ mouseOver.Set <- false
+
+ return newEnv(parent,
+ func(event Event, events chan<- Event) {
+ switch event := event.(type) {
+ case MoMove:
+ mouseOver.Set <- event.Point.In(lastResize.Get())
+ case MoScroll:
+ if !mouseOver.Get() {
+ break
+ }
+
+ oldoff := s.Offset
+ v := s.Length*s.ChildHeight + ((s.Length + 1) * s.Gap)
+ bounds := lastResize.Get()
+
+ if s.Vertical {
+ h := bounds.Dx()
+ s.Offset = clamp(s.Offset+event.Point.X*16, h-v, 0)
+ } else {
+ h := bounds.Dy()
+ s.Offset = clamp(s.Offset+event.Point.Y*16, h-v, 0)
+ }
+
+ if oldoff != s.Offset {
+ m := img.Get()
+ s.redraw(m, m.Bounds())
+ events <- Resize{bounds}
+ }
+ case Resize:
+ lastResize.Set <- event.Rectangle
+
+ m := image.NewRGBA(event.Rectangle)
+ img.Set <- m
+ s.redraw(m, m.Bounds())
+
+ events <- event
+ default:
+ events <- event
+ }
+ },
+ func(drawFunc func(draw.Image) image.Rectangle, drawChan chan<- func(draw.Image) image.Rectangle) {
+ m := img.Get()
+ if drawFunc(m).Intersect(m.Bounds()) != image.ZR {
+ drawChan <- func(drw draw.Image) image.Rectangle {
+ bounds := lastResize.Get()
+ draw.Draw(drw, bounds, m, bounds.Min, draw.Over)
+ return m.Bounds()
+ }
+ }
+ },
+ func() {
+ lastResize.Close()
+ img.Close()
+ mouseOver.Close()
+ })
+}