From b5469e103d6f1ebf5ef4cd654cb94d074094e740 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Thu, 12 Jan 2023 19:52:21 -0500 Subject: [PATCH] Analog clock widget!! --- elements/fun/clock.go | 88 +++++++++++++++++++++++++++++++++++++ examples/goroutines/main.go | 10 ++++- 2 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 elements/fun/clock.go diff --git a/elements/fun/clock.go b/elements/fun/clock.go new file mode 100644 index 0000000..42d685b --- /dev/null +++ b/elements/fun/clock.go @@ -0,0 +1,88 @@ +package fun + +import "time" +import "math" +import "image" +import "git.tebibyte.media/sashakoshka/tomo" +import "git.tebibyte.media/sashakoshka/tomo/theme" +import "git.tebibyte.media/sashakoshka/tomo/artist" +import "git.tebibyte.media/sashakoshka/tomo/elements/core" + +type AnalogClock struct { + *core.Core + core core.CoreControl + time time.Time +} + +func NewAnalogClock (newTime time.Time) (element *AnalogClock) { + element = &AnalogClock { } + element.Core, element.core = core.NewCore(element) + element.core.SetMinimumSize(64, 64) + return +} + +func (element *AnalogClock) Handle (event tomo.Event) { + switch event.(type) { + case tomo.EventResize: + resizeEvent := event.(tomo.EventResize) + element.core.AllocateCanvas ( + resizeEvent.Width, + resizeEvent.Height) + element.draw() + } +} + +func (element *AnalogClock) SetTime (newTime time.Time) { + if newTime == element.time { return } + element.time = newTime + if element.core.HasImage() { + element.draw() + element.core.PushAll() + } +} + +func (element *AnalogClock) draw () { + bounds := element.core.Bounds() + + artist.ChiseledRectangle ( + element.core, + theme.BackgroundProfile(true), + bounds) + + for hour := 0; hour < 12; hour ++ { + element.radialLine ( + theme.ForegroundImage(), + 0.8, 0.9, float64(hour) / 6 * math.Pi) + } + + element.radialLine ( + theme.ForegroundImage(), + 0, 0.5, float64(element.time.Hour() - 3) / 6 * math.Pi) + element.radialLine ( + theme.ForegroundImage(), + 0, 0.7, float64(element.time.Minute() - 15) / 30 * math.Pi) + element.radialLine ( + theme.AccentImage(), + 0, 0.7, float64(element.time.Second() - 15) / 30 * math.Pi) + // TODO: engraved background, draw lines with std foreground, draw the + // second hand with the accent color. +} + +func (element *AnalogClock) radialLine ( + source tomo.Image, + inner float64, + outer float64, + radian float64, +) { + bounds := element.core.Bounds() + width := float64(bounds.Dx()) / 2 + height := float64(bounds.Dy()) / 2 + min := image.Pt ( + int(math.Cos(radian) * inner * width + width), + int(math.Sin(radian) * inner * height + height)) + max := image.Pt ( + int(math.Cos(radian) * outer * width + width), + int(math.Sin(radian) * outer * height + height)) + // println(min.String(), max.String()) + artist.Line(element.core, source, 1, min, max) +} diff --git a/examples/goroutines/main.go b/examples/goroutines/main.go index 1354e48..e41504c 100644 --- a/examples/goroutines/main.go +++ b/examples/goroutines/main.go @@ -3,6 +3,7 @@ package main import "os" import "time" import "git.tebibyte.media/sashakoshka/tomo" +import "git.tebibyte.media/sashakoshka/tomo/elements/fun" import "git.tebibyte.media/sashakoshka/tomo/elements/basic" import "git.tebibyte.media/sashakoshka/tomo/elements/layouts" import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" @@ -17,20 +18,25 @@ func run () { window.SetTitle("clock") container := basic.NewContainer(layouts.Vertical { true, true }) window.Adopt(container) + + clock := fun.NewAnalogClock(time.Now()) + container.Adopt(clock, true) label := basic.NewLabel(formatTime(), false) container.Adopt(label, false) + window.OnClose(tomo.Stop) window.Show() - go tick(label) + go tick(label, clock) } func formatTime () (timeString string) { return time.Now().Format("2006-01-02 15:04:05") } -func tick (label *basic.Label) { +func tick (label *basic.Label, clock *fun.AnalogClock) { for { label.SetText(formatTime()) + clock.SetTime(time.Now()) time.Sleep(time.Second) } }