127 lines
3.0 KiB
Go
127 lines
3.0 KiB
Go
// Example clock demonstrates the use of goroutines and tomo.Do() to provide
|
|
// live-updating information.
|
|
package main
|
|
|
|
import "time"
|
|
import "math"
|
|
import "image"
|
|
import "image/color"
|
|
import "git.tebibyte.media/tomo/tomo"
|
|
import "git.tebibyte.media/tomo/nasin"
|
|
import "git.tebibyte.media/tomo/objects"
|
|
import "git.tebibyte.media/tomo/tomo/canvas"
|
|
import "git.tebibyte.media/tomo/objects/layouts"
|
|
|
|
type Application struct {
|
|
clockFace *ClockFace
|
|
timeLabel *objects.Label
|
|
}
|
|
|
|
func (this *Application) Describe () nasin.ApplicationDescription {
|
|
return nasin.ApplicationDescription {
|
|
Name: "Clock",
|
|
ID: "xyz.holanet.TomoClockExample",
|
|
}
|
|
}
|
|
|
|
func (this *Application) Init () error {
|
|
window, err := nasin.NewApplicationWindow(this, image.Rect(0, 0, 128, 160))
|
|
if err != nil { return err }
|
|
|
|
this.clockFace = NewClockFace()
|
|
this.timeLabel = objects.NewLabel("")
|
|
this.timeLabel.SetAlign(tomo.AlignMiddle, tomo.AlignMiddle)
|
|
container := objects.NewOuterContainer (
|
|
layouts.NewGrid([]bool { true }, []bool { true, false }),
|
|
this.clockFace,
|
|
this.timeLabel)
|
|
window.SetRoot(container)
|
|
|
|
go func () {
|
|
for {
|
|
tomo.Do(this.updateTime)
|
|
time.Sleep(time.Second)
|
|
}
|
|
} ()
|
|
|
|
window.OnClose(tomo.Stop)
|
|
window.SetVisible(true)
|
|
return nil
|
|
}
|
|
|
|
func (this *Application) updateTime () {
|
|
now := time.Now()
|
|
this.clockFace.SetTime(now)
|
|
this.timeLabel.SetText(now.Format(time.DateTime))
|
|
}
|
|
|
|
func main () {
|
|
nasin.RunApplication(&Application { })
|
|
}
|
|
|
|
type ClockFace struct {
|
|
tomo.CanvasBox
|
|
time time.Time
|
|
}
|
|
|
|
func NewClockFace () *ClockFace {
|
|
box := &ClockFace {
|
|
CanvasBox: tomo.NewCanvasBox(),
|
|
}
|
|
box.SetRole(tomo.R("nasin", "ClockFace", ""))
|
|
tomo.Apply(box)
|
|
box.SetDrawer(box)
|
|
return box
|
|
}
|
|
|
|
// TODO move ClockFace to objects
|
|
|
|
func (this *ClockFace) SetTime (when time.Time) {
|
|
this.time = when
|
|
this.Invalidate()
|
|
}
|
|
|
|
func (this *ClockFace) Draw (destination canvas.Canvas) {
|
|
pen := destination.Pen()
|
|
pen.Fill(color.Transparent)
|
|
pen.Rectangle(destination.Bounds())
|
|
|
|
for hour := 0; hour < 12; hour ++ {
|
|
radialLine (
|
|
destination,
|
|
tomo.ColorForeground,
|
|
0.8, 0.9, float64(hour) / 6 * math.Pi)
|
|
}
|
|
|
|
second := float64(this.time.Second())
|
|
minute := float64(this.time.Minute()) + second / 60
|
|
hour := float64(this.time.Hour()) + minute / 60
|
|
|
|
radialLine(destination, tomo.ColorForeground, 0, 0.5, (hour - 3) / 6 * math.Pi)
|
|
radialLine(destination, tomo.ColorForeground, 0, 0.7, (minute - 15) / 30 * math.Pi)
|
|
radialLine(destination, tomo.ColorAccent, 0, 0.7, (second - 15) / 30 * math.Pi)
|
|
}
|
|
|
|
func radialLine (
|
|
destination canvas.Canvas,
|
|
source color.Color,
|
|
inner float64,
|
|
outer float64,
|
|
theta float64,
|
|
) {
|
|
pen := destination.Pen()
|
|
bounds := destination.Bounds()
|
|
width := float64(bounds.Dx()) / 2
|
|
height := float64(bounds.Dy()) / 2
|
|
min := bounds.Min.Add(image.Pt (
|
|
int(math.Cos(theta) * inner * width + width),
|
|
int(math.Sin(theta) * inner * height + height)))
|
|
max := bounds.Min.Add(image.Pt (
|
|
int(math.Cos(theta) * outer * width + width),
|
|
int(math.Sin(theta) * outer * height + height)))
|
|
|
|
pen.Stroke(source)
|
|
pen.StrokeWeight(1)
|
|
pen.Path(min, max)
|
|
}
|