diff options
| -rw-r--r-- | layout/doc.go | 10 | ||||
| -rw-r--r-- | layout/scroller.go | 132 | ||||
| -rw-r--r-- | scroller.go | 127 |
3 files changed, 127 insertions, 142 deletions
diff --git a/layout/doc.go b/layout/doc.go deleted file mode 100644 index 8305d43..0000000 --- a/layout/doc.go +++ /dev/null @@ -1,10 +0,0 @@ -/* -Package layout provides a Layout system for faiface/gui. - -The core of the package is the Layout interface, everything else is just -implementation. - -The Layouts represent a Layout, and the Mux makes them usable. -The Mux basically acts as a sort of driver. -*/ -package layout diff --git a/layout/scroller.go b/layout/scroller.go deleted file mode 100644 index c532f93..0000000 --- a/layout/scroller.go +++ /dev/null @@ -1,132 +0,0 @@ -package layout - -import ( - "image" - "image/color" - "image/draw" - // "log" - "sync" - - "github.com/faiface/gui" - "github.com/faiface/gui/win" -) - -var _ Layout = &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) Intercept(env gui.Env) gui.Env { - out, in := gui.MakeEventsChan() - drawChan := make(chan func(draw.Image) image.Rectangle) - ret := &muxEnv{out, drawChan} - var lastResize gui.Resize - var img draw.Image - img = image.NewRGBA(image.ZR) - var mu sync.Mutex - var over bool - - go func() { - for dc := range drawChan { - mu.Lock() - // draw.Draw will not draw out of bounds, call should be inexpensive if element not visible - res := dc(img) - // Only send a draw call up if visibly changed - if res.Intersect(img.Bounds()) != image.ZR { - env.Draw() <- func(drw draw.Image) image.Rectangle { - draw.Draw(drw, lastResize.Rectangle, img, lastResize.Rectangle.Min, draw.Over) - return img.Bounds() - } - } - mu.Unlock() - } - }() - - go func() { - for ev := range env.Events() { - switch ev := ev.(type) { - case win.MoMove: - mu.Lock() - over = ev.Point.In(lastResize.Rectangle) - mu.Unlock() - case win.MoScroll: - if !over { - continue - } - mu.Lock() - oldoff := s.Offset - v := s.Length*s.ChildHeight + ((s.Length + 1) * s.Gap) - if s.Vertical { - h := lastResize.Dx() - s.Offset = clamp(s.Offset+ev.Point.X*16, h-v, 0) - } else { - h := lastResize.Dy() - s.Offset = clamp(s.Offset+ev.Point.Y*16, h-v, 0) - } - if oldoff != s.Offset { - s.redraw(img, img.Bounds()) - in <- lastResize - } - mu.Unlock() - case gui.Resize: - mu.Lock() - lastResize = ev - img = image.NewRGBA(lastResize.Rectangle) - s.redraw(img, img.Bounds()) - mu.Unlock() - in <- ev - default: - in <- ev - } - } - }() - return ret -} - -func (s Scroller) Lay(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 -} 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() + }) +} |