/* This is -*- C -*- */
/* $Id: guppi-axis-item.c,v 1.37 2002/01/20 05:21:09 trow Exp $ */
/*
* guppi-axis-item.c
*
* Copyright (C) 2000 EMC Capital Management, Inc.
* Copyright (C) 2001 Free Software Foundation, Inc.
*
* 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-axis-item.h"
#include <guppi-useful.h>
#include <guppi-alpha-template.h>
#include <guppi-seq-scalar.h>
#include <guppi-basic-tools.h>
#include "guppi-axis-view.h"
#include "guppi-axis-state.h"
static GtkObjectClass *parent_class = NULL;
static void
guppi_axis_item_destroy (GtkObject *obj)
{
if (parent_class->destroy)
parent_class->destroy (obj);
}
static void
guppi_axis_item_finalize (GtkObject *obj)
{
GuppiAxisItem *item = GUPPI_AXIS_ITEM (obj);
GList *iter;
if (item->label_list) {
iter = item->label_list;
while (iter != NULL) {
guppi_unref (iter->data);
iter = g_list_next (iter);
}
}
guppi_unref0 (item->legend_text);
if (parent_class->finalize)
parent_class->finalize (obj);
}
/**************************************************************************/
static void
prepare_legend (GuppiCanvasItem *gci)
{
GuppiAxisState *state;
GuppiAxisItem *item;
GnomeFont *font;
gint pos;
double rot;
gchar *txt;
double sc;
GuppiTextBlock *legend_block;
g_return_if_fail (gci != NULL);
state = GUPPI_AXIS_STATE (guppi_canvas_item_state (gci));
item = GUPPI_AXIS_ITEM (gci);
sc = guppi_canvas_item_scale (gci);
txt = guppi_axis_state_displayed_legend (state);
if (txt == NULL) {
guppi_unref0 (item->legend_text);
return;
}
if (item->legend_text == NULL)
item->legend_text = guppi_raster_text_new (NULL);
legend_block = guppi_raster_text_block (item->legend_text);
guppi_element_state_get (GUPPI_ELEMENT_STATE (state),
"position", &pos,
"legend_font", &font,
NULL);
rot = 0;
if (pos == GUPPI_WEST)
rot = -90;
else if (pos == GUPPI_EAST)
rot = +90;
guppi_text_block_set_angle (legend_block, rot);
guppi_text_block_set_text (legend_block, txt);
guppi_text_block_set_font (legend_block, font);
guppi_raster_text_set_scale (item->legend_text, sc);
guppi_free (txt);
guppi_unref (font);
}
static void
prepare_labels (GuppiCanvasItem *gci)
{
GuppiAxisMarkers *marks;
GuppiAxisItem *item;
GuppiAxisState *state;
GuppiElementView *view;
GList *iter;
GList *new_list;
gint i, N, pos;
double sc, size, span, rot = 0;
gboolean rotate_labels, shrink_to_fit;
g_return_if_fail (gci != NULL);
item = GUPPI_AXIS_ITEM (gci);
state = GUPPI_AXIS_STATE (guppi_canvas_item_state (gci));
view = guppi_canvas_item_view (gci);
sc = guppi_canvas_item_scale (gci);
guppi_element_state_get (GUPPI_ELEMENT_STATE (state),
"position", &pos,
"rotate_labels", &rotate_labels,
"shrink_labels_to_fit", &shrink_to_fit,
NULL);
if (pos == GUPPI_NORTH || pos == GUPPI_SOUTH) {
marks = guppi_element_view_axis_markers (view, GUPPI_X_AXIS);
if (rotate_labels)
rot = -90;
span = guppi_geometry_height (guppi_element_view_geometry (view));
} else {
marks = guppi_element_view_axis_markers (view, GUPPI_Y_AXIS);
if (rotate_labels)
rot = -90;
span = guppi_geometry_width (guppi_element_view_geometry (view));
}
if (marks == NULL)
return;
if (shrink_to_fit) {
item->label_scale = guppi_axis_view_label_shrink_to_fit_factor ((GuppiAxisView *) view, marks);
} else {
item->label_scale = 1.0;
}
N = guppi_axis_markers_size (marks);
new_list = NULL;
for (i = 0; i < N; ++i) {
const GuppiTick *tick;
GnomeFont *font = NULL;
gboolean shown = FALSE;
tick = guppi_axis_markers_get (marks, i);
if (tick != NULL)
guppi_axis_view_tick_properties (GUPPI_AXIS_VIEW (view), tick, item->label_scale,
NULL, NULL, NULL, NULL,
&shown, NULL, NULL, &font);
if (shown && tick->label) {
GuppiRasterText *raster_text = NULL;
/* We attempt to re-use our previous text rasterizations. */
/* (This crappy linear search is ugly, but mostly harmless) */
iter = item->label_list;
while (iter != NULL && raster_text == NULL) {
if (iter->data) {
GuppiRasterText *rt = GUPPI_RASTER_TEXT (iter->data);
GuppiTextBlock *block = guppi_raster_text_block (rt);
gchar *txt = guppi_text_block_text (block);
if (txt && !strcmp (tick->label, txt)) {
raster_text = rt;
iter->data = NULL;
}
guppi_free (txt);
}
iter = g_list_next (iter);
}
size = sc * item->label_scale;
/* If we didn't find anything to re-use, create a clean slate. */
if (raster_text == NULL && font != NULL) {
GuppiTextBlock *block;
raster_text = guppi_raster_text_new (NULL);
block = guppi_raster_text_block (raster_text);
guppi_text_block_set_text (block, guppi_tick_label (tick));
guppi_text_block_set_font (block, font);
guppi_text_block_set_angle (block, rot);
}
if (size > 0)
guppi_raster_text_set_scale (raster_text, size);
gtk_object_set_user_data (GTK_OBJECT (raster_text), (gpointer)tick);
new_list = g_list_append (new_list, raster_text);
}
}
/* Clean up the old list and replace it with the new one. */
iter = item->label_list;
while (iter != NULL) {
guppi_unref (iter->data);
iter = g_list_next (iter);
}
g_list_free (item->label_list);
item->label_list = new_list;
}
static void
update (GuppiCanvasItem *gci, double aff[6], ArtSVP *svp, gint flags)
{
prepare_legend (gci);
prepare_labels (gci);
}
static void
render (GuppiCanvasItem *gci, GnomeCanvasBuf *buf)
{
GuppiAxisItem *axi = GUPPI_AXIS_ITEM (gci);
GuppiElementView *view = guppi_canvas_item_view (gci);
GuppiAxisState *state = GUPPI_AXIS_STATE (guppi_canvas_item_state (gci));
double sc = guppi_canvas_item_scale (gci);
gint cx0, cy0, cx1, cy1;
double x0 = 0, y0 = 0, x1 = 0, y1 = 0;
gint pos;
gboolean horizontal, show_edge;
double edge_thickness;
guint32 edge_color, legend_color;
guppi_canvas_item_get_bbox_c (gci, &cx0, &cy0, &cx1, &cy1);
guppi_element_state_get (GUPPI_ELEMENT_STATE (state),
"position", &pos,
"show_edge", &show_edge,
"edge_thickness", &edge_thickness,
"edge_color", &edge_color,
"legend_color", &legend_color,
NULL);
horizontal = pos == GUPPI_NORTH || pos == GUPPI_SOUTH;
/* First, paint the edge (if necessary) */
if (show_edge && edge_thickness > 0) {
double t;
t = edge_thickness * sc;
if (horizontal) {
t = guppi_y_pt2px (t);
} else {
t = guppi_x_pt2px (t);
}
switch (pos) {
case GUPPI_NORTH:
x0 = cx0;
x1 = cx1;
y0 = cy1 - t;
y1 = cy1;
break;
case GUPPI_SOUTH:
x0 = cx0;
x1 = cx1;
y0 = cy0;
y1 = cy0 + t;
break;
case GUPPI_WEST:
x0 = cx1;
x1 = cx1 - t;
y0 = cy0;
y1 = cy1;
break;
case GUPPI_EAST:
x0 = cx0;
x1 = cx0 + t;
y0 = cy0;
y1 = cy1;
break;
default:
g_assert_not_reached ();
}
guppi_paint_sharp_box (buf, x0, y0, x1, y1, edge_color);
}
/* Next, paint the legend (if necessary) */
if (axi->legend_text != NULL) {
double lx = 0, ly = 0;
double w, h;
guint r, g, b, a;
w = guppi_raster_text_template (axi->legend_text)->width;
h = guppi_raster_text_template (axi->legend_text)->height;
switch (pos) {
case GUPPI_NORTH:
lx = (cx0 + cx1) / 2 - w / 2;
ly = cy0;
break;
case GUPPI_SOUTH:
lx = (cx0 + cx1) / 2 - w / 2;
ly = cy1 - h;
break;
case GUPPI_WEST:
lx = cx0;
ly = (cy0 + cy1) / 2 - h / 2;
break;
case GUPPI_EAST:
lx = cx1 - w;
ly = (cy0 + cy1) / 2 - h / 2;
break;
default:
g_assert_not_reached ();
}
UINT_TO_RGBA (legend_color, &r, &g, &b, &a);
guppi_alpha_template_print (guppi_raster_text_template (axi->legend_text),
lx, ly, r, g, b, a, buf);
}
/* Next, paint the markers (again, if necessary) */
{
GuppiAxisMarkers *marks = NULL;
marks = guppi_element_view_axis_markers (view, horizontal ? GUPPI_X_AXIS : GUPPI_Y_AXIS);
if (marks) {
gint i, N;
GList *label_iter;
N = guppi_axis_markers_size (marks);
/* label_iter = axi->label_list; */
for (i = 0; i < N; ++i) {
const GuppiTick *tick = guppi_axis_markers_get (marks, i);
double tick_pos = tick->position, pos_c = 0;
gboolean show = FALSE, show_label = FALSE;
double length = 0, thick = 0, label_offset = 0;
guint32 tick_color = 0, label_color = 0;
GnomeFont *font = NULL;
guppi_axis_view_tick_properties (GUPPI_AXIS_VIEW (view), tick, axi->label_scale,
&show, &tick_color, &thick, &length,
&show_label, &label_offset,
&label_color, &font);
if (show || show_label) {
if (horizontal)
guppi_canvas_item_vp2c_d (gci, tick_pos, 0, &pos_c, NULL);
else
guppi_canvas_item_vp2c_d (gci, 0, tick_pos, NULL, &pos_c);
}
/* Paint tick */
if (show && length > 0 && thick > 0) {
label_offset += length;
if (horizontal) {
length = guppi_y_pt2px (length);
thick = guppi_x_pt2px (thick);
} else {
length = guppi_x_pt2px (length);
thick = guppi_y_pt2px (thick);
}
length *= sc;
thick *= sc;
switch (pos) {
case GUPPI_NORTH:
x0 = pos_c - thick / 2;
x1 = pos_c + thick / 2;
y0 = cy1 - length;
y1 = cy1;
break;
case GUPPI_SOUTH:
x0 = pos_c - thick / 2;
x1 = pos_c + thick / 2;
y0 = cy0;
y1 = cy0 + length;
break;
case GUPPI_WEST:
x0 = cx1 - length;
x1 = cx1;
y0 = pos_c - thick / 2;
y1 = pos_c + thick / 2;
break;
case GUPPI_EAST:
x0 = cx0;
x1 = cx0 + length;
y0 = pos_c - thick / 2;
y1 = pos_c + thick / 2;
break;
default:
g_assert_not_reached ();
}
guppi_paint_sharp_box (buf, x0, y0, x1, y1, tick_color);
}
/* Paint label */
if (show_label && font != NULL) {
GuppiRasterText *raster_text = NULL;
gint xl = 0, yl = 0;
guint r, g, b, a;
label_offset *= sc;
label_iter = axi->label_list;
while (label_iter != NULL && raster_text == NULL) {
GuppiRasterText *rt = GUPPI_RASTER_TEXT (label_iter->data);
if (gtk_object_get_user_data (GTK_OBJECT (rt)) == (gpointer) tick)
raster_text = rt;
label_iter = g_list_next (label_iter);
}
if (raster_text) {
gboolean print_template = TRUE;
GuppiAlphaTemplate *template;
template = guppi_raster_text_template (raster_text);
/* template can be NULL if we try to rasterize the empty string */
if (template) {
switch (pos) {
case GUPPI_NORTH:
xl = pos_c - template->width / 2;
yl = cy1 - guppi_y_pt2px (label_offset) - template->height;
break;
case GUPPI_SOUTH:
xl = pos_c - template->width / 2;
yl = cy0 + guppi_y_pt2px (label_offset);
break;
case GUPPI_WEST:
xl = cx1 - guppi_x_pt2px (label_offset) - template->width;
yl = pos_c - template->height / 2;
break;
case GUPPI_EAST:
xl = cx0 + guppi_x_pt2px (label_offset);
yl = pos_c - template->height / 2;
break;
default:
g_assert_not_reached ();
}
UINT_TO_RGBA (label_color, &r, &g, &b, &a);
if (print_template)
guppi_alpha_template_print (template, xl, yl,
r, g, b, a, buf);
}
}
}
}
}
}
}
static gboolean
data_drop (GuppiCanvasItem *gci, GuppiData *data)
{
if (data == NULL || GUPPI_IS_SEQ_SCALAR (data)) {
guppi_element_state_set (guppi_canvas_item_state (gci),
"data", data,
NULL);
return TRUE;
}
return FALSE;
}
/**************************************************************************/
static GuppiPlotToolkit *
guppi_axis_toolkit_default (void)
{
GuppiPlotToolkit *tk = guppi_plot_toolkit_new (_("Default"));
guppi_plot_toolkit_set_button_tool (tk, 1, 0,
guppi_basic_tool_new_rescale (0.9));
guppi_plot_toolkit_set_button_tool (tk, 2, 0, guppi_basic_tool_new_drag ());
guppi_plot_toolkit_set_button_tool (tk, 3, 0,
guppi_basic_tool_new_rescale (1 / 0.9));
guppi_add_keyboard_navigation_to_toolkit (tk);
return tk;
}
static void
guppi_axis_item_class_init (GuppiAxisItemClass *klass)
{
GtkObjectClass *object_class = (GtkObjectClass *) klass;
GuppiCanvasItemClass *gci_class = GUPPI_CANVAS_ITEM_CLASS (klass);
parent_class = gtk_type_class (GUPPI_TYPE_CANVAS_ITEM);
object_class->destroy = guppi_axis_item_destroy;
object_class->finalize = guppi_axis_item_finalize;
gci_class->guppi_update = update;
gci_class->guppi_render = render;
gci_class->data_drop = data_drop;
gci_class->uses_vp_coordinates = TRUE;
guppi_canvas_item_class_set_item_class_toolkit (gci_class, guppi_axis_toolkit_default ());
}
static void
guppi_axis_item_init (GuppiAxisItem *obj)
{
}
GtkType guppi_axis_item_get_type (void)
{
static GtkType guppi_axis_item_type = 0;
if (!guppi_axis_item_type) {
static const GtkTypeInfo guppi_axis_item_info = {
"GuppiAxisItem",
sizeof (GuppiAxisItem),
sizeof (GuppiAxisItemClass),
(GtkClassInitFunc) guppi_axis_item_class_init,
(GtkObjectInitFunc) guppi_axis_item_init,
NULL, NULL, (GtkClassInitFunc) NULL
};
guppi_axis_item_type = gtk_type_unique (GUPPI_TYPE_CANVAS_ITEM,
&guppi_axis_item_info);
}
return guppi_axis_item_type;
}
/* $Id: guppi-axis-item.c,v 1.37 2002/01/20 05:21:09 trow Exp $ */
syntax highlighted by Code2HTML, v. 0.9.1