1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010,2011 Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
23 * @short_description: The drawing container
25 * The canvas is the toplevel entity of an ADG drawing. It can be
26 * bound to a GTK+ widget, such as #AdgGtkArea, or manually rendered
27 * to a custom surface.
29 * Tipically, the canvas contains the description and properties of
30 * the media used, such as such as size (if relevant), margins,
31 * border and paddings. This approach clearly follows the block model
32 * of the CSS specifications level 2.
34 * The paddings specify the distance between the entities contained
35 * by the canvas and the border. The margins specify the distance
36 * between the canvas border and the media extents.
38 * The canvas (hence the media) size can be explicitely specified
39 * by directly writing to the #AdgCanvas:size property or using any
40 * valid setter, such as adg_canvas_set_size(),
41 * adg_canvas_set_size_explicit() or the convenient
42 * adg_canvas_set_paper() GTK+ wrapper. You can also set explicitely
43 * only one dimension and let the other one be computed automatically.
44 * This is done by using the special value %0 that specifies a side
45 * must be autocalculated.
47 * By default either width and height must be autocalculated (are
48 * set to %0), so the arrange() phase on the canvas is performed.
49 * Margins and paddings are then added to the extents to get the
50 * border coordinates and the final bounding box.
52 * When the size is explicitely set, instead, the final bounding
53 * box is forcibly set to this value without taking the canvas
54 * extents into account. The margins are then subtracted to get
55 * the coordinates of the border. In this case, the paddings are
64 * All fields are private and should not be used directly.
65 * Use its public methods instead.
71 #include "adg-internal.h"
76 #include "adg-container.h"
77 #include "adg-table.h"
78 #include "adg-title-block.h"
79 #include "adg-style.h"
80 #include "adg-color-style.h"
81 #include "adg-dress.h"
82 #include "adg-dress-builtins.h"
84 #include "adg-canvas.h"
85 #include "adg-canvas-private.h"
88 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_canvas_parent_class)
89 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_canvas_parent_class)
92 G_DEFINE_TYPE(AdgCanvas
, adg_canvas
, ADG_TYPE_CONTAINER
)
97 PROP_BACKGROUND_DRESS
,
112 static void _adg_dispose (GObject
*object
);
113 static void _adg_get_property (GObject
*object
,
117 static void _adg_set_property (GObject
*object
,
121 static void _adg_global_changed (AdgEntity
*entity
);
122 static void _adg_local_changed (AdgEntity
*entity
);
123 static void _adg_invalidate (AdgEntity
*entity
);
124 static void _adg_arrange (AdgEntity
*entity
);
125 static void _adg_render (AdgEntity
*entity
,
130 adg_canvas_class_init(AdgCanvasClass
*klass
)
132 GObjectClass
*gobject_class
;
133 AdgEntityClass
*entity_class
;
136 gobject_class
= (GObjectClass
*) klass
;
137 entity_class
= (AdgEntityClass
*) klass
;
139 g_type_class_add_private(klass
, sizeof(AdgCanvasPrivate
));
141 gobject_class
->dispose
= _adg_dispose
;
142 gobject_class
->get_property
= _adg_get_property
;
143 gobject_class
->set_property
= _adg_set_property
;
145 entity_class
->global_changed
= _adg_global_changed
;
146 entity_class
->local_changed
= _adg_local_changed
;
147 entity_class
->invalidate
= _adg_invalidate
;
148 entity_class
->arrange
= _adg_arrange
;
149 entity_class
->render
= _adg_render
;
151 param
= g_param_spec_boxed("size",
153 P_("The size set on this canvas: use 0 to have an automatic dimension based on the canvas extents"),
156 g_object_class_install_property(gobject_class
, PROP_SIZE
, param
);
158 param
= adg_param_spec_dress("background-dress",
159 P_("Background Dress"),
160 P_("The color dress to use for the canvas background"),
161 ADG_DRESS_COLOR_BACKGROUND
,
163 g_object_class_install_property(gobject_class
, PROP_BACKGROUND_DRESS
, param
);
165 param
= adg_param_spec_dress("frame-dress",
167 P_("Line dress to use while drawing the frame around the canvas"),
168 ADG_DRESS_LINE_FRAME
,
170 g_object_class_install_property(gobject_class
, PROP_FRAME_DRESS
, param
);
172 param
= g_param_spec_object("title-block",
174 P_("The title block to assign to this canvas"),
175 ADG_TYPE_TITLE_BLOCK
,
177 g_object_class_install_property(gobject_class
, PROP_TITLE_BLOCK
, param
);
179 param
= g_param_spec_double("top-margin",
181 P_("The margin (in global space) to leave above the frame"),
182 -G_MAXDOUBLE
, G_MAXDOUBLE
, 15,
184 g_object_class_install_property(gobject_class
, PROP_TOP_MARGIN
, param
);
186 param
= g_param_spec_double("right-margin",
188 P_("The margin (in global space) to leave empty at the right of the frame"),
189 -G_MAXDOUBLE
, G_MAXDOUBLE
, 15,
191 g_object_class_install_property(gobject_class
, PROP_RIGHT_MARGIN
, param
);
193 param
= g_param_spec_double("bottom-margin",
195 P_("The margin (in global space) to leave empty below the frame"),
196 -G_MAXDOUBLE
, G_MAXDOUBLE
, 15,
198 g_object_class_install_property(gobject_class
, PROP_BOTTOM_MARGIN
, param
);
200 param
= g_param_spec_double("left-margin",
202 P_("The margin (in global space) to leave empty at the left of the frame"),
203 -G_MAXDOUBLE
, G_MAXDOUBLE
, 15,
205 g_object_class_install_property(gobject_class
, PROP_LEFT_MARGIN
, param
);
207 param
= g_param_spec_boolean("has-frame",
208 P_("Has Frame Flag"),
209 P_("If enabled, a frame using the frame dress will be drawn around the canvas extents, taking into account the margins"),
212 g_object_class_install_property(gobject_class
, PROP_HAS_FRAME
, param
);
214 param
= g_param_spec_double("top-padding",
216 P_("The padding (in global space) to leave empty above between the drawing and the frame"),
217 -G_MAXDOUBLE
, G_MAXDOUBLE
, 15,
219 g_object_class_install_property(gobject_class
, PROP_TOP_PADDING
, param
);
221 param
= g_param_spec_double("right-padding",
223 P_("The padding (in global space) to leave empty at the right between the drawing and the frame"),
224 -G_MAXDOUBLE
, G_MAXDOUBLE
, 15,
226 g_object_class_install_property(gobject_class
, PROP_RIGHT_PADDING
, param
);
228 param
= g_param_spec_double("bottom-padding",
229 P_("Bottom Padding"),
230 P_("The padding (in global space) to leave empty below between the drawing and the frame"),
231 -G_MAXDOUBLE
, G_MAXDOUBLE
, 15,
233 g_object_class_install_property(gobject_class
, PROP_BOTTOM_PADDING
, param
);
235 param
= g_param_spec_double("left-padding",
237 P_("The padding (in global space) to leave empty at the left between the drawing and the frame"),
238 -G_MAXDOUBLE
, G_MAXDOUBLE
, 15,
240 g_object_class_install_property(gobject_class
, PROP_LEFT_PADDING
, param
);
244 adg_canvas_init(AdgCanvas
*canvas
)
246 AdgCanvasPrivate
*data
= G_TYPE_INSTANCE_GET_PRIVATE(canvas
,
252 data
->background_dress
= ADG_DRESS_COLOR_BACKGROUND
;
253 data
->frame_dress
= ADG_DRESS_LINE_FRAME
;
254 data
->title_block
= NULL
;
255 data
->top_margin
= 15;
256 data
->right_margin
= 15;
257 data
->bottom_margin
= 15;
258 data
->left_margin
= 15;
259 data
->has_frame
= TRUE
;
260 data
->top_padding
= 15;
261 data
->right_padding
= 15;
262 data
->bottom_padding
= 15;
263 data
->left_padding
= 15;
269 _adg_dispose(GObject
*object
)
271 AdgCanvasPrivate
*data
= ((AdgCanvas
*) object
)->data
;
273 if (data
->title_block
) {
274 g_object_unref(data
->title_block
);
275 data
->title_block
= NULL
;
278 if (_ADG_OLD_OBJECT_CLASS
->dispose
)
279 _ADG_OLD_OBJECT_CLASS
->dispose(object
);
284 _adg_get_property(GObject
*object
, guint prop_id
,
285 GValue
*value
, GParamSpec
*pspec
)
287 AdgCanvasPrivate
*data
= ((AdgCanvas
*) object
)->data
;
291 g_value_set_boxed(value
, &data
->size
);
293 case PROP_BACKGROUND_DRESS
:
294 g_value_set_int(value
, data
->background_dress
);
296 case PROP_FRAME_DRESS
:
297 g_value_set_int(value
, data
->frame_dress
);
299 case PROP_TITLE_BLOCK
:
300 g_value_set_object(value
, data
->title_block
);
302 case PROP_TOP_MARGIN
:
303 g_value_set_double(value
, data
->top_margin
);
305 case PROP_RIGHT_MARGIN
:
306 g_value_set_double(value
, data
->right_margin
);
308 case PROP_BOTTOM_MARGIN
:
309 g_value_set_double(value
, data
->bottom_margin
);
311 case PROP_LEFT_MARGIN
:
312 g_value_set_double(value
, data
->left_margin
);
315 g_value_set_boolean(value
, data
->has_frame
);
317 case PROP_TOP_PADDING
:
318 g_value_set_double(value
, data
->top_padding
);
320 case PROP_RIGHT_PADDING
:
321 g_value_set_double(value
, data
->right_padding
);
323 case PROP_BOTTOM_PADDING
:
324 g_value_set_double(value
, data
->bottom_padding
);
326 case PROP_LEFT_PADDING
:
327 g_value_set_double(value
, data
->left_padding
);
330 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
336 _adg_set_property(GObject
*object
, guint prop_id
,
337 const GValue
*value
, GParamSpec
*pspec
)
340 AdgCanvasPrivate
*data
;
341 AdgTitleBlock
*title_block
;
343 canvas
= (AdgCanvas
*) object
;
348 adg_pair_copy(&data
->size
, g_value_get_boxed(value
));
350 case PROP_BACKGROUND_DRESS
:
351 data
->background_dress
= g_value_get_int(value
);
353 case PROP_FRAME_DRESS
:
354 data
->frame_dress
= g_value_get_int(value
);
356 case PROP_TITLE_BLOCK
:
357 title_block
= g_value_get_object(value
);
359 g_object_ref(title_block
);
360 adg_entity_set_parent((AdgEntity
*) title_block
,
361 (AdgEntity
*) canvas
);
363 if (data
->title_block
)
364 g_object_unref(data
->title_block
);
365 data
->title_block
= title_block
;
367 case PROP_TOP_MARGIN
:
368 data
->top_margin
= g_value_get_double(value
);
370 case PROP_RIGHT_MARGIN
:
371 data
->right_margin
= g_value_get_double(value
);
373 case PROP_BOTTOM_MARGIN
:
374 data
->bottom_margin
= g_value_get_double(value
);
376 case PROP_LEFT_MARGIN
:
377 data
->left_margin
= g_value_get_double(value
);
380 data
->has_frame
= g_value_get_boolean(value
);
382 case PROP_TOP_PADDING
:
383 data
->top_padding
= g_value_get_double(value
);
385 case PROP_RIGHT_PADDING
:
386 data
->right_padding
= g_value_get_double(value
);
388 case PROP_BOTTOM_PADDING
:
389 data
->bottom_padding
= g_value_get_double(value
);
391 case PROP_LEFT_PADDING
:
392 data
->left_padding
= g_value_get_double(value
);
395 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
404 * Creates a new empty canvas object.
406 * Returns: the canvas
413 return g_object_new(ADG_TYPE_CANVAS
, NULL
);
417 * adg_canvas_set_size:
418 * @canvas: an #AdgCanvas
419 * @size: the new size for the canvas
421 * Sets a specific size on @canvas. The x and/or y
422 * components of the returned #AdgPair could be %0, in which
423 * case the size returned by adg_entity_get_extents() on
424 * @canvas will be used instead.
429 adg_canvas_set_size(AdgCanvas
*canvas
, const AdgPair
*size
)
431 g_return_if_fail(ADG_IS_CANVAS(canvas
));
432 g_return_if_fail(size
!= NULL
);
434 g_object_set(canvas
, "size", size
, NULL
);
438 * adg_canvas_set_size_explicit:
439 * @canvas: an #AdgCanvas
440 * @x: the new width of the canvas or %0 to reset
441 * @y: the new height of the canvas or %0 to reset
443 * A convenient function to set the size of @canvas using
444 * explicit coordinates. Check adg_canvas_set_size() for
450 adg_canvas_set_size_explicit(AdgCanvas
*canvas
, gdouble x
, gdouble y
)
457 adg_canvas_set_size(canvas
, &size
);
461 * adg_canvas_get_size:
462 * @canvas: an #AdgCanvas
464 * Gets the specific size set on @canvas. The x and/or y
465 * components of the returned #AdgPair could be %0, in which
466 * case the size returned by adg_entity_get_extents() on
467 * @canvas will be used instead.
469 * Returns: the explicit size set on this canvas or %NULL on errors
474 adg_canvas_get_size(AdgCanvas
*canvas
)
476 AdgCanvasPrivate
*data
;
478 g_return_val_if_fail(ADG_IS_CANVAS(canvas
), NULL
);
485 * adg_canvas_set_background_dress:
486 * @canvas: an #AdgCanvas
487 * @dress: the new #AdgDress to use
489 * Sets a new background dress for rendering @canvas: the new
490 * dress must be a color dress.
495 adg_canvas_set_background_dress(AdgCanvas
*canvas
, AdgDress dress
)
497 g_return_if_fail(ADG_IS_CANVAS(canvas
));
498 g_object_set(canvas
, "background-dress", dress
, NULL
);
502 * adg_canvas_get_background_dress:
503 * @canvas: an #AdgCanvas
505 * Gets the background dress to be used in rendering @canvas.
507 * Returns: the current background dress
512 adg_canvas_get_background_dress(AdgCanvas
*canvas
)
514 AdgCanvasPrivate
*data
;
516 g_return_val_if_fail(ADG_IS_CANVAS(canvas
), ADG_DRESS_UNDEFINED
);
520 return data
->background_dress
;
524 * adg_canvas_set_frame_dress:
525 * @canvas: an #AdgCanvas
526 * @dress: the new #AdgDress to use
528 * Sets the #AdgCanvas:frame-dress property of @canvas to @dress:
529 * the new dress must be a line dress.
534 adg_canvas_set_frame_dress(AdgCanvas
*canvas
, AdgDress dress
)
536 g_return_if_fail(ADG_IS_CANVAS(canvas
));
537 g_object_set(canvas
, "frame-dress", dress
, NULL
);
541 * adg_canvas_get_frame_dress:
542 * @canvas: an #AdgCanvas
544 * Gets the frame dress to be used in rendering the border of @canvas.
546 * Returns: the current frame dress
551 adg_canvas_get_frame_dress(AdgCanvas
*canvas
)
553 AdgCanvasPrivate
*data
;
555 g_return_val_if_fail(ADG_IS_CANVAS(canvas
), ADG_DRESS_UNDEFINED
);
558 return data
->frame_dress
;
562 * adg_canvas_set_title_block:
563 * @canvas: an #AdgCanvas
564 * @title_block: a title block
566 * Sets the #AdgCanvas:title-block property of @canvas to @title_block.
568 * Although a title block entity could be added to @canvas in the usual
569 * way, that is using the adg_container_add() method, assigning a title
570 * block with adg_canvas_set_title_block() is somewhat different:
572 * - @title_block will be automatically attached to the bottom right
573 * corner of to the @canvas frame (this could be accomplished in the
574 * usual way too, by resetting the right and bottom paddings);
575 * - the @title_block boundary box is not taken into account while
576 * computing the extents of @canvas.
581 adg_canvas_set_title_block(AdgCanvas
*canvas
, AdgTitleBlock
*title_block
)
583 g_return_if_fail(ADG_IS_CANVAS(canvas
));
584 g_return_if_fail(title_block
== NULL
|| ADG_IS_TITLE_BLOCK(title_block
));
585 g_object_set(canvas
, "title-block", title_block
, NULL
);
589 * adg_canvas_get_title_block:
590 * @canvas: an #AdgCanvas
592 * Gets the #AdgTitleBlock object of @canvas: check
593 * adg_canvas_set_title_block() for details.
595 * Returns: the title block object or %NULL
600 adg_canvas_get_title_block(AdgCanvas
*canvas
)
602 AdgCanvasPrivate
*data
;
604 g_return_val_if_fail(ADG_IS_CANVAS(canvas
), NULL
);
607 return data
->title_block
;
611 * adg_canvas_set_top_margin:
612 * @canvas: an #AdgCanvas
613 * @value: the new margin, in global space
615 * Changes the top margin of @canvas by setting #AdgCanvas:top-margin
616 * to @value. Negative values are allowed.
621 adg_canvas_set_top_margin(AdgCanvas
*canvas
, gdouble value
)
623 g_return_if_fail(ADG_IS_CANVAS(canvas
));
624 g_object_set(canvas
, "top-margin", value
, NULL
);
628 * adg_canvas_get_top_margin:
629 * @canvas: an #AdgCanvas
631 * Gets the top margin (in global space) of @canvas.
633 * Returns: the requested margin or %0 on error
638 adg_canvas_get_top_margin(AdgCanvas
*canvas
)
640 AdgCanvasPrivate
*data
;
642 g_return_val_if_fail(ADG_IS_CANVAS(canvas
), 0.);
645 return data
->top_margin
;
649 * adg_canvas_set_right_margin:
650 * @canvas: an #AdgCanvas
651 * @value: the new margin, in global space
653 * Changes the right margin of @canvas by setting #AdgCanvas:right-margin
654 * to @value. Negative values are allowed.
659 adg_canvas_set_right_margin(AdgCanvas
*canvas
, gdouble value
)
661 g_return_if_fail(ADG_IS_CANVAS(canvas
));
662 g_object_set(canvas
, "right-margin", value
, NULL
);
666 * adg_canvas_get_right_margin:
667 * @canvas: an #AdgCanvas
669 * Gets the right margin (in global space) of @canvas.
671 * Returns: the requested margin or %0 on error
676 adg_canvas_get_right_margin(AdgCanvas
*canvas
)
678 AdgCanvasPrivate
*data
;
680 g_return_val_if_fail(ADG_IS_CANVAS(canvas
), 0.);
683 return data
->right_margin
;
688 * adg_canvas_set_bottom_margin:
689 * @canvas: an #AdgCanvas
690 * @value: the new margin, in global space
692 * Changes the bottom margin of @canvas by setting #AdgCanvas:bottom-margin
693 * to @value. Negative values are allowed.
698 adg_canvas_set_bottom_margin(AdgCanvas
*canvas
, gdouble value
)
700 g_return_if_fail(ADG_IS_CANVAS(canvas
));
701 g_object_set(canvas
, "bottom-margin", value
, NULL
);
705 * adg_canvas_get_bottom_margin:
706 * @canvas: an #AdgCanvas
708 * Gets the bottom margin (in global space) of @canvas.
710 * Returns: the requested margin or %0 on error
715 adg_canvas_get_bottom_margin(AdgCanvas
*canvas
)
717 AdgCanvasPrivate
*data
;
719 g_return_val_if_fail(ADG_IS_CANVAS(canvas
), 0.);
722 return data
->bottom_margin
;
726 * adg_canvas_set_left_margin:
727 * @canvas: an #AdgCanvas
728 * @value: the new margin, in global space
730 * Changes the left margin of @canvas by setting #AdgCanvas:left-margin
731 * to @value. Negative values are allowed.
736 adg_canvas_set_left_margin(AdgCanvas
*canvas
, gdouble value
)
738 g_return_if_fail(ADG_IS_CANVAS(canvas
));
739 g_object_set(canvas
, "left-margin", value
, NULL
);
743 * adg_canvas_get_left_margin:
744 * @canvas: an #AdgCanvas
746 * Gets the left margin (in global space) of @canvas.
748 * Returns: the requested margin or %0 on error
753 adg_canvas_get_left_margin(AdgCanvas
*canvas
)
755 AdgCanvasPrivate
*data
;
757 g_return_val_if_fail(ADG_IS_CANVAS(canvas
), 0.);
760 return data
->left_margin
;
764 * adg_canvas_set_margins:
765 * @canvas: an #AdgCanvas
766 * @top: top margin, in global space
767 * @right: right margin, in global space
768 * @bottom: bottom margin, in global space
769 * @left: left margin, in global space
771 * Convenient function to set all the margins at once.
776 adg_canvas_set_margins(AdgCanvas
*canvas
, gdouble top
, gdouble right
,
777 gdouble bottom
, gdouble left
)
779 g_return_if_fail(ADG_IS_CANVAS(canvas
));
780 g_object_set(canvas
, "top-margin", top
, "right-margin", right
,
781 "bottom-margin", bottom
, "left-margin", left
, NULL
);
785 * adg_canvas_apply_margins:
786 * @canvas: an #AdgCanvas
787 * @extents: where apply the margins
789 * A convenient function to apply the margins of @canvas to the
790 * arbitrary #CpmlExtents struct @extents.
795 adg_canvas_apply_margins(AdgCanvas
*canvas
, CpmlExtents
*extents
)
797 AdgCanvasPrivate
*data
;
799 g_return_if_fail(ADG_IS_CANVAS(canvas
));
803 extents
->org
.x
-= data
->left_margin
;
804 extents
->org
.y
-= data
->top_margin
;
805 extents
->size
.x
+= data
->left_margin
+ data
->right_margin
;
806 extents
->size
.y
+= data
->top_margin
+ data
->bottom_margin
;
810 * adg_canvas_switch_frame:
811 * @canvas: an #AdgCanvas
812 * @new_state: the new flag status
814 * Sets a new status on the #AdgCanvas:has-frame property: %TRUE
815 * means a border around the canvas extents (less the margins)
816 * should be rendered.
821 adg_canvas_switch_frame(AdgCanvas
*canvas
, gboolean new_state
)
823 g_return_if_fail(ADG_IS_CANVAS(canvas
));
824 g_object_set(canvas
, "has-frame", new_state
, NULL
);
828 * adg_canvas_has_frame:
829 * @canvas: an #AdgCanvas
831 * Gets the current status of the #AdgCanvas:has-frame property,
832 * that is whether a border around the canvas extents (less the
833 * margins) should be rendered (%TRUE) or not (%FALSE).
835 * Returns: the current status of the frame flag
840 adg_canvas_has_frame(AdgCanvas
*canvas
)
842 AdgCanvasPrivate
*data
;
844 g_return_val_if_fail(ADG_IS_CANVAS(canvas
), FALSE
);
847 return data
->has_frame
;
851 * adg_canvas_set_top_padding:
852 * @canvas: an #AdgCanvas
853 * @value: the new padding, in global space
855 * Changes the top padding of @canvas by setting #AdgCanvas:top-padding
856 * to @value. Negative values are allowed.
861 adg_canvas_set_top_padding(AdgCanvas
*canvas
, gdouble value
)
863 g_return_if_fail(ADG_IS_CANVAS(canvas
));
864 g_object_set(canvas
, "top-padding", value
, NULL
);
868 * adg_canvas_get_top_padding:
869 * @canvas: an #AdgCanvas
871 * Gets the top padding (in global space) of @canvas.
873 * Returns: the requested padding or %0 on error
878 adg_canvas_get_top_padding(AdgCanvas
*canvas
)
880 AdgCanvasPrivate
*data
;
882 g_return_val_if_fail(ADG_IS_CANVAS(canvas
), 0.);
885 return data
->top_padding
;
889 * adg_canvas_set_right_padding:
890 * @canvas: an #AdgCanvas
891 * @value: the new padding, in global space
893 * Changes the right padding of @canvas by setting #AdgCanvas:right-padding
894 * to @value. Negative values are allowed.
899 adg_canvas_set_right_padding(AdgCanvas
*canvas
, gdouble value
)
901 g_return_if_fail(ADG_IS_CANVAS(canvas
));
902 g_object_set(canvas
, "right-padding", value
, NULL
);
906 * adg_canvas_get_right_padding:
907 * @canvas: an #AdgCanvas
909 * Gets the right padding (in global space) of @canvas.
911 * Returns: the requested padding or %0 on error
916 adg_canvas_get_right_padding(AdgCanvas
*canvas
)
918 AdgCanvasPrivate
*data
;
920 g_return_val_if_fail(ADG_IS_CANVAS(canvas
), 0.);
923 return data
->right_padding
;
928 * adg_canvas_set_bottom_padding:
929 * @canvas: an #AdgCanvas
930 * @value: the new padding, in global space
932 * Changes the bottom padding of @canvas by setting #AdgCanvas:bottom-padding
933 * to @value. Negative values are allowed.
938 adg_canvas_set_bottom_padding(AdgCanvas
*canvas
, gdouble value
)
940 g_return_if_fail(ADG_IS_CANVAS(canvas
));
941 g_object_set(canvas
, "bottom-padding", value
, NULL
);
945 * adg_canvas_get_bottom_padding:
946 * @canvas: an #AdgCanvas
948 * Gets the bottom padding (in global space) of @canvas.
950 * Returns: the requested padding or %0 on error
955 adg_canvas_get_bottom_padding(AdgCanvas
*canvas
)
957 AdgCanvasPrivate
*data
;
959 g_return_val_if_fail(ADG_IS_CANVAS(canvas
), 0.);
962 return data
->bottom_padding
;
966 * adg_canvas_set_left_padding:
967 * @canvas: an #AdgCanvas
968 * @value: the new padding, in global space
970 * Changes the left padding of @canvas by setting #AdgCanvas:left-padding
971 * to @value. Negative values are allowed.
976 adg_canvas_set_left_padding(AdgCanvas
*canvas
, gdouble value
)
978 g_return_if_fail(ADG_IS_CANVAS(canvas
));
979 g_object_set(canvas
, "left-padding", value
, NULL
);
983 * adg_canvas_get_left_padding:
984 * @canvas: an #AdgCanvas
986 * Gets the left padding (in global space) of @canvas.
988 * Returns: the requested padding or %0 on error
993 adg_canvas_get_left_padding(AdgCanvas
*canvas
)
995 AdgCanvasPrivate
*data
;
997 g_return_val_if_fail(ADG_IS_CANVAS(canvas
), 0.);
1000 return data
->left_padding
;
1004 * adg_canvas_set_paddings:
1005 * @canvas: an #AdgCanvas
1006 * @top: top padding, in global space
1007 * @right: right padding, in global space
1008 * @bottom: bottom padding, in global space
1009 * @left: left padding, in global space
1011 * Convenient function to set all the paddings at once.
1016 adg_canvas_set_paddings(AdgCanvas
*canvas
, gdouble top
, gdouble right
,
1017 gdouble bottom
, gdouble left
)
1019 g_return_if_fail(ADG_IS_CANVAS(canvas
));
1020 g_object_set(canvas
, "top-padding", top
, "right-padding", right
,
1021 "bottom-padding", bottom
, "left-padding", left
, NULL
);
1026 _adg_global_changed(AdgEntity
*entity
)
1028 AdgCanvasPrivate
*data
= ((AdgCanvas
*) entity
)->data
;
1030 if (_ADG_OLD_ENTITY_CLASS
->global_changed
)
1031 _ADG_OLD_ENTITY_CLASS
->global_changed(entity
);
1033 if (data
->title_block
)
1034 adg_entity_global_changed((AdgEntity
*) data
->title_block
);
1038 _adg_local_changed(AdgEntity
*entity
)
1040 AdgCanvasPrivate
*data
= ((AdgCanvas
*) entity
)->data
;
1042 if (_ADG_OLD_ENTITY_CLASS
->local_changed
)
1043 _ADG_OLD_ENTITY_CLASS
->local_changed(entity
);
1045 if (data
->title_block
)
1046 adg_entity_local_changed((AdgEntity
*) data
->title_block
);
1050 _adg_invalidate(AdgEntity
*entity
)
1052 AdgCanvasPrivate
*data
= ((AdgCanvas
*) entity
)->data
;
1054 if (_ADG_OLD_ENTITY_CLASS
->invalidate
)
1055 _ADG_OLD_ENTITY_CLASS
->invalidate(entity
);
1057 if (data
->title_block
)
1058 adg_entity_invalidate((AdgEntity
*) data
->title_block
);
1062 _adg_arrange(AdgEntity
*entity
)
1064 AdgCanvasPrivate
*data
;
1065 CpmlExtents extents
;
1067 if (_ADG_OLD_ENTITY_CLASS
->arrange
)
1068 _ADG_OLD_ENTITY_CLASS
->arrange(entity
);
1070 cpml_extents_copy(&extents
, adg_entity_get_extents(entity
));
1072 /* The extents should be defined, otherwise there is no drawing */
1073 g_return_if_fail(extents
.is_defined
);
1075 data
= ((AdgCanvas
*) entity
)->data
;
1077 if (data
->size
.x
> 0 || data
->size
.y
> 0) {
1078 const AdgMatrix
*global
= adg_entity_get_global_matrix(entity
);
1083 paper
.size
.x
= data
->size
.x
;
1084 paper
.size
.y
= data
->size
.y
;
1086 cairo_matrix_transform_point(global
, &paper
.org
.x
, &paper
.org
.y
);
1087 cairo_matrix_transform_distance(global
, &paper
.size
.x
, &paper
.size
.y
);
1089 if (data
->size
.x
> 0) {
1090 extents
.org
.x
= paper
.org
.x
;
1091 extents
.size
.x
= paper
.size
.x
;
1093 if (data
->size
.y
> 0) {
1094 extents
.org
.y
= paper
.org
.y
;
1095 extents
.size
.y
= paper
.size
.y
;
1099 if (data
->size
.x
== 0) {
1100 extents
.org
.x
-= data
->left_padding
;
1101 extents
.size
.x
+= data
->left_padding
+ data
->right_padding
;
1103 if (data
->size
.y
== 0) {
1104 extents
.org
.y
-= data
->top_padding
;
1105 extents
.size
.y
+= data
->top_padding
+ data
->bottom_padding
;
1108 /* Impose the new extents */
1109 adg_entity_set_extents(entity
, &extents
);
1111 if (data
->title_block
) {
1112 AdgEntity
*title_block_entity
;
1113 const CpmlExtents
*title_block_extents
;
1116 title_block_entity
= (AdgEntity
*) data
->title_block
;
1117 adg_entity_arrange(title_block_entity
);
1118 title_block_extents
= adg_entity_get_extents(title_block_entity
);
1120 shift
.x
= extents
.org
.x
+ extents
.size
.x
- title_block_extents
->org
.x
1121 - title_block_extents
->size
.x
;
1122 shift
.y
= extents
.org
.y
+ extents
.size
.y
- title_block_extents
->org
.y
1123 - title_block_extents
->size
.y
;
1125 /* The following block could be optimized by skipping tiny shift,
1126 * usually left by rounding errors */
1127 if (shift
.x
!= 0 || shift
.y
!= 0) {
1128 AdgMatrix unglobal
, map
;
1129 adg_matrix_copy(&unglobal
, adg_entity_get_global_matrix(entity
));
1130 cairo_matrix_invert(&unglobal
);
1132 cairo_matrix_transform_distance(&unglobal
, &shift
.x
, &shift
.y
);
1133 cairo_matrix_init_translate(&map
, shift
.x
, shift
.y
);
1134 adg_entity_transform_global_map(title_block_entity
, &map
,
1135 ADG_TRANSFORM_AFTER
);
1137 adg_entity_global_changed(title_block_entity
);
1138 adg_entity_arrange(title_block_entity
);
1144 _adg_render(AdgEntity
*entity
, cairo_t
*cr
)
1146 AdgCanvasPrivate
*data
;
1147 const CpmlExtents
*extents
;
1149 data
= ((AdgCanvas
*) entity
)->data
;
1150 extents
= adg_entity_get_extents(entity
);
1154 /* Background fill */
1155 cairo_rectangle(cr
, extents
->org
.x
- data
->left_margin
,
1156 extents
->org
.y
- data
->top_margin
,
1157 extents
->size
.x
+ data
->left_margin
+ data
->right_margin
,
1158 extents
->size
.y
+ data
->top_margin
+ data
->bottom_margin
);
1159 adg_entity_apply_dress(entity
, data
->background_dress
, cr
);
1163 if (data
->has_frame
) {
1164 cairo_rectangle(cr
, extents
->org
.x
, extents
->org
.y
,
1165 extents
->size
.x
, extents
->size
.y
);
1166 cairo_transform(cr
, adg_entity_get_global_matrix(entity
));
1167 adg_entity_apply_dress(entity
, data
->frame_dress
, cr
);
1173 if (data
->title_block
)
1174 adg_entity_render((AdgEntity
*) data
->title_block
, cr
);
1176 if (_ADG_OLD_ENTITY_CLASS
->render
)
1177 _ADG_OLD_ENTITY_CLASS
->render(entity
, cr
);
1183 * adg_canvas_set_paper:
1184 * @canvas: an #AdgCanvas
1185 * @paper_name: a paper name
1186 * @orientation: the page orientation
1188 * A convenient function to set the size of @canvas using a
1189 * @paper_name and an @orientation value. This should be a
1190 * PWG 5101.1-2002 paper name and it will be passed as is to
1191 * gtk_paper_size_new(), so use any valid name accepted by
1194 * To reset this size, you could use adg_canvas_set_size() with a
1195 * %NULL size: in this way the size will match the boundary boxes
1196 * of the entities contained by the canvas.
1198 * Furthermore, the margins will be set to their default values,
1199 * that is the margins returned by the #GtkPaperSize API.
1200 * If you want to use your own margins on a named paper size,
1201 * set them <emphasis>after</emphasis> the call to this function.
1206 adg_canvas_set_paper(AdgCanvas
*canvas
, const gchar
*paper_name
,
1207 GtkPageOrientation orientation
)
1209 GtkPageSetup
*page_setup
;
1210 GtkPaperSize
*paper_size
;
1212 g_return_if_fail(ADG_IS_CANVAS(canvas
));
1213 g_return_if_fail(paper_name
!= NULL
);
1215 page_setup
= gtk_page_setup_new();
1216 paper_size
= gtk_paper_size_new(paper_name
);
1218 gtk_page_setup_set_paper_size(page_setup
, paper_size
);
1219 gtk_page_setup_set_orientation(page_setup
, orientation
);
1220 gtk_paper_size_free(paper_size
);
1222 adg_canvas_set_page_setup(canvas
, page_setup
);
1223 g_object_unref(page_setup
);
1227 * adg_canvas_set_page_setup:
1228 * @canvas: an #AdgCanvas
1229 * @page_setup: the page setup
1231 * A convenient function to setup the page of @canvas so it can
1232 * also be subsequentially used for printing. It is allowed to
1233 * pass %NULL for @page_setup to unset the setup data from @canvas.
1235 * A reference to @page_setup is added, so there is no need to keep
1236 * alive this object outside this function. The @page_setup pointer
1237 * is stored in the associative key %_adg_page_setup and can be
1238 * retrieved at any time with:
1241 * page_setup = g_object_get_data(G_OBJECT(canvas), "_adg_page_setup");
1244 * The size and margins provided by @page_setup are used to set the
1245 * size and margins of @canvas much in the same way as what
1246 * adg_canvas_set_paper() does. This means if you set a page and
1247 * then unset it, the canvas will retain size and margins of the
1248 * original page although @page_setup will not be used for printing.
1249 * You must unset the size with adg_canvas_set_size() with a %NULL size.
1252 * // By default, canvas does not have an explicit size
1253 * adg_canvas_set_page_setup(canvas, a4);
1254 * // Here canvas has the size and margins specified by a4
1255 * adg_canvas_set_page_setup(canvas, NULL);
1256 * // Now the only difference is that canvas is no more bound
1257 * // to the a4 page setup, so the following will return NULL:
1258 * page_setup = g_object_get_data(G_OBJECT(canvas), "_adg_page_setup");
1259 * // To restore the original status and have an autocomputed size:
1260 * adg_canvas_set_size(canvas, NULL);
1266 adg_canvas_set_page_setup(AdgCanvas
*canvas
, GtkPageSetup
*page_setup
)
1268 gdouble top
, right
, bottom
, left
;
1271 g_return_if_fail(ADG_IS_CANVAS(canvas
));
1273 if (page_setup
== NULL
) {
1274 /* By convention, NULL resets the default page but
1275 * does not change any other property */
1276 g_object_set_data((GObject
*) canvas
, "_adg_page_setup", NULL
);
1280 g_return_if_fail(GTK_IS_PAGE_SETUP(page_setup
));
1282 top
= gtk_page_setup_get_top_margin(page_setup
, GTK_UNIT_POINTS
);
1283 right
= gtk_page_setup_get_right_margin(page_setup
, GTK_UNIT_POINTS
);
1284 bottom
= gtk_page_setup_get_bottom_margin(page_setup
, GTK_UNIT_POINTS
);
1285 left
= gtk_page_setup_get_left_margin(page_setup
, GTK_UNIT_POINTS
);
1286 size
.x
= gtk_page_setup_get_page_width(page_setup
, GTK_UNIT_POINTS
);
1287 size
.y
= gtk_page_setup_get_page_height(page_setup
, GTK_UNIT_POINTS
);
1289 adg_canvas_set_size(canvas
, &size
);
1290 adg_canvas_set_margins(canvas
, top
, right
, bottom
, left
);
1292 g_object_ref(page_setup
);
1293 g_object_set_data_full((GObject
*) canvas
, "_adg_page_setup",
1294 page_setup
, g_object_unref
);