/* This is -*- C -*- */ /* $Id: guppi-object-pie.c,v 1.3 2002/01/08 06:28:53 trow Exp $ */ /* * guppi-object-pie.c * * Copyright (C) 2000 EMC Capital Management, Inc. * Copyright (C) 2001 The Free Software Foundation * * Developed by Jon Trowbridge and * Havoc Pennington . * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #include #include #include #include #include #include #include #include #include #include "guppi-object-pie.h" static GtkObjectClass *parent_class = NULL; enum { ARG_0, ARG_DATA_SIZE, ARG_DATA, ARG_LABELS, ARG_COLORS, ARG_COLORS_RGB, ARG_RADIUS_SIZE, ARG_RADIUS_LOCK, ARG_RADIUS_MAXIMIZE, ARG_LEGEND_FONT, ARG_SLICE_CALLBACK1, ARG_SLICE_CALLBACK1_DATA, ARG_SLICE_CALLBACK1_NAME, ARG_SLICE_CALLBACK2, ARG_SLICE_CALLBACK2_DATA, ARG_SLICE_CALLBACK2_NAME, ARG_SLICE_CALLBACK3, ARG_SLICE_CALLBACK3_DATA, ARG_SLICE_CALLBACK3_NAME, ARG_LEGEND_CALLBACK1, ARG_LEGEND_CALLBACK1_DATA, ARG_LEGEND_CALLBACK1_NAME, ARG_LEGEND_CALLBACK2, ARG_LEGEND_CALLBACK2_DATA, ARG_LEGEND_CALLBACK2_NAME, ARG_LEGEND_CALLBACK3, ARG_LEGEND_CALLBACK3_DATA, ARG_LEGEND_CALLBACK3_NAME }; static void guppi_object_pie_set_arg (GtkObject *obj, GtkArg *arg, guint arg_id) { GuppiObjectPie *opie = GUPPI_OBJECT_PIE (obj); const gchar **ptr; gint i; switch (arg_id) { case ARG_DATA_SIZE: opie->data_size = GTK_VALUE_INT (*arg); if (opie->data_size <= 0) g_warning ("illegal data size: %d", opie->data_size); break; case ARG_DATA: if (opie->data_size <= 0) g_warning ("data: Illegal data size: %d", opie->data_size); else { guppi_free (opie->data); opie->data = guppi_new (double, opie->data_size); memcpy (opie->data, GTK_VALUE_POINTER (*arg), opie->data_size *sizeof (double)); } break; case ARG_LABELS: if (opie->data_size <= 0) g_warning ("labels: illegal data size: %d", opie->data_size); else { if (opie->labels) { for (i = 0; i < opie->data_size; ++i) guppi_free (opie->labels[i]); guppi_free (opie->labels); } ptr = (const gchar **) GTK_VALUE_POINTER (*arg); opie->labels = guppi_new (gchar *, opie->data_size); for (i = 0; i < opie->data_size; ++i) opie->labels[i] = guppi_strdup (ptr[i]); } break; case ARG_COLORS: if (opie->data_size <= 0) g_warning ("colors: illegal data size: %d", opie->data_size); else { if (opie->colors) { for (i = 0; i < opie->data_size; ++i) guppi_free (opie->colors[i]); guppi_free (opie->colors); } ptr = (const gchar **) GTK_VALUE_POINTER (*arg); opie->colors = guppi_new (gchar *, opie->data_size); for (i = 0; i < opie->data_size; ++i) opie->colors[i] = guppi_strdup (ptr[i]); } break; case ARG_COLORS_RGB: if (opie->data_size <= 0) g_warning ("colors_rgb: Illegal data size: %d", opie->data_size); else { guppi_free (opie->colors_rgb); opie->colors_rgb = guppi_new (guint32, opie->data_size); memcpy (opie->colors_rgb, GTK_VALUE_POINTER (*arg), opie->data_size * sizeof (guint32)); } break; case ARG_RADIUS_SIZE: opie->radius_size = GTK_VALUE_DOUBLE (*arg); break; case ARG_RADIUS_MAXIMIZE: opie->radius_maximize = GTK_VALUE_BOOL (*arg); break; case ARG_RADIUS_LOCK: opie->radius_lock = GTK_VALUE_BOOL (*arg); break; case ARG_LEGEND_FONT: guppi_refcounting_assign (opie->legend_font, GNOME_FONT (GTK_VALUE_POINTER (*arg))); break; case ARG_SLICE_CALLBACK1: opie->slice_callback1 = (void (*)(gint, gpointer)) GTK_VALUE_POINTER (*arg); break; case ARG_SLICE_CALLBACK1_DATA: opie->slice_callback1_data = GTK_VALUE_POINTER (*arg); break; case ARG_SLICE_CALLBACK1_NAME: opie->slice_callback1_name = guppi_strdup (GTK_VALUE_POINTER (*arg)); break; case ARG_SLICE_CALLBACK2: opie->slice_callback2 = (void (*)(gint, gpointer)) GTK_VALUE_POINTER (*arg); break; case ARG_SLICE_CALLBACK2_DATA: opie->slice_callback2_data = GTK_VALUE_POINTER (*arg); break; case ARG_SLICE_CALLBACK2_NAME: opie->slice_callback2_name = guppi_strdup (GTK_VALUE_POINTER (*arg)); break; case ARG_SLICE_CALLBACK3: opie->slice_callback3 = (void (*)(gint, gpointer)) GTK_VALUE_POINTER (*arg); break; case ARG_SLICE_CALLBACK3_DATA: opie->slice_callback3_data = GTK_VALUE_POINTER (*arg); break; case ARG_SLICE_CALLBACK3_NAME: opie->slice_callback3_name = guppi_strdup (GTK_VALUE_POINTER (*arg)); break; case ARG_LEGEND_CALLBACK1: opie->legend_callback1 = (void (*)(gint, gpointer)) GTK_VALUE_POINTER (*arg); break; case ARG_LEGEND_CALLBACK1_DATA: opie->legend_callback1_data = GTK_VALUE_POINTER (*arg); break; case ARG_LEGEND_CALLBACK1_NAME: opie->legend_callback1_name = guppi_strdup (GTK_VALUE_POINTER (*arg)); break; case ARG_LEGEND_CALLBACK2: opie->legend_callback2 = (void (*)(gint, gpointer)) GTK_VALUE_POINTER (*arg); break; case ARG_LEGEND_CALLBACK2_DATA: opie->legend_callback2_data = GTK_VALUE_POINTER (*arg); break; case ARG_LEGEND_CALLBACK2_NAME: opie->legend_callback2_name = guppi_strdup (GTK_VALUE_POINTER (*arg)); break; case ARG_LEGEND_CALLBACK3: opie->legend_callback3 = (void (*)(gint, gpointer)) GTK_VALUE_POINTER (*arg); break; case ARG_LEGEND_CALLBACK3_DATA: opie->legend_callback3_data = GTK_VALUE_POINTER (*arg); break; case ARG_LEGEND_CALLBACK3_NAME: opie->legend_callback3_name = guppi_strdup (GTK_VALUE_POINTER (*arg)); break; default: break; } } /***************************************************************************/ static void guppi_object_pie_destroy (GtkObject *obj) { if (parent_class->destroy) parent_class->destroy (obj); } static void guppi_object_pie_finalize (GtkObject *obj) { GuppiObjectPie *objpie = GUPPI_OBJECT_PIE (obj); gint i; guppi_free (objpie->data); if (objpie->labels) for (i = 0; i < objpie->data_size; ++i) guppi_free (objpie->labels[i]); guppi_free (objpie->labels); if (objpie->colors) for (i = 0; i < objpie->data_size; ++i) guppi_free (objpie->colors[i]); guppi_free (objpie->colors); guppi_free (objpie->colors_rgb); guppi_unref (objpie->legend_font); guppi_free (objpie->slice_callback1_name); guppi_free (objpie->slice_callback2_name); guppi_free (objpie->slice_callback3_name); guppi_free (objpie->legend_callback1_name); guppi_free (objpie->legend_callback2_name); guppi_free (objpie->legend_callback3_name); if (parent_class->finalize) parent_class->finalize (obj); } /***************************************************************************/ static GuppiSeqScalar * pie_build_data(GuppiObjectPie *opie) { GuppiSeqScalar *data; int i; data = GUPPI_SEQ_SCALAR (guppi_seq_scalar_core_new ()); for(i = 0; i < opie->data_size; i++) guppi_seq_scalar_append(data, opie->data[i]); return data; } static GuppiSeqString * pie_build_labels(GuppiObjectPie *opie) { GuppiSeqString *labels; int i; labels = GUPPI_SEQ_STRING (guppi_seq_string_core_new ()); for(i = 0; i < opie->data_size; i++) guppi_seq_string_append (labels, opie->labels[i]); return labels; } static GuppiColorPalette * pie_build_colors(GuppiObjectPie *opie) { GuppiColorPalette *palette; guint32 c; int i; palette = guppi_color_palette_new (); guppi_color_palette_set_custom (palette, opie->data_size, NULL); for(i = 0; i < opie->data_size; i++) { if (opie->colors_rgb) { c = RGB_TO_RGBA (opie->colors_rgb[i], 0xff); } else { c = guppi_str2color_rgba (opie->colors[i]); if(!c) g_message ("Unknown color: \"%s\"", opie->colors[i]); } guppi_color_palette_set (palette, i, c); } return palette; } static void update (GuppiObject *obj) { GuppiGroupView *grp_view; GuppiObjectPie *opie; GuppiSeqScalar *pie_data; GuppiSeqString *pie_labels = NULL; GuppiColorPalette *pie_colors = NULL; GuppiElementState *legend_state = NULL; GuppiElementState *pie_state = NULL; GnomeFont *font; g_return_if_fail (obj != NULL); g_return_if_fail (GUPPI_IS_OBJECT_PIE (obj)); opie = GUPPI_OBJECT_PIE (obj); grp_view = GUPPI_GROUP_VIEW (guppi_object_view (obj)); if (opie->data == NULL) { g_warning("No pie data specified."); return; } pie_state = guppi_element_view_state(opie->pie_view); guppi_ref (pie_state); /* FIXME: if the object now contains data for a lengend, but that legend wasn't constructed in build(), we may need to construct it here. Right now it dosen't do that. */ if (opie->legend_view) { legend_state = guppi_element_view_state (opie->legend_view); guppi_ref (legend_state); } pie_data = pie_build_data(opie); if (opie->labels) { pie_labels = pie_build_labels(opie); } if (opie->colors_rgb || opie->colors) { pie_colors = pie_build_colors(opie); } guppi_element_state_set (pie_state, "data", pie_data, "radius_maximize", opie->radius_maximize, "radius_lock", opie->radius_lock, "radius", opie->radius_size, "data_labels", pie_labels, "data_styles", pie_colors, NULL); guppi_element_state_changed(pie_state); if (legend_state) { font = opie->legend_font; if (font == NULL) font = guppi_default_font (); guppi_element_state_set (legend_state, "labels", pie_labels, "swatch_colors", pie_colors, "fallback_to_stock_colors", TRUE, "label_font::adopt", font, NULL); } guppi_unref (legend_state); guppi_unref (pie_state); guppi_unref (pie_data); guppi_unref (pie_labels); guppi_unref (pie_colors); } static gpointer build (GuppiObject *obj, double hsize, double vsize) { GuppiObjectPie *opie; GuppiElementState *grp_state; GuppiGroupView *grp_view; GnomeFont *font; GuppiSeqScalar *pie_data; GuppiSeqString *pie_labels = NULL; GuppiColorPalette *pie_colors = NULL; GuppiElementState *legend_state = NULL; GuppiElementState *pie_state; GuppiElementView *legend_view = NULL; GuppiElementView *pie_view; const double outer_margin = 3.6; const double inner_gap = 3.6; g_return_val_if_fail (obj != NULL, NULL); g_return_val_if_fail (GUPPI_IS_OBJECT_PIE (obj), NULL); opie = GUPPI_OBJECT_PIE (obj); if (opie->data == NULL) { g_warning ("No pie data specified."); return NULL; } /* Construct the group which will contain our item. */ grp_state = guppi_group_state_new (); grp_view = GUPPI_GROUP_VIEW (guppi_element_state_make_view (grp_state)); guppi_unref0 (grp_state); /* Copy our data into a GuppiSeqScalar */ pie_data = pie_build_data(opie); if (opie->labels) pie_labels = pie_build_labels(opie); if (opie->colors_rgb || opie->colors) pie_colors = pie_build_colors (opie); /* We should take the font size into account here. */ pie_state = guppi_element_state_new ("pie", "data", pie_data, "radius_maximize", opie->radius_maximize, "radius_lock", opie->radius_lock, "radius", opie->radius_size, "label_data", pie_labels, "slice_colors", pie_colors, NULL); pie_view = guppi_element_state_make_view (pie_state); if (pie_labels != NULL) { font = opie->legend_font; if (font == NULL) font = guppi_default_font (); legend_state = guppi_element_state_new ("legend", "labels", pie_labels, "swatch_colors", pie_colors, "label_font", font, NULL); legend_view = guppi_element_state_make_view (legend_state); } /* Lay out our plot */ guppi_group_view_layout_fill_vertically (grp_view, pie_view, outer_margin, outer_margin); guppi_group_view_layout_flush_left (grp_view, pie_view, outer_margin); if (legend_view) { guppi_group_view_layout_flush_right (grp_view, legend_view, outer_margin); guppi_group_view_layout_same_vertical_center (grp_view, legend_view, pie_view); guppi_group_view_layout_horizontally_adjacent (grp_view, pie_view, legend_view, inner_gap); } else { guppi_group_view_layout_flush_right (grp_view, pie_view, outer_margin); } /* Save our view objects */ opie->pie_view = pie_view; opie->legend_view = legend_view; /* Clean up */ guppi_unref (pie_data); guppi_unref (pie_labels); guppi_unref (pie_colors); guppi_unref (pie_state); guppi_unref (legend_state); return GUPPI_ELEMENT_VIEW (grp_view); } static void clicked_slice_cb (GuppiCanvasItem *item, gint slice, guint button, guint state, GuppiObjectPie *opie) { if (button == 1 && opie->slice_callback1) { opie->slice_callback1 (slice, opie->slice_callback1_data); } else if (button == 2 && opie->slice_callback2) { opie->slice_callback2 (slice, opie->slice_callback2_data); } else if (button == 3 && opie->slice_callback3) { opie->slice_callback3 (slice, opie->slice_callback3_data); } } static void clicked_box_cb (GuppiCanvasItem *item, gint box, guint button, guint state, GuppiObjectPie *opie) { if (button == 1 && opie->legend_callback1) { opie->legend_callback1 (box, opie->legend_callback1_data); } else if (button == 2 && opie->legend_callback2) { opie->legend_callback2 (box, opie->legend_callback2_data); } else if (button == 3 && opie->legend_callback3) { opie->legend_callback3 (box, opie->legend_callback3_data); } } static void item_init (GuppiObject *obj, GnomeCanvasItem *item) { GuppiObjectPie *pieobj = GUPPI_OBJECT_PIE (obj); GuppiCanvasGroup *grp_item = GUPPI_CANVAS_GROUP (item); GuppiCanvasItem *pie_item; GuppiCanvasItem *legend_item; pie_item = guppi_canvas_group_find_by_view (grp_item, pieobj->pie_view); legend_item = guppi_canvas_group_find_by_view (grp_item, pieobj->legend_view); if (pie_item) { gtk_signal_connect (GTK_OBJECT (pie_item), "clicked_slice", GTK_SIGNAL_FUNC (clicked_slice_cb), pieobj); } if (legend_item) { gtk_signal_connect (GTK_OBJECT (legend_item), "clicked_box", GTK_SIGNAL_FUNC (clicked_box_cb), pieobj); } } /***************************************************************************/ #define add_arg(str, t, symb) \ gtk_object_add_arg_type("GuppiObjectPie::" str, t, GTK_ARG_WRITABLE, symb) static void guppi_object_pie_class_init (GuppiObjectPieClass *klass) { GtkObjectClass *object_class = (GtkObjectClass *) klass; GuppiObjectClass *gobj_class = GUPPI_OBJECT_CLASS (klass); parent_class = gtk_type_class (GUPPI_TYPE_OBJECT); object_class->set_arg = guppi_object_pie_set_arg; object_class->destroy = guppi_object_pie_destroy; object_class->finalize = guppi_object_pie_finalize; gobj_class->build = build; gobj_class->item_init = item_init; gobj_class->update = update; add_arg ("data_size", GTK_TYPE_INT, ARG_DATA_SIZE); add_arg ("data", GTK_TYPE_POINTER, ARG_DATA); add_arg ("labels", GTK_TYPE_POINTER, ARG_LABELS); add_arg ("colors", GTK_TYPE_POINTER, ARG_COLORS); add_arg ("colors_rgb", GTK_TYPE_POINTER, ARG_COLORS_RGB); add_arg ("radius_size", GTK_TYPE_DOUBLE, ARG_RADIUS_SIZE); add_arg ("radius_maximize", GTK_TYPE_BOOL, ARG_RADIUS_MAXIMIZE); add_arg ("radius_lock", GTK_TYPE_BOOL, ARG_RADIUS_LOCK); add_arg ("legend_font", GTK_TYPE_POINTER, ARG_LEGEND_FONT); add_arg ("slice_callback1", GTK_TYPE_POINTER, ARG_SLICE_CALLBACK1); add_arg ("slice_callback1_data", GTK_TYPE_POINTER, ARG_SLICE_CALLBACK1_DATA); add_arg ("slice_callback1_name", GTK_TYPE_POINTER, ARG_SLICE_CALLBACK1_NAME); add_arg ("slice_callback2", GTK_TYPE_POINTER, ARG_SLICE_CALLBACK2); add_arg ("slice_callback2_data", GTK_TYPE_POINTER, ARG_SLICE_CALLBACK2_DATA); add_arg ("slice_callback2_name", GTK_TYPE_POINTER, ARG_SLICE_CALLBACK2_NAME); add_arg ("slice_callback3", GTK_TYPE_POINTER, ARG_SLICE_CALLBACK3); add_arg ("slice_callback3_data", GTK_TYPE_POINTER, ARG_SLICE_CALLBACK3_DATA); add_arg ("slice_callback3_name", GTK_TYPE_POINTER, ARG_SLICE_CALLBACK3_NAME); add_arg ("legend_callback1", GTK_TYPE_POINTER, ARG_LEGEND_CALLBACK1); add_arg ("legend_callback1_data", GTK_TYPE_POINTER, ARG_LEGEND_CALLBACK1_DATA); add_arg ("legend_callback1_name", GTK_TYPE_POINTER, ARG_LEGEND_CALLBACK1_NAME); add_arg ("legend_callback2", GTK_TYPE_POINTER, ARG_LEGEND_CALLBACK2); add_arg ("legend_callback2_data", GTK_TYPE_POINTER, ARG_LEGEND_CALLBACK2_DATA); add_arg ("legend_callback2_name", GTK_TYPE_POINTER, ARG_LEGEND_CALLBACK2_NAME); add_arg ("legend_callback3", GTK_TYPE_POINTER, ARG_LEGEND_CALLBACK3); add_arg ("legend_callback3_data", GTK_TYPE_POINTER, ARG_LEGEND_CALLBACK3_DATA); add_arg ("legend_callback3_name", GTK_TYPE_POINTER, ARG_LEGEND_CALLBACK3_NAME); } static void guppi_object_pie_init (GuppiObjectPie *obj) { obj->data_size = 0; obj->radius_maximize = TRUE; } GtkType guppi_object_pie_get_type (void) { static GtkType guppi_object_pie_type = 0; if (!guppi_object_pie_type) { static const GtkTypeInfo guppi_object_pie_info = { "GuppiObjectPie", sizeof (GuppiObjectPie), sizeof (GuppiObjectPieClass), (GtkClassInitFunc) guppi_object_pie_class_init, (GtkObjectInitFunc) guppi_object_pie_init, NULL, NULL, (GtkClassInitFunc) NULL }; guppi_object_pie_type = gtk_type_unique (GUPPI_TYPE_OBJECT, &guppi_object_pie_info); } return guppi_object_pie_type; } /* $Id: guppi-object-pie.c,v 1.3 2002/01/08 06:28:53 trow Exp $ */