aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2024-05-09 17:32:54 -0400
committerSam Anthony <sam@samanthony.xyz>2024-05-09 17:32:54 -0400
commitd463bb90ad629dfc8f1cd4f4b6b9590b0008832d (patch)
treebf8763649c6a2f1af1fe46821216e327c094dcfa
parent76980fe3014b5c133c4e30590e92bd922aa9b9c1 (diff)
downloadvolute-d463bb90ad629dfc8f1cd4f4b6b9590b0008832d.zip
tree widget
-rw-r--r--gui/layout/split.go16
-rw-r--r--gui/text/concurrent_face.go (renamed from gui/widget/concurrent_face.go)2
-rw-r--r--gui/text/text.go (renamed from gui/widget/text.go)6
-rw-r--r--gui/widget/widget.go73
-rw-r--r--main.go84
-rw-r--r--ui.go17
6 files changed, 171 insertions, 27 deletions
diff --git a/gui/layout/split.go b/gui/layout/split.go
index db04225..455d74b 100644
--- a/gui/layout/split.go
+++ b/gui/layout/split.go
@@ -1,6 +1,10 @@
package layout
-import "fmt"
+import (
+ "fmt"
+
+ "volute/gui/text"
+)
// SplitFunc represents a way to split a space among a number of elements.
// The length of the returned slice must be equal to the number of elements.
@@ -24,3 +28,13 @@ func EvenSplit(elements int, width int) []int {
}
return ret
}
+
+func TextRowSplit(elements int, space int) []int {
+ bounds := make([]int, elements)
+ height := text.Size("1").Y
+ for i := 0; i < elements && space > 0; i++ {
+ bounds[i] = min(height, space)
+ space -= bounds[i]
+ }
+ return bounds
+}
diff --git a/gui/widget/concurrent_face.go b/gui/text/concurrent_face.go
index 98db572..c865251 100644
--- a/gui/widget/concurrent_face.go
+++ b/gui/text/concurrent_face.go
@@ -1,4 +1,4 @@
-package widget
+package text
import (
"image"
diff --git a/gui/widget/text.go b/gui/text/text.go
index 1b40096..dfe60e1 100644
--- a/gui/widget/text.go
+++ b/gui/text/text.go
@@ -1,4 +1,4 @@
-package widget
+package text
import (
"log"
@@ -38,12 +38,12 @@ func init() {
face = &concurrentFace{sync.Mutex{}, fce}
}
-func TextSize(text string) image.Point {
+func Size(text string) image.Point {
bounds := textBounds([]byte(text), font.Drawer{Face: face})
return image.Point{bounds.Max.X - bounds.Min.X + 2*PAD, bounds.Max.Y - bounds.Min.Y + 2*PAD}
}
-func drawText(text []byte, dst draw.Image, r image.Rectangle, fg, bg color.Color) {
+func Draw(text []byte, dst draw.Image, r image.Rectangle, fg, bg color.Color) {
drawer := font.Drawer{
Src: &image.Uniform{fg},
Face: face,
diff --git a/gui/widget/widget.go b/gui/widget/widget.go
index 2e7c671..3fd9637 100644
--- a/gui/widget/widget.go
+++ b/gui/widget/widget.go
@@ -11,6 +11,8 @@ import (
"image/draw"
"volute/gui"
+ "volute/gui/layout"
+ "volute/gui/text"
"volute/gui/win"
)
@@ -23,12 +25,71 @@ var (
interpolator = xdraw.ApproxBiLinear
)
-func Label(text string, r image.Rectangle, env gui.Env, wg *sync.WaitGroup) {
+type Node[T any] struct {
+ Label string
+ Value T
+ Children []Node[T]
+
+ expanded bool
+}
+
+func Tree[T any](trees []Node[T], r image.Rectangle, focus FocusSlave, mux *gui.Mux, wg *sync.WaitGroup) {
+ defer wg.Done()
+
+ var nodes []string
+ for _, root := range trees {
+ nodes = append(nodes, flatten(root, 0)...)
+ }
+
+ bounds := layout.Grid{
+ Rows: populate(make([]int, len(nodes)), 1),
+ Background: color.Gray{255},
+ Gap: 1,
+ Split: layout.EvenSplit,
+ SplitRows: layout.TextRowSplit,
+ Margin: 0,
+ Border: 0,
+ BorderColor: color.Gray{16},
+ Flip: false,
+ }.Lay(r)
+ for i := range nodes {
+ wg.Add(1)
+ go Label(nodes[i], bounds[i], mux.MakeEnv(), wg)
+ }
+
+ /*
+ globalFocus := focus;
+ localFocus := NewFocusMaster([]int{1, 1, 1});
+ defer localFocus.Close()
+ */
+ // TODO
+}
+
+func flatten[T any](root Node[T], depth int) []string {
+ indent := string(populate(make([]byte, 2*depth), ' '))
+ nodes := []string{indent + root.Label}
+ root.expanded = true // TODO: remove me
+ if root.expanded {
+ for _, c := range root.Children {
+ nodes = append(nodes, flatten(c, depth+1)...)
+ }
+ }
+ return nodes
+}
+
+func populate[T any](arr []T, v T) []T {
+ for i := range arr {
+ arr[i] = v
+ }
+ return arr
+}
+
+func Label(str string, r image.Rectangle, env gui.Env, wg *sync.WaitGroup) {
defer wg.Done()
defer close(env.Draw())
redraw := func(drw draw.Image) image.Rectangle {
- drawText([]byte(text), drw, r, BLACK, WHITE)
+ text.Draw([]byte(str), drw, r, BLACK, WHITE)
return r
}
@@ -93,12 +154,12 @@ Loop:
}
}
-func inputDraw(text []byte, focused bool, r image.Rectangle) func(draw.Image) image.Rectangle {
+func inputDraw(str []byte, focused bool, r image.Rectangle) func(draw.Image) image.Rectangle {
return func(drw draw.Image) image.Rectangle {
if focused {
- drawText(text, drw, r, GREEN, FOCUS_COLOR)
+ text.Draw(str, drw, r, GREEN, FOCUS_COLOR)
} else {
- drawText(text, drw, r, GREEN, WHITE)
+ text.Draw(str, drw, r, GREEN, WHITE)
}
return r
}
@@ -128,7 +189,7 @@ Loop:
func outputDraw(v float64, r image.Rectangle) func(draw.Image) image.Rectangle {
return func(drw draw.Image) image.Rectangle {
- drawText([]byte(fmt.Sprintf("%.3f", v)), drw, r, BLACK, WHITE)
+ text.Draw([]byte(fmt.Sprintf("%.3f", v)), drw, r, BLACK, WHITE)
return r
}
}
diff --git a/main.go b/main.go
index 7654c48..aab5eb5 100644
--- a/main.go
+++ b/main.go
@@ -2,12 +2,16 @@ package main
import (
"fmt"
- "image"
"os"
"sync"
+ "image"
+ _ "image/jpeg"
+ _ "image/png"
+
"github.com/faiface/mainthread"
"volute/gui"
+ "volute/gui/text"
"volute/gui/widget"
"volute/gui/win"
)
@@ -28,7 +32,7 @@ func run() {
wg := new(sync.WaitGroup)
defer wg.Wait()
- focus := widget.NewFocusMaster([]int{1, POINTS, POINTS, POINTS, POINTS})
+ focus := widget.NewFocusMaster([]int{1, POINTS, POINTS, POINTS, POINTS, 1})
defer focus.Close()
displacementChan := make(chan uint)
@@ -63,15 +67,89 @@ func run() {
wg,
)
+ compressors := []widget.Node[string]{
+ {
+ Label: "BorgWarner",
+ Value: "bw",
+ Children: []widget.Node[string]{
+ {
+ Label: "EFR",
+ Value: "efr",
+ Children: []widget.Node[string]{
+ {
+ Label: "6258",
+ Value: "6258",
+ Children: nil,
+ }, {
+ Label: "7064",
+ Value: "7064",
+ Children: nil,
+ },
+ },
+ }, {
+ Label: "K",
+ Value: "k",
+ Children: []widget.Node[string]{
+ {
+ Label: "03",
+ Value: "03",
+ Children: nil,
+ }, {
+ Label: "04",
+ Value: "04",
+ Children: nil,
+ },
+ },
+ },
+ },
+ }, {
+ Label: "Garrett",
+ Value: "garrett",
+ Children: []widget.Node[string]{
+ {
+ Label: "G",
+ Value: "g",
+ Children: []widget.Node[string]{
+ {
+ Label: "25-550",
+ Value: "25-550",
+ Children: nil,
+ },
+ },
+ },
+ },
+ },
+ }
+ wg.Add(1)
+ go widget.Tree(
+ compressors,
+ image.Rect(text.PAD, 125, 250, HEIGHT-text.PAD),
+ focus.Slave(5, 0),
+ mux,
+ wg,
+ )
+
imChan := make(chan image.Image)
defer close(imChan)
wg.Add(1)
go widget.Image(
imChan,
- image.Rect(0, 200, 100, 300),
+ image.Rect(250+text.PAD, 125, WIDTH-text.PAD, HEIGHT-text.PAD),
mux.MakeEnv(),
wg,
)
+ f, err := os.Open("compressor_maps/borgwarner/efr/8374.jpg")
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ return
+ }
+ im, _, err := image.Decode(f)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ return
+ }
+ f.Close()
+ imChan <- im
for i := 0; i < POINTS; i++ {
wg.Add(1)
diff --git a/ui.go b/ui.go
index 9355989..64e7ce5 100644
--- a/ui.go
+++ b/ui.go
@@ -7,6 +7,7 @@ import (
"volute/gui"
"volute/gui/layout"
+ "volute/gui/text"
"volute/gui/widget"
)
@@ -23,7 +24,7 @@ func spawnWidgets(
Background: color.Gray{255},
Gap: 1,
Split: split,
- SplitRows: splitRows,
+ SplitRows: layout.TextRowSplit,
Margin: 0,
Border: 0,
BorderColor: color.Gray{16},
@@ -96,8 +97,8 @@ func spawnWidgets(
func split(elements int, space int) []int {
bounds := make([]int, elements)
widths := []int{
- widget.TextSize(WIDEST_LABEL).X,
- widget.TextSize("123456").X,
+ text.Size(WIDEST_LABEL).X,
+ text.Size("123456").X,
}
for i := 0; i < elements && space > 0; i++ {
bounds[i] = min(widths[min(i, len(widths)-1)], space)
@@ -105,13 +106,3 @@ func split(elements int, space int) []int {
}
return bounds
}
-
-func splitRows(elements int, space int) []int {
- bounds := make([]int, elements)
- height := widget.TextSize("1").Y
- for i := 0; i < elements && space > 0; i++ {
- bounds[i] = min(height, space)
- space -= bounds[i]
- }
- return bounds
-}