/* uber-heat-map.c * * Copyright (C) 2010 Christian Hergert * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "uber-heat-map.h" #include "g-ring.h" /** * SECTION:uber-heat-map.h * @title: UberHeatMap * @short_description: * * Section overview. */ G_DEFINE_TYPE(UberHeatMap, uber_heat_map, UBER_TYPE_GRAPH) struct _UberHeatMapPrivate { GRing *raw_data; gboolean fg_color_set; GdkRGBA fg_color; UberHeatMapFunc func; GDestroyNotify func_destroy; gpointer func_user_data; }; /** * uber_heat_map_new: * * Creates a new instance of #UberHeatMap. * * Returns: the newly created instance of #UberHeatMap. * Side effects: None. */ GtkWidget* uber_heat_map_new (void) { UberHeatMap *map; map = g_object_new(UBER_TYPE_HEAT_MAP, NULL); return GTK_WIDGET(map); } /** * uber_heat_map_destroy_array: * @array: A #GArray. * * XXX * * Returns: None. * Side effects: None. */ static void uber_heat_map_destroy_array (gpointer data) /* IN */ { GArray **ar = data; if (ar) { g_array_unref(*ar); } } /** * uber_heat_map_set_stride: * @graph: A #UberGraph. * * XXX * * Returns: None. * Side effects: None. */ static void uber_heat_map_set_stride (UberGraph *graph, /* IN */ guint stride) /* IN */ { UberHeatMapPrivate *priv; g_return_if_fail(UBER_IS_HEAT_MAP(graph)); priv = UBER_HEAT_MAP(graph)->priv; if (priv->raw_data) { g_ring_unref(priv->raw_data); } priv->raw_data = g_ring_sized_new(sizeof(GArray*), stride, uber_heat_map_destroy_array); } /** * uber_heat_map_set_data_func: * @map: A #UberHeatMap. * * XXX * * Returns: None. * Side effects: None. */ void uber_heat_map_set_data_func (UberHeatMap *map, /* IN */ UberHeatMapFunc func, /* IN */ gpointer user_data, /* IN */ GDestroyNotify destroy) /* IN */ { UberHeatMapPrivate *priv; g_return_if_fail(UBER_IS_HEAT_MAP(map)); priv = map->priv; if (priv->func_destroy) { priv->func_destroy(priv->func_user_data); } priv->func = func; priv->func_destroy = destroy; priv->func_user_data = user_data; } /** * uber_heat_map_render: * @graph: A #UberGraph. * * XXX * * Returns: None. * Side effects: None. */ static void uber_heat_map_render (UberGraph *graph, /* IN */ cairo_t *cr, /* IN */ GdkRectangle *area, /* IN */ guint epoch, /* IN */ gfloat each) /* IN */ { #if 0 UberGraphPrivate *priv; cairo_pattern_t *cp; g_return_if_fail(UBER_IS_HEAT_MAP(graph)); priv = graph->priv; /* * XXX: Temporarily draw a nice little gradient to test sliding. */ cp = cairo_pattern_create_linear(0, 0, area->width, 0); cairo_pattern_add_color_stop_rgb(cp, 0, .1, .1, .1); cairo_pattern_add_color_stop_rgb(cp, .2, .3, .3, .5); cairo_pattern_add_color_stop_rgb(cp, .4, .2, .7, .4); cairo_pattern_add_color_stop_rgb(cp, .7, .6, .2, .1); cairo_pattern_add_color_stop_rgb(cp, .8, .6, .8, .1); cairo_pattern_add_color_stop_rgb(cp, 1., .3, .8, .5); gdk_cairo_rectangle(cr, area); cairo_set_source(cr, cp); cairo_fill(cr); cairo_pattern_destroy(cp); #endif } /** * uber_heat_map_render_fast: * @graph: A #UberGraph. * * XXX * * Returns: None. * Side effects: None. */ static void uber_heat_map_render_fast (UberGraph *graph, /* IN */ cairo_t *cr, /* IN */ GdkRectangle *area, /* IN */ guint epoch, /* IN */ gfloat each) /* IN */ { UberHeatMapPrivate *priv; GtkStyleContext *style; GdkRGBA color; gfloat height; gint i; g_return_if_fail(UBER_IS_HEAT_MAP(graph)); priv = UBER_HEAT_MAP(graph)->priv; color = priv->fg_color; if (!priv->fg_color_set) { style = gtk_widget_get_style_context(GTK_WIDGET(graph)); gtk_style_context_get_color(style, GTK_STATE_FLAG_SELECTED, &color); } /* * XXX: Temporarily draw nice little squares. */ #define COUNT 10 height = area->height / (gfloat)COUNT; for (i = 0; i < COUNT; i++) { cairo_rectangle(cr, area->x + area->width - each, area->y + (i * height), each, height); cairo_set_source_rgba(cr, color.red, color.green, color.blue, g_random_double_range(0., 1.)); cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); cairo_fill(cr); } } /** * uber_heat_map_get_next_data: * @graph: A #UberGraph. * * Retrieve the next data point for the graph. * * Returns: None. * Side effects: None. */ static gboolean uber_heat_map_get_next_data (UberGraph *graph) /* IN */ { UberHeatMapPrivate *priv; GArray *array = NULL; g_return_val_if_fail(UBER_IS_HEAT_MAP(graph), FALSE); priv = UBER_HEAT_MAP(graph)->priv; if (!priv->func) { return FALSE; } /* * Retrieve the next data point. */ if (!priv->func(UBER_HEAT_MAP(graph), &array, priv->func_user_data)) { return FALSE; } /* * Store data points. */ g_ring_append_val(priv->raw_data, array); // for (int i = 0; i < array->len; i++) { // g_print("==> %f\n", g_array_index(array, gdouble, i)); // } return TRUE; } /** * uber_heat_map_set_fg_color: * @map: A #UberHeatMap. * * XXX * * Returns: None. * Side effects: None. */ void uber_heat_map_set_fg_color (UberHeatMap *map, /* IN */ const GdkRGBA *color) /* IN */ { UberHeatMapPrivate *priv; g_return_if_fail(UBER_IS_HEAT_MAP(map)); priv = map->priv; if (!color) { priv->fg_color_set = FALSE; memset(&priv->fg_color, 0, sizeof(priv->fg_color)); } else { priv->fg_color = *color; priv->fg_color_set = TRUE; } } /** * uber_heat_map_finalize: * @object: A #UberHeatMap. * * Finalizer for a #UberHeatMap instance. Frees any resources held by * the instance. * * Returns: None. * Side effects: None. */ static void uber_heat_map_finalize (GObject *object) /* IN */ { G_OBJECT_CLASS(uber_heat_map_parent_class)->finalize(object); } /** * uber_heat_map_class_init: * @klass: A #UberHeatMapClass. * * Initializes the #UberHeatMapClass and prepares the vtable. * * Returns: None. * Side effects: None. */ static void uber_heat_map_class_init (UberHeatMapClass *klass) /* IN */ { GObjectClass *object_class; UberGraphClass *graph_class; object_class = G_OBJECT_CLASS(klass); object_class->finalize = uber_heat_map_finalize; g_type_class_add_private(object_class, sizeof(UberHeatMapPrivate)); graph_class = UBER_GRAPH_CLASS(klass); graph_class->render = uber_heat_map_render; graph_class->render_fast = uber_heat_map_render_fast; graph_class->set_stride = uber_heat_map_set_stride; graph_class->get_next_data = uber_heat_map_get_next_data; } /** * uber_heat_map_init: * @map: A #UberHeatMap. * * Initializes the newly created #UberHeatMap instance. * * Returns: None. * Side effects: None. */ static void uber_heat_map_init (UberHeatMap *map) /* IN */ { map->priv = G_TYPE_INSTANCE_GET_PRIVATE(map, UBER_TYPE_HEAT_MAP, UberHeatMapPrivate); }