aboutsummaryrefslogtreecommitdiff
path: root/src/statistics/gtk_statistics.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/statistics/gtk_statistics.c')
-rw-r--r--src/statistics/gtk_statistics.c220
1 files changed, 190 insertions, 30 deletions
diff --git a/src/statistics/gtk_statistics.c b/src/statistics/gtk_statistics.c
index e6151a59..b1d7fe84 100644
--- a/src/statistics/gtk_statistics.c
+++ b/src/statistics/gtk_statistics.c
@@ -30,6 +30,19 @@
30#define MAX_HISTORY 1280 30#define MAX_HISTORY 1280
31 31
32/** 32/**
33 * Number of ticks on the x-axis.
34 */
35#define XTICKS 4
36
37/**
38 * Number of ticks on the y-axis.
39 */
40#define YTICKS 5
41
42#define BORDER 10.0
43
44
45/**
33 * Information about a value we received. 46 * Information about a value we received.
34 */ 47 */
35struct HistoricValue 48struct HistoricValue
@@ -58,9 +71,9 @@ struct ValueHistory
58 char *label; 71 char *label;
59 72
60 /** 73 /**
61 * Color name. 74 * Color values (rgb).
62 */ 75 */
63 char *color_name; 76 double red, green, blue;
64 77
65 /** 78 /**
66 * Recent values for this number. 79 * Recent values for this number.
@@ -100,7 +113,7 @@ static gboolean gtk_statistics_draw (GtkWidget *widget,
100static void gtk_statistics_finalize (GObject *object); 113static void gtk_statistics_finalize (GObject *object);
101 114
102 115
103G_DEFINE_TYPE (GtkStatistics, gtk_statistics, GTK_TYPE_MISC) 116G_DEFINE_TYPE (GtkStatistics, gtk_statistics, GTK_TYPE_WIDGET)
104 117
105 118
106static void 119static void
@@ -114,6 +127,7 @@ gtk_statistics_class_init (GtkStatisticsClass *class)
114 127
115 gobject_class->finalize = gtk_statistics_finalize; 128 gobject_class->finalize = gtk_statistics_finalize;
116 widget_class->draw = gtk_statistics_draw; 129 widget_class->draw = gtk_statistics_draw;
130
117 g_type_class_add_private (class, sizeof (GtkStatisticsPrivate)); 131 g_type_class_add_private (class, sizeof (GtkStatisticsPrivate));
118} 132}
119 133
@@ -152,6 +166,7 @@ gtk_statistics_new ()
152 priv = statistics->priv; 166 priv = statistics->priv;
153 priv->values = NULL; 167 priv->values = NULL;
154 priv->num_values = 0; 168 priv->num_values = 0;
169
155 return GTK_WIDGET (statistics); 170 return GTK_WIDGET (statistics);
156} 171}
157 172
@@ -165,14 +180,18 @@ gtk_statistics_add_line (GtkStatistics *statistics,
165{ 180{
166 GtkStatisticsPrivate *priv; 181 GtkStatisticsPrivate *priv;
167 struct ValueHistory *vh; 182 struct ValueHistory *vh;
183 GdkColor c;
168 184
169 g_return_if_fail (GTK_IS_STATISTICS (statistics)); 185 g_return_if_fail (GTK_IS_STATISTICS (statistics));
186 g_return_if_fail (gdk_color_parse (color_name, &c));
170 priv = statistics->priv; 187 priv = statistics->priv;
171 priv->values = g_realloc (priv->values, 188 priv->values = g_realloc (priv->values,
172 sizeof (struct ValueHistory*) * (1 + priv->num_values)); 189 sizeof (struct ValueHistory*) * (1 + priv->num_values));
173 priv->values[priv->num_values++] = vh = g_malloc (sizeof (struct ValueHistory)); 190 priv->values[priv->num_values++] = vh = g_malloc (sizeof (struct ValueHistory));
174 vh->label = strdup (label); 191 vh->label = strdup (label);
175 vh->color_name = strdup (color_name); 192 vh->red = c.red / 65535.0;
193 vh->green = c.green / 65535.0;
194 vh->blue = c.blue / 65535.0;
176} 195}
177 196
178 197
@@ -202,11 +221,6 @@ gtk_statistics_update_value (GtkStatistics *statistics,
202 vh->history_size++; 221 vh->history_size++;
203 vh->history[vh->last_history_offset].x = x; 222 vh->history[vh->last_history_offset].x = x;
204 vh->history[vh->last_history_offset].y = y; 223 vh->history[vh->last_history_offset].y = y;
205
206 g_object_freeze_notify (G_OBJECT (statistics));
207 g_object_notify (G_OBJECT (statistics), "statistics-value");
208 g_object_thaw_notify (G_OBJECT (statistics));
209
210 widget = GTK_WIDGET (statistics); 224 widget = GTK_WIDGET (statistics);
211 if (gtk_widget_is_drawable (widget)) 225 if (gtk_widget_is_drawable (widget))
212 gtk_widget_queue_draw (widget); 226 gtk_widget_queue_draw (widget);
@@ -214,38 +228,179 @@ gtk_statistics_update_value (GtkStatistics *statistics,
214} 228}
215 229
216 230
231static void
232num_to_label (unsigned long long num,
233 char *label)
234{
235 if (num > 1000LL * 1000 * 1000 * 3)
236 sprintf (label, "%llu g", num / 1000LL / 1000LL / 1000LL);
237 else if (num > 1000LL * 1000 * 3)
238 sprintf (label, "%llu m", num / 1000LL / 1000LL);
239 else if (num > 1000LL * 3)
240 sprintf (label, "%llu k", num / 1000LL);
241 else
242 sprintf (label, "%llu", num);
243}
244
245
217static gboolean 246static gboolean
218gtk_statistics_draw (GtkWidget *widget, 247gtk_statistics_draw (GtkWidget *widget,
219 cairo_t *cr) 248 cairo_t *cr)
220{ 249{
221 GtkStatistics *statistics = GTK_STATISTICS (widget); 250 GtkStatistics *statistics = GTK_STATISTICS (widget);
222 GtkStatisticsPrivate *priv = statistics->priv; 251 GtkStatisticsPrivate *priv = statistics->priv;
252 int width;
253 int height;
254 uint64_t xmin;
255 uint64_t xmax;
256 uint64_t ymax;
257 unsigned int i;
258 unsigned int j;
259 struct ValueHistory *vh;
260 struct HistoricValue *hv;
261 char label[64];
262 cairo_text_extents_t te;
263 cairo_text_extents_t tex_max;
264 cairo_text_extents_t tey_max;
265 double rx;
266 double ry;
267
268 /* collect basic data */
269 xmin = UINT64_MAX;
270 xmax = 0;
271 ymax = 0;
272 for (i=0;i<priv->num_values;i++)
273 {
274 vh = priv->values[i];
275 for (j=0;j<vh->history_size;j++)
276 {
277 hv = &vh->history[(vh->last_history_offset - j + MAX_HISTORY) % MAX_HISTORY];
278 xmin = GNUNET_MIN (hv->x, xmin);
279 xmax = GNUNET_MAX (hv->x, xmax);
280 ymax = GNUNET_MAX (hv->y, ymax);
281 }
282 }
283 /* round to 10x for nicer legends */
284 while (0 != (ymax % 10)) ymax++;
285 while (0 != (xmax % 10)) xmax++;
286 while (0 != (xmin % 10)) xmin--;
223 287
224 fprintf (stderr, "DRAW!\n"); 288 width = gtk_widget_get_allocated_width (widget);
225#if 0 289 height = gtk_widget_get_allocated_height (widget);
226 gdk_color_parse (info[i].color_name, &color);
227 gdk_gc_set_foreground (gc, &color);
228#endif
229 cairo_translate(cr, 0, 7);
230 290
231 cairo_set_source_rgb(cr, 0, 0, 0); 291 /* fill with black background */
292 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
232 cairo_paint(cr); 293 cairo_paint(cr);
294
295 if (0 == priv->num_values)
296 return FALSE; /* done */
297 /* select font */
298 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
299 cairo_select_font_face (cr, "Georgia",
300 CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
301 cairo_set_font_size (cr,
302 GNUNET_MIN (20, height / (2 * XTICKS)));
303
304 /* find out needed space for axis labels */
305 tex_max.width = 0;
306 tex_max.height = 0;
307 for (i=0;i<XTICKS;i++)
308 {
309 num_to_label ((unsigned long long) (xmin + (xmax - xmin) * ((uint64_t) i) / (XTICKS - 1)),
310 label);
311 cairo_text_extents (cr, label, &te);
312 tex_max.width = GNUNET_MAX (te.width, tex_max.width);
313 tex_max.height = GNUNET_MAX (te.height, tex_max.height);
314 }
315 tey_max.width = 0;
316 tey_max.height = 0;
317 for (i=0;i<YTICKS;i++)
318 {
319 num_to_label ((unsigned long long) ymax * ((uint64_t) i) / (YTICKS - 1),
320 label);
321 cairo_text_extents (cr, label, &te);
322 tey_max.width = GNUNET_MAX (te.width, tey_max.width);
323 tey_max.height = GNUNET_MAX (te.height, tey_max.height);
324 }
233 325
234 gint pos = priv->num_values; 326 /* draw y-axis labels */
235 gint rect = pos / 5; 327 for (i=0;i<YTICKS;i++)
328 {
329 num_to_label ((unsigned long long) ymax * ((uint64_t) i) / (YTICKS - 1),
330 label);
331 cairo_text_extents (cr, label, &te);
332 cairo_move_to (cr,
333 BORDER + tey_max.width - te.width,
334 BORDER + tey_max.height + (YTICKS - i - 1) * (height - 2.0 * BORDER - tey_max.height - tex_max.height) / (double) (YTICKS - 1));
335 cairo_show_text (cr, label);
336
337
338 cairo_move_to (cr,
339 2.0 * BORDER + tey_max.width,
340 BORDER + tey_max.height / 2.0 + (YTICKS - i - 1) * (height - 2.0 * BORDER - tex_max.height - tey_max.height) / (double) (YTICKS - 1));
341 cairo_line_to (cr,
342 2.0 * BORDER + tey_max.width + BORDER / 2.0,
343 BORDER + tey_max.height / 2.0 + (YTICKS - i - 1) * (height - 2.0 * BORDER - tex_max.height - tey_max.height) / (double) (YTICKS - 1));
344
345 cairo_stroke (cr);
346 }
236 347
237 cairo_set_source_rgb(cr, 0.2, 0.4, 0); 348 /* draw x-axis labels */
349 for (i=0;i<XTICKS;i++)
350 {
351 num_to_label ((unsigned long long) (xmin + (xmax - xmin) * ((uint64_t) i) / (XTICKS - 1)),
352 label);
353 cairo_text_extents (cr, label, &te);
354 if (i != 0)
355 {
356 cairo_move_to (cr,
357 2.0 * BORDER + tey_max.width + (width - tey_max.width - tex_max.width / 2.0 - 3.0 * BORDER) * i / (XTICKS - 1.0) - te.width / 2.0,
358 height - BORDER / 2.0 - tex_max.height / 2.0);
359 cairo_show_text (cr, label);
360 }
361 cairo_move_to (cr,
362 2.0 * BORDER + tey_max.width + (width - tey_max.width - tex_max.width / 2.0 - 3.0 * BORDER) * i / (XTICKS - 1.0),
363 height - BORDER - tey_max.height / 2.0 - tex_max.height);
364 cairo_line_to (cr,
365 2.0 * BORDER + tey_max.width + (width - tey_max.width - tex_max.width / 2.0 - 3.0 * BORDER) * i / (XTICKS - 1.0),
366 height - BORDER - tey_max.height / 2.0 - tex_max.height - BORDER / 2.0);
367
368 cairo_stroke (cr);
369 }
238 370
239 gint i; 371 /* plot border */
240 for ( i = 1; i <= 20; i++) { 372 cairo_set_line_width (cr, 1.0);
241 if (i > 20 - rect) { 373 cairo_rectangle (cr,
242 cairo_set_source_rgb(cr, 0.6, 1.0, 0); 374 tey_max.width + BORDER * 2.0,
243 } else { 375 BORDER + tey_max.height / 2.0,
244 cairo_set_source_rgb(cr, 0.2, 0.4, 0); 376 width - BORDER * 3.0 - tey_max.width - tex_max.width / 2.0,
377 height - BORDER * 2.0 - tey_max.height - tex_max.height);
378 cairo_stroke (cr);
379
380 /* finally, plot lines */
381 cairo_set_line_width (cr, 2.0);
382 for (i=0;i<priv->num_values;i++)
383 {
384 vh = priv->values[i];
385 cairo_set_source_rgb(cr, vh->red, vh->green, vh->blue);
386 for (j=0;j<vh->history_size;j++)
387 {
388 hv = &vh->history[(vh->last_history_offset - j + MAX_HISTORY) % MAX_HISTORY];
389 rx = (hv->x - xmin) / (double) (xmax - xmin);
390 ry = hv->y / (double) ymax;
391
392 rx = tey_max.width + BORDER * 2.0 + (rx * (width - BORDER * 3.0 - tey_max.width - tex_max.width / 2.0));
393 ry = BORDER + tex_max.height / 2.0 + (1.0 - ry) * (height - BORDER * 2.0 - tey_max.height - tex_max.height);
394 if (j == 0)
395 {
396 cairo_move_to (cr, rx, ry);
397 }
398 else
399 {
400 cairo_line_to (cr, rx, ry);
245 } 401 }
246 cairo_rectangle(cr, 8, i*4, 30, 3); 402 }
247 cairo_rectangle(cr, 42, i*4, 30, 3); 403 cairo_stroke (cr);
248 cairo_fill(cr);
249 } 404 }
250 return FALSE; 405 return FALSE;
251} 406}
@@ -256,9 +411,14 @@ gtk_statistics_finalize (GObject *object)
256{ 411{
257 GtkStatistics *label = GTK_STATISTICS (object); 412 GtkStatistics *label = GTK_STATISTICS (object);
258 GtkStatisticsPrivate *priv = label->priv; 413 GtkStatisticsPrivate *priv = label->priv;
414 unsigned int i;
259 415
260 g_free (priv->values); 416 for (i=0;i<priv->num_values;i++)
261 417 {
418 g_free (priv->values[i]->label);
419 g_free (priv->values[i]);
420 }
421 g_free (priv->values);
262 G_OBJECT_CLASS (gtk_statistics_parent_class)->finalize (object); 422 G_OBJECT_CLASS (gtk_statistics_parent_class)->finalize (object);
263} 423}
264 424