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