v / examples / clock
Raw file | 172 loc (151 sloc) | 4.39 KB | Latest commit hash 816e9319d
1// An X11 clock modeled after https://en.wikipedia.org/wiki/Station_clock
2// This is a small V example that was based off of the fireworks example.
3// Written by Stefan Schroeder in 2021 for the v project examples.
4// See LICENSE for license information.
5import os
6import gg
7import gx
8import math
9import time
10
11const (
12 // All coordinates are designed for a clock size of this many pixel.
13 // You cannot change the size of the clock by adjusting this value.
14 design_size = 700
15 center = 350
16
17 // Half the width of a tic-mark.
18 tw = 9
19 // Height of a minute tic-mark. (hour is twice, 3-hour is thrice)
20 th = 25
21 // Padding of tic-mark to window border
22 tp = 10
23
24 tic_color = gx.Color{
25 r: 50
26 g: 50
27 b: 50
28 }
29 hand_color = gx.black
30 second_hand_color = gx.red
31)
32
33struct App {
34 minutes_tic []f32 = [f32(center - tw), tp, center + tw, tp, center + tw, tp, center + tw,
35 tp + 1 * th, center - tw, tp + 1 * th]
36 hours_tic []f32 = [f32(center - tw), tp, center + tw, tp, center + tw, tp, center + tw, tp + 2 * th,
37 center - tw, tp + 2 * th]
38 hours3_tic []f32 = [f32(center - tw), tp, center + tw, tp, center + tw, tp, center + tw, tp + 3 * th,
39 center - tw, tp + 3 * th]
40
41 hour_hand []f32 = [f32(329), 161, 350, 140, 371, 161, 371, 413, 329, 413]
42 minute_hand []f32 = [f32(334.25), 40.25, 350, 24.5, 365.75, 40.25, 365.75, 427, 334.25, 427]
43 second_hand []f32 = [f32(345.8), 38.5, 350, 34.3, 354.2000, 38.5, 358.75, 427, 341.25, 427]
44mut:
45 gg &gg.Context = unsafe { nil }
46 draw_flag bool = true
47 dpi_scale f32 = 1.0
48}
49
50fn on_frame(mut app App) {
51 if !app.draw_flag {
52 return
53 }
54 app.gg.begin()
55
56 for i in 0 .. 60 { // draw minute tics
57 draw_convex_poly_rotate(mut app.gg, app.dpi_scale, app.minutes_tic, tic_color,
58 i * 6)
59 }
60 for i in 0 .. 12 { // hours
61 draw_convex_poly_rotate(mut app.gg, app.dpi_scale, app.hours_tic, tic_color, i * 30)
62 }
63 for i in 0 .. 4 { // 3 hours
64 draw_convex_poly_rotate(mut app.gg, app.dpi_scale, app.hours3_tic, tic_color,
65 i * 90)
66 }
67
68 n := time.now()
69
70 // draw hour hand
71 i := f32(n.hour) + f32(n.minute) / 60.0
72 draw_convex_poly_rotate(mut app.gg, app.dpi_scale, app.hour_hand, hand_color, i * 30)
73
74 // draw minute hand
75 mut j := f32(n.minute)
76 if n.second == 59 { // make minute hand move smoothly
77 j += f32(math.sin(f32(n.nanosecond) / 1e9 * math.pi / 2.0))
78 }
79 draw_convex_poly_rotate(mut app.gg, app.dpi_scale, app.minute_hand, hand_color, j * 6)
80
81 // draw second hand with smooth transition
82 k := f32(n.second) + f32(math.sin(f32(n.nanosecond) / 1e9 * math.pi / 2.0))
83 draw_convex_poly_rotate(mut app.gg, app.dpi_scale, app.second_hand, second_hand_color,
84 0 + k * 6)
85
86 app.gg.end()
87}
88
89// Rotate a polygon round the centerpoint
90[manualfree]
91fn draw_convex_poly_rotate(mut ctx gg.Context, dpi_scale f32, points []f32, c gx.Color, angle f32) {
92 sa := math.sin(math.pi * angle / 180.0)
93 ca := math.cos(math.pi * angle / 180.0)
94
95 mut rotated_points := []f32{cap: points.len}
96 for i := 0; i < points.len / 2; i++ {
97 x := points[2 * i]
98 y := points[2 * i + 1]
99 xn := f32((x - center) * ca - (y - center) * sa)
100 yn := f32((x - center) * sa + (y - center) * ca)
101 rotated_points << (xn + center) * dpi_scale
102 rotated_points << (yn + center) * dpi_scale
103 }
104 ctx.draw_convex_poly(rotated_points, c)
105 unsafe { rotated_points.free() }
106}
107
108fn (mut app App) resize() {
109 size := gg.window_size()
110 // avoid calls when minimized
111 if size.width < 2 && size.height < 2 {
112 return
113 }
114 w := f32(size.width) / design_size
115 h := f32(size.height) / design_size
116 app.dpi_scale = if w < h { w } else { h }
117}
118
119fn on_event(e &gg.Event, mut app App) {
120 match e.typ {
121 .resized, .resumed {
122 app.resize()
123 }
124 .iconified {
125 app.draw_flag = false
126 }
127 .restored {
128 app.draw_flag = true
129 app.resize()
130 }
131 else {
132 if e.typ == .key_down {
133 match e.key_code {
134 .q {
135 println('Good bye.')
136 // do we need to free anything here?
137 app.gg.quit()
138 }
139 else {}
140 }
141 }
142 }
143 }
144}
145
146fn on_init(mut app App) {
147 app.resize()
148}
149
150fn main() {
151 println("Press 'q' to quit.")
152 mut font_path := os.resource_abs_path(os.join_path('..', 'assets', 'fonts', 'RobotoMono-Regular.ttf'))
153 $if android {
154 font_path = 'fonts/RobotoMono-Regular.ttf'
155 }
156
157 mut app := &App{}
158
159 app.gg = gg.new_context(
160 width: design_size
161 height: design_size
162 window_title: 'Clock!'
163 bg_color: gx.white
164 user_data: app
165 frame_fn: on_frame
166 event_fn: on_event
167 init_fn: on_init
168 font_path: font_path
169 )
170
171 app.gg.run()
172}