~ubuntu-branches/ubuntu/lucid/docky/lucid-proposed

« back to all changes in this revision

Viewing changes to StandardPlugins/Weather/src/WeatherPainter.cs

  • Committer: Bazaar Package Importer
  • Author(s): Christopher James Halse Rogers
  • Date: 2010-02-17 15:10:07 UTC
  • Revision ID: james.westby@ubuntu.com-20100217151007-msxpd0lsj300ndde
Tags: upstream-2.0.0
ImportĀ upstreamĀ versionĀ 2.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//  
 
2
//  Copyright (C) 2009 GNOME Do
 
3
// 
 
4
//  This program is free software: you can redistribute it and/or modify
 
5
//  it under the terms of the GNU General Public License as published by
 
6
//  the Free Software Foundation, either version 3 of the License, or
 
7
//  (at your option) any later version.
 
8
// 
 
9
//  This program is distributed in the hope that it will be useful,
 
10
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
//  GNU General Public License for more details.
 
13
// 
 
14
//  You should have received a copy of the GNU General Public License
 
15
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
// 
 
17
 
 
18
using System;
 
19
using System.Collections.Generic;
 
20
 
 
21
using Cairo;
 
22
using Gtk;
 
23
using Mono.Unix;
 
24
 
 
25
using Docky.CairoHelper;
 
26
using Docky.Painters;
 
27
using Docky.Services;
 
28
 
 
29
namespace WeatherDocklet
 
30
{
 
31
        /// <summary>
 
32
        /// A painter that displays information about weather forecasts.
 
33
        /// </summary>
 
34
        public class WeatherPainter : PagingDockPainter
 
35
        {
 
36
                /// <value>
 
37
                /// The color to draw most text in.
 
38
                /// </value>
 
39
                static readonly Cairo.Color colorTitle = new Cairo.Color (0.627, 0.627, 0.627, 1);
 
40
                
 
41
                /// <value>
 
42
                /// The color to draw high temperatures in.
 
43
                /// </value>
 
44
                static readonly Cairo.Color colorHigh = new Cairo.Color (0.945, 0.431, 0.431, 1);
 
45
                
 
46
                /// <value>
 
47
                /// The color to draw low temperatures in.
 
48
                /// </value>
 
49
                static readonly Cairo.Color colorLow = new Cairo.Color (0.427, 0.714, 0.945, 1);
 
50
                
 
51
                /// <summary>
 
52
                /// Creates a new weather painter object.
 
53
                /// </summary>
 
54
                public WeatherPainter () : base (3)
 
55
                {
 
56
                }
 
57
                
 
58
                public override int MinimumHeight {
 
59
                        get {
 
60
                                return 42;
 
61
                        }
 
62
                }
 
63
                
 
64
                public override int MinimumWidth {
 
65
                        get {
 
66
                                return 2 * BUTTON_SIZE + 2 * WeatherController.Weather.ForecastDays * Math.Max (MinimumHeight, Allocation.Height);
 
67
                        }
 
68
                }
 
69
                
 
70
                #region IDockPainter implementation 
 
71
                
 
72
                protected override void DrawPageOnSurface (int page, DockySurface surface)
 
73
                {
 
74
                        switch (page)
 
75
                        {
 
76
                                default:
 
77
                                case 0:
 
78
                                        DrawCurrentCondition (surface.Context);
 
79
                                        break;
 
80
                                
 
81
                                case 1:
 
82
                                        DrawForecast (surface.Context);
 
83
                                        break;
 
84
                                
 
85
                                case 2:
 
86
                                        DrawTempGraph (surface.Context);
 
87
                                        break;
 
88
                        }
 
89
                }
 
90
                
 
91
                #endregion
 
92
                
 
93
                /// <summary>
 
94
                /// Paints an overview of the forecast including high/low temps and a condition icon.
 
95
                /// </summary>
 
96
                /// <param name="cr">
 
97
                /// A <see cref="Cairo.Context"/> to do the painting.
 
98
                /// </param>
 
99
                void DrawForecast (Cairo.Context cr)
 
100
                {
 
101
                        int xOffset = BUTTON_SIZE;
 
102
                        
 
103
                        Pango.Layout layout = DockServices.Drawing.ThemedPangoLayout ();
 
104
                        Pango.Rectangle inkRect, logicalRect;
 
105
                        
 
106
                        layout.FontDescription = new Gtk.Style().FontDescription;
 
107
                        layout.FontDescription.Weight = Pango.Weight.Bold;
 
108
                        layout.Ellipsize = Pango.EllipsizeMode.None;
 
109
                        layout.Width = Pango.Units.FromPixels (Allocation.Height);
 
110
                        
 
111
                        for (int day = 0; day < WeatherController.Weather.ForecastDays; day++)
 
112
                        {
 
113
                                layout.FontDescription.AbsoluteSize = Pango.Units.FromPixels ((int) (Allocation.Height / 5));
 
114
                                
 
115
                                cr.Color = colorTitle;
 
116
                                layout.SetText (string.Format ("{0}", WeatherForecast.DayShortName (WeatherController.Weather.Forecasts [day].dow)));
 
117
                                layout.GetPixelExtents (out inkRect, out logicalRect);
 
118
                                cr.MoveTo (xOffset + (Allocation.Height - inkRect.Width) / 2, 0);
 
119
                                Pango.CairoHelper.LayoutPath (cr, layout);
 
120
                                cr.Fill ();
 
121
                                
 
122
                                cr.Color = colorHigh;
 
123
                                layout.SetText (string.Format ("{0}{1}", WeatherController.Weather.Forecasts [day].high, WeatherUnits.TempUnit));
 
124
                                layout.GetPixelExtents (out inkRect, out logicalRect);
 
125
                                cr.MoveTo (xOffset + (Allocation.Height - inkRect.Width) / 2, Allocation.Height / 2 - logicalRect.Height / 2);
 
126
                                Pango.CairoHelper.LayoutPath (cr, layout);
 
127
                                cr.Fill ();
 
128
                                
 
129
                                cr.Color = colorLow;
 
130
                                layout.SetText (string.Format ("{0}{1}", WeatherController.Weather.Forecasts [day].low, WeatherUnits.TempUnit));
 
131
                                layout.GetPixelExtents (out inkRect, out logicalRect);
 
132
                                cr.MoveTo (xOffset + (Allocation.Height - inkRect.Width) / 2, Allocation.Height - logicalRect.Height);
 
133
                                Pango.CairoHelper.LayoutPath (cr, layout);
 
134
                                cr.Fill ();
 
135
                                
 
136
                                using (Gdk.Pixbuf pbuf = DockServices.Drawing.LoadIcon (WeatherController.Weather.Forecasts [day].image, Allocation.Height - 5))
 
137
                                {
 
138
                                        Gdk.CairoHelper.SetSourcePixbuf (cr, pbuf, xOffset + Allocation.Height + 2, 5);
 
139
                                        cr.PaintWithAlpha (WeatherController.Weather.Forecasts [day].chanceOf ? .6 : 1);
 
140
                                }
 
141
                                
 
142
                                if (WeatherController.Weather.Forecasts [day].chanceOf)
 
143
                                {
 
144
                                        layout.FontDescription.AbsoluteSize = Pango.Units.FromPixels ((int) (Allocation.Height / 2));
 
145
                                        
 
146
                                        layout.SetText ("?");
 
147
                                        
 
148
                                        layout.GetPixelExtents (out inkRect, out logicalRect);
 
149
                                        cr.MoveTo (xOffset + Allocation.Height + (Allocation.Height - inkRect.Width) / 2, Allocation.Height / 2 - logicalRect.Height / 2);
 
150
                                        
 
151
                                        cr.LineWidth = 4;
 
152
                                        cr.Color = new Cairo.Color (0, 0, 0, 0.3);
 
153
                                        Pango.CairoHelper.LayoutPath (cr, layout);
 
154
                                        cr.StrokePreserve ();
 
155
                                        
 
156
                                        cr.Color = new Cairo.Color (1, 1, 1, .6);
 
157
                                        cr.Fill ();
 
158
                                }
 
159
                                
 
160
                                xOffset += 2 * (Allocation.Height);
 
161
                        }
 
162
                }
 
163
                
 
164
                /// <summary>
 
165
                /// Paints the forecast temperatures as a chart.
 
166
                /// </summary>
 
167
                /// <param name="cr">
 
168
                /// A <see cref="Cairo.Context"/> to do the painting.
 
169
                /// </param>
 
170
                void DrawTempGraph (Cairo.Context cr)
 
171
                {
 
172
                        int max = -1000, min = 1000;
 
173
                        
 
174
                        for (int day = 0; day < WeatherController.Weather.ForecastDays; day++)
 
175
                        {
 
176
                                if (WeatherController.Weather.Forecasts [day].high > max)
 
177
                                        max = WeatherController.Weather.Forecasts [day].high;
 
178
                                if (WeatherController.Weather.Forecasts [day].low > max)
 
179
                                        max = WeatherController.Weather.Forecasts [day].low;
 
180
                                if (WeatherController.Weather.Forecasts [day].high < min)
 
181
                                        min = WeatherController.Weather.Forecasts [day].high;
 
182
                                if (WeatherController.Weather.Forecasts [day].low < min)
 
183
                                        min = WeatherController.Weather.Forecasts [day].low;
 
184
                    }
 
185
                        
 
186
                        if (max <= min)
 
187
                                return;
 
188
                        
 
189
                        Pango.Layout layout = DockServices.Drawing.ThemedPangoLayout ();
 
190
                        Pango.Rectangle inkRect, logicalRect;
 
191
                        
 
192
                        layout.FontDescription = new Gtk.Style().FontDescription;
 
193
                        layout.FontDescription.Weight = Pango.Weight.Bold;
 
194
                        layout.Ellipsize = Pango.EllipsizeMode.None;
 
195
                        layout.FontDescription.AbsoluteSize = Pango.Units.FromPixels ((int) (Allocation.Height / 5));
 
196
                        
 
197
                        // high/low temp
 
198
                        layout.Width = Pango.Units.FromPixels (Allocation.Height);
 
199
                        cr.Color = colorHigh;
 
200
                        layout.SetText (string.Format ("{0}{1}", max, WeatherUnits.TempUnit));
 
201
                        layout.GetPixelExtents (out inkRect, out logicalRect);
 
202
                        cr.MoveTo (Allocation.Width - Allocation.Height + (Allocation.Height - inkRect.Width) / 2 - BUTTON_SIZE, Allocation.Height / 6 - logicalRect.Height / 2);
 
203
                        Pango.CairoHelper.LayoutPath (cr, layout);
 
204
                        cr.Fill ();
 
205
                        
 
206
                        cr.Color = colorLow;
 
207
                        layout.SetText (string.Format ("{0}{1}", min, WeatherUnits.TempUnit));
 
208
                        layout.GetPixelExtents (out inkRect, out logicalRect);
 
209
                        cr.MoveTo (Allocation.Width - Allocation.Height + (Allocation.Height - inkRect.Width) / 2 - BUTTON_SIZE, Allocation.Height * 6 / 9 - logicalRect.Height / 2);
 
210
                        Pango.CairoHelper.LayoutPath (cr, layout);
 
211
                        cr.Fill ();
 
212
                        
 
213
                        // day names
 
214
                        layout.Width = Pango.Units.FromPixels (2 * Allocation.Height);
 
215
                        
 
216
                        cr.Color = colorTitle;
 
217
                        for (int day = 0; day < WeatherController.Weather.ForecastDays; day++)
 
218
                        {
 
219
                                layout.SetText (WeatherForecast.DayShortName (WeatherController.Weather.Forecasts [day].dow));
 
220
                                layout.GetPixelExtents (out inkRect, out logicalRect);
 
221
                                cr.MoveTo (BUTTON_SIZE + day * Allocation.Height * 2 + (Allocation.Height - inkRect.Width) / 2, Allocation.Height * 8 / 9 - logicalRect.Height / 2);
 
222
                                Pango.CairoHelper.LayoutPath (cr, layout);
 
223
                        }
 
224
                        cr.Fill ();
 
225
                        cr.Save ();
 
226
                        
 
227
                        // draw tick lines
 
228
                        cr.Color = new Cairo.Color (0.627, 0.627, 0.627, .8);
 
229
                        cr.LineWidth = 1;
 
230
                        cr.LineCap = LineCap.Round;
 
231
                        
 
232
                        int lines = 5;
 
233
                        for (int line = 0; line < lines - 1; line++) {
 
234
                                cr.MoveTo (BUTTON_SIZE + Allocation.Height / 4, 4.5 + Allocation.Height * line / lines);
 
235
                                cr.LineTo (BUTTON_SIZE + (2 * WeatherController.Weather.ForecastDays - 1) * Allocation.Height - Allocation.Height / 4, 4.5 + Allocation.Height * line / lines);
 
236
                                cr.Stroke ();
 
237
                        }
 
238
                        for (int line = 0; ; line++) {
 
239
                                double x = BUTTON_SIZE + Allocation.Height / 2 + line * 2 * Allocation.Height - 0.5;
 
240
                                if (x >= BUTTON_SIZE + (2 * WeatherController.Weather.ForecastDays - 1) * Allocation.Height - Allocation.Height / 4)
 
241
                                        break;
 
242
                                cr.MoveTo (x, 4.5);
 
243
                                cr.LineTo (x, 4.5 + Allocation.Height * (lines - 2) / lines);
 
244
                                cr.Stroke ();
 
245
                        }
 
246
                        
 
247
                        cr.Restore ();
 
248
                        cr.LineWidth = 3;
 
249
                        double height = ((double) Allocation.Height * 2 / 3 - 5) / (max - min);
 
250
                        
 
251
                        // high temp graph
 
252
                        cr.Color = colorHigh;
 
253
                        cr.MoveTo (BUTTON_SIZE + Allocation.Height / 2, 5 + height * (max - WeatherController.Weather.Forecasts [0].high));
 
254
                        for (int day = 1; day < WeatherController.Weather.ForecastDays; day++)
 
255
                                cr.LineTo (BUTTON_SIZE + day * Allocation.Height * 2 + Allocation.Height / 2, 5 + height * (max - WeatherController.Weather.Forecasts [day].high));
 
256
                        cr.Stroke ();
 
257
                        
 
258
                        // low temp graph
 
259
                        cr.Color = colorLow;
 
260
                        cr.MoveTo (BUTTON_SIZE + Allocation.Height / 2, 5 + height * (max - WeatherController.Weather.Forecasts [0].low));
 
261
                        for (int day = 1; day < WeatherController.Weather.ForecastDays; day++)
 
262
                                cr.LineTo (BUTTON_SIZE + day * Allocation.Height * 2 + Allocation.Height / 2, 5 + height * (max - WeatherController.Weather.Forecasts [day].low));
 
263
                        cr.Stroke ();
 
264
                        
 
265
                        // high temp points
 
266
                        for (int day = 0; day < WeatherController.Weather.ForecastDays; day++)
 
267
                                DrawDataPoint (cr, Allocation.Height, height, max, day, WeatherController.Weather.Forecasts [day].high);
 
268
                        
 
269
                        // low temp points
 
270
                        for (int day = 0; day < WeatherController.Weather.ForecastDays; day++)
 
271
                                DrawDataPoint (cr, Allocation.Height, height, max, day, WeatherController.Weather.Forecasts [day].low);
 
272
                }
 
273
                
 
274
                void DrawDataPoint (Cairo.Context cr, int cellWidth, double height, int max, int day, int temp)
 
275
                {
 
276
                        cr.Color = new Cairo.Color (0, 0, 0, 0.4);
 
277
                        cr.Arc (BUTTON_SIZE + day * cellWidth * 2 + cellWidth / 2 + 2, 7 + height * (max - temp), 3, 0, 2 * Math.PI);
 
278
                        cr.Fill ();
 
279
                        
 
280
                        cr.Color = colorTitle;
 
281
                        cr.Arc (BUTTON_SIZE + day * cellWidth * 2 + cellWidth / 2, 5 + height * (max - temp), 3, 0, 2 * Math.PI);
 
282
                        cr.Fill ();
 
283
                }
 
284
                
 
285
                /// <summary>
 
286
                /// Paints the current condition.
 
287
                /// </summary>
 
288
                /// <param name="cr">
 
289
                /// A <see cref="Cairo.Context"/> to do the painting.
 
290
                /// </param>
 
291
                void DrawCurrentCondition (Cairo.Context cr)
 
292
                {
 
293
                        Pango.Layout layout = DockServices.Drawing.ThemedPangoLayout ();
 
294
                        Pango.Rectangle inkRect, logicalRect;
 
295
                        
 
296
                        layout.FontDescription = new Gtk.Style().FontDescription;
 
297
                        layout.FontDescription.Weight = Pango.Weight.Bold;
 
298
                        layout.Ellipsize = Pango.EllipsizeMode.None;
 
299
                        layout.Width = Pango.Units.FromPixels ((int) ((Allocation.Width - 4 * BUTTON_SIZE) / 4.5));
 
300
                        
 
301
                        layout.FontDescription.AbsoluteSize = Pango.Units.FromPixels ((int) (Allocation.Height / 3));
 
302
                        
 
303
                        cr.Color = new Cairo.Color (1, 1, 1, 1);
 
304
                        
 
305
                        layout.SetText (WeatherController.Weather.City);
 
306
                        layout.GetPixelExtents (out inkRect, out logicalRect);
 
307
                        cr.MoveTo (2 * BUTTON_SIZE, Allocation.Height / 3.5 - logicalRect.Height / 2);
 
308
                        Pango.CairoHelper.LayoutPath (cr, layout);
 
309
                        cr.Fill ();
 
310
                        
 
311
                        DrawCondition (cr, WeatherController.Weather.SupportsFeelsLike ? 1 : 2, 2, Catalog.GetString ("Humidity"), WeatherController.Weather.Humidity);
 
312
                        
 
313
                        DrawCondition (cr, 2, 1, Catalog.GetString ("Temp"), WeatherController.Weather.Temp + WeatherUnits.TempUnit);
 
314
                        if (WeatherController.Weather.SupportsFeelsLike)
 
315
                                DrawCondition (cr, 2, 2, Catalog.GetString ("Feels Like"), WeatherController.Weather.FeelsLike + WeatherUnits.TempUnit);
 
316
                        
 
317
                        DrawCondition (cr, 3, 1, Catalog.GetString ("Wind"), WeatherController.Weather.Wind + " " + WeatherUnits.WindUnit);
 
318
                        DrawCondition (cr, 3, 2, Catalog.GetString ("Direction"), WeatherController.Weather.WindDirection);
 
319
                        
 
320
                        DrawCondition (cr, 4, 1, Catalog.GetString ("Sunrise"), WeatherController.Weather.SunRise.ToShortTimeString ());
 
321
                        DrawCondition (cr, 4, 2, Catalog.GetString ("Sunset"), WeatherController.Weather.SunSet.ToShortTimeString ());
 
322
                }
 
323
                
 
324
                void DrawCondition (Cairo.Context cr, int column, int row, string label, string val)
 
325
                {
 
326
                        int xWidth = (Allocation.Width - 4 * BUTTON_SIZE) / 8;
 
327
                        
 
328
                        Pango.Layout layout = DockServices.Drawing.ThemedPangoLayout ();
 
329
                        Pango.Rectangle inkRect, logicalRect;
 
330
                        
 
331
                        layout.FontDescription = new Gtk.Style().FontDescription;
 
332
                        layout.FontDescription.Weight = Pango.Weight.Bold;
 
333
                        layout.Ellipsize = Pango.EllipsizeMode.None;
 
334
                        layout.Width = Pango.Units.FromPixels (xWidth);
 
335
                        
 
336
                        if (WeatherController.Weather.ForecastDays < 6)
 
337
                                layout.FontDescription.AbsoluteSize = Pango.Units.FromPixels ((int) (Allocation.Height / 6.5));
 
338
                        else
 
339
                                layout.FontDescription.AbsoluteSize = Pango.Units.FromPixels ((int) (Allocation.Height / 4.5));
 
340
                        
 
341
                        int xOffset = 2 * BUTTON_SIZE + (column - 1) * 2 * xWidth;
 
342
                        int yOffset = row == 1 ? Allocation.Height : (int) (Allocation.Height * 2.5);
 
343
                        yOffset = (int) (yOffset / 3.5);
 
344
                        
 
345
                        cr.Color = new Cairo.Color (1, 1, 1, 0.9);
 
346
                        layout.SetText (label);
 
347
                        layout.GetPixelExtents (out inkRect, out logicalRect);
 
348
                        cr.MoveTo (xOffset + (xWidth - inkRect.Width) / 2, yOffset - logicalRect.Height / 2);
 
349
                        Pango.CairoHelper.LayoutPath (cr, layout);
 
350
                        cr.Fill ();
 
351
                        
 
352
                        cr.Color = new Cairo.Color (1, 1, 1, 0.7);
 
353
                        layout.SetText (val);
 
354
                        layout.GetPixelExtents (out inkRect, out logicalRect);
 
355
                        cr.MoveTo (xOffset + xWidth + (xWidth - inkRect.Width) / 2, yOffset - logicalRect.Height / 2);
 
356
                        Pango.CairoHelper.LayoutPath (cr, layout);
 
357
                        cr.Fill ();
 
358
                }
 
359
                
 
360
                /// <summary>
 
361
                /// Called when new weather data arrives, to purge the buffers and redraw.
 
362
                /// </summary>
 
363
                public void WeatherChanged ()
 
364
                {
 
365
                        ResetBuffers ();
 
366
                        QueueRepaint ();
 
367
                }
 
368
        }
 
369
}