1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
// Local clocks; click the button or press Space to switch. Q/Escape exits.
// Any argument runs ten frames, exercising both faces for smoke tests.
u32 GREEN=0x62ff70, DIM=0x123d20, BACKGROUND=0x020b05;
val main = { u8[~][] args ->
val screen=new sys.draw.Canvas(720,540);
if( sys.gfx.open("Simple digital and analog clocks",screen.width,screen.height)!=sys.gfx.OK ) return 1;
val button=new sys.draw.Button(220,454,280,52,"ANALOG CLOCK");
val timers=new sys.time.Timers();
i64 frame=timers.every(33);
if( frame<0 ) { sys.gfx.close(); return 1; }
bool analog=false, held=false;
int frames=0, status=sys.gfx.OK;
while( status==sys.gfx.OK ) {
bool space=sys.gfx.key(' ');
bool down=sys.gfx.button(sys.gfx.LEFT);
bool click=button.update(sys.gfx.mouseX(),sys.gfx.mouseY(),down);
if( click || (space && !held) ) analog=!analog;
held=space;
button.label=analog ? "DIGITAL CLOCK" : "ANALOG CLOCK";
if( sys.gfx.key('Q') ) break;
if( timers.poll(sys.time.monotonic())==frame ) {
_draw(screen,sys.time.now(),analog);
button.draw(screen,3,GREEN,BACKGROUND,DIM);
status=sys.gfx.present(screen.pixels);
if( args#>1 ) {
frames++;
if( frames==5 ) analog=true;
if( frames==10 ) break;
}
}
if( status==sys.gfx.OK ) status=sys.gfx.wait(sys.time.remaining(timers.nextDeadline(),sys.time.monotonic()));
}
sys.gfx.close();
return status==sys.gfx.ERROR ? 1 : 0;
};
val _draw = { !sys.draw.Canvas screen, i64 wall, i64 analog ->
val d=sys.time.local(wall);
screen.clear(BACKGROUND);
screen.text(266,24,"SIMPLE CLOCK",4,GREEN);
if( analog ) _analog_noInline(screen,d.hour,d.minute,d.second,d.millisecond);
else _digital_noInline(screen,d.hour,d.minute,d.second);
screen.text(298,412,"%(sys.time.formatLocal(wall,sys.time.DATE))",4,GREEN);
screen.text(249,520,"SPACE SWITCH Q OR ESC QUIT",2,GREEN);
};
// a..g bits: top, upper-right, lower-right, bottom, lower-left, upper-left,
// middle. Faint unlit bars retain the old LED figure-eight silhouette.
val _digit_noInline = { !sys.draw.Canvas c, int x, int y, i64 digit ->
int bits=digit==0 ? 0x3f : digit==1 ? 0x06 : digit==2 ? 0x5b :
digit==3 ? 0x4f : digit==4 ? 0x66 : digit==5 ? 0x6d :
digit==6 ? 0x7d : digit==7 ? 0x07 : digit==8 ? 0x7f : digit==9 ? 0x6f : 0;
for( int i=0; i<7; i++ ) {
u32 color=(bits&(1<<i))!=0 ? GREEN : DIM;
if( i==0 || i==3 || i==6 ) {
int dy=i==0 ? 0 : i==3 ? 144 : 72;
c.line(x+14,y+dy,x+58,y+dy,10,color);
} else {
bool right=i==1 || i==2;
int dx=right ? 68 : 4, dy=i==1 || i==5 ? 12 : 84;
c.line(x+dx,y+dy,x+dx,y+dy+48,10,color);
}
}
};
val _digital_noInline = { !sys.draw.Canvas c, int hour, int minute, int second ->
_digit_noInline(c,68,166,hour/10); _digit_noInline(c,154,166,hour-hour/10*10);
_digit_noInline(c,284,166,minute/10); _digit_noInline(c,370,166,minute-minute/10*10);
_digit_noInline(c,500,166,second/10); _digit_noInline(c,586,166,second-second/10*10);
for( int i=0; i<2; i++ ) {
c.fillCircle(254+i*216,214,6,GREEN);
c.fillCircle(254+i*216,262,6,GREEN);
}
c.text(272,352,"LOCAL TIME 24H",3,GREEN);
};
// Rational sine approximation, accurate enough for pixel clock geometry.
// Arguments are nonnegative turns; no additional native math dependency.
val _sin_noInline = { f64 turn ->
i64 whole=turn; turn-=whole;
bool negative=turn>0.5;
f64 x=(negative ? turn-0.5 : turn)*6.283185307179586;
f64 product=x*(3.141592653589793-x);
f64 numerator=negative ? -16.0 : 16.0;
return numerator*product/(49.34802200544679-4*product);
};
val _hand_noInline = { !sys.draw.Canvas c, f64 turn, int length, int thickness, u32 color ->
int x=360+_sin_noInline(turn)*length, y=232-_sin_noInline(turn+0.25)*length;
c.line(360,232,x,y,thickness,color);
};
val _analog_noInline = { !sys.draw.Canvas c, int hour, int minute, int second, int millisecond ->
c.circle(360,232,154,3,GREEN);
for( int i=0; i<60; i++ ) {
f64 turn=i/60.0;
bool major=i-i/5*5==0;
int inner=major ? 133 : 143;
int x0=360+_sin_noInline(turn)*inner, y0=232-_sin_noInline(turn+0.25)*inner;
int x1=360+_sin_noInline(turn)*149, y1=232-_sin_noInline(turn+0.25)*149;
c.line(x0,y0,x1,y1,major ? 3 : 1,GREEN);
}
c.text(349,100,"12",2,GREEN); c.text(484,227,"3",2,GREEN);
c.text(357,354,"6",2,GREEN); c.text(230,227,"9",2,GREEN);
f64 seconds=second+millisecond/1000.0;
f64 minutes=minute+seconds/60.0;
_hand_noInline(c,(hour-hour/12*12+minutes/60.0)/12.0,78,8,GREEN);
_hand_noInline(c,minutes/60.0,112,5,GREEN);
_hand_noInline(c,seconds/60.0,128,2,0xc3ffcb);
c.fillCircle(360,232,6,GREEN);
};
|