alternative to assert
[gtkD.git] / gtkD / demos / cairo / clock.d
blobc9b1b4e1d9afc3b08d9f1ecae286effc83d0d73e
1 /**
2 * clock.d
4 * A Duit widget that implements a clock face
6 * Based on the Gtkmm example by:
7 * Jonathon Jongsma
9 * and the original GTK+ example by:
10 * (c) 2005-2006, Davyd Madeley
12 * Authors:
13 * Joonas Kiviharju (D version)
14 * Jonathon Jongsma (C++ version)
15 * Davyd Madeley (C version)
19 * from http://www.dsource.org/forums/viewtopic.php?t=1666
20 * satelliittipupu wrote:
21 * You can use it for Duit demos!
24 module cairo.clock;
26 import std.stdio;
28 private import std.math;
29 private import std.date;
31 private import gtk.GtkD;
33 private import gtk.Timeout;
35 private import cairoLib.Cairo;
36 private import cairoLib.Surface;
37 private import gtkc.cairoLibtypes;
39 private import gtk.Widget;
40 private import gdk.Drawable;
41 private import gdk.Window;
42 private import gdk.Rectangle;
44 private import gtk.DrawingArea;
46 class Clock : public DrawingArea
48 public:
49 this()
51 //Attach our expose callback, which will draw the window.
52 addOnExpose(&exposeCallback);
57 protected:
58 //Override default signal handler:
59 int exposeCallback(GdkEventExpose* event, Widget widget)
61 if ( m_timeout is null )
63 //Create a new timeout that will ask the window to be drawn once every second.
64 m_timeout = new Timeout( 1000, &onSecondElapsed, false );
66 // This is where we draw on the window
68 Drawable dr = getDrawable();
70 int width;
71 int height;
73 dr.drawableGetSize(&width, &height);
75 Cairo cr = new Cairo (dr);
77 if (event)
79 // clip to the area indicated by the expose event so that we only redraw
80 // the portion of the window that needs to be redrawn
81 cr.rectangle(event.area.x, event.area.y,
82 event.area.width, event.area.height);
83 cr.clip();
86 // scale to unit square and translate (0, 0) to be (0.5, 0.5), i.e. the
87 // center of the window
88 cr.scale(width, height);
89 cr.translate(0.5, 0.5);
90 cr.setLineWidth(m_lineWidth);
92 cr.save();
93 cr.setSourceRgba(0.3, 0.6, 0.2, 0.9); // brownish green
94 cr.paint();
95 cr.restore();
97 cr.arc(0, 0, m_radius, 0, 2 * PI);
99 cr.save();
100 cr.setSourceRgba(0.0, 0.0, 0.0, 0.8);
101 cr.fillPreserve();
102 cr.restore();
104 cr.save();
105 cr.setSourceRgba(1.0, 1.0, 1.0, 1.0);
106 cr.setLineWidth( m_lineWidth * 1.7);
107 cr.strokePreserve();
108 cr.clip();
109 cr.restore();
112 //clock ticks
114 for (int i = 0; i < 12; i++)
116 double inset = 0.07;
118 cr.save();
119 cr.setSourceRgba(1.0, 1.0, 1.0, 1.0);
120 cr.setLineWidth( m_lineWidth * 0.25);
121 cr.setLineCap(cairo_line_cap_t.ROUND);
123 if (i % 3 != 0)
125 inset *= 1.2;
126 cr.setLineWidth( m_lineWidth * 0.5 );
129 cr.moveTo(
130 (m_radius - inset) * cos (i * PI / 6),
131 (m_radius - inset) * sin (i * PI / 6));
132 cr.lineTo (
133 m_radius * cos (i * PI / 6),
134 m_radius * sin (i * PI / 6));
135 cr.stroke();
136 cr.restore(); // stack-pen-size
140 d_time lNow;
141 char[] lNowString;
143 // Grab the date and time relative to UTC
144 lNow = std.date.getUTCtime();
145 // Convert this into the local date and time for display.
146 lNowString = std.date.toString(lNow);
148 Date timeinfo;
149 timeinfo.parse(lNowString);
151 // compute the angles of the indicators of our clock
152 double minutes = timeinfo.minute * PI / 30;
153 double hours = timeinfo.hour * PI / 6;
154 double seconds= timeinfo.second * PI / 30;
156 //writefln(timeinfo.hour, ".", timeinfo.minute, ".", timeinfo.second);
158 cr.save();
159 cr.setLineCap(cairo_line_cap_t.ROUND);
161 // draw the seconds hand
162 cr.save();
163 cr.setLineWidth(m_lineWidth / 3);
164 cr.setSourceRgba(0.7, 0.7, 0.85, 0.8); // blueish gray
165 cr.moveTo(0, 0);
166 cr.lineTo(sin(seconds) * (m_radius * 0.8),
167 -cos(seconds) * (m_radius * 0.8));
168 cr.stroke();
169 cr.restore();
171 // draw the minutes hand
172 //cr.setSourceRgba(0.117, 0.337, 0.612, 0.9); // blue
173 cr.setSourceRgba(0.712, 0.337, 0.117, 0.9); // red
174 cr.moveTo(0, 0);
175 cr.lineTo(sin(minutes + seconds / 60) * (m_radius * 0.7),
176 -cos(minutes + seconds / 60) * (m_radius * 0.7));
177 cr.stroke();
179 // draw the hours hand
180 cr.setSourceRgba(0.337, 0.612, 0.117, 0.9); // green
181 cr.moveTo(0, 0);
182 cr.lineTo(sin(hours + minutes / 12.0) * (m_radius * 0.4),
183 -cos(hours + minutes / 12.0) * (m_radius * 0.4));
184 cr.stroke();
185 cr.restore();
187 // draw a little dot in the middle
188 cr.arc(0, 0, m_lineWidth / 3.0, 0, 2 * PI);
189 cr.fill();
191 delete cr;
193 return 1;
196 bool onSecondElapsed()
198 // force our program to redraw the entire clock.
201 Drawable dr = getDrawable();
202 Window win = cast(Window); //this combinations crashes for some reason?
204 Drawable dr = getDrawable();
205 Window win = new Window( cast(Window)dr ); //and this one doesn't even compile, as there's no constructor like this.
208 //So, we need a new function that could be like this:
209 //It's the same as getDrawable but it returns a window from GtkWidget.window.
210 //We need it for the invalidateRect which isn't found in a GdkDrawable.
211 Window win = getWindow();
213 if(win)
216 int width;
217 int height;
219 win.drawableGetSize(&width, &height);
221 //I think this should be also made possible:
222 //width = win.getWidth();
223 //height = win.getHeight();
225 //And there should be a constructor like: Rectangle( int x, int y, int width, int height );
226 //because at the moment we have to do this to use a Rectangle, and that it needed for
227 //invalidateRect. The easiest way would be a new invalidate( int x, int y, int width, int height)
228 //that would do everything that we're doing here. And maybe also invalidateAll();
229 GdkRectangle* grect = new GdkRectangle();
231 grect.x = 0;
232 grect.y = 0;
233 grect.width = width;
234 grect.height = height;
236 //Rectangle r = new Rectangle(0, 0, width, height);
237 Rectangle r = new Rectangle(grect);
239 win.invalidateRect(r, false);
241 else writefln("The Gdk.Window doesn't exist. Something went wrong in clock.d onSecondsElapsed()");
243 return true;
247 double m_radius = 0.40;
248 double m_lineWidth = 0.065;
250 Timeout m_timeout;