/* 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 <trow@gnu.org> and
* Havoc Pennington <hp@pobox.com>.
*
* 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 <config.h>
#include <guppi-useful.h>
#include <guppi-seq-scalar-core.h>
#include <guppi-seq-string-core.h>
#include <guppi-color-palette.h>
#include <guppi-group-state.h>
#include <guppi-group-view.h>
#include <guppi-group-view-layout.h>
#include <guppi-canvas-group.h>
#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 $ */
syntax highlighted by Code2HTML, v. 0.9.1