1 /**
2  * clock.d
3  *
4  * A gtkD widget that implements a clock face
5  *
6  * Based on the Gtkmm example by:
7  * Jonathon Jongsma
8  *
9  * and the original GTK+ example by:
10  * (c) 2005-2006, Davyd Madeley
11  *
12  * Authors:
13  *   Jonas Kivi (D version)
14  *   Jonathon Jongsma (C++ version)
15  *   Davyd Madeley (C version)
16  */
17 
18 module clock;
19 
20 import std.stdio;
21 import std.math;
22 import std.datetime;
23 
24 import glib.Timeout;
25 
26 import cairo.Context;
27 import cairo.Surface;
28 
29 import gtk.Widget;
30 import gtk.DrawingArea;
31 
32 class Clock : DrawingArea
33 {
34 public:
35 	this()
36 	{
37 		//Attach our expose callback, which will draw the window.
38 		addOnDraw(&drawCallback);
39 	}
40 
41 protected:
42 	//Override default signal handler:
43 	bool drawCallback(Scoped!Context cr, Widget widget)
44 	{
45 		if ( m_timeout is null )
46 		{
47 			//Create a new timeout that will ask the window to be drawn once every second.
48 			m_timeout = new Timeout( 1000, &onSecondElapsed, false );
49 		}
50 
51 		// This is where we draw on the window
52 
53 		GtkAllocation size;
54 
55 		getAllocation(size);
56 
57 		// scale to unit square and translate (0, 0) to be (0.5, 0.5), i.e. the
58 		// center of the window
59 		cr.scale(size.width, size.height);
60 		cr.translate(0.5, 0.5);
61 		cr.setLineWidth(m_lineWidth);
62 
63 		cr.save();
64 			cr.setSourceRgba(0.3, 0.6, 0.2, 0.9);   // brownish green
65 			cr.paint();
66 		cr.restore();
67 
68 		cr.arc(0, 0, m_radius, 0, 2 * PI);
69 
70 		cr.save();
71 			cr.setSourceRgba(0.0, 0.0, 0.0, 0.8);
72 			cr.fillPreserve();
73 		cr.restore();
74 
75 		cr.save();
76 			cr.setSourceRgba(1.0, 1.0, 1.0, 1.0);
77 			cr.setLineWidth( m_lineWidth * 1.7);
78 			cr.strokePreserve();
79 			cr.clip();
80 		cr.restore();
81 
82 
83 		//clock ticks
84 
85 		for (int i = 0; i < 12; i++)
86 		{
87 			double inset = 0.07;
88 
89 			cr.save();
90 				cr.setSourceRgba(1.0, 1.0, 1.0, 1.0);
91 				cr.setLineWidth( m_lineWidth * 0.25);
92 				cr.setLineCap(cairo_line_cap_t.ROUND);
93 
94 				if (i % 3 != 0)
95 				{
96 					inset *= 1.2;
97 					cr.setLineWidth( m_lineWidth * 0.5 );
98 				}
99 
100 				cr.moveTo(
101 					(m_radius - inset) * cos (i * PI / 6),
102 					(m_radius - inset) * sin (i * PI / 6));
103 				cr.lineTo (
104 					m_radius * cos (i * PI / 6),
105 					m_radius * sin (i * PI / 6));
106 				cr.stroke();
107 			cr.restore(); // stack-pen-size
108 		}
109 
110 		SysTime lNow = std.datetime.Clock.currTime();
111 
112 		// compute the angles of the indicators of our clock
113 		double minutes = lNow.minute * PI / 30; 
114 		double hours = lNow.hour * PI / 6; 
115 		double seconds= lNow.second * PI / 30; 
116 		
117 		cr.save();
118 			cr.setLineCap(cairo_line_cap_t.ROUND);
119 
120 			// draw the seconds hand
121 			cr.save();
122 				cr.setLineWidth(m_lineWidth / 3);
123 				cr.setSourceRgba(0.7, 0.7, 0.85, 0.8); // blueish gray
124 				cr.moveTo(0, 0);
125 				cr.lineTo(sin(seconds) * (m_radius * 0.8),
126 					-cos(seconds) * (m_radius * 0.8));
127 				cr.stroke();
128 			cr.restore();
129 
130 			// draw the minutes hand
131 			//cr.setSourceRgba(0.117, 0.337, 0.612, 0.9);   // blue
132 			cr.setSourceRgba(0.712, 0.337, 0.117, 0.9);   // red
133 			cr.moveTo(0, 0);
134 			cr.lineTo(sin(minutes + seconds / 60) * (m_radius * 0.7),
135 				-cos(minutes + seconds / 60) * (m_radius * 0.7));
136 			cr.stroke();
137 
138 			// draw the hours hand
139 			cr.setSourceRgba(0.337, 0.612, 0.117, 0.9);   // green
140 			cr.moveTo(0, 0);
141 			cr.lineTo(sin(hours + minutes / 12.0) * (m_radius * 0.4),
142 				-cos(hours + minutes / 12.0) * (m_radius * 0.4));
143 			cr.stroke();
144 		cr.restore();
145 
146 		// draw a little dot in the middle
147 		cr.arc(0, 0, m_lineWidth / 3.0, 0, 2 * PI);
148 		cr.fill();
149 
150 		return true;
151 	}
152 
153 	bool onSecondElapsed()
154 	{
155 		//force our program to redraw the entire clock once per every second.
156 		GtkAllocation area;
157 		getAllocation(area);
158 
159 		queueDrawArea(area.x, area.y, area.width, area.height);
160 		
161 		return true;
162 	}
163 
164 	double m_radius = 0.40;
165 	double m_lineWidth = 0.065;
166 
167 	Timeout m_timeout;
168 }
169