3 * gnm-so-line.c: Lines, arrows, arcs
5 * Copyright (C) 2004-2007 Jody Goldberg (jody@gnome.org)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) version 3.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
23 #include <gnumeric-config.h>
25 #include <gnm-so-line.h>
26 #include <sheet-object-impl.h>
30 #include <goffice/goffice.h>
31 #include <gsf/gsf-impl-utils.h>
32 #include <glib/gi18n-lib.h>
35 #define CXML2C(s) ((char const *)(s))
37 static inline gboolean
38 attr_eq (const xmlChar
*a
, const char *s
)
40 return !strcmp (CXML2C (a
), s
);
43 #define GNM_SO_LINE(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GNM_SO_LINE_TYPE, GnmSOLine))
44 #define GNM_SO_LINE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GNM_SO_LINE_TYPE, GnmSOLineClass))
46 /*****************************************************************************/
52 GOArrow start_arrow
, end_arrow
;
54 typedef SheetObjectClass GnmSOLineClass
;
56 static SheetObjectClass
*gnm_so_line_parent_class
;
60 so_line_view_set_bounds (SheetObjectView
*sov
, double const *coords
, gboolean visible
)
62 GocItem
*view
= GOC_ITEM (sov
), *item
= GOC_ITEM (GOC_GROUP (view
)->children
->data
);
63 SheetObject
*so
= sheet_object_view_get_so (sov
);
64 GOStyleLine
const *style
= &GNM_SO_LINE (so
)->style
->line
;
65 double scale
= goc_canvas_get_pixels_per_unit (view
->canvas
);
67 sheet_object_direction_set (so
, coords
);
70 style
->color
!= 0 && style
->width
>= 0 && style
->dash_type
!= GO_LINE_NONE
) {
72 "x0", coords
[0] / scale
,
73 "y0", coords
[1] / scale
,
74 "x1", coords
[2] / scale
,
75 "y1", coords
[3] / scale
,
83 so_line_goc_view_class_init (SheetObjectViewClass
*sov_klass
)
85 sov_klass
->set_bounds
= so_line_view_set_bounds
;
87 typedef SheetObjectView LineGocView
;
88 typedef SheetObjectViewClass LineGocViewClass
;
89 static GSF_CLASS (LineGocView
, so_line_goc_view
,
90 so_line_goc_view_class_init
, NULL
,
93 #endif /* GNM_WITH_GTK */
102 sol_default_style (void)
104 GOStyle
*res
= go_style_new ();
105 res
->interesting_fields
= GO_STYLE_LINE
;
106 res
->line
.width
= 0; /* hairline */
107 res
->line
.color
= GO_COLOR_BLACK
;
108 res
->line
.dash_type
= GO_LINE_SOLID
; /* anything but 0 */
113 #include <sheet-control-gui.h>
114 #include <dialogs/dialogs.h>
115 #include <gnumeric-simple-canvas.h>
116 #include <gnm-pane.h>
119 gnm_so_line_user_config (SheetObject
*so
, SheetControl
*sc
)
121 dialog_so_styled (scg_wbcg (GNM_SCG (sc
)), G_OBJECT (so
),
122 sol_default_style (),
123 _("Line/Arrow Properties"), SO_STYLED_LINE
);
127 cb_gnm_so_line_changed (GnmSOLine
const *sol
,
128 G_GNUC_UNUSED GParamSpec
*pspec
,
131 item
= GOC_ITEM (GOC_GROUP (item
)->children
->data
);
133 "start-arrow", &sol
->start_arrow
,
134 "end-arrow", &sol
->end_arrow
,
139 static SheetObjectView
*
140 gnm_so_line_new_view (SheetObject
*so
, SheetObjectViewContainer
*container
)
142 GnmSOLine
const *sol
= GNM_SO_LINE (so
);
143 GocItem
*item
= goc_item_new (
144 gnm_pane_object_group (GNM_PANE (container
)),
145 so_line_goc_view_get_type (),
147 goc_item_new (GOC_GROUP (item
), GOC_TYPE_LINE
, NULL
);
148 cb_gnm_so_line_changed (sol
, NULL
, item
);
149 g_signal_connect_object (G_OBJECT (sol
),
150 "notify", G_CALLBACK (cb_gnm_so_line_changed
),
152 return gnm_pane_object_register (so
, item
, TRUE
);
155 #endif /* GNM_WITH_GTK */
158 draw_arrow (const GOArrow
*arrow
, cairo_t
*cr
,
159 double *x
, double *y
, double phi
)
164 cairo_translate (cr
, *x
, *y
);
165 go_arrow_draw (arrow
, cr
, &dx
, &dy
, phi
);
172 gnm_so_line_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
173 double width
, double height
)
175 GnmSOLine
*sol
= GNM_SO_LINE (so
);
176 GOStyle
const *style
= sol
->style
;
177 double x1
, y1
, x2
, y2
;
180 if (style
->line
.color
== 0 ||
181 style
->line
.width
< 0 ||
182 style
->line
.dash_type
== GO_LINE_NONE
)
185 if ((so
->anchor
.base
.direction
& GOD_ANCHOR_DIR_H_MASK
) == GOD_ANCHOR_DIR_RIGHT
) {
193 if ((so
->anchor
.base
.direction
& GOD_ANCHOR_DIR_V_MASK
) == GOD_ANCHOR_DIR_DOWN
) {
201 cairo_set_source_rgba (cr
, GO_COLOR_TO_CAIRO (style
->line
.color
));
203 phi
= atan2 (y2
- y1
, x2
- x1
) - M_PI_2
;
204 draw_arrow (&sol
->start_arrow
, cr
, &x1
, &y1
, phi
+ M_PI
);
205 draw_arrow (&sol
->end_arrow
, cr
, &x2
, &y2
, phi
);
207 cairo_move_to (cr
, x1
, y1
);
208 cairo_line_to (cr
, x2
, y2
);
209 if (go_style_set_cairo_line (style
, cr
))
216 write_xml_sax_arrow (GOArrow
const *arrow
, const char *prefix
,
219 const char *typename
= go_arrow_type_as_str (arrow
->typ
);
222 if (!typename
|| arrow
->typ
== GO_ARROW_NONE
)
225 attr
= g_strconcat (prefix
, "ArrowType", NULL
);
226 gsf_xml_out_add_cstr (output
, attr
, typename
);
229 attr
= g_strconcat (prefix
, "ArrowShapeA", NULL
);
230 go_xml_out_add_double (output
, attr
, arrow
->a
);
233 attr
= g_strconcat (prefix
, "ArrowShapeB", NULL
);
234 go_xml_out_add_double (output
, attr
, arrow
->b
);
237 attr
= g_strconcat (prefix
, "ArrowShapeC", NULL
);
238 go_xml_out_add_double (output
, attr
, arrow
->c
);
243 gnm_so_line_write_xml_sax (SheetObject
const *so
, GsfXMLOut
*output
,
244 GnmConventions
const *convs
)
246 GnmSOLine
const *sol
= GNM_SO_LINE (so
);
248 gsf_xml_out_add_int (output
, "Type", 1);
249 write_xml_sax_arrow (&sol
->start_arrow
, "Start", output
);
250 write_xml_sax_arrow (&sol
->end_arrow
, "End", output
);
252 gsf_xml_out_start_element (output
, "Style");
253 go_persist_sax_save (GO_PERSIST (sol
->style
), output
);
254 gsf_xml_out_end_element (output
); /* </Style> */
258 sol_sax_style (GsfXMLIn
*xin
, xmlChar
const **attrs
)
260 SheetObject
*so
= gnm_xml_in_cur_obj (xin
);
261 GnmSOLine
*sol
= GNM_SO_LINE (so
);
262 go_persist_prep_sax (GO_PERSIST (sol
->style
), xin
, attrs
);
267 read_xml_sax_arrow (xmlChar
const **attrs
, const char *prefix
,
270 size_t plen
= strlen (prefix
);
271 const char *attr
= CXML2C (attrs
[0]);
272 const char *val
= CXML2C (attrs
[1]);
274 if (strncmp (attr
, prefix
, plen
) != 0)
278 if (strcmp (attr
, "ArrowType") == 0) {
279 arrow
->typ
= go_arrow_type_from_str (val
);
280 } else if (strcmp (attr
, "ArrowShapeA") == 0) {
281 arrow
->a
= go_strtod (val
, NULL
);
282 } else if (strcmp (attr
, "ArrowShapeB") == 0) {
283 arrow
->b
= go_strtod (val
, NULL
);
284 } else if (strcmp (attr
, "ArrowShapeC") == 0) {
285 arrow
->c
= go_strtod (val
, NULL
);
293 gnm_so_line_prep_sax_parser (SheetObject
*so
, GsfXMLIn
*xin
,
294 xmlChar
const **attrs
,
295 GnmConventions
const *convs
)
297 static GsfXMLInNode
const dtd
[] = {
298 GSF_XML_IN_NODE (STYLE
, STYLE
, -1, "Style", GSF_XML_NO_CONTENT
, &sol_sax_style
, NULL
),
301 static GsfXMLInDoc
*doc
= NULL
;
302 GnmSOLine
*sol
= GNM_SO_LINE (so
);
303 gboolean old_format
= FALSE
;
304 double tmp
, arrow_a
= -1., arrow_b
= -1., arrow_c
= -1.;
308 doc
= gsf_xml_in_doc_new (dtd
, NULL
);
309 gnm_xml_in_doc_dispose_on_exit (&doc
);
311 gsf_xml_in_push_state (xin
, doc
, NULL
, NULL
, attrs
);
313 go_arrow_clear (&sol
->start_arrow
);
314 go_arrow_clear (&sol
->end_arrow
);
316 for (; attrs
!= NULL
&& attrs
[0] && attrs
[1] ; attrs
+= 2) {
317 /* Old 1.0 and 1.2 */
318 if (gnm_xml_attr_double (attrs
, "Width", &tmp
)) {
320 sol
->style
->line
.width
= tmp
;
321 } else if (attr_eq (attrs
[0], "FillColor")) {
322 go_color_from_str (CXML2C (attrs
[1]), &sol
->style
->line
.color
);
324 } else if (gnm_xml_attr_int (attrs
, "Type", &type
)) {
325 } else if (gnm_xml_attr_double (attrs
, "ArrowShapeA", &arrow_a
) ||
326 gnm_xml_attr_double (attrs
, "ArrowShapeB", &arrow_b
) ||
327 gnm_xml_attr_double (attrs
, "ArrowShapeC", &arrow_c
))
329 else if (read_xml_sax_arrow (attrs
, "Start", &sol
->start_arrow
) ||
330 read_xml_sax_arrow (attrs
, "End", &sol
->end_arrow
))
337 arrow_a
>= 0. && arrow_b
>= 0. && arrow_c
>= 0.)
338 go_arrow_init_kite (&sol
->end_arrow
,
339 arrow_a
, arrow_b
, arrow_c
);
343 gnm_so_line_copy (SheetObject
*dst
, SheetObject
const *src
)
345 GnmSOLine
const *sol
= GNM_SO_LINE (src
);
346 GnmSOLine
*new_sol
= GNM_SO_LINE (dst
);
348 g_object_unref (new_sol
->style
);
349 new_sol
->style
= go_style_dup (sol
->style
);
350 new_sol
->start_arrow
= sol
->start_arrow
;
351 new_sol
->end_arrow
= sol
->end_arrow
;
355 gnm_so_line_set_property (GObject
*obj
, guint param_id
,
356 GValue
const *value
, GParamSpec
*pspec
)
358 GnmSOLine
*sol
= GNM_SO_LINE (obj
);
360 case SOL_PROP_STYLE
: {
361 GOStyle
*style
= go_style_dup (g_value_get_object (value
));
362 style
->interesting_fields
= GO_STYLE_LINE
;
363 g_object_unref (sol
->style
);
367 case SOL_PROP_START_ARROW
:
368 sol
->start_arrow
= *((GOArrow
*)g_value_peek_pointer (value
));
370 case SOL_PROP_END_ARROW
:
371 sol
->end_arrow
= *((GOArrow
* )g_value_peek_pointer (value
));
374 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
380 gnm_so_line_get_property (GObject
*obj
, guint param_id
,
381 GValue
*value
, GParamSpec
*pspec
)
383 GnmSOLine
*sol
= GNM_SO_LINE (obj
);
386 g_value_set_object (value
, sol
->style
);
388 case SOL_PROP_START_ARROW
:
389 g_value_set_boxed (value
, &sol
->start_arrow
);
391 case SOL_PROP_END_ARROW
:
392 g_value_set_boxed (value
, &sol
->end_arrow
);
395 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
401 gnm_so_line_finalize (GObject
*object
)
403 GnmSOLine
*sol
= GNM_SO_LINE (object
);
404 g_clear_object (&sol
->style
);
405 G_OBJECT_CLASS (gnm_so_line_parent_class
)->finalize (object
);
409 gnm_so_line_class_init (GObjectClass
*gobject_class
)
411 SheetObjectClass
*so_class
= GNM_SO_CLASS (gobject_class
);
413 gnm_so_line_parent_class
= g_type_class_peek_parent (gobject_class
);
415 gobject_class
->finalize
= gnm_so_line_finalize
;
416 gobject_class
->set_property
= gnm_so_line_set_property
;
417 gobject_class
->get_property
= gnm_so_line_get_property
;
418 so_class
->write_xml_sax
= gnm_so_line_write_xml_sax
;
419 so_class
->prep_sax_parser
= gnm_so_line_prep_sax_parser
;
420 so_class
->copy
= gnm_so_line_copy
;
421 so_class
->rubber_band_directly
= TRUE
;
422 so_class
->xml_export_name
= "SheetObjectGraphic";
425 so_class
->draw_cairo
= gnm_so_line_draw_cairo
;
426 so_class
->user_config
= gnm_so_line_user_config
;
427 so_class
->new_view
= gnm_so_line_new_view
;
428 #endif /* GNM_WITH_GTK */
430 g_object_class_install_property (gobject_class
, SOL_PROP_STYLE
,
431 g_param_spec_object ("style", NULL
, NULL
, GO_TYPE_STYLE
,
432 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
433 g_object_class_install_property (gobject_class
, SOL_PROP_START_ARROW
,
434 g_param_spec_boxed ("start-arrow", NULL
, NULL
,
436 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
437 g_object_class_install_property (gobject_class
, SOL_PROP_END_ARROW
,
438 g_param_spec_boxed ("end-arrow", NULL
, NULL
,
440 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
444 gnm_so_line_init (GObject
*obj
)
446 GnmSOLine
*sol
= GNM_SO_LINE (obj
);
447 sol
->style
= sol_default_style ();
448 go_arrow_clear (&sol
->start_arrow
);
449 go_arrow_clear (&sol
->end_arrow
);
450 GNM_SO (obj
)->anchor
.base
.direction
= GOD_ANCHOR_DIR_NONE_MASK
;
453 GSF_CLASS (GnmSOLine
, gnm_so_line
,
454 gnm_so_line_class_init
, gnm_so_line_init
,