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