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 version(Tango) import tango.io.Stdout;
21 else import std.stdio;
22 
23 version(Tango) import tango.math.Math;
24 else import std.math;
25 
26 version(Tango)
27 {
28 	import tango.time.Time;
29 	import tangoClock = tango.time.WallClock;
30 }
31 else version(D_Version2)
32 {
33 	import std.datetime;
34 }
35 else
36 {
37 	import std.date;
38 }
39 
40 import glib.Timeout;
41 
42 import cairo.Context;
43 import cairo.Surface;
44 
45 import gtk.Widget;
46 import gtk.DrawingArea;
47 
48 class Clock : DrawingArea
49 {
50 public:
51 	this()
52 	{
53 		//Attach our expose callback, which will draw the window.
54 		addOnDraw(&drawCallback);
55 	}
56 
57 protected:
58 	//Override default signal handler:
59 	bool drawCallback(Context cr, Widget widget)
60 	{
61 		if ( m_timeout is null )
62 		{
63 			//Create a new timeout that will ask the window to be drawn once every second.
64 			m_timeout = new Timeout( 1000, &onSecondElapsed, false );
65 		}
66 
67 		// This is where we draw on the window
68 
69 		GtkAllocation size;
70 
71 		getAllocation(size);
72 
73 		// scale to unit square and translate (0, 0) to be (0.5, 0.5), i.e. the
74 		// center of the window
75 		cr.scale(size.width, size.height);
76 		cr.translate(0.5, 0.5);
77 		cr.setLineWidth(m_lineWidth);
78 
79 		cr.save();
80 			cr.setSourceRgba(0.3, 0.6, 0.2, 0.9);   // brownish green
81 			cr.paint();
82 		cr.restore();
83 
84 		cr.arc(0, 0, m_radius, 0, 2 * PI);
85 
86 		cr.save();
87 			cr.setSourceRgba(0.0, 0.0, 0.0, 0.8);
88 			cr.fillPreserve();
89 		cr.restore();
90 
91 		cr.save();
92 			cr.setSourceRgba(1.0, 1.0, 1.0, 1.0);
93 			cr.setLineWidth( m_lineWidth * 1.7);
94 			cr.strokePreserve();
95 			cr.clip();
96 		cr.restore();
97 
98 
99 		//clock ticks
100 
101 		for (int i = 0; i < 12; i++)
102 		{
103 			double inset = 0.07;
104 
105 			cr.save();
106 				cr.setSourceRgba(1.0, 1.0, 1.0, 1.0);
107 				cr.setLineWidth( m_lineWidth * 0.25);
108 				cr.setLineCap(cairo_line_cap_t.ROUND);
109 
110 				if (i % 3 != 0)
111 				{
112 					inset *= 1.2;
113 					cr.setLineWidth( m_lineWidth * 0.5 );
114 				}
115 
116 				cr.moveTo(
117 					(m_radius - inset) * cos (i * PI / 6),
118 					(m_radius - inset) * sin (i * PI / 6));
119 				cr.lineTo (
120 					m_radius * cos (i * PI / 6),
121 					m_radius * sin (i * PI / 6));
122 				cr.stroke();
123 			cr.restore(); // stack-pen-size
124 		}
125 
126 		version(Tango)
127 		{
128 			auto time = tangoClock.WallClock.now.time;
129 
130 			double minutes = time.minutes * PI / 30;
131 			double hours = time.hours * PI / 6;
132 			double seconds = time.seconds * PI / 30;
133 		}
134 		else version(D_Version2)
135 		{
136 			SysTime lNow = std.datetime.Clock.currTime();
137 
138 			// compute the angles of the indicators of our clock
139 			double minutes = lNow.minute * PI / 30; 
140 			double hours = lNow.hour * PI / 6; 
141 			double seconds= lNow.second * PI / 30; 
142 		}
143 		else
144 		{
145 			d_time lNow;
146 			string lNowString;
147 
148 			// Grab the date and time relative to UTC
149 			lNow = std.date.getUTCtime();
150 			// Convert this into the local date and time for display.
151 			lNowString = std.date.toString(lNow);
152 
153 			Date timeinfo;
154 			timeinfo.parse(lNowString);
155 
156 			// compute the angles of the indicators of our clock
157 			double minutes = timeinfo.minute * PI / 30;
158 			double hours = timeinfo.hour * PI / 6;
159 			double seconds= timeinfo.second * PI / 30;
160 		}
161 
162 		cr.save();
163 			cr.setLineCap(cairo_line_cap_t.ROUND);
164 
165 			// draw the seconds hand
166 			cr.save();
167 				cr.setLineWidth(m_lineWidth / 3);
168 				cr.setSourceRgba(0.7, 0.7, 0.85, 0.8); // blueish gray
169 				cr.moveTo(0, 0);
170 				cr.lineTo(sin(seconds) * (m_radius * 0.8),
171 					-cos(seconds) * (m_radius * 0.8));
172 				cr.stroke();
173 			cr.restore();
174 
175 			// draw the minutes hand
176 			//cr.setSourceRgba(0.117, 0.337, 0.612, 0.9);   // blue
177 			cr.setSourceRgba(0.712, 0.337, 0.117, 0.9);   // red
178 			cr.moveTo(0, 0);
179 			cr.lineTo(sin(minutes + seconds / 60) * (m_radius * 0.7),
180 				-cos(minutes + seconds / 60) * (m_radius * 0.7));
181 			cr.stroke();
182 
183 			// draw the hours hand
184 			cr.setSourceRgba(0.337, 0.612, 0.117, 0.9);   // green
185 			cr.moveTo(0, 0);
186 			cr.lineTo(sin(hours + minutes / 12.0) * (m_radius * 0.4),
187 				-cos(hours + minutes / 12.0) * (m_radius * 0.4));
188 			cr.stroke();
189 		cr.restore();
190 
191 		// draw a little dot in the middle
192 		cr.arc(0, 0, m_lineWidth / 3.0, 0, 2 * PI);
193 		cr.fill();
194 
195 		return true;
196 	}
197 
198 	bool onSecondElapsed()
199 	{
200 		//force our program to redraw the entire clock once per every second.
201 		GtkAllocation area;
202 		getAllocation(area);
203 
204 		queueDrawArea(area.x, area.y, area.width, area.height);
205 		
206 		return true;
207 	}
208 
209 	double m_radius = 0.40;
210 	double m_lineWidth = 0.065;
211 
212 	Timeout m_timeout;
213 }
214