ADG: corrected g-ir-scanner warnings where possible
[adg.git] / src / adg / adg-canvas.c
blob8f1fc1b7b5c8a0886fa64c271664071e270a4980
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.
21 /**
22 * SECTION:adg-canvas
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
56 * simply ignored.
58 * Since: 1.0
59 **/
61 /**
62 * AdgCanvas:
64 * All fields are private and should not be used directly.
65 * Use its public methods instead.
67 * Since: 1.0
68 **/
71 #include "adg-internal.h"
72 #if GTK2_ENABLED
73 #include <gtk/gtk.h>
74 #endif
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)
94 enum {
95 PROP_0,
96 PROP_SIZE,
97 PROP_BACKGROUND_DRESS,
98 PROP_FRAME_DRESS,
99 PROP_TITLE_BLOCK,
100 PROP_TOP_MARGIN,
101 PROP_RIGHT_MARGIN,
102 PROP_BOTTOM_MARGIN,
103 PROP_LEFT_MARGIN,
104 PROP_HAS_FRAME,
105 PROP_TOP_PADDING,
106 PROP_RIGHT_PADDING,
107 PROP_BOTTOM_PADDING,
108 PROP_LEFT_PADDING
112 static void _adg_dispose (GObject *object);
113 static void _adg_get_property (GObject *object,
114 guint param_id,
115 GValue *value,
116 GParamSpec *pspec);
117 static void _adg_set_property (GObject *object,
118 guint param_id,
119 const GValue *value,
120 GParamSpec *pspec);
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,
126 cairo_t *cr);
129 static void
130 adg_canvas_class_init(AdgCanvasClass *klass)
132 GObjectClass *gobject_class;
133 AdgEntityClass *entity_class;
134 GParamSpec *param;
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",
152 P_("Canvas Size"),
153 P_("The size set on this canvas: use 0 to have an automatic dimension based on the canvas extents"),
154 ADG_TYPE_PAIR,
155 G_PARAM_READWRITE);
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,
162 G_PARAM_READWRITE);
163 g_object_class_install_property(gobject_class, PROP_BACKGROUND_DRESS, param);
165 param = adg_param_spec_dress("frame-dress",
166 P_("Frame Dress"),
167 P_("Line dress to use while drawing the frame around the canvas"),
168 ADG_DRESS_LINE_FRAME,
169 G_PARAM_READWRITE);
170 g_object_class_install_property(gobject_class, PROP_FRAME_DRESS, param);
172 param = g_param_spec_object("title-block",
173 P_("Title Block"),
174 P_("The title block to assign to this canvas"),
175 ADG_TYPE_TITLE_BLOCK,
176 G_PARAM_READWRITE);
177 g_object_class_install_property(gobject_class, PROP_TITLE_BLOCK, param);
179 param = g_param_spec_double("top-margin",
180 P_("Top Margin"),
181 P_("The margin (in global space) to leave above the frame"),
182 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
183 G_PARAM_READWRITE);
184 g_object_class_install_property(gobject_class, PROP_TOP_MARGIN, param);
186 param = g_param_spec_double("right-margin",
187 P_("Right Margin"),
188 P_("The margin (in global space) to leave empty at the right of the frame"),
189 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
190 G_PARAM_READWRITE);
191 g_object_class_install_property(gobject_class, PROP_RIGHT_MARGIN, param);
193 param = g_param_spec_double("bottom-margin",
194 P_("Bottom Margin"),
195 P_("The margin (in global space) to leave empty below the frame"),
196 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
197 G_PARAM_READWRITE);
198 g_object_class_install_property(gobject_class, PROP_BOTTOM_MARGIN, param);
200 param = g_param_spec_double("left-margin",
201 P_("Left Margin"),
202 P_("The margin (in global space) to leave empty at the left of the frame"),
203 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
204 G_PARAM_READWRITE);
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"),
210 TRUE,
211 G_PARAM_READWRITE);
212 g_object_class_install_property(gobject_class, PROP_HAS_FRAME, param);
214 param = g_param_spec_double("top-padding",
215 P_("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,
218 G_PARAM_READWRITE);
219 g_object_class_install_property(gobject_class, PROP_TOP_PADDING, param);
221 param = g_param_spec_double("right-padding",
222 P_("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,
225 G_PARAM_READWRITE);
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,
232 G_PARAM_READWRITE);
233 g_object_class_install_property(gobject_class, PROP_BOTTOM_PADDING, param);
235 param = g_param_spec_double("left-padding",
236 P_("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,
239 G_PARAM_READWRITE);
240 g_object_class_install_property(gobject_class, PROP_LEFT_PADDING, param);
243 static void
244 adg_canvas_init(AdgCanvas *canvas)
246 AdgCanvasPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(canvas,
247 ADG_TYPE_CANVAS,
248 AdgCanvasPrivate);
250 data->size.x = 0;
251 data->size.y = 0;
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;
265 canvas->data = data;
268 static void
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);
283 static void
284 _adg_get_property(GObject *object, guint prop_id,
285 GValue *value, GParamSpec *pspec)
287 AdgCanvasPrivate *data = ((AdgCanvas *) object)->data;
289 switch (prop_id) {
290 case PROP_SIZE:
291 g_value_set_boxed(value, &data->size);
292 break;
293 case PROP_BACKGROUND_DRESS:
294 g_value_set_int(value, data->background_dress);
295 break;
296 case PROP_FRAME_DRESS:
297 g_value_set_int(value, data->frame_dress);
298 break;
299 case PROP_TITLE_BLOCK:
300 g_value_set_object(value, data->title_block);
301 break;
302 case PROP_TOP_MARGIN:
303 g_value_set_double(value, data->top_margin);
304 break;
305 case PROP_RIGHT_MARGIN:
306 g_value_set_double(value, data->right_margin);
307 break;
308 case PROP_BOTTOM_MARGIN:
309 g_value_set_double(value, data->bottom_margin);
310 break;
311 case PROP_LEFT_MARGIN:
312 g_value_set_double(value, data->left_margin);
313 break;
314 case PROP_HAS_FRAME:
315 g_value_set_boolean(value, data->has_frame);
316 break;
317 case PROP_TOP_PADDING:
318 g_value_set_double(value, data->top_padding);
319 break;
320 case PROP_RIGHT_PADDING:
321 g_value_set_double(value, data->right_padding);
322 break;
323 case PROP_BOTTOM_PADDING:
324 g_value_set_double(value, data->bottom_padding);
325 break;
326 case PROP_LEFT_PADDING:
327 g_value_set_double(value, data->left_padding);
328 break;
329 default:
330 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
331 break;
335 static void
336 _adg_set_property(GObject *object, guint prop_id,
337 const GValue *value, GParamSpec *pspec)
339 AdgCanvas *canvas;
340 AdgCanvasPrivate *data;
341 AdgTitleBlock *title_block;
343 canvas = (AdgCanvas *) object;
344 data = canvas->data;
346 switch (prop_id) {
347 case PROP_SIZE:
348 adg_pair_copy(&data->size, g_value_get_boxed(value));
349 break;
350 case PROP_BACKGROUND_DRESS:
351 data->background_dress = g_value_get_int(value);
352 break;
353 case PROP_FRAME_DRESS:
354 data->frame_dress = g_value_get_int(value);
355 break;
356 case PROP_TITLE_BLOCK:
357 title_block = g_value_get_object(value);
358 if (title_block) {
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;
366 break;
367 case PROP_TOP_MARGIN:
368 data->top_margin = g_value_get_double(value);
369 break;
370 case PROP_RIGHT_MARGIN:
371 data->right_margin = g_value_get_double(value);
372 break;
373 case PROP_BOTTOM_MARGIN:
374 data->bottom_margin = g_value_get_double(value);
375 break;
376 case PROP_LEFT_MARGIN:
377 data->left_margin = g_value_get_double(value);
378 break;
379 case PROP_HAS_FRAME:
380 data->has_frame = g_value_get_boolean(value);
381 break;
382 case PROP_TOP_PADDING:
383 data->top_padding = g_value_get_double(value);
384 break;
385 case PROP_RIGHT_PADDING:
386 data->right_padding = g_value_get_double(value);
387 break;
388 case PROP_BOTTOM_PADDING:
389 data->bottom_padding = g_value_get_double(value);
390 break;
391 case PROP_LEFT_PADDING:
392 data->left_padding = g_value_get_double(value);
393 break;
394 default:
395 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
396 break;
402 * adg_canvas_new:
404 * Creates a new empty canvas object.
406 * Returns: (transfer full): the newly created canvas.
408 * Since: 1.0
410 AdgCanvas *
411 adg_canvas_new(void)
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.
426 * Since: 1.0
428 void
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
445 * further details.
447 * Since: 1.0
449 void
450 adg_canvas_set_size_explicit(AdgCanvas *canvas, gdouble x, gdouble y)
452 AdgPair size;
454 size.x = x;
455 size.y = 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.
471 * Since: 1.0
473 const AdgPair *
474 adg_canvas_get_size(AdgCanvas *canvas)
476 AdgCanvasPrivate *data;
478 g_return_val_if_fail(ADG_IS_CANVAS(canvas), NULL);
480 data = canvas->data;
481 return &data->size;
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.
492 * Since: 1.0
494 void
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: (transfer none): the current background dress.
509 * Since: 1.0
511 AdgDress
512 adg_canvas_get_background_dress(AdgCanvas *canvas)
514 AdgCanvasPrivate *data;
516 g_return_val_if_fail(ADG_IS_CANVAS(canvas), ADG_DRESS_UNDEFINED);
518 data = canvas->data;
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.
531 * Since: 1.0
533 void
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: (transfer none): the current frame dress.
548 * Since: 1.0
550 AdgDress
551 adg_canvas_get_frame_dress(AdgCanvas *canvas)
553 AdgCanvasPrivate *data;
555 g_return_val_if_fail(ADG_IS_CANVAS(canvas), ADG_DRESS_UNDEFINED);
557 data = canvas->data;
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.
578 * Since: 1.0
580 void
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 * The returned entity is owned by @canvas and should not be
596 * modified or freed.
598 * Returns: (transfer none): the title block object or %NULL.
600 * Since: 1.0
602 AdgTitleBlock *
603 adg_canvas_get_title_block(AdgCanvas *canvas)
605 AdgCanvasPrivate *data;
607 g_return_val_if_fail(ADG_IS_CANVAS(canvas), NULL);
609 data = canvas->data;
610 return data->title_block;
614 * adg_canvas_set_top_margin:
615 * @canvas: an #AdgCanvas
616 * @value: the new margin, in global space
618 * Changes the top margin of @canvas by setting #AdgCanvas:top-margin
619 * to @value. Negative values are allowed.
621 * Since: 1.0
623 void
624 adg_canvas_set_top_margin(AdgCanvas *canvas, gdouble value)
626 g_return_if_fail(ADG_IS_CANVAS(canvas));
627 g_object_set(canvas, "top-margin", value, NULL);
631 * adg_canvas_get_top_margin:
632 * @canvas: an #AdgCanvas
634 * Gets the top margin (in global space) of @canvas.
636 * Returns: the requested margin or %0 on error.
638 * Since: 1.0
640 gdouble
641 adg_canvas_get_top_margin(AdgCanvas *canvas)
643 AdgCanvasPrivate *data;
645 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
647 data = canvas->data;
648 return data->top_margin;
652 * adg_canvas_set_right_margin:
653 * @canvas: an #AdgCanvas
654 * @value: the new margin, in global space
656 * Changes the right margin of @canvas by setting #AdgCanvas:right-margin
657 * to @value. Negative values are allowed.
659 * Since: 1.0
661 void
662 adg_canvas_set_right_margin(AdgCanvas *canvas, gdouble value)
664 g_return_if_fail(ADG_IS_CANVAS(canvas));
665 g_object_set(canvas, "right-margin", value, NULL);
669 * adg_canvas_get_right_margin:
670 * @canvas: an #AdgCanvas
672 * Gets the right margin (in global space) of @canvas.
674 * Returns: the requested margin or %0 on error.
676 * Since: 1.0
678 gdouble
679 adg_canvas_get_right_margin(AdgCanvas *canvas)
681 AdgCanvasPrivate *data;
683 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
685 data = canvas->data;
686 return data->right_margin;
691 * adg_canvas_set_bottom_margin:
692 * @canvas: an #AdgCanvas
693 * @value: the new margin, in global space
695 * Changes the bottom margin of @canvas by setting #AdgCanvas:bottom-margin
696 * to @value. Negative values are allowed.
698 * Since: 1.0
700 void
701 adg_canvas_set_bottom_margin(AdgCanvas *canvas, gdouble value)
703 g_return_if_fail(ADG_IS_CANVAS(canvas));
704 g_object_set(canvas, "bottom-margin", value, NULL);
708 * adg_canvas_get_bottom_margin:
709 * @canvas: an #AdgCanvas
711 * Gets the bottom margin (in global space) of @canvas.
713 * Returns: the requested margin or %0 on error.
715 * Since: 1.0
717 gdouble
718 adg_canvas_get_bottom_margin(AdgCanvas *canvas)
720 AdgCanvasPrivate *data;
722 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
724 data = canvas->data;
725 return data->bottom_margin;
729 * adg_canvas_set_left_margin:
730 * @canvas: an #AdgCanvas
731 * @value: the new margin, in global space
733 * Changes the left margin of @canvas by setting #AdgCanvas:left-margin
734 * to @value. Negative values are allowed.
736 * Since: 1.0
738 void
739 adg_canvas_set_left_margin(AdgCanvas *canvas, gdouble value)
741 g_return_if_fail(ADG_IS_CANVAS(canvas));
742 g_object_set(canvas, "left-margin", value, NULL);
746 * adg_canvas_get_left_margin:
747 * @canvas: an #AdgCanvas
749 * Gets the left margin (in global space) of @canvas.
751 * Returns: the requested margin or %0 on error.
753 * Since: 1.0
755 gdouble
756 adg_canvas_get_left_margin(AdgCanvas *canvas)
758 AdgCanvasPrivate *data;
760 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
762 data = canvas->data;
763 return data->left_margin;
767 * adg_canvas_set_margins:
768 * @canvas: an #AdgCanvas
769 * @top: top margin, in global space
770 * @right: right margin, in global space
771 * @bottom: bottom margin, in global space
772 * @left: left margin, in global space
774 * Convenient function to set all the margins at once.
776 * Since: 1.0
778 void
779 adg_canvas_set_margins(AdgCanvas *canvas, gdouble top, gdouble right,
780 gdouble bottom, gdouble left)
782 g_return_if_fail(ADG_IS_CANVAS(canvas));
783 g_object_set(canvas, "top-margin", top, "right-margin", right,
784 "bottom-margin", bottom, "left-margin", left, NULL);
788 * adg_canvas_apply_margins:
789 * @canvas: an #AdgCanvas
790 * @extents: where apply the margins
792 * A convenient function to apply the margins of @canvas to the
793 * arbitrary #CpmlExtents struct @extents.
795 * Since: 1.0
797 void
798 adg_canvas_apply_margins(AdgCanvas *canvas, CpmlExtents *extents)
800 AdgCanvasPrivate *data;
802 g_return_if_fail(ADG_IS_CANVAS(canvas));
804 data = canvas->data;
806 extents->org.x -= data->left_margin;
807 extents->org.y -= data->top_margin;
808 extents->size.x += data->left_margin + data->right_margin;
809 extents->size.y += data->top_margin + data->bottom_margin;
813 * adg_canvas_switch_frame:
814 * @canvas: an #AdgCanvas
815 * @new_state: the new flag status
817 * Sets a new status on the #AdgCanvas:has-frame property: %TRUE
818 * means a border around the canvas extents (less the margins)
819 * should be rendered.
821 * Since: 1.0
823 void
824 adg_canvas_switch_frame(AdgCanvas *canvas, gboolean new_state)
826 g_return_if_fail(ADG_IS_CANVAS(canvas));
827 g_object_set(canvas, "has-frame", new_state, NULL);
831 * adg_canvas_has_frame:
832 * @canvas: an #AdgCanvas
834 * Gets the current status of the #AdgCanvas:has-frame property,
835 * that is whether a border around the canvas extents (less the
836 * margins) should be rendered (%TRUE) or not (%FALSE).
838 * Returns: the current status of the frame flag.
840 * Since: 1.0
842 gboolean
843 adg_canvas_has_frame(AdgCanvas *canvas)
845 AdgCanvasPrivate *data;
847 g_return_val_if_fail(ADG_IS_CANVAS(canvas), FALSE);
849 data = canvas->data;
850 return data->has_frame;
854 * adg_canvas_set_top_padding:
855 * @canvas: an #AdgCanvas
856 * @value: the new padding, in global space
858 * Changes the top padding of @canvas by setting #AdgCanvas:top-padding
859 * to @value. Negative values are allowed.
861 * Since: 1.0
863 void
864 adg_canvas_set_top_padding(AdgCanvas *canvas, gdouble value)
866 g_return_if_fail(ADG_IS_CANVAS(canvas));
867 g_object_set(canvas, "top-padding", value, NULL);
871 * adg_canvas_get_top_padding:
872 * @canvas: an #AdgCanvas
874 * Gets the top padding (in global space) of @canvas.
876 * Returns: the requested padding or %0 on error.
878 * Since: 1.0
880 gdouble
881 adg_canvas_get_top_padding(AdgCanvas *canvas)
883 AdgCanvasPrivate *data;
885 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
887 data = canvas->data;
888 return data->top_padding;
892 * adg_canvas_set_right_padding:
893 * @canvas: an #AdgCanvas
894 * @value: the new padding, in global space
896 * Changes the right padding of @canvas by setting #AdgCanvas:right-padding
897 * to @value. Negative values are allowed.
899 * Since: 1.0
901 void
902 adg_canvas_set_right_padding(AdgCanvas *canvas, gdouble value)
904 g_return_if_fail(ADG_IS_CANVAS(canvas));
905 g_object_set(canvas, "right-padding", value, NULL);
909 * adg_canvas_get_right_padding:
910 * @canvas: an #AdgCanvas
912 * Gets the right padding (in global space) of @canvas.
914 * Returns: the requested padding or %0 on error.
916 * Since: 1.0
918 gdouble
919 adg_canvas_get_right_padding(AdgCanvas *canvas)
921 AdgCanvasPrivate *data;
923 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
925 data = canvas->data;
926 return data->right_padding;
931 * adg_canvas_set_bottom_padding:
932 * @canvas: an #AdgCanvas
933 * @value: the new padding, in global space
935 * Changes the bottom padding of @canvas by setting #AdgCanvas:bottom-padding
936 * to @value. Negative values are allowed.
938 * Since: 1.0
940 void
941 adg_canvas_set_bottom_padding(AdgCanvas *canvas, gdouble value)
943 g_return_if_fail(ADG_IS_CANVAS(canvas));
944 g_object_set(canvas, "bottom-padding", value, NULL);
948 * adg_canvas_get_bottom_padding:
949 * @canvas: an #AdgCanvas
951 * Gets the bottom padding (in global space) of @canvas.
953 * Returns: the requested padding or %0 on error.
955 * Since: 1.0
957 gdouble
958 adg_canvas_get_bottom_padding(AdgCanvas *canvas)
960 AdgCanvasPrivate *data;
962 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
964 data = canvas->data;
965 return data->bottom_padding;
969 * adg_canvas_set_left_padding:
970 * @canvas: an #AdgCanvas
971 * @value: the new padding, in global space
973 * Changes the left padding of @canvas by setting #AdgCanvas:left-padding
974 * to @value. Negative values are allowed.
976 * Since: 1.0
978 void
979 adg_canvas_set_left_padding(AdgCanvas *canvas, gdouble value)
981 g_return_if_fail(ADG_IS_CANVAS(canvas));
982 g_object_set(canvas, "left-padding", value, NULL);
986 * adg_canvas_get_left_padding:
987 * @canvas: an #AdgCanvas
989 * Gets the left padding (in global space) of @canvas.
991 * Returns: the requested padding or %0 on error.
993 * Since: 1.0
995 gdouble
996 adg_canvas_get_left_padding(AdgCanvas *canvas)
998 AdgCanvasPrivate *data;
1000 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
1002 data = canvas->data;
1003 return data->left_padding;
1007 * adg_canvas_set_paddings:
1008 * @canvas: an #AdgCanvas
1009 * @top: top padding, in global space
1010 * @right: right padding, in global space
1011 * @bottom: bottom padding, in global space
1012 * @left: left padding, in global space
1014 * Convenient function to set all the paddings at once.
1016 * Since: 1.0
1018 void
1019 adg_canvas_set_paddings(AdgCanvas *canvas, gdouble top, gdouble right,
1020 gdouble bottom, gdouble left)
1022 g_return_if_fail(ADG_IS_CANVAS(canvas));
1023 g_object_set(canvas, "top-padding", top, "right-padding", right,
1024 "bottom-padding", bottom, "left-padding", left, NULL);
1028 static void
1029 _adg_global_changed(AdgEntity *entity)
1031 AdgCanvasPrivate *data = ((AdgCanvas *) entity)->data;
1033 if (_ADG_OLD_ENTITY_CLASS->global_changed)
1034 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
1036 if (data->title_block)
1037 adg_entity_global_changed((AdgEntity *) data->title_block);
1040 static void
1041 _adg_local_changed(AdgEntity *entity)
1043 AdgCanvasPrivate *data = ((AdgCanvas *) entity)->data;
1045 if (_ADG_OLD_ENTITY_CLASS->local_changed)
1046 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
1048 if (data->title_block)
1049 adg_entity_local_changed((AdgEntity *) data->title_block);
1052 static void
1053 _adg_invalidate(AdgEntity *entity)
1055 AdgCanvasPrivate *data = ((AdgCanvas *) entity)->data;
1057 if (_ADG_OLD_ENTITY_CLASS->invalidate)
1058 _ADG_OLD_ENTITY_CLASS->invalidate(entity);
1060 if (data->title_block)
1061 adg_entity_invalidate((AdgEntity *) data->title_block);
1064 static void
1065 _adg_arrange(AdgEntity *entity)
1067 AdgCanvasPrivate *data;
1068 CpmlExtents extents;
1070 if (_ADG_OLD_ENTITY_CLASS->arrange)
1071 _ADG_OLD_ENTITY_CLASS->arrange(entity);
1073 cpml_extents_copy(&extents, adg_entity_get_extents(entity));
1075 /* The extents should be defined, otherwise there is no drawing */
1076 g_return_if_fail(extents.is_defined);
1078 data = ((AdgCanvas *) entity)->data;
1080 if (data->size.x > 0 || data->size.y > 0) {
1081 const AdgMatrix *global = adg_entity_get_global_matrix(entity);
1082 CpmlExtents paper;
1084 paper.org.x = 0;
1085 paper.org.y = 0;
1086 paper.size.x = data->size.x;
1087 paper.size.y = data->size.y;
1089 cairo_matrix_transform_point(global, &paper.org.x, &paper.org.y);
1090 cairo_matrix_transform_distance(global, &paper.size.x, &paper.size.y);
1092 if (data->size.x > 0) {
1093 extents.org.x = paper.org.x;
1094 extents.size.x = paper.size.x;
1096 if (data->size.y > 0) {
1097 extents.org.y = paper.org.y;
1098 extents.size.y = paper.size.y;
1102 if (data->size.x == 0) {
1103 extents.org.x -= data->left_padding;
1104 extents.size.x += data->left_padding + data->right_padding;
1106 if (data->size.y == 0) {
1107 extents.org.y -= data->top_padding;
1108 extents.size.y += data->top_padding + data->bottom_padding;
1111 /* Impose the new extents */
1112 adg_entity_set_extents(entity, &extents);
1114 if (data->title_block) {
1115 AdgEntity *title_block_entity;
1116 const CpmlExtents *title_block_extents;
1117 AdgPair shift;
1119 title_block_entity = (AdgEntity *) data->title_block;
1120 adg_entity_arrange(title_block_entity);
1121 title_block_extents = adg_entity_get_extents(title_block_entity);
1123 shift.x = extents.org.x + extents.size.x - title_block_extents->org.x
1124 - title_block_extents->size.x;
1125 shift.y = extents.org.y + extents.size.y - title_block_extents->org.y
1126 - title_block_extents->size.y;
1128 /* The following block could be optimized by skipping tiny shift,
1129 * usually left by rounding errors */
1130 if (shift.x != 0 || shift.y != 0) {
1131 AdgMatrix unglobal, map;
1132 adg_matrix_copy(&unglobal, adg_entity_get_global_matrix(entity));
1133 cairo_matrix_invert(&unglobal);
1135 cairo_matrix_transform_distance(&unglobal, &shift.x, &shift.y);
1136 cairo_matrix_init_translate(&map, shift.x, shift.y);
1137 adg_entity_transform_global_map(title_block_entity, &map,
1138 ADG_TRANSFORM_AFTER);
1140 adg_entity_global_changed(title_block_entity);
1141 adg_entity_arrange(title_block_entity);
1146 static void
1147 _adg_render(AdgEntity *entity, cairo_t *cr)
1149 AdgCanvasPrivate *data;
1150 const CpmlExtents *extents;
1152 data = ((AdgCanvas *) entity)->data;
1153 extents = adg_entity_get_extents(entity);
1155 cairo_save(cr);
1157 /* Background fill */
1158 cairo_rectangle(cr, extents->org.x - data->left_margin,
1159 extents->org.y - data->top_margin,
1160 extents->size.x + data->left_margin + data->right_margin,
1161 extents->size.y + data->top_margin + data->bottom_margin);
1162 adg_entity_apply_dress(entity, data->background_dress, cr);
1163 cairo_fill(cr);
1165 /* Frame line */
1166 if (data->has_frame) {
1167 cairo_rectangle(cr, extents->org.x, extents->org.y,
1168 extents->size.x, extents->size.y);
1169 cairo_transform(cr, adg_entity_get_global_matrix(entity));
1170 adg_entity_apply_dress(entity, data->frame_dress, cr);
1171 cairo_stroke(cr);
1174 cairo_restore(cr);
1176 if (data->title_block)
1177 adg_entity_render((AdgEntity *) data->title_block, cr);
1179 if (_ADG_OLD_ENTITY_CLASS->render)
1180 _ADG_OLD_ENTITY_CLASS->render(entity, cr);
1183 #if GTK2_ENABLED
1186 * adg_canvas_set_paper:
1187 * @canvas: an #AdgCanvas
1188 * @paper_name: a paper name
1189 * @orientation: the page orientation
1191 * A convenient function to set the size of @canvas using a
1192 * @paper_name and an @orientation value. This should be a
1193 * PWG 5101.1-2002 paper name and it will be passed as is to
1194 * gtk_paper_size_new(), so use any valid name accepted by
1195 * that function.
1197 * To reset this size, you could use adg_canvas_set_size() with a
1198 * %NULL size: in this way the size will match the boundary boxes
1199 * of the entities contained by the canvas.
1201 * Furthermore, the margins will be set to their default values,
1202 * that is the margins returned by the #GtkPaperSize API.
1203 * If you want to use your own margins on a named paper size,
1204 * set them <emphasis>after</emphasis> the call to this function.
1206 * Since: 1.0
1208 void
1209 adg_canvas_set_paper(AdgCanvas *canvas, const gchar *paper_name,
1210 GtkPageOrientation orientation)
1212 GtkPageSetup *page_setup;
1213 GtkPaperSize *paper_size;
1215 g_return_if_fail(ADG_IS_CANVAS(canvas));
1216 g_return_if_fail(paper_name != NULL);
1218 page_setup = gtk_page_setup_new();
1219 paper_size = gtk_paper_size_new(paper_name);
1221 gtk_page_setup_set_paper_size(page_setup, paper_size);
1222 gtk_page_setup_set_orientation(page_setup, orientation);
1223 gtk_paper_size_free(paper_size);
1225 adg_canvas_set_page_setup(canvas, page_setup);
1226 g_object_unref(page_setup);
1230 * adg_canvas_set_page_setup:
1231 * @canvas: an #AdgCanvas
1232 * @page_setup: the page setup
1234 * A convenient function to setup the page of @canvas so it can
1235 * also be subsequentially used for printing. It is allowed to
1236 * pass %NULL for @page_setup to unset the setup data from @canvas.
1238 * A reference to @page_setup is added, so there is no need to keep
1239 * alive this object outside this function. The @page_setup pointer
1240 * is stored in the associative key %_adg_page_setup and can be
1241 * retrieved at any time with:
1243 * |[
1244 * page_setup = g_object_get_data(G_OBJECT(canvas), "_adg_page_setup");
1245 * ]|
1247 * The size and margins provided by @page_setup are used to set the
1248 * size and margins of @canvas much in the same way as what
1249 * adg_canvas_set_paper() does. This means if you set a page and
1250 * then unset it, the canvas will retain size and margins of the
1251 * original page although @page_setup will not be used for printing.
1252 * You must unset the size with adg_canvas_set_size() with a %NULL size.
1254 * |[
1255 * // By default, canvas does not have an explicit size
1256 * adg_canvas_set_page_setup(canvas, a4);
1257 * // Here canvas has the size and margins specified by a4
1258 * adg_canvas_set_page_setup(canvas, NULL);
1259 * // Now the only difference is that canvas is no more bound
1260 * // to the a4 page setup, so the following will return NULL:
1261 * page_setup = g_object_get_data(G_OBJECT(canvas), "_adg_page_setup");
1262 * // To restore the original status and have an autocomputed size:
1263 * adg_canvas_set_size(canvas, NULL);
1264 * ]|
1266 * Since: 1.0
1268 void
1269 adg_canvas_set_page_setup(AdgCanvas *canvas, GtkPageSetup *page_setup)
1271 gdouble top, right, bottom, left;
1272 AdgPair size;
1274 g_return_if_fail(ADG_IS_CANVAS(canvas));
1276 if (page_setup == NULL) {
1277 /* By convention, NULL resets the default page but
1278 * does not change any other property */
1279 g_object_set_data((GObject *) canvas, "_adg_page_setup", NULL);
1280 return;
1283 g_return_if_fail(GTK_IS_PAGE_SETUP(page_setup));
1285 top = gtk_page_setup_get_top_margin(page_setup, GTK_UNIT_POINTS);
1286 right = gtk_page_setup_get_right_margin(page_setup, GTK_UNIT_POINTS);
1287 bottom = gtk_page_setup_get_bottom_margin(page_setup, GTK_UNIT_POINTS);
1288 left = gtk_page_setup_get_left_margin(page_setup, GTK_UNIT_POINTS);
1289 size.x = gtk_page_setup_get_page_width(page_setup, GTK_UNIT_POINTS);
1290 size.y = gtk_page_setup_get_page_height(page_setup, GTK_UNIT_POINTS);
1292 adg_canvas_set_size(canvas, &size);
1293 adg_canvas_set_margins(canvas, top, right, bottom, left);
1295 g_object_ref(page_setup);
1296 g_object_set_data_full((GObject *) canvas, "_adg_page_setup",
1297 page_setup, g_object_unref);
1300 #endif