summaryrefslogtreecommitdiff
path: root/internal/slider
diff options
context:
space:
mode:
authorBenjamin Chausse <benjamin@chausse.xyz>2024-11-23 18:12:03 -0500
committerBenjamin Chausse <benjamin@chausse.xyz>2024-11-23 18:12:03 -0500
commit89094fecf4cb1c018f15c976641cd18c255eac28 (patch)
tree9f6e32c38013bc526399ab324891e0b3269e50dc /internal/slider
Semi-working POC
Diffstat (limited to 'internal/slider')
-rw-r--r--internal/slider/evaluation.go46
-rw-r--r--internal/slider/keys.go52
-rw-r--r--internal/slider/slider.go71
3 files changed, 169 insertions, 0 deletions
diff --git a/internal/slider/evaluation.go b/internal/slider/evaluation.go
new file mode 100644
index 0000000..363efe7
--- /dev/null
+++ b/internal/slider/evaluation.go
@@ -0,0 +1,46 @@
+package slider
+
+func (m Model) Val() int { return m.current }
+
+func (m *Model) Set(v int) {
+ m.current = v
+ m.fixRange()
+}
+
+func (m *Model) Inc(v int) {
+ m.current += v
+ m.fixRange()
+}
+
+func (m *Model) Dec(v int) {
+ m.current -= v
+ m.fixRange()
+}
+
+func (m *Model) Pcnt() float64 {
+ return float64(m.current) / float64(m.max)
+}
+
+func (m *Model) SetPcnt(p float64) {
+ m.current = int(float64(m.max) * p)
+ m.fixRange()
+}
+
+func (m *Model) IncPcnt(p float64) {
+ m.current += int(float64(m.max) * p)
+ m.fixRange()
+}
+
+func (m *Model) DecPcnt(p float64) {
+ m.current -= int(float64(m.max) * p)
+ m.fixRange()
+}
+
+func (m *Model) fixRange() {
+ if m.current > m.max {
+ m.current = m.max
+ }
+ if m.current < 0 {
+ m.current = 0
+ }
+}
diff --git a/internal/slider/keys.go b/internal/slider/keys.go
new file mode 100644
index 0000000..9f96903
--- /dev/null
+++ b/internal/slider/keys.go
@@ -0,0 +1,52 @@
+package slider
+
+import "github.com/charmbracelet/bubbles/key"
+
+type keybinds struct {
+ incRegular key.Binding
+ decRegular key.Binding
+ incPrecise key.Binding
+ decPrecise key.Binding
+ // quitApp key.Binding
+}
+
+func newKeybinds() keybinds {
+ return keybinds{
+ incRegular: key.NewBinding(
+ key.WithKeys("right", "l"),
+ key.WithHelp("l", "Increase (coarse)"),
+ ),
+ decRegular: key.NewBinding(
+ key.WithKeys("left", "h"),
+ key.WithHelp("h", "Decrease (coarse)"),
+ ),
+ incPrecise: key.NewBinding(
+ key.WithKeys("shift+right", "L"),
+ key.WithHelp("L", "Increase (fine)"),
+ ),
+ decPrecise: key.NewBinding(
+ key.WithKeys("shift+left", "H"),
+ key.WithHelp("H", "Decrease (fine)"),
+ ),
+ }
+}
+
+// Join all keybindings into a single slice
+// a parent can use to know what Keys
+// it's children have.
+func Keys() []key.Binding {
+ k := newKeybinds()
+ return []key.Binding{
+ k.incRegular,
+ k.decRegular,
+ k.incPrecise,
+ k.decPrecise,
+ }
+}
+
+// AllKeys returns key.Bindings for the Model
+// and all of its active children. The parent
+// can use this to generate help text.
+func (m Model) AllKeys() []key.Binding {
+ return Keys()
+}
diff --git a/internal/slider/slider.go b/internal/slider/slider.go
new file mode 100644
index 0000000..d726e7b
--- /dev/null
+++ b/internal/slider/slider.go
@@ -0,0 +1,71 @@
+package slider
+
+import (
+ "fmt"
+
+ "github.com/charmbracelet/bubbles/key"
+ "github.com/charmbracelet/bubbles/progress"
+ tea "github.com/charmbracelet/bubbletea"
+)
+
+type Model struct {
+ label byte
+ progress progress.Model
+ max int
+ current int
+ mappings keybinds
+}
+
+func New(label byte, maxVal int, opts ...progress.Option) Model {
+ slider := Model{
+ label: label,
+ progress: progress.New(
+ progress.WithoutPercentage(),
+ ),
+ max: maxVal,
+ current: maxVal / 2,
+ mappings: newKeybinds(),
+ }
+ for _, opt := range opts {
+ opt(&slider.progress)
+ }
+ return slider
+}
+
+func (m Model) Title() string { return fmt.Sprintf("%c", m.label) }
+
+func (m Model) Init() tea.Cmd {
+ return nil
+}
+
+func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+ keys := newKeybinds()
+ switch msg := msg.(type) {
+ case tea.KeyMsg:
+ switch {
+ case key.Matches(msg, keys.incRegular):
+ m.IncPcnt(0.05)
+ case key.Matches(msg, keys.decRegular):
+ m.DecPcnt(0.05)
+ case key.Matches(msg, keys.incPrecise):
+ m.Inc(1)
+ case key.Matches(msg, keys.decPrecise):
+ m.Dec(1)
+ }
+ return m, m.progress.SetPercent(m.Pcnt())
+ case progress.FrameMsg:
+ progressModel, cmd := m.progress.Update(msg)
+ m.progress = progressModel.(progress.Model)
+ return m, cmd
+ default:
+ return m, nil
+ }
+}
+
+func (m Model) ViewValue(current int) string {
+ return fmt.Sprintf("(%3d/%d)", current, m.max)
+}
+
+func (m Model) View() string {
+ return fmt.Sprintf("%v: %v %v", m.Title(), m.progress.View(), m.ViewValue(m.current))
+}