static void gnm_so_path_copy (SheetObject *dst, SheetObject const *src) { GnmSOPath const *sop = GNM_SO_PATH (src); GnmSOPath *new_sop = GNM_SO_PATH (dst); g_object_unref (new_sop->style); new_sop->style = go_style_dup (sop->style); new_sop->x_offset = sop->x_offset; new_sop->y_offset = sop->y_offset; new_sop->width = sop->width; new_sop->height = sop->height; if (new_sop->path) { go_path_free (new_sop->path); new_sop->path = NULL; } else if (new_sop->paths) { g_ptr_array_unref (new_sop->paths); new_sop->paths = NULL; } if (sop->path) new_sop->path = go_path_ref (sop->path); else { unsigned i; new_sop->paths = g_ptr_array_new_full (sop->paths->len, (GDestroyNotify) go_path_free); for (i = 0; i < sop->paths->len; i++) g_ptr_array_add (new_sop->paths, go_path_ref (g_ptr_array_index (sop->paths, i))); } gnm_so_path_parent_class->copy (dst, src); }
static void gnm_so_path_finalize (GObject *object) { GnmSOPath *sop = GNM_SO_PATH (object); if (sop->path != NULL) go_path_free (sop->path); sop->path = NULL; if (sop->paths != NULL) g_ptr_array_unref (sop->paths); sop->paths = NULL; g_object_unref (sop->style); sop->style = NULL; sop->paths = NULL; g_free (sop->text); sop->text = NULL; if (NULL != sop->markup) { pango_attr_list_unref (sop->markup); sop->markup = NULL; } G_OBJECT_CLASS (gnm_so_path_parent_class)->finalize (object); }
static void gnm_so_path_prep_sax_parser (SheetObject *so, GsfXMLIn *xin, xmlChar const **attrs, G_GNUC_UNUSED GnmConventions const *convs) { static GsfXMLInNode const dtd[] = { GSF_XML_IN_NODE (SOPATH, SOPATH, -1, "SheetObjectPath", GSF_XML_NO_CONTENT, NULL, NULL), GSF_XML_IN_NODE (SOPATH, PATH, -1, "Path", GSF_XML_NO_CONTENT, &sop_sax_path, NULL), GSF_XML_IN_NODE (SOPATH, STYLE, -1, "Style", GSF_XML_NO_CONTENT, &sop_sax_style, NULL), GSF_XML_IN_NODE_END }; static GsfXMLInDoc *doc = NULL; GnmSOPath *sop = GNM_SO_PATH(so); if (NULL == doc) { doc = gsf_xml_in_doc_new (dtd, NULL); gnm_xml_in_doc_dispose_on_exit (&doc); } gsf_xml_in_push_state (xin, doc, NULL, NULL, attrs); for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) if (attr_eq (attrs[0], "Label")) g_object_set (G_OBJECT (sop), "text", attrs[1], NULL); else if (attr_eq (attrs[0], "LabelFormat")) { GOFormat * fmt = go_format_new_from_XL (attrs[1]); if (go_format_is_markup (fmt)) g_object_set (G_OBJECT (sop), "markup", go_format_get_markup (fmt), NULL); go_format_unref (fmt); } else if (attr_eq (attrs[0], "Path")) { GOPath *path = go_path_new_from_svg (attrs[1]); if (path) { g_object_set (G_OBJECT (sop), "path", path, NULL); go_path_free (path); } } }
static void gog_smoothed_curve_view_render (GogView *view, GogViewAllocation const *bbox) { GogSmoothedCurve *curve = GOG_SMOOTHED_CURVE (view->model); GogSeries *series = GOG_SERIES ((GOG_OBJECT (curve))->parent); GogPlot *plot = series->plot; GogChart *chart = GOG_CHART (GOG_OBJECT (plot)->parent); GogChartMap *chart_map; GOStyle *style; GOPath *path; if (curve->nb == 0 || curve->x == NULL || curve->y == NULL) return; chart_map = gog_chart_map_new (chart, &view->residual, plot->axis[GOG_AXIS_X], plot->axis[GOG_AXIS_Y], NULL, FALSE); if (!gog_chart_map_is_valid (chart_map)) { gog_chart_map_free (chart_map); return; } gog_renderer_push_clip_rectangle (view->renderer, view->residual.x, view->residual.y, view->residual.w, view->residual.h); path = gog_chart_map_make_path (chart_map, curve->x, curve->y, curve->nb, GO_LINE_INTERPOLATION_LINEAR, FALSE, NULL); style = GOG_STYLED_OBJECT (curve)->style; gog_renderer_push_style (view->renderer, style); gog_renderer_stroke_serie (view->renderer, path); gog_renderer_pop_style (view->renderer); go_path_free (path); gog_renderer_pop_clip (view->renderer); gog_chart_map_free (chart_map); }
static void gog_pie_view_render (GogView *view, GogViewAllocation const *bbox) { GogPiePlot const *model = GOG_PIE_PLOT (view->model); GogPieSeries const *series = NULL; double separated_cx, separated_cy, cx, cy, r, theta, len, *vals, scale; double default_sep; unsigned elem, k; GOPath *path; GogTheme *theme = gog_object_get_theme (GOG_OBJECT (model)); GOStyle *style, *white_style = NULL, *elt_style = NULL; GSList *ptr; unsigned num_series = 0; unsigned index; double center_radius; double center_size = 0.0; double r_ext, r_int, r_tot; double outline_width_max; gboolean has_hole; double separation_max, separation; GogPieSeriesElement *gpse; GList const *overrides; GogShowNegsMode mode = model->show_negatives; gboolean negative; /* compute number of valid series */ for (ptr = model->base.series ; ptr != NULL ; ptr = ptr->next) { series = ptr->data; if (!gog_series_is_valid (GOG_SERIES (ptr->data))) continue; num_series++; } if (num_series <= 0) return; separation_max = .0; outline_width_max = .0; if ((style = go_styled_object_get_style (GO_STYLED_OBJECT (series)))) outline_width_max = gog_renderer_line_size (view->renderer, style->line.width); if (mode == GOG_SHOW_NEGS_WHITE) { white_style = go_style_dup (style); white_style->fill.type = GO_STYLE_FILL_PATTERN; go_pattern_set_solid (&white_style->fill.pattern, GO_COLOR_WHITE); } for (overrides = gog_series_get_overrides (GOG_SERIES (series)); overrides != NULL; overrides = overrides->next) { separation = GOG_PIE_SERIES_ELEMENT (overrides->data)->separation; if (separation_max < separation) separation_max = separation; style = go_styled_object_get_style (GO_STYLED_OBJECT (overrides->data)); if (outline_width_max < style->line.width) outline_width_max = style->line.width; } if (separation_max < -model->default_separation) separation_max = -model->default_separation; if (GOG_IS_RING_PLOT (model)) center_size = GOG_RING_PLOT(model)->center_size; else if (num_series > 1) num_series = 1; /* calculate things when span < 100. */ if (model->span < 100.) { double xmin, xmax, ymin, ymax, ratio; double begin, cur, end; if (num_series == 1) { begin = (model->initial_angle + series->initial_angle) * M_PI / 180. - M_PI / 2.; end = begin + model->span * M_PI / 50.; } else { /* WARNING: this code has not been checked */ ptr = model->base.series; while (!gog_series_is_valid (GOG_SERIES (ptr->data))) ptr = ptr->next; series = ptr->data; begin = end = series->initial_angle; for (ptr = ptr->next; ptr != NULL; ptr = ptr->next) { if (!gog_series_is_valid (GOG_SERIES (ptr->data))) continue; series = ptr->data; cur = series->initial_angle; if (cur < begin) begin = cur; if (cur > end) end = cur; } begin = (model->initial_angle + begin) * M_PI / 180. - M_PI / 2.; end = ((model->initial_angle + end) / 180. + model->span / 50.) * M_PI - M_PI / 2.; } cur = ceil (begin / M_PI * 2 - 1e-10) * M_PI / 2; xmin = xmax = cos (begin); ymin = ymax = sin (begin); while (cur < end) { cx = cos (cur); cy = sin (cur); if (cx > xmax) xmax = cx; if (cx < xmin) xmin = cx; if (cy > ymax) ymax = cy; if (cy < ymin) ymin = cy; cur += M_PI / 2; } cx = cos (end); cy = sin (end); if (cx > xmax) xmax = cx; if (cx < xmin) xmin = cx; if (cy > ymax) ymax = cy; if (cy < ymin) ymin = cy; /* we ensure that the center will be visible */ if (xmin > 0.) xmin = 0.; if (xmax < 0.) xmax = 0.; if (ymin > 0.) ymin = 0.; if (ymax < 0.) ymax = 0.; ratio = (ymax - ymin) / (xmax - xmin); if (view->allocation.h > view->allocation.w * ratio) { r_tot = view->allocation.w * MAX (xmax, -xmin) / (xmax - xmin); cx = view->allocation.x - view->allocation.w * xmin / (xmax - xmin); cy = view->allocation.y + (view->allocation.h + view->allocation.w * ratio) / 2. - view->allocation.w * ratio * ymax / (ymax - ymin); } else { r_tot = view->allocation.h * MAX (ymax, -ymin) / (ymax - ymin); cx = view->allocation.x + (view->allocation.w - view->allocation.h / ratio) / 2. - view->allocation.h / ratio * xmin / (xmax - xmin); cy = view->allocation.y - view->allocation.h * ymin / (ymax - ymin); } r_tot /= 1. + model->default_separation + separation_max; } else { /* centre things */ cx = view->allocation.x + view->allocation.w/2.; cy = view->allocation.y + view->allocation.h/2.; r_tot = view->allocation.h; if (r_tot > view->allocation.w) r_tot = view->allocation.w; r_tot /= 2. * (1. + model->default_separation + separation_max); } path = go_path_new (); default_sep = r_tot * model->default_separation; center_radius = r_tot * center_size; r = r_tot * (1. - center_size); elem = model->base.index_num; index = 1; for (ptr = model->base.series ; ptr != NULL ; ptr = ptr->next) { series = ptr->data; if (!gog_series_is_valid (GOG_SERIES (series))) continue; if (index > num_series) /* people snuck extra series into a pie */ break; if (num_series == index) r -= outline_width_max / 2.0; has_hole = center_radius > 0. || index > 1; r_int = center_radius + r * ((double)index - 1.0) / (double)num_series; r_ext = center_radius + r * (double)index / (double)num_series; theta = (model->initial_angle + series->initial_angle) * M_PI / 180. - M_PI / 2.; scale = 2 * M_PI / 100 * model->span / series->total; vals = go_data_get_values (series->base.values[1].data); style = GOG_STYLED_OBJECT (series)->style; if (model->base.vary_style_by_element || mode == GOG_SHOW_NEGS_WHITE) style = go_style_dup (style); gog_renderer_push_style (view->renderer, style); overrides = gog_series_get_overrides (GOG_SERIES (series)); for (k = 0 ; k < series->base.num_elements; k++) { len = vals[k] * scale; negative = len < 0; if (negative) { if (mode == GOG_SHOW_NEGS_SKIP) { if ((overrides != NULL) && (GOG_SERIES_ELEMENT (overrides->data)->index == k)) overrides = overrides->next; continue; } len = -len; } if (!go_finite (len) || len < 1e-3) { if ((overrides != NULL) && (GOG_SERIES_ELEMENT (overrides->data)->index == k)) overrides = overrides->next; continue; } gpse = NULL; if ((overrides != NULL) && (GOG_SERIES_ELEMENT (overrides->data)->index == k)) { gpse = GOG_PIE_SERIES_ELEMENT (overrides->data); overrides = overrides->next; if (negative && mode == GOG_SHOW_NEGS_WHITE) { elt_style = go_style_dup (go_styled_object_get_style ( GO_STYLED_OBJECT (gpse))); elt_style->fill.type = GO_STYLE_FILL_PATTERN; go_pattern_set_solid (&elt_style->fill.pattern, GO_COLOR_WHITE); gog_renderer_push_style (view->renderer, elt_style); } else gog_renderer_push_style (view->renderer, go_styled_object_get_style ( GO_STYLED_OBJECT (gpse))); } else { if (negative && mode == GOG_SHOW_NEGS_WHITE) gog_renderer_push_style (view->renderer, white_style); else if (model->base.vary_style_by_element) gog_theme_fillin_style (theme, style, GOG_OBJECT (series), model->base.index_num + k, GO_STYLE_FILL); } /* only separate the outer ring */ separated_cx = cx; separated_cy = cy; if (num_series == index && (default_sep > 0. || gpse != NULL)) { separation = default_sep; if (gpse != NULL) separation += gpse->separation * r_tot; separated_cx += separation * cos (theta + len/2.); separated_cy += separation * sin (theta + len/2.); } theta += len; go_path_ring_wedge (path, separated_cx, separated_cy, r_ext, r_ext, has_hole ? r_int : 0.0, has_hole ? r_int : 0.0, theta - len, theta); gog_renderer_draw_shape (view->renderer, path); go_path_clear (path); if (gpse != NULL || (negative && mode == GOG_SHOW_NEGS_WHITE)) { gog_renderer_pop_style (view->renderer); if (elt_style) { g_object_unref (elt_style); elt_style = NULL; } } } gog_renderer_pop_style (view->renderer); if (model->base.vary_style_by_element || mode == GOG_SHOW_NEGS_WHITE) g_object_unref (style); if (white_style) g_object_unref (white_style); index ++; } go_path_free (path); }
static void so_path_view_set_bounds (SheetObjectView *sov, double const *coords, gboolean visible) { GnmSOPathView *spv = (GnmSOPathView *) sov; if (visible) { SheetObject *so = sheet_object_view_get_so (sov); GnmSOPath const *sop = GNM_SO_PATH (so); GOPath *path; double scale, x_scale, y_scale, x, y; if ((sop->path == NULL && sop->paths == NULL) || sop->width <=0. || sop->height <=0.) return; scale = goc_canvas_get_pixels_per_unit (GOC_ITEM (sov)->canvas); x_scale = fabs (coords[2] - coords[0]) / sop->width / scale; y_scale = fabs (coords[3] - coords[1]) / sop->height / scale; x = MIN (coords[0], coords[2]) / scale - sop->x_offset * x_scale; y = MIN (coords[1], coords[3]) / scale - sop->y_offset * y_scale; if (sop->path != NULL) { path = go_path_scale (sop->path, x_scale, y_scale); goc_item_set (spv->path, "x", x, "y", y, "path", path, NULL); go_path_free (path); } else { unsigned i; for (i = 0; i < sop->paths->len; i++) { path = go_path_scale ((GOPath *) g_ptr_array_index (sop->paths, i), x_scale, y_scale); goc_item_set (GOC_ITEM (g_ptr_array_index (spv->paths, i)), "x", x, "y", y, "path", path, NULL); go_path_free (path); } } if (spv->text != NULL && GOC_ITEM (spv->text)) { double x0, y0, x1, y1; if (spv->path) goc_item_get_bounds (spv->path, &x0, &y0, &x1, &y1); else { unsigned i; double mx, my, Mx, My; x0 = y0 = G_MAXDOUBLE; x1 = y1 = -G_MAXDOUBLE; for (i = 0; i < spv->paths->len; i++) { goc_item_get_bounds (GOC_ITEM (g_ptr_array_index (spv->paths, i)), &mx, &my, &Mx, &My); if (mx < x0) x0 = mx; if (my < y0) y0 = my; if (Mx > x1) x1 = Mx; if (My > y1) y1 = My; } } x1 -= x0 + sop->margin_pts.left + sop->margin_pts.right; y1 -= y0 + sop->margin_pts.top + sop->margin_pts.bottom; x0 += x1 / 2. + sop->margin_pts.left; y0 += y1 / 2. + sop->margin_pts.top; x1 = MAX (x1, DBL_MIN); y1 = MAX (y1, DBL_MIN); goc_item_set (GOC_ITEM (spv->text), "x", x0, "y", y0, "clip-height", y1, "clip-width", x1, "wrap-width", x1, NULL); } } else goc_item_hide (GOC_ITEM (sov)); }
static void gnm_so_path_set_property (GObject *obj, guint param_id, GValue const *value, GParamSpec *pspec) { GnmSOPath *sop = GNM_SO_PATH (obj); switch (param_id) { case SOP_PROP_STYLE: { GOStyle *style = go_style_dup (g_value_get_object (value)); style->interesting_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL; g_object_unref (sop->style); sop->style = style; break; } case SOP_PROP_PATH: { GOPath *path = g_value_get_boxed (value); if (sop->path) go_path_free (sop->path); else if (sop->paths) g_ptr_array_unref (sop->paths); sop->path = NULL; sop->paths = NULL; if (path) { cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); cairo_t *cr = cairo_create (surface); sop->path = go_path_ref (path); /* evaluates the bounding rectangle */ go_path_to_cairo (path, GO_PATH_DIRECTION_FORWARD, cr); cairo_fill_extents (cr, &sop->x_offset, &sop->y_offset, &sop->width, &sop->height); sop->width -= sop->x_offset; sop->height -= sop->y_offset; cairo_destroy (cr); cairo_surface_destroy (surface); } break; } case SOP_PROP_PATHS: { GPtrArray *paths = g_value_get_boxed (value); unsigned i; for (i = 0; i < paths->len; i++) /* we can only check that the path is not NULL */ g_return_if_fail (g_ptr_array_index (paths, i) != NULL); if (sop->path) go_path_free (sop->path); else if (sop->paths) g_ptr_array_unref (sop->paths); sop->path = NULL; sop->paths = NULL; if (paths) { cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); cairo_t *cr = cairo_create (surface); sop->paths = g_ptr_array_ref (paths); /* evaluates the bounding rectangle */ for (i = 0; i < paths->len; i++) go_path_to_cairo ((GOPath *) g_ptr_array_index (paths, i), GO_PATH_DIRECTION_FORWARD, cr); cairo_fill_extents (cr, &sop->x_offset, &sop->y_offset, &sop->width, &sop->height); sop->width -= sop->x_offset; sop->height -= sop->y_offset; cairo_destroy (cr); cairo_surface_destroy (surface); } break; } case SOP_PROP_TEXT: { char const *str = g_value_get_string (value); g_free (sop->text); sop->text = g_strdup (str == NULL ? "" : str); break; } case SOP_PROP_MARKUP: if (sop->markup != NULL) pango_attr_list_unref (sop->markup); sop->markup = g_value_peek_pointer (value); if (sop->markup != NULL) pango_attr_list_ref (sop->markup); break; case SOP_PROP_VIEWBOX: /* not settable */ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec); return; } }