1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * gnm-so-line.c: Lines, arrows, arcs
6 * Copyright (C) 2004-2007 Jody Goldberg (jody@gnome.org)
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) version 3.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
24 #include <gnumeric-config.h>
26 #include "gnm-so-line.h"
27 #include "sheet-object-impl.h"
31 #include <goffice/goffice.h>
32 #include <gsf/gsf-impl-utils.h>
33 #include <glib/gi18n-lib.h>
36 #define CXML2C(s) ((char const *)(s))
38 static inline gboolean
39 attr_eq (const xmlChar
*a
, const char *s
)
41 return !strcmp (CXML2C (a
), s
);
44 #define GNM_SO_LINE(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GNM_SO_LINE_TYPE, GnmSOLine))
45 #define GNM_SO_LINE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GNM_SO_LINE_TYPE, GnmSOLineClass))
47 /*****************************************************************************/
53 GOArrow start_arrow
, end_arrow
;
55 typedef SheetObjectClass GnmSOLineClass
;
57 static SheetObjectClass
*gnm_so_line_parent_class
;
61 so_line_view_set_bounds (SheetObjectView
*sov
, double const *coords
, gboolean visible
)
63 GocItem
*view
= GOC_ITEM (sov
), *item
= GOC_ITEM (GOC_GROUP (view
)->children
->data
);
64 SheetObject
*so
= sheet_object_view_get_so (sov
);
65 GOStyleLine
const *style
= &GNM_SO_LINE (so
)->style
->line
;
66 double scale
= goc_canvas_get_pixels_per_unit (view
->canvas
);
68 sheet_object_direction_set (so
, coords
);
71 style
->color
!= 0 && style
->width
>= 0 && style
->dash_type
!= GO_LINE_NONE
) {
73 "x0", coords
[0] / scale
,
74 "y0", coords
[1] / scale
,
75 "x1", coords
[2] / scale
,
76 "y1", coords
[3] / scale
,
84 so_line_goc_view_class_init (SheetObjectViewClass
*sov_klass
)
86 sov_klass
->set_bounds
= so_line_view_set_bounds
;
88 typedef SheetObjectView LineGocView
;
89 typedef SheetObjectViewClass LineGocViewClass
;
90 static GSF_CLASS (LineGocView
, so_line_goc_view
,
91 so_line_goc_view_class_init
, NULL
,
94 #endif /* GNM_WITH_GTK */
103 sol_default_style (void)
105 GOStyle
*res
= go_style_new ();
106 res
->interesting_fields
= GO_STYLE_LINE
;
107 res
->line
.width
= 0; /* hairline */
108 res
->line
.color
= GO_COLOR_BLACK
;
109 res
->line
.dash_type
= GO_LINE_SOLID
; /* anything but 0 */
114 #include <sheet-control-gui.h>
115 #include <dialogs/dialogs.h>
116 #include <gnumeric-simple-canvas.h>
117 #include <gnm-pane.h>
120 gnm_so_line_user_config (SheetObject
*so
, SheetControl
*sc
)
122 dialog_so_styled (scg_wbcg (GNM_SCG (sc
)), G_OBJECT (so
),
123 sol_default_style (),
124 _("Line/Arrow Properties"), SO_STYLED_LINE
);
128 cb_gnm_so_line_changed (GnmSOLine
const *sol
,
129 G_GNUC_UNUSED GParamSpec
*pspec
,
132 item
= GOC_ITEM (GOC_GROUP (item
)->children
->data
);
134 "start-arrow", &sol
->start_arrow
,
135 "end-arrow", &sol
->end_arrow
,
140 static SheetObjectView
*
141 gnm_so_line_new_view (SheetObject
*so
, SheetObjectViewContainer
*container
)
143 GnmSOLine
const *sol
= GNM_SO_LINE (so
);
144 GocItem
*item
= goc_item_new (
145 gnm_pane_object_group (GNM_PANE (container
)),
146 so_line_goc_view_get_type (),
148 goc_item_new (GOC_GROUP (item
), GOC_TYPE_LINE
, NULL
);
149 cb_gnm_so_line_changed (sol
, NULL
, item
);
150 g_signal_connect_object (G_OBJECT (sol
),
151 "notify", G_CALLBACK (cb_gnm_so_line_changed
),
153 return gnm_pane_object_register (so
, item
, TRUE
);
156 #endif /* GNM_WITH_GTK */
159 draw_arrow (const GOArrow
*arrow
, cairo_t
*cr
,
160 double *x
, double *y
, double phi
)
165 cairo_translate (cr
, *x
, *y
);
166 go_arrow_draw (arrow
, cr
, &dx
, &dy
, phi
);
173 gnm_so_line_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
174 double width
, double height
)
176 GnmSOLine
*sol
= GNM_SO_LINE (so
);
177 GOStyle
const *style
= sol
->style
;
178 double x1
, y1
, x2
, y2
;
181 if (style
->line
.color
== 0 ||
182 style
->line
.width
< 0 ||
183 style
->line
.dash_type
== GO_LINE_NONE
)
186 if ((so
->anchor
.base
.direction
& GOD_ANCHOR_DIR_H_MASK
) == GOD_ANCHOR_DIR_RIGHT
) {
194 if ((so
->anchor
.base
.direction
& GOD_ANCHOR_DIR_V_MASK
) == GOD_ANCHOR_DIR_DOWN
) {
202 cairo_set_source_rgba (cr
, GO_COLOR_TO_CAIRO (style
->line
.color
));
204 phi
= atan2 (y2
- y1
, x2
- x1
) - M_PI_2
;
205 draw_arrow (&sol
->start_arrow
, cr
, &x1
, &y1
, phi
+ M_PI
);
206 draw_arrow (&sol
->end_arrow
, cr
, &x2
, &y2
, phi
);
208 cairo_move_to (cr
, x1
, y1
);
209 cairo_line_to (cr
, x2
, y2
);
210 if (go_style_set_cairo_line (style
, cr
))
217 write_xml_sax_arrow (GOArrow
const *arrow
, const char *prefix
,
220 const char *typename
= go_arrow_type_as_str (arrow
->typ
);
223 if (!typename
|| arrow
->typ
== GO_ARROW_NONE
)
226 attr
= g_strconcat (prefix
, "ArrowType", NULL
);
227 gsf_xml_out_add_cstr (output
, attr
, typename
);
230 attr
= g_strconcat (prefix
, "ArrowShapeA", NULL
);
231 go_xml_out_add_double (output
, attr
, arrow
->a
);
234 attr
= g_strconcat (prefix
, "ArrowShapeB", NULL
);
235 go_xml_out_add_double (output
, attr
, arrow
->b
);
238 attr
= g_strconcat (prefix
, "ArrowShapeC", NULL
);
239 go_xml_out_add_double (output
, attr
, arrow
->c
);
244 gnm_so_line_write_xml_sax (SheetObject
const *so
, GsfXMLOut
*output
,
245 GnmConventions
const *convs
)
247 GnmSOLine
const *sol
= GNM_SO_LINE (so
);
249 gsf_xml_out_add_int (output
, "Type", 1);
250 write_xml_sax_arrow (&sol
->start_arrow
, "Start", output
);
251 write_xml_sax_arrow (&sol
->end_arrow
, "End", output
);
253 gsf_xml_out_start_element (output
, "Style");
254 go_persist_sax_save (GO_PERSIST (sol
->style
), output
);
255 gsf_xml_out_end_element (output
); /* </Style> */
259 sol_sax_style (GsfXMLIn
*xin
, xmlChar
const **attrs
)
261 SheetObject
*so
= gnm_xml_in_cur_obj (xin
);
262 GnmSOLine
*sol
= GNM_SO_LINE (so
);
263 go_persist_prep_sax (GO_PERSIST (sol
->style
), xin
, attrs
);
268 read_xml_sax_arrow (xmlChar
const **attrs
, const char *prefix
,
271 size_t plen
= strlen (prefix
);
272 const char *attr
= CXML2C (attrs
[0]);
273 const char *val
= CXML2C (attrs
[1]);
275 if (strncmp (attr
, prefix
, plen
) != 0)
279 if (strcmp (attr
, "ArrowType") == 0) {
280 arrow
->typ
= go_arrow_type_from_str (val
);
281 } else if (strcmp (attr
, "ArrowShapeA") == 0) {
282 arrow
->a
= go_strtod (val
, NULL
);
283 } else if (strcmp (attr
, "ArrowShapeB") == 0) {
284 arrow
->b
= go_strtod (val
, NULL
);
285 } else if (strcmp (attr
, "ArrowShapeC") == 0) {
286 arrow
->c
= go_strtod (val
, NULL
);
294 gnm_so_line_prep_sax_parser (SheetObject
*so
, GsfXMLIn
*xin
,
295 xmlChar
const **attrs
,
296 GnmConventions
const *convs
)
298 static GsfXMLInNode
const dtd
[] = {
299 GSF_XML_IN_NODE (STYLE
, STYLE
, -1, "Style", GSF_XML_NO_CONTENT
, &sol_sax_style
, NULL
),
302 static GsfXMLInDoc
*doc
= NULL
;
303 GnmSOLine
*sol
= GNM_SO_LINE (so
);
304 gboolean old_format
= FALSE
;
305 double tmp
, arrow_a
= -1., arrow_b
= -1., arrow_c
= -1.;
309 doc
= gsf_xml_in_doc_new (dtd
, NULL
);
310 gnm_xml_in_doc_dispose_on_exit (&doc
);
312 gsf_xml_in_push_state (xin
, doc
, NULL
, NULL
, attrs
);
314 go_arrow_clear (&sol
->start_arrow
);
315 go_arrow_clear (&sol
->end_arrow
);
317 for (; attrs
!= NULL
&& attrs
[0] && attrs
[1] ; attrs
+= 2) {
318 /* Old 1.0 and 1.2 */
319 if (gnm_xml_attr_double (attrs
, "Width", &tmp
)) {
321 sol
->style
->line
.width
= tmp
;
322 } else if (attr_eq (attrs
[0], "FillColor")) {
323 go_color_from_str (CXML2C (attrs
[1]), &sol
->style
->line
.color
);
325 } else if (gnm_xml_attr_int (attrs
, "Type", &type
)) {
326 } else if (gnm_xml_attr_double (attrs
, "ArrowShapeA", &arrow_a
) ||
327 gnm_xml_attr_double (attrs
, "ArrowShapeB", &arrow_b
) ||
328 gnm_xml_attr_double (attrs
, "ArrowShapeC", &arrow_c
))
330 else if (read_xml_sax_arrow (attrs
, "Start", &sol
->start_arrow
) ||
331 read_xml_sax_arrow (attrs
, "End", &sol
->end_arrow
))
338 arrow_a
>= 0. && arrow_b
>= 0. && arrow_c
>= 0.)
339 go_arrow_init_kite (&sol
->end_arrow
,
340 arrow_a
, arrow_b
, arrow_c
);
344 gnm_so_line_copy (SheetObject
*dst
, SheetObject
const *src
)
346 GnmSOLine
const *sol
= GNM_SO_LINE (src
);
347 GnmSOLine
*new_sol
= GNM_SO_LINE (dst
);
349 g_object_unref (new_sol
->style
);
350 new_sol
->style
= go_style_dup (sol
->style
);
351 new_sol
->start_arrow
= sol
->start_arrow
;
352 new_sol
->end_arrow
= sol
->end_arrow
;
356 gnm_so_line_set_property (GObject
*obj
, guint param_id
,
357 GValue
const *value
, GParamSpec
*pspec
)
359 GnmSOLine
*sol
= GNM_SO_LINE (obj
);
361 case SOL_PROP_STYLE
: {
362 GOStyle
*style
= go_style_dup (g_value_get_object (value
));
363 style
->interesting_fields
= GO_STYLE_LINE
;
364 g_object_unref (sol
->style
);
368 case SOL_PROP_START_ARROW
:
369 sol
->start_arrow
= *((GOArrow
*)g_value_peek_pointer (value
));
371 case SOL_PROP_END_ARROW
:
372 sol
->end_arrow
= *((GOArrow
* )g_value_peek_pointer (value
));
375 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
381 gnm_so_line_get_property (GObject
*obj
, guint param_id
,
382 GValue
*value
, GParamSpec
*pspec
)
384 GnmSOLine
*sol
= GNM_SO_LINE (obj
);
387 g_value_set_object (value
, sol
->style
);
389 case SOL_PROP_START_ARROW
:
390 g_value_set_boxed (value
, &sol
->start_arrow
);
392 case SOL_PROP_END_ARROW
:
393 g_value_set_boxed (value
, &sol
->end_arrow
);
396 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
402 gnm_so_line_finalize (GObject
*object
)
404 GnmSOLine
*sol
= GNM_SO_LINE (object
);
405 g_clear_object (&sol
->style
);
406 G_OBJECT_CLASS (gnm_so_line_parent_class
)->finalize (object
);
410 gnm_so_line_class_init (GObjectClass
*gobject_class
)
412 SheetObjectClass
*so_class
= GNM_SO_CLASS (gobject_class
);
414 gnm_so_line_parent_class
= g_type_class_peek_parent (gobject_class
);
416 gobject_class
->finalize
= gnm_so_line_finalize
;
417 gobject_class
->set_property
= gnm_so_line_set_property
;
418 gobject_class
->get_property
= gnm_so_line_get_property
;
419 so_class
->write_xml_sax
= gnm_so_line_write_xml_sax
;
420 so_class
->prep_sax_parser
= gnm_so_line_prep_sax_parser
;
421 so_class
->copy
= gnm_so_line_copy
;
422 so_class
->rubber_band_directly
= TRUE
;
423 so_class
->xml_export_name
= "SheetObjectGraphic";
426 so_class
->draw_cairo
= gnm_so_line_draw_cairo
;
427 so_class
->user_config
= gnm_so_line_user_config
;
428 so_class
->new_view
= gnm_so_line_new_view
;
429 #endif /* GNM_WITH_GTK */
431 g_object_class_install_property (gobject_class
, SOL_PROP_STYLE
,
432 g_param_spec_object ("style", NULL
, NULL
, GO_TYPE_STYLE
,
433 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
434 g_object_class_install_property (gobject_class
, SOL_PROP_START_ARROW
,
435 g_param_spec_boxed ("start-arrow", NULL
, NULL
,
437 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
438 g_object_class_install_property (gobject_class
, SOL_PROP_END_ARROW
,
439 g_param_spec_boxed ("end-arrow", NULL
, NULL
,
441 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
445 gnm_so_line_init (GObject
*obj
)
447 GnmSOLine
*sol
= GNM_SO_LINE (obj
);
448 sol
->style
= sol_default_style ();
449 go_arrow_clear (&sol
->start_arrow
);
450 go_arrow_clear (&sol
->end_arrow
);
451 GNM_SO (obj
)->anchor
.base
.direction
= GOD_ANCHOR_DIR_NONE_MASK
;
454 GSF_CLASS (GnmSOLine
, gnm_so_line
,
455 gnm_so_line_class_init
, gnm_so_line_init
,