package fun import "time" import "math" import "image" import "git.tebibyte.media/sashakoshka/tomo/theme" import "git.tebibyte.media/sashakoshka/tomo/config" import "git.tebibyte.media/sashakoshka/tomo/artist" import "git.tebibyte.media/sashakoshka/tomo/elements/core" // AnalogClock can display the time of day in an analog format. type AnalogClock struct { *core.Core core core.CoreControl time time.Time config config.Wrapped theme theme.Wrapped } // NewAnalogClock creates a new analog clock that displays the specified time. func NewAnalogClock (newTime time.Time) (element *AnalogClock) { element = &AnalogClock { } element.theme.Case = theme.C("fun", "clock") element.Core, element.core = core.NewCore(element.draw) element.core.SetMinimumSize(64, 64) return } // SetTime changes the time that the clock displays. func (element *AnalogClock) SetTime (newTime time.Time) { if newTime == element.time { return } element.time = newTime element.redo() } // SetTheme sets the element's theme. func (element *AnalogClock) SetTheme (new theme.Theme) { if new == element.theme.Theme { return } element.theme.Theme = new element.redo() } // SetConfig sets the element's configuration. func (element *AnalogClock) SetConfig (new config.Config) { if new == element.config.Config { return } element.config.Config = new element.redo() } func (element *AnalogClock) redo () { if element.core.HasImage() { element.draw() element.core.DamageAll() } } func (element *AnalogClock) draw () { bounds := element.Bounds() state := theme.PatternState { } pattern := element.theme.Pattern(theme.PatternSunken, state) inset := element.theme.Inset(theme.PatternSunken) artist.FillRectangle(element.core, pattern, bounds) bounds = inset.Apply(bounds) foreground := element.theme.Pattern(theme.PatternForeground, state) accent := element.theme.Pattern(theme.PatternAccent, state) for hour := 0; hour < 12; hour ++ { element.radialLine ( foreground, 0.8, 0.9, float64(hour) / 6 * math.Pi) } second := float64(element.time.Second()) minute := float64(element.time.Minute()) + second / 60 hour := float64(element.time.Hour()) + minute / 60 element.radialLine(foreground, 0, 0.5, (hour - 3) / 6 * math.Pi) element.radialLine(foreground, 0, 0.7, (minute - 15) / 30 * math.Pi) element.radialLine(accent, 0, 0.7, (second - 15) / 30 * math.Pi) } // FlexibleHeightFor constrains the clock's minimum size to a 1:1 aspect ratio. func (element *AnalogClock) FlexibleHeightFor (width int) (height int) { return width } // OnFlexibleHeightChange sets a function to be called when the parameters // affecting the clock's flexible height change. func (element *AnalogClock) OnFlexibleHeightChange (func ()) { } func (element *AnalogClock) radialLine ( source artist.Pattern, inner float64, outer float64, radian float64, ) { bounds := element.Bounds() width := float64(bounds.Dx()) / 2 height := float64(bounds.Dy()) / 2 min := element.Bounds().Min.Add(image.Pt ( int(math.Cos(radian) * inner * width + width), int(math.Sin(radian) * inner * height + height))) max := element.Bounds().Min.Add(image.Pt ( int(math.Cos(radian) * outer * width + width), int(math.Sin(radian) * outer * height + height))) artist.Line(element.core, source, 1, min, max) }