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 gtk.Timeout; 41 42 import cairo.Context; 43 import cairo.Surface; 44 45 import gtk.Widget; 46 import gdk.Drawable; 47 import gdk.Window; 48 import gdk.Rectangle; 49 50 import gtk.DrawingArea; 51 52 class Clock : DrawingArea 53 { 54 public: 55 this() 56 { 57 //Attach our expose callback, which will draw the window. 58 addOnExpose(&exposeCallback); 59 } 60 61 protected: 62 //Override default signal handler: 63 bool exposeCallback(GdkEventExpose* event, Widget widget) 64 { 65 if ( m_timeout is null ) 66 { 67 //Create a new timeout that will ask the window to be drawn once every second. 68 m_timeout = new Timeout( 1000, &onSecondElapsed, false ); 69 } 70 71 // This is where we draw on the window 72 73 Drawable dr = getWindow(); 74 75 int width; 76 int height; 77 78 dr.getSize(width, height); 79 80 auto cr = new Context (dr); 81 82 if (event) 83 { 84 // clip to the area indicated by the expose event so that we only redraw 85 // the portion of the window that needs to be redrawn 86 cr.rectangle(event.area.x, event.area.y, 87 event.area.width, event.area.height); 88 cr.clip(); 89 } 90 91 // scale to unit square and translate (0, 0) to be (0.5, 0.5), i.e. the 92 // center of the window 93 cr.scale(width, height); 94 cr.translate(0.5, 0.5); 95 cr.setLineWidth(m_lineWidth); 96 97 cr.save(); 98 cr.setSourceRgba(0.3, 0.6, 0.2, 0.9); // brownish green 99 cr.paint(); 100 cr.restore(); 101 102 cr.arc(0, 0, m_radius, 0, 2 * PI); 103 104 cr.save(); 105 cr.setSourceRgba(0.0, 0.0, 0.0, 0.8); 106 cr.fillPreserve(); 107 cr.restore(); 108 109 cr.save(); 110 cr.setSourceRgba(1.0, 1.0, 1.0, 1.0); 111 cr.setLineWidth( m_lineWidth * 1.7); 112 cr.strokePreserve(); 113 cr.clip(); 114 cr.restore(); 115 116 117 //clock ticks 118 119 for (int i = 0; i < 12; i++) 120 { 121 double inset = 0.07; 122 123 cr.save(); 124 cr.setSourceRgba(1.0, 1.0, 1.0, 1.0); 125 cr.setLineWidth( m_lineWidth * 0.25); 126 cr.setLineCap(cairo_line_cap_t.ROUND); 127 128 if (i % 3 != 0) 129 { 130 inset *= 1.2; 131 cr.setLineWidth( m_lineWidth * 0.5 ); 132 } 133 134 cr.moveTo( 135 (m_radius - inset) * cos (i * PI / 6), 136 (m_radius - inset) * sin (i * PI / 6)); 137 cr.lineTo ( 138 m_radius * cos (i * PI / 6), 139 m_radius * sin (i * PI / 6)); 140 cr.stroke(); 141 cr.restore(); // stack-pen-size 142 } 143 144 version(Tango) 145 { 146 auto time = tangoClock.WallClock.now.time; 147 148 double minutes = time.minutes * PI / 30; 149 double hours = time.hours * PI / 6; 150 double seconds = time.seconds * PI / 30; 151 } 152 else version(D_Version2) 153 { 154 SysTime lNow = std.datetime.Clock.currTime(); 155 156 // compute the angles of the indicators of our clock 157 double minutes = lNow.minute * PI / 30; 158 double hours = lNow.hour * PI / 6; 159 double seconds= lNow.second * PI / 30; 160 } 161 else 162 { 163 d_time lNow; 164 string lNowString; 165 166 // Grab the date and time relative to UTC 167 lNow = std.date.getUTCtime(); 168 // Convert this into the local date and time for display. 169 lNowString = std.date.toString(lNow); 170 171 Date timeinfo; 172 timeinfo.parse(lNowString); 173 174 // compute the angles of the indicators of our clock 175 double minutes = timeinfo.minute * PI / 30; 176 double hours = timeinfo.hour * PI / 6; 177 double seconds= timeinfo.second * PI / 30; 178 } 179 180 cr.save(); 181 cr.setLineCap(cairo_line_cap_t.ROUND); 182 183 // draw the seconds hand 184 cr.save(); 185 cr.setLineWidth(m_lineWidth / 3); 186 cr.setSourceRgba(0.7, 0.7, 0.85, 0.8); // blueish gray 187 cr.moveTo(0, 0); 188 cr.lineTo(sin(seconds) * (m_radius * 0.8), 189 -cos(seconds) * (m_radius * 0.8)); 190 cr.stroke(); 191 cr.restore(); 192 193 // draw the minutes hand 194 //cr.setSourceRgba(0.117, 0.337, 0.612, 0.9); // blue 195 cr.setSourceRgba(0.712, 0.337, 0.117, 0.9); // red 196 cr.moveTo(0, 0); 197 cr.lineTo(sin(minutes + seconds / 60) * (m_radius * 0.7), 198 -cos(minutes + seconds / 60) * (m_radius * 0.7)); 199 cr.stroke(); 200 201 // draw the hours hand 202 cr.setSourceRgba(0.337, 0.612, 0.117, 0.9); // green 203 cr.moveTo(0, 0); 204 cr.lineTo(sin(hours + minutes / 12.0) * (m_radius * 0.4), 205 -cos(hours + minutes / 12.0) * (m_radius * 0.4)); 206 cr.stroke(); 207 cr.restore(); 208 209 // draw a little dot in the middle 210 cr.arc(0, 0, m_lineWidth / 3.0, 0, 2 * PI); 211 cr.fill(); 212 213 delete cr; 214 215 return true; 216 } 217 218 bool onSecondElapsed() 219 { 220 //force our program to redraw the entire clock once per every second. 221 222 Window win = getWindow(); 223 224 if(win) 225 { 226 227 int width; 228 int height; 229 230 win.getSize(width, height); 231 232 //I think this should be also made possible: 233 //width = win.getWidth(); 234 //height = win.getHeight(); 235 236 //And there should be a constructor like: Rectangle( int x, int y, int width, int height ); 237 //because at the moment we have to do this to use a Rectangle, and that it needed for 238 //invalidateRect. The easiest way would be a new invalidate( int x, int y, int width, int height) 239 //that would do everything that we're doing here. And maybe also invalidateAll(); 240 GdkRectangle* grect = new GdkRectangle(); 241 242 grect.x = 0; 243 grect.y = 0; 244 grect.width = width; 245 grect.height = height; 246 247 //Rectangle r = new Rectangle(0, 0, width, height); 248 Rectangle r = new Rectangle(grect); 249 250 win.invalidateRect(r, false); 251 } 252 //else writefln("The Gdk.Window doesn't exist. Something went wrong in clock.d onSecondsElapsed()"); 253 254 return true; 255 256 } 257 258 double m_radius = 0.40; 259 double m_lineWidth = 0.065; 260 261 Timeout m_timeout; 262 } 263