diff --git a/backends/x/x.go b/backends/x/x.go index cdea721..bd6cb15 100644 --- a/backends/x/x.go +++ b/backends/x/x.go @@ -31,6 +31,7 @@ type Backend struct { func NewBackend () (output tomo.Backend, err error) { backend := &Backend { windows: map[xproto.Window] *Window { }, + doChannel: make(chan func (), 0), } // connect to X @@ -51,10 +52,12 @@ func (backend *Backend) Run () (err error) { pingQuit := xevent.MainPing(backend.connection) for { select { - case <- pingBefore: <- pingAfter + case <- pingBefore: + <- pingAfter case callback := <- backend.doChannel: callback() - case <- pingQuit: return + case <- pingQuit: + return } } } diff --git a/elements/basic/progressbar.go b/elements/basic/progressbar.go new file mode 100644 index 0000000..6ac9778 --- /dev/null +++ b/elements/basic/progressbar.go @@ -0,0 +1,56 @@ +package basic + +import "image" +import "git.tebibyte.media/sashakoshka/tomo/theme" +import "git.tebibyte.media/sashakoshka/tomo/artist" +import "git.tebibyte.media/sashakoshka/tomo/elements/core" + +// ProgressBar displays a visual indication of how far along a task is. +type ProgressBar struct { + *core.Core + core core.CoreControl + progress float64 +} + +// NewProgressBar creates a new progress bar displaying the given progress +// level. +func NewProgressBar (progress float64) (element *ProgressBar) { + element = &ProgressBar { progress: progress } + element.Core, element.core = core.NewCore(element) + element.core.SetMinimumSize(theme.Padding() * 2, theme.Padding() * 2) + return +} + +// Resize resizes the progress bar. +func (element *ProgressBar) Resize (width, height int) { + element.core.AllocateCanvas(width, height) + element.draw() + return +} + +// SetProgress sets the progress level of the bar. +func (element *ProgressBar) SetProgress (progress float64) { + if progress == element.progress { return } + element.progress = progress + if element.core.HasImage() { + element.draw() + element.core.PushAll() + } +} + +func (element *ProgressBar) draw () { + bounds := element.core.Bounds() + + artist.FillRectangle ( + element.core, + theme.SunkenPattern(), + bounds) + meterBounds := image.Rect ( + bounds.Min.X + 2, bounds.Min.Y + 2, + bounds.Min.X - 1 + int(float64(bounds.Dx()) * element.progress), + bounds.Dy() - 1) + artist.FillRectangle ( + element.core, + theme.AccentPattern(), + meterBounds) +} diff --git a/examples/goroutines/main.go b/examples/goroutines/main.go index 9fc02c6..f0253f7 100644 --- a/examples/goroutines/main.go +++ b/examples/goroutines/main.go @@ -35,8 +35,10 @@ func formatTime () (timeString string) { func tick (label *basic.Label, clock *fun.AnalogClock) { for { - label.SetText(formatTime()) - clock.SetTime(time.Now()) + tomo.Do (func () { + label.SetText(formatTime()) + clock.SetTime(time.Now()) + }) time.Sleep(time.Second) } } diff --git a/examples/progress/main.go b/examples/progress/main.go new file mode 100644 index 0000000..97c3ff2 --- /dev/null +++ b/examples/progress/main.go @@ -0,0 +1,40 @@ +package main + +import "time" +import "git.tebibyte.media/sashakoshka/tomo" +import "git.tebibyte.media/sashakoshka/tomo/layouts" +import "git.tebibyte.media/sashakoshka/tomo/elements/basic" +import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" + +func main () { + tomo.Run(run) +} + +func run () { + window, _ := tomo.NewWindow(2, 2) + window.SetTitle("Approaching") + container := basic.NewContainer(layouts.Vertical { true, true }) + window.Adopt(container) + + container.Adopt (basic.NewLabel ( + "Rapidly approaching your location...", false), false) + bar := basic.NewProgressBar(0) + container.Adopt(bar, false) + button := basic.NewButton("Stop") + button.SetEnabled(false) + container.Adopt(button, false) + + window.OnClose(tomo.Stop) + window.Show() + go fill(bar) +} + +func fill (bar *basic.ProgressBar) { + println("-") + for progress := 0.0; progress < 1.0; progress += 0.01 { + time.Sleep(time.Second / 24) + tomo.Do(func () { + bar.SetProgress(progress) + }) + } +}