aboutsummaryrefslogtreecommitdiffstats
path: root/gui
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2024-02-27 18:53:17 -0500
committerSam Anthony <sam@samanthony.xyz>2024-02-27 18:53:17 -0500
commit257f254bd9d15c74ac50934ca1a8ddeb73e1b617 (patch)
treec168af95b9ca7fe2781b8181d3c6d7366f54c992 /gui
parent530c7461647152753bbf34bca4e79678cfa6ccb2 (diff)
downloadvolute-257f254bd9d15c74ac50934ca1a8ddeb73e1b617.zip
allow widgets to lock focus on themselves
Diffstat (limited to 'gui')
-rw-r--r--gui/widget/focus.go84
-rw-r--r--gui/widget/widget.go24
2 files changed, 68 insertions, 40 deletions
diff --git a/gui/widget/focus.go b/gui/widget/focus.go
index e2d1074..f1bc06e 100644
--- a/gui/widget/focus.go
+++ b/gui/widget/focus.go
@@ -1,70 +1,98 @@
package widget
-import "image"
+import (
+ "image"
+ "sync"
+)
-// Focus keeps track of the currently selected widget.
-// A widget receives true when it gains focus and false when it loses focus.
-type Focus struct {
- Widgets [][]chan bool
- p image.Point // coordinates of currently focused widget
+type FocusMaster struct {
+ slaves [][]chan bool
+ mu sync.Mutex
+ p image.Point // coordinates of currently focused slave
}
-func NewFocus(rows []int) Focus {
- f := Focus{
+type FocusSlave struct {
+ Focus <-chan bool
+ Mu *sync.Mutex
+}
+
+func NewFocusMaster(rows []int) FocusMaster {
+ f := FocusMaster{
make([][]chan bool, len(rows)),
+ sync.Mutex{},
image.Point{},
}
- for i := range f.Widgets {
- f.Widgets[i] = make([]chan bool, rows[i])
- for j := range f.Widgets[i] {
- f.Widgets[i][j] = make(chan bool)
+ for i := range f.slaves {
+ f.slaves[i] = make([]chan bool, rows[i])
+ for j := range f.slaves[i] {
+ f.slaves[i][j] = make(chan bool)
}
}
return f
}
-func (f *Focus) Close() {
- for i := range f.Widgets {
- for j := range f.Widgets[i] {
- close(f.Widgets[i][j])
+func (f *FocusMaster) Slave(y, x int) FocusSlave {
+ return FocusSlave{f.slaves[y][x], &f.mu}
+}
+
+func (f *FocusMaster) Close() {
+ for i := range f.slaves {
+ for j := range f.slaves[i] {
+ close(f.slaves[i][j])
}
}
}
-func (f *Focus) Focus(focus bool) {
- f.Widgets[f.p.Y][f.p.X] <- focus
+func (f *FocusMaster) Focus(focus bool) {
+ f.slaves[f.p.Y][f.p.X] <- focus
}
-func (f *Focus) Left() {
+func (f *FocusMaster) TryLeft() {
+ if !f.mu.TryLock() {
+ return
+ }
+ defer f.mu.Unlock()
f.Focus(false)
if f.p.X <= 0 {
- f.p.X = len(f.Widgets[f.p.Y]) - 1
+ f.p.X = len(f.slaves[f.p.Y]) - 1
} else {
f.p.X--
}
f.Focus(true)
}
-func (f *Focus) Right() {
+func (f *FocusMaster) TryRight() {
+ if !f.mu.TryLock() {
+ return
+ }
+ defer f.mu.Unlock()
f.Focus(false)
- f.p.X = (f.p.X + 1) % len(f.Widgets[f.p.Y])
+ f.p.X = (f.p.X + 1) % len(f.slaves[f.p.Y])
f.Focus(true)
}
-func (f *Focus) Up() {
+func (f *FocusMaster) TryUp() {
+ if !f.mu.TryLock() {
+ return
+ }
+ defer f.mu.Unlock()
f.Focus(false)
if f.p.Y <= 0 {
- f.p.Y = len(f.Widgets) - 1
+ f.p.Y = len(f.slaves) - 1
} else {
f.p.Y--
}
- f.p.X = min(f.p.X, len(f.Widgets[f.p.Y])-1)
+ f.p.X = min(f.p.X, len(f.slaves[f.p.Y])-1)
f.Focus(true)
}
-func (f *Focus) Down() {
+func (f *FocusMaster) TryDown() {
+ if !f.mu.TryLock() {
+ return
+ }
+ defer f.mu.Unlock()
f.Focus(false)
- f.p.Y = (f.p.Y + 1) % len(f.Widgets)
- f.p.X = min(f.p.X, len(f.Widgets[f.p.Y])-1)
+ f.p.Y = (f.p.Y + 1) % len(f.slaves)
+ f.p.X = min(f.p.X, len(f.slaves[f.p.Y])-1)
f.Focus(true)
}
diff --git a/gui/widget/widget.go b/gui/widget/widget.go
index ae09160..8c80551 100644
--- a/gui/widget/widget.go
+++ b/gui/widget/widget.go
@@ -41,14 +41,14 @@ func Label(text string, r image.Rectangle, env gui.Env, wg *sync.WaitGroup) {
}
}
-func Input(val chan<- uint, r image.Rectangle, focusChan <-chan bool, env gui.Env, wg *sync.WaitGroup) {
+func Input(val chan<- uint, r image.Rectangle, focus FocusSlave, env gui.Env, wg *sync.WaitGroup) {
defer wg.Done()
defer close(env.Draw())
defer close(val)
- redraw := func(text []byte, focus bool) func(draw.Image) image.Rectangle {
+ redraw := func(text []byte, haveFocus bool) func(draw.Image) image.Rectangle {
return func(drw draw.Image) image.Rectangle {
- if focus {
+ if haveFocus {
drawText(text, drw, r, GREEN, FOCUS_COLOR)
} else {
drawText(text, drw, r, GREEN, WHITE)
@@ -57,14 +57,14 @@ func Input(val chan<- uint, r image.Rectangle, focusChan <-chan bool, env gui.En
}
}
text := []byte{'0'}
- focus := false
+ haveFocus := false
- env.Draw() <- redraw(text, focus)
+ env.Draw() <- redraw(text, haveFocus)
Loop:
for {
select {
- case focus = <-focusChan:
- env.Draw() <- redraw(text, focus)
+ case haveFocus = <-focus.Focus:
+ env.Draw() <- redraw(text, haveFocus)
case event, ok := <-env.Events():
if !ok { // channel closed
break Loop
@@ -72,18 +72,18 @@ Loop:
switch event := event.(type) {
case win.WiFocus:
if event.Focused {
- env.Draw() <- redraw(text, focus)
+ env.Draw() <- redraw(text, haveFocus)
}
case win.KbType:
- if focus && isDigit(event.Rune) {
+ if haveFocus && isDigit(event.Rune) {
text = fmt.Appendf(text, "%c", event.Rune)
- env.Draw() <- redraw(text, focus)
+ env.Draw() <- redraw(text, haveFocus)
val <- atoi(text)
}
case win.KbDown:
- if focus && event.Key == win.KeyBackspace && len(text) > 0 {
+ if haveFocus && event.Key == win.KeyBackspace && len(text) > 0 {
text = text[:len(text)-1]
- env.Draw() <- redraw(text, focus)
+ env.Draw() <- redraw(text, haveFocus)
val <- atoi(text)
}
}