diff options
Diffstat (limited to 'src/statistics/gtk_statistics.c')
-rw-r--r-- | src/statistics/gtk_statistics.c | 87 |
1 files changed, 74 insertions, 13 deletions
diff --git a/src/statistics/gtk_statistics.c b/src/statistics/gtk_statistics.c index b1d7fe84..c483794d 100644 --- a/src/statistics/gtk_statistics.c +++ b/src/statistics/gtk_statistics.c | |||
@@ -39,6 +39,9 @@ | |||
39 | */ | 39 | */ |
40 | #define YTICKS 5 | 40 | #define YTICKS 5 |
41 | 41 | ||
42 | /** | ||
43 | * Additional distance between text and lines / borders in pixels. | ||
44 | */ | ||
42 | #define BORDER 10.0 | 45 | #define BORDER 10.0 |
43 | 46 | ||
44 | 47 | ||
@@ -66,6 +69,11 @@ struct ValueHistory | |||
66 | { | 69 | { |
67 | 70 | ||
68 | /** | 71 | /** |
72 | * ID for value updates. | ||
73 | */ | ||
74 | char *id; | ||
75 | |||
76 | /** | ||
69 | * Label for the subsystem. | 77 | * Label for the subsystem. |
70 | */ | 78 | */ |
71 | char *label; | 79 | char *label; |
@@ -172,9 +180,16 @@ gtk_statistics_new () | |||
172 | 180 | ||
173 | 181 | ||
174 | /** | 182 | /** |
183 | * Add another data series to plot by the statistics widget. | ||
184 | * | ||
185 | * @param statistics widget to modify | ||
186 | * @param id identifier for the series | ||
187 | * @param label label to use | ||
188 | * @param color_name name of the color to use | ||
175 | */ | 189 | */ |
176 | void | 190 | void |
177 | gtk_statistics_add_line (GtkStatistics *statistics, | 191 | gtk_statistics_add_line (GtkStatistics *statistics, |
192 | const char *id, | ||
178 | const char *label, | 193 | const char *label, |
179 | const char *color_name) | 194 | const char *color_name) |
180 | { | 195 | { |
@@ -188,6 +203,7 @@ gtk_statistics_add_line (GtkStatistics *statistics, | |||
188 | priv->values = g_realloc (priv->values, | 203 | priv->values = g_realloc (priv->values, |
189 | sizeof (struct ValueHistory*) * (1 + priv->num_values)); | 204 | sizeof (struct ValueHistory*) * (1 + priv->num_values)); |
190 | priv->values[priv->num_values++] = vh = g_malloc (sizeof (struct ValueHistory)); | 205 | priv->values[priv->num_values++] = vh = g_malloc (sizeof (struct ValueHistory)); |
206 | vh->id = strdup (id); | ||
191 | vh->label = strdup (label); | 207 | vh->label = strdup (label); |
192 | vh->red = c.red / 65535.0; | 208 | vh->red = c.red / 65535.0; |
193 | vh->green = c.green / 65535.0; | 209 | vh->green = c.green / 65535.0; |
@@ -196,10 +212,16 @@ gtk_statistics_add_line (GtkStatistics *statistics, | |||
196 | 212 | ||
197 | 213 | ||
198 | /** | 214 | /** |
215 | * Add another value to a data series. | ||
216 | * | ||
217 | * @param statistics widget to update | ||
218 | * @param id identifier of the series | ||
219 | * @param x new x-value | ||
220 | * @param y new y-value | ||
199 | */ | 221 | */ |
200 | void | 222 | void |
201 | gtk_statistics_update_value (GtkStatistics *statistics, | 223 | gtk_statistics_update_value (GtkStatistics *statistics, |
202 | const char *label, | 224 | const char *id, |
203 | uint64_t x, | 225 | uint64_t x, |
204 | uint64_t y) | 226 | uint64_t y) |
205 | { | 227 | { |
@@ -213,14 +235,15 @@ gtk_statistics_update_value (GtkStatistics *statistics, | |||
213 | for (i=0;i<priv->num_values;i++) | 235 | for (i=0;i<priv->num_values;i++) |
214 | { | 236 | { |
215 | vh = priv->values[i]; | 237 | vh = priv->values[i]; |
216 | if (0 != strcmp (label, vh->label)) | 238 | if (0 != strcmp (id, vh->id)) |
217 | continue; | 239 | continue; |
240 | |||
218 | if (++vh->last_history_offset == MAX_HISTORY) | 241 | if (++vh->last_history_offset == MAX_HISTORY) |
219 | vh->last_history_offset = 0; | 242 | vh->last_history_offset = 0; |
220 | if (vh->history_size < MAX_HISTORY) | 243 | if (vh->history_size < MAX_HISTORY) |
221 | vh->history_size++; | 244 | vh->history_size++; |
222 | vh->history[vh->last_history_offset].x = x; | 245 | vh->history[vh->last_history_offset].x = x; |
223 | vh->history[vh->last_history_offset].y = y; | 246 | vh->history[vh->last_history_offset].y = y; |
224 | widget = GTK_WIDGET (statistics); | 247 | widget = GTK_WIDGET (statistics); |
225 | if (gtk_widget_is_drawable (widget)) | 248 | if (gtk_widget_is_drawable (widget)) |
226 | gtk_widget_queue_draw (widget); | 249 | gtk_widget_queue_draw (widget); |
@@ -228,11 +251,19 @@ gtk_statistics_update_value (GtkStatistics *statistics, | |||
228 | } | 251 | } |
229 | 252 | ||
230 | 253 | ||
254 | /** | ||
255 | * Convert a number to a nice label for the axis. | ||
256 | * | ||
257 | * @param num number to convert | ||
258 | * @param label where to store the string (must be big enough!) | ||
259 | */ | ||
231 | static void | 260 | static void |
232 | num_to_label (unsigned long long num, | 261 | num_to_label (unsigned long long num, |
233 | char *label) | 262 | char *label) |
234 | { | 263 | { |
235 | if (num > 1000LL * 1000 * 1000 * 3) | 264 | if (num > 1000LL * 1000 * 1000 * 1000 * 3) |
265 | sprintf (label, "%llu t", num / 1000LL / 1000LL / 1000LL / 1000LL); | ||
266 | else if (num > 1000LL * 1000 * 1000 * 3) | ||
236 | sprintf (label, "%llu g", num / 1000LL / 1000LL / 1000LL); | 267 | sprintf (label, "%llu g", num / 1000LL / 1000LL / 1000LL); |
237 | else if (num > 1000LL * 1000 * 3) | 268 | else if (num > 1000LL * 1000 * 3) |
238 | sprintf (label, "%llu m", num / 1000LL / 1000LL); | 269 | sprintf (label, "%llu m", num / 1000LL / 1000LL); |
@@ -243,6 +274,12 @@ num_to_label (unsigned long long num, | |||
243 | } | 274 | } |
244 | 275 | ||
245 | 276 | ||
277 | /** | ||
278 | * Draw the statistics widget. | ||
279 | * | ||
280 | * @param widget widget to draw | ||
281 | * @param cr drawing context | ||
282 | */ | ||
246 | static gboolean | 283 | static gboolean |
247 | gtk_statistics_draw (GtkWidget *widget, | 284 | gtk_statistics_draw (GtkWidget *widget, |
248 | cairo_t *cr) | 285 | cairo_t *cr) |
@@ -264,6 +301,7 @@ gtk_statistics_draw (GtkWidget *widget, | |||
264 | cairo_text_extents_t tey_max; | 301 | cairo_text_extents_t tey_max; |
265 | double rx; | 302 | double rx; |
266 | double ry; | 303 | double ry; |
304 | unsigned int h; | ||
267 | 305 | ||
268 | /* collect basic data */ | 306 | /* collect basic data */ |
269 | xmin = UINT64_MAX; | 307 | xmin = UINT64_MAX; |
@@ -292,7 +330,7 @@ gtk_statistics_draw (GtkWidget *widget, | |||
292 | cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); | 330 | cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); |
293 | cairo_paint(cr); | 331 | cairo_paint(cr); |
294 | 332 | ||
295 | if (0 == priv->num_values) | 333 | if ( (0 == priv->num_values) || (ymax == 0) ) |
296 | return FALSE; /* done */ | 334 | return FALSE; /* done */ |
297 | /* select font */ | 335 | /* select font */ |
298 | cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); | 336 | cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); |
@@ -379,10 +417,26 @@ gtk_statistics_draw (GtkWidget *widget, | |||
379 | 417 | ||
380 | /* finally, plot lines */ | 418 | /* finally, plot lines */ |
381 | cairo_set_line_width (cr, 2.0); | 419 | cairo_set_line_width (cr, 2.0); |
420 | |||
421 | cairo_set_font_size (cr, | ||
422 | GNUNET_MIN (20, (height - 3.0 * BORDER - tex_max.height - tey_max.height / 2) / (priv->num_values + 1))); | ||
423 | |||
424 | h = 2.0 * BORDER + tey_max.height / 2; | ||
425 | |||
382 | for (i=0;i<priv->num_values;i++) | 426 | for (i=0;i<priv->num_values;i++) |
383 | { | 427 | { |
384 | vh = priv->values[i]; | 428 | vh = priv->values[i]; |
385 | cairo_set_source_rgb(cr, vh->red, vh->green, vh->blue); | 429 | cairo_set_source_rgb(cr, vh->red, vh->green, vh->blue); |
430 | cairo_text_extents (cr, vh->label, &te); | ||
431 | h += te.height / 2; | ||
432 | cairo_move_to (cr, | ||
433 | 3.0 * BORDER + tey_max.width, | ||
434 | h); | ||
435 | h += te.height / 2 + 1.0; | ||
436 | cairo_show_text (cr, vh->label); | ||
437 | if (xmax == xmin) | ||
438 | continue; | ||
439 | |||
386 | for (j=0;j<vh->history_size;j++) | 440 | for (j=0;j<vh->history_size;j++) |
387 | { | 441 | { |
388 | hv = &vh->history[(vh->last_history_offset - j + MAX_HISTORY) % MAX_HISTORY]; | 442 | hv = &vh->history[(vh->last_history_offset - j + MAX_HISTORY) % MAX_HISTORY]; |
@@ -391,14 +445,15 @@ gtk_statistics_draw (GtkWidget *widget, | |||
391 | 445 | ||
392 | rx = tey_max.width + BORDER * 2.0 + (rx * (width - BORDER * 3.0 - tey_max.width - tex_max.width / 2.0)); | 446 | 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); | 447 | ry = BORDER + tex_max.height / 2.0 + (1.0 - ry) * (height - BORDER * 2.0 - tey_max.height - tex_max.height); |
394 | if (j == 0) | 448 | |
395 | { | 449 | /* if y-values are small, offset y-values a bit to allow overlapping curves to still show up */ |
396 | cairo_move_to (cr, rx, ry); | 450 | if (ymax < height / (priv->num_values * 4)) |
397 | } | 451 | ry += priv->num_values * 2 - (4 * i); |
398 | else | 452 | if (j == 0) |
399 | { | 453 | cairo_move_to (cr, |
400 | cairo_line_to (cr, rx, ry); | 454 | width - BORDER - tex_max.width / 2.0, |
401 | } | 455 | ry); |
456 | cairo_line_to (cr, rx, ry); | ||
402 | } | 457 | } |
403 | cairo_stroke (cr); | 458 | cairo_stroke (cr); |
404 | } | 459 | } |
@@ -406,6 +461,11 @@ gtk_statistics_draw (GtkWidget *widget, | |||
406 | } | 461 | } |
407 | 462 | ||
408 | 463 | ||
464 | /** | ||
465 | * Free memory used by statistics object. | ||
466 | * | ||
467 | * @param object object to release | ||
468 | */ | ||
409 | static void | 469 | static void |
410 | gtk_statistics_finalize (GObject *object) | 470 | gtk_statistics_finalize (GObject *object) |
411 | { | 471 | { |
@@ -416,6 +476,7 @@ gtk_statistics_finalize (GObject *object) | |||
416 | for (i=0;i<priv->num_values;i++) | 476 | for (i=0;i<priv->num_values;i++) |
417 | { | 477 | { |
418 | g_free (priv->values[i]->label); | 478 | g_free (priv->values[i]->label); |
479 | g_free (priv->values[i]->id); | ||
419 | g_free (priv->values[i]); | 480 | g_free (priv->values[i]); |
420 | } | 481 | } |
421 | g_free (priv->values); | 482 | g_free (priv->values); |