/* 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 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 "guppi-axis-item.h" #include #include #include #include #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 $ */