[build] Major rewrite: merged adg-gtk into adg
[adg.git] / src / adg / adg-canvas.c
blob6b08325a514d665de93b8a1df9093df098c9d384
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"
73 #include "adg-container.h"
74 #include "adg-table.h"
75 #include "adg-title-block.h"
76 #include "adg-style.h"
77 #include "adg-color-style.h"
78 #include "adg-dress.h"
79 #include "adg-dress-builtins.h"
81 #include "adg-canvas.h"
82 #include "adg-canvas-private.h"
84 #if GTK2_ENABLED
85 #include <gtk/gtk.h>
86 #include "adg-canvas-gtk.h"
87 #endif
90 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_canvas_parent_class)
91 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_canvas_parent_class)
94 G_DEFINE_TYPE(AdgCanvas, adg_canvas, ADG_TYPE_CONTAINER)
96 enum {
97 PROP_0,
98 PROP_SIZE,
99 PROP_BACKGROUND_DRESS,
100 PROP_FRAME_DRESS,
101 PROP_TITLE_BLOCK,
102 PROP_TOP_MARGIN,
103 PROP_RIGHT_MARGIN,
104 PROP_BOTTOM_MARGIN,
105 PROP_LEFT_MARGIN,
106 PROP_HAS_FRAME,
107 PROP_TOP_PADDING,
108 PROP_RIGHT_PADDING,
109 PROP_BOTTOM_PADDING,
110 PROP_LEFT_PADDING
114 static void _adg_dispose (GObject *object);
115 static void _adg_get_property (GObject *object,
116 guint param_id,
117 GValue *value,
118 GParamSpec *pspec);
119 static void _adg_set_property (GObject *object,
120 guint param_id,
121 const GValue *value,
122 GParamSpec *pspec);
123 static void _adg_global_changed (AdgEntity *entity);
124 static void _adg_local_changed (AdgEntity *entity);
125 static void _adg_invalidate (AdgEntity *entity);
126 static void _adg_arrange (AdgEntity *entity);
127 static void _adg_render (AdgEntity *entity,
128 cairo_t *cr);
131 static void
132 adg_canvas_class_init(AdgCanvasClass *klass)
134 GObjectClass *gobject_class;
135 AdgEntityClass *entity_class;
136 GParamSpec *param;
138 gobject_class = (GObjectClass *) klass;
139 entity_class = (AdgEntityClass *) klass;
141 g_type_class_add_private(klass, sizeof(AdgCanvasPrivate));
143 gobject_class->dispose = _adg_dispose;
144 gobject_class->get_property = _adg_get_property;
145 gobject_class->set_property = _adg_set_property;
147 entity_class->global_changed = _adg_global_changed;
148 entity_class->local_changed = _adg_local_changed;
149 entity_class->invalidate = _adg_invalidate;
150 entity_class->arrange = _adg_arrange;
151 entity_class->render = _adg_render;
153 param = g_param_spec_boxed("size",
154 P_("Canvas Size"),
155 P_("The size set on this canvas: use 0 to have an automatic dimension based on the canvas extents"),
156 ADG_TYPE_PAIR,
157 G_PARAM_READWRITE);
158 g_object_class_install_property(gobject_class, PROP_SIZE, param);
160 param = adg_param_spec_dress("background-dress",
161 P_("Background Dress"),
162 P_("The color dress to use for the canvas background"),
163 ADG_DRESS_COLOR_BACKGROUND,
164 G_PARAM_READWRITE);
165 g_object_class_install_property(gobject_class, PROP_BACKGROUND_DRESS, param);
167 param = adg_param_spec_dress("frame-dress",
168 P_("Frame Dress"),
169 P_("Line dress to use while drawing the frame around the canvas"),
170 ADG_DRESS_LINE_FRAME,
171 G_PARAM_READWRITE);
172 g_object_class_install_property(gobject_class, PROP_FRAME_DRESS, param);
174 param = g_param_spec_object("title-block",
175 P_("Title Block"),
176 P_("The title block to assign to this canvas"),
177 ADG_TYPE_TITLE_BLOCK,
178 G_PARAM_READWRITE);
179 g_object_class_install_property(gobject_class, PROP_TITLE_BLOCK, param);
181 param = g_param_spec_double("top-margin",
182 P_("Top Margin"),
183 P_("The margin (in global space) to leave above the frame"),
184 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
185 G_PARAM_READWRITE);
186 g_object_class_install_property(gobject_class, PROP_TOP_MARGIN, param);
188 param = g_param_spec_double("right-margin",
189 P_("Right Margin"),
190 P_("The margin (in global space) to leave empty at the right of the frame"),
191 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
192 G_PARAM_READWRITE);
193 g_object_class_install_property(gobject_class, PROP_RIGHT_MARGIN, param);
195 param = g_param_spec_double("bottom-margin",
196 P_("Bottom Margin"),
197 P_("The margin (in global space) to leave empty below the frame"),
198 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
199 G_PARAM_READWRITE);
200 g_object_class_install_property(gobject_class, PROP_BOTTOM_MARGIN, param);
202 param = g_param_spec_double("left-margin",
203 P_("Left Margin"),
204 P_("The margin (in global space) to leave empty at the left of the frame"),
205 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
206 G_PARAM_READWRITE);
207 g_object_class_install_property(gobject_class, PROP_LEFT_MARGIN, param);
209 param = g_param_spec_boolean("has-frame",
210 P_("Has Frame Flag"),
211 P_("If enabled, a frame using the frame dress will be drawn around the canvas extents, taking into account the margins"),
212 TRUE,
213 G_PARAM_READWRITE);
214 g_object_class_install_property(gobject_class, PROP_HAS_FRAME, param);
216 param = g_param_spec_double("top-padding",
217 P_("Top Padding"),
218 P_("The padding (in global space) to leave empty above between the drawing and the frame"),
219 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
220 G_PARAM_READWRITE);
221 g_object_class_install_property(gobject_class, PROP_TOP_PADDING, param);
223 param = g_param_spec_double("right-padding",
224 P_("Right Padding"),
225 P_("The padding (in global space) to leave empty at the right between the drawing and the frame"),
226 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
227 G_PARAM_READWRITE);
228 g_object_class_install_property(gobject_class, PROP_RIGHT_PADDING, param);
230 param = g_param_spec_double("bottom-padding",
231 P_("Bottom Padding"),
232 P_("The padding (in global space) to leave empty below between the drawing and the frame"),
233 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
234 G_PARAM_READWRITE);
235 g_object_class_install_property(gobject_class, PROP_BOTTOM_PADDING, param);
237 param = g_param_spec_double("left-padding",
238 P_("Left Padding"),
239 P_("The padding (in global space) to leave empty at the left between the drawing and the frame"),
240 -G_MAXDOUBLE, G_MAXDOUBLE, 15,
241 G_PARAM_READWRITE);
242 g_object_class_install_property(gobject_class, PROP_LEFT_PADDING, param);
245 static void
246 adg_canvas_init(AdgCanvas *canvas)
248 AdgCanvasPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(canvas,
249 ADG_TYPE_CANVAS,
250 AdgCanvasPrivate);
252 data->size.x = 0;
253 data->size.y = 0;
254 data->background_dress = ADG_DRESS_COLOR_BACKGROUND;
255 data->frame_dress = ADG_DRESS_LINE_FRAME;
256 data->title_block = NULL;
257 data->top_margin = 15;
258 data->right_margin = 15;
259 data->bottom_margin = 15;
260 data->left_margin = 15;
261 data->has_frame = TRUE;
262 data->top_padding = 15;
263 data->right_padding = 15;
264 data->bottom_padding = 15;
265 data->left_padding = 15;
267 canvas->data = data;
270 static void
271 _adg_dispose(GObject *object)
273 AdgCanvasPrivate *data = ((AdgCanvas *) object)->data;
275 if (data->title_block) {
276 g_object_unref(data->title_block);
277 data->title_block = NULL;
280 if (_ADG_OLD_OBJECT_CLASS->dispose)
281 _ADG_OLD_OBJECT_CLASS->dispose(object);
285 static void
286 _adg_get_property(GObject *object, guint prop_id,
287 GValue *value, GParamSpec *pspec)
289 AdgCanvasPrivate *data = ((AdgCanvas *) object)->data;
291 switch (prop_id) {
292 case PROP_SIZE:
293 g_value_set_boxed(value, &data->size);
294 break;
295 case PROP_BACKGROUND_DRESS:
296 g_value_set_int(value, data->background_dress);
297 break;
298 case PROP_FRAME_DRESS:
299 g_value_set_int(value, data->frame_dress);
300 break;
301 case PROP_TITLE_BLOCK:
302 g_value_set_object(value, data->title_block);
303 break;
304 case PROP_TOP_MARGIN:
305 g_value_set_double(value, data->top_margin);
306 break;
307 case PROP_RIGHT_MARGIN:
308 g_value_set_double(value, data->right_margin);
309 break;
310 case PROP_BOTTOM_MARGIN:
311 g_value_set_double(value, data->bottom_margin);
312 break;
313 case PROP_LEFT_MARGIN:
314 g_value_set_double(value, data->left_margin);
315 break;
316 case PROP_HAS_FRAME:
317 g_value_set_boolean(value, data->has_frame);
318 break;
319 case PROP_TOP_PADDING:
320 g_value_set_double(value, data->top_padding);
321 break;
322 case PROP_RIGHT_PADDING:
323 g_value_set_double(value, data->right_padding);
324 break;
325 case PROP_BOTTOM_PADDING:
326 g_value_set_double(value, data->bottom_padding);
327 break;
328 case PROP_LEFT_PADDING:
329 g_value_set_double(value, data->left_padding);
330 break;
331 default:
332 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
333 break;
337 static void
338 _adg_set_property(GObject *object, guint prop_id,
339 const GValue *value, GParamSpec *pspec)
341 AdgCanvas *canvas;
342 AdgCanvasPrivate *data;
343 AdgTitleBlock *title_block;
345 canvas = (AdgCanvas *) object;
346 data = canvas->data;
348 switch (prop_id) {
349 case PROP_SIZE:
350 adg_pair_copy(&data->size, g_value_get_boxed(value));
351 break;
352 case PROP_BACKGROUND_DRESS:
353 data->background_dress = g_value_get_int(value);
354 break;
355 case PROP_FRAME_DRESS:
356 data->frame_dress = g_value_get_int(value);
357 break;
358 case PROP_TITLE_BLOCK:
359 title_block = g_value_get_object(value);
360 if (title_block) {
361 g_object_ref(title_block);
362 adg_entity_set_parent((AdgEntity *) title_block,
363 (AdgEntity *) canvas);
365 if (data->title_block)
366 g_object_unref(data->title_block);
367 data->title_block = title_block;
368 break;
369 case PROP_TOP_MARGIN:
370 data->top_margin = g_value_get_double(value);
371 break;
372 case PROP_RIGHT_MARGIN:
373 data->right_margin = g_value_get_double(value);
374 break;
375 case PROP_BOTTOM_MARGIN:
376 data->bottom_margin = g_value_get_double(value);
377 break;
378 case PROP_LEFT_MARGIN:
379 data->left_margin = g_value_get_double(value);
380 break;
381 case PROP_HAS_FRAME:
382 data->has_frame = g_value_get_boolean(value);
383 break;
384 case PROP_TOP_PADDING:
385 data->top_padding = g_value_get_double(value);
386 break;
387 case PROP_RIGHT_PADDING:
388 data->right_padding = g_value_get_double(value);
389 break;
390 case PROP_BOTTOM_PADDING:
391 data->bottom_padding = g_value_get_double(value);
392 break;
393 case PROP_LEFT_PADDING:
394 data->left_padding = g_value_get_double(value);
395 break;
396 default:
397 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
398 break;
404 * adg_canvas_new:
406 * Creates a new empty canvas object.
408 * Returns: the canvas
410 * Since: 1.0
412 AdgCanvas *
413 adg_canvas_new(void)
415 return g_object_new(ADG_TYPE_CANVAS, NULL);
419 * adg_canvas_set_size:
420 * @canvas: an #AdgCanvas
421 * @size: the new size for the canvas
423 * Sets a specific size on @canvas. The x and/or y
424 * components of the returned #AdgPair could be %0, in which
425 * case the size returned by adg_entity_get_extents() on
426 * @canvas will be used instead.
428 * Since: 1.0
430 void
431 adg_canvas_set_size(AdgCanvas *canvas, const AdgPair *size)
433 g_return_if_fail(ADG_IS_CANVAS(canvas));
434 g_return_if_fail(size != NULL);
436 g_object_set(canvas, "size", size, NULL);
440 * adg_canvas_set_size_explicit:
441 * @canvas: an #AdgCanvas
442 * @x: the new width of the canvas or %0 to reset
443 * @y: the new height of the canvas or %0 to reset
445 * A convenient function to set the size of @canvas using
446 * explicit coordinates. Check adg_canvas_set_size() for
447 * further details.
449 * Since: 1.0
451 void
452 adg_canvas_set_size_explicit(AdgCanvas *canvas, gdouble x, gdouble y)
454 AdgPair size;
456 size.x = x;
457 size.y = y;
459 adg_canvas_set_size(canvas, &size);
463 * adg_canvas_get_size:
464 * @canvas: an #AdgCanvas
466 * Gets the specific size set on @canvas. The x and/or y
467 * components of the returned #AdgPair could be %0, in which
468 * case the size returned by adg_entity_get_extents() on
469 * @canvas will be used instead.
471 * Returns: the explicit size set on this canvas or %NULL on errors
473 * Since: 1.0
475 const AdgPair *
476 adg_canvas_get_size(AdgCanvas *canvas)
478 AdgCanvasPrivate *data;
480 g_return_val_if_fail(ADG_IS_CANVAS(canvas), NULL);
482 data = canvas->data;
483 return &data->size;
487 * adg_canvas_set_background_dress:
488 * @canvas: an #AdgCanvas
489 * @dress: the new #AdgDress to use
491 * Sets a new background dress for rendering @canvas: the new
492 * dress must be a color dress.
494 * Since: 1.0
496 void
497 adg_canvas_set_background_dress(AdgCanvas *canvas, AdgDress dress)
499 g_return_if_fail(ADG_IS_CANVAS(canvas));
500 g_object_set(canvas, "background-dress", dress, NULL);
504 * adg_canvas_get_background_dress:
505 * @canvas: an #AdgCanvas
507 * Gets the background dress to be used in rendering @canvas.
509 * Returns: the current background dress
511 * Since: 1.0
513 AdgDress
514 adg_canvas_get_background_dress(AdgCanvas *canvas)
516 AdgCanvasPrivate *data;
518 g_return_val_if_fail(ADG_IS_CANVAS(canvas), ADG_DRESS_UNDEFINED);
520 data = canvas->data;
522 return data->background_dress;
526 * adg_canvas_set_frame_dress:
527 * @canvas: an #AdgCanvas
528 * @dress: the new #AdgDress to use
530 * Sets the #AdgCanvas:frame-dress property of @canvas to @dress:
531 * the new dress must be a line dress.
533 * Since: 1.0
535 void
536 adg_canvas_set_frame_dress(AdgCanvas *canvas, AdgDress dress)
538 g_return_if_fail(ADG_IS_CANVAS(canvas));
539 g_object_set(canvas, "frame-dress", dress, NULL);
543 * adg_canvas_get_frame_dress:
544 * @canvas: an #AdgCanvas
546 * Gets the frame dress to be used in rendering the border of @canvas.
548 * Returns: the current frame dress
550 * Since: 1.0
552 AdgDress
553 adg_canvas_get_frame_dress(AdgCanvas *canvas)
555 AdgCanvasPrivate *data;
557 g_return_val_if_fail(ADG_IS_CANVAS(canvas), ADG_DRESS_UNDEFINED);
559 data = canvas->data;
560 return data->frame_dress;
564 * adg_canvas_set_title_block:
565 * @canvas: an #AdgCanvas
566 * @title_block: a title block
568 * Sets the #AdgCanvas:title-block property of @canvas to @title_block.
570 * Although a title block entity could be added to @canvas in the usual
571 * way, that is using the adg_container_add() method, assigning a title
572 * block with adg_canvas_set_title_block() is somewhat different:
574 * - @title_block will be automatically attached to the bottom right
575 * corner of to the @canvas frame (this could be accomplished in the
576 * usual way too, by resetting the right and bottom paddings);
577 * - the @title_block boundary box is not taken into account while
578 * computing the extents of @canvas.
580 * Since: 1.0
582 void
583 adg_canvas_set_title_block(AdgCanvas *canvas, AdgTitleBlock *title_block)
585 g_return_if_fail(ADG_IS_CANVAS(canvas));
586 g_return_if_fail(title_block == NULL || ADG_IS_TITLE_BLOCK(title_block));
587 g_object_set(canvas, "title-block", title_block, NULL);
591 * adg_canvas_get_title_block:
592 * @canvas: an #AdgCanvas
594 * Gets the #AdgTitleBlock object of @canvas: check
595 * adg_canvas_set_title_block() for details.
597 * Returns: the title block object or %NULL
599 * Since: 1.0
601 AdgTitleBlock *
602 adg_canvas_get_title_block(AdgCanvas *canvas)
604 AdgCanvasPrivate *data;
606 g_return_val_if_fail(ADG_IS_CANVAS(canvas), NULL);
608 data = canvas->data;
609 return data->title_block;
613 * adg_canvas_set_top_margin:
614 * @canvas: an #AdgCanvas
615 * @value: the new margin, in global space
617 * Changes the top margin of @canvas by setting #AdgCanvas:top-margin
618 * to @value. Negative values are allowed.
620 * Since: 1.0
622 void
623 adg_canvas_set_top_margin(AdgCanvas *canvas, gdouble value)
625 g_return_if_fail(ADG_IS_CANVAS(canvas));
626 g_object_set(canvas, "top-margin", value, NULL);
630 * adg_canvas_get_top_margin:
631 * @canvas: an #AdgCanvas
633 * Gets the top margin (in global space) of @canvas.
635 * Returns: the requested margin or %0 on error
637 * Since: 1.0
639 gdouble
640 adg_canvas_get_top_margin(AdgCanvas *canvas)
642 AdgCanvasPrivate *data;
644 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
646 data = canvas->data;
647 return data->top_margin;
651 * adg_canvas_set_right_margin:
652 * @canvas: an #AdgCanvas
653 * @value: the new margin, in global space
655 * Changes the right margin of @canvas by setting #AdgCanvas:right-margin
656 * to @value. Negative values are allowed.
658 * Since: 1.0
660 void
661 adg_canvas_set_right_margin(AdgCanvas *canvas, gdouble value)
663 g_return_if_fail(ADG_IS_CANVAS(canvas));
664 g_object_set(canvas, "right-margin", value, NULL);
668 * adg_canvas_get_right_margin:
669 * @canvas: an #AdgCanvas
671 * Gets the right margin (in global space) of @canvas.
673 * Returns: the requested margin or %0 on error
675 * Since: 1.0
677 gdouble
678 adg_canvas_get_right_margin(AdgCanvas *canvas)
680 AdgCanvasPrivate *data;
682 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
684 data = canvas->data;
685 return data->right_margin;
690 * adg_canvas_set_bottom_margin:
691 * @canvas: an #AdgCanvas
692 * @value: the new margin, in global space
694 * Changes the bottom margin of @canvas by setting #AdgCanvas:bottom-margin
695 * to @value. Negative values are allowed.
697 * Since: 1.0
699 void
700 adg_canvas_set_bottom_margin(AdgCanvas *canvas, gdouble value)
702 g_return_if_fail(ADG_IS_CANVAS(canvas));
703 g_object_set(canvas, "bottom-margin", value, NULL);
707 * adg_canvas_get_bottom_margin:
708 * @canvas: an #AdgCanvas
710 * Gets the bottom margin (in global space) of @canvas.
712 * Returns: the requested margin or %0 on error
714 * Since: 1.0
716 gdouble
717 adg_canvas_get_bottom_margin(AdgCanvas *canvas)
719 AdgCanvasPrivate *data;
721 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
723 data = canvas->data;
724 return data->bottom_margin;
728 * adg_canvas_set_left_margin:
729 * @canvas: an #AdgCanvas
730 * @value: the new margin, in global space
732 * Changes the left margin of @canvas by setting #AdgCanvas:left-margin
733 * to @value. Negative values are allowed.
735 * Since: 1.0
737 void
738 adg_canvas_set_left_margin(AdgCanvas *canvas, gdouble value)
740 g_return_if_fail(ADG_IS_CANVAS(canvas));
741 g_object_set(canvas, "left-margin", value, NULL);
745 * adg_canvas_get_left_margin:
746 * @canvas: an #AdgCanvas
748 * Gets the left margin (in global space) of @canvas.
750 * Returns: the requested margin or %0 on error
752 * Since: 1.0
754 gdouble
755 adg_canvas_get_left_margin(AdgCanvas *canvas)
757 AdgCanvasPrivate *data;
759 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
761 data = canvas->data;
762 return data->left_margin;
766 * adg_canvas_set_margins:
767 * @canvas: an #AdgCanvas
768 * @top: top margin, in global space
769 * @right: right margin, in global space
770 * @bottom: bottom margin, in global space
771 * @left: left margin, in global space
773 * Convenient function to set all the margins at once.
775 * Since: 1.0
777 void
778 adg_canvas_set_margins(AdgCanvas *canvas, gdouble top, gdouble right,
779 gdouble bottom, gdouble left)
781 g_return_if_fail(ADG_IS_CANVAS(canvas));
782 g_object_set(canvas, "top-margin", top, "right-margin", right,
783 "bottom-margin", bottom, "left-margin", left, NULL);
787 * adg_canvas_apply_margins:
788 * @canvas: an #AdgCanvas
789 * @extents: where apply the margins
791 * A convenient function to apply the margins of @canvas to the
792 * arbitrary #CpmlExtents struct @extents.
794 * Since: 1.0
796 void
797 adg_canvas_apply_margins(AdgCanvas *canvas, CpmlExtents *extents)
799 AdgCanvasPrivate *data;
801 g_return_if_fail(ADG_IS_CANVAS(canvas));
803 data = canvas->data;
805 extents->org.x -= data->left_margin;
806 extents->org.y -= data->top_margin;
807 extents->size.x += data->left_margin + data->right_margin;
808 extents->size.y += data->top_margin + data->bottom_margin;
812 * adg_canvas_switch_frame:
813 * @canvas: an #AdgCanvas
814 * @new_state: the new flag status
816 * Sets a new status on the #AdgCanvas:has-frame property: %TRUE
817 * means a border around the canvas extents (less the margins)
818 * should be rendered.
820 * Since: 1.0
822 void
823 adg_canvas_switch_frame(AdgCanvas *canvas, gboolean new_state)
825 g_return_if_fail(ADG_IS_CANVAS(canvas));
826 g_object_set(canvas, "has-frame", new_state, NULL);
830 * adg_canvas_has_frame:
831 * @canvas: an #AdgCanvas
833 * Gets the current status of the #AdgCanvas:has-frame property,
834 * that is whether a border around the canvas extents (less the
835 * margins) should be rendered (%TRUE) or not (%FALSE).
837 * Returns: the current status of the frame flag
839 * Since: 1.0
841 gboolean
842 adg_canvas_has_frame(AdgCanvas *canvas)
844 AdgCanvasPrivate *data;
846 g_return_val_if_fail(ADG_IS_CANVAS(canvas), FALSE);
848 data = canvas->data;
849 return data->has_frame;
853 * adg_canvas_set_top_padding:
854 * @canvas: an #AdgCanvas
855 * @value: the new padding, in global space
857 * Changes the top padding of @canvas by setting #AdgCanvas:top-padding
858 * to @value. Negative values are allowed.
860 * Since: 1.0
862 void
863 adg_canvas_set_top_padding(AdgCanvas *canvas, gdouble value)
865 g_return_if_fail(ADG_IS_CANVAS(canvas));
866 g_object_set(canvas, "top-padding", value, NULL);
870 * adg_canvas_get_top_padding:
871 * @canvas: an #AdgCanvas
873 * Gets the top padding (in global space) of @canvas.
875 * Returns: the requested padding or %0 on error
877 * Since: 1.0
879 gdouble
880 adg_canvas_get_top_padding(AdgCanvas *canvas)
882 AdgCanvasPrivate *data;
884 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
886 data = canvas->data;
887 return data->top_padding;
891 * adg_canvas_set_right_padding:
892 * @canvas: an #AdgCanvas
893 * @value: the new padding, in global space
895 * Changes the right padding of @canvas by setting #AdgCanvas:right-padding
896 * to @value. Negative values are allowed.
898 * Since: 1.0
900 void
901 adg_canvas_set_right_padding(AdgCanvas *canvas, gdouble value)
903 g_return_if_fail(ADG_IS_CANVAS(canvas));
904 g_object_set(canvas, "right-padding", value, NULL);
908 * adg_canvas_get_right_padding:
909 * @canvas: an #AdgCanvas
911 * Gets the right padding (in global space) of @canvas.
913 * Returns: the requested padding or %0 on error
915 * Since: 1.0
917 gdouble
918 adg_canvas_get_right_padding(AdgCanvas *canvas)
920 AdgCanvasPrivate *data;
922 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
924 data = canvas->data;
925 return data->right_padding;
930 * adg_canvas_set_bottom_padding:
931 * @canvas: an #AdgCanvas
932 * @value: the new padding, in global space
934 * Changes the bottom padding of @canvas by setting #AdgCanvas:bottom-padding
935 * to @value. Negative values are allowed.
937 * Since: 1.0
939 void
940 adg_canvas_set_bottom_padding(AdgCanvas *canvas, gdouble value)
942 g_return_if_fail(ADG_IS_CANVAS(canvas));
943 g_object_set(canvas, "bottom-padding", value, NULL);
947 * adg_canvas_get_bottom_padding:
948 * @canvas: an #AdgCanvas
950 * Gets the bottom padding (in global space) of @canvas.
952 * Returns: the requested padding or %0 on error
954 * Since: 1.0
956 gdouble
957 adg_canvas_get_bottom_padding(AdgCanvas *canvas)
959 AdgCanvasPrivate *data;
961 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
963 data = canvas->data;
964 return data->bottom_padding;
968 * adg_canvas_set_left_padding:
969 * @canvas: an #AdgCanvas
970 * @value: the new padding, in global space
972 * Changes the left padding of @canvas by setting #AdgCanvas:left-padding
973 * to @value. Negative values are allowed.
975 * Since: 1.0
977 void
978 adg_canvas_set_left_padding(AdgCanvas *canvas, gdouble value)
980 g_return_if_fail(ADG_IS_CANVAS(canvas));
981 g_object_set(canvas, "left-padding", value, NULL);
985 * adg_canvas_get_left_padding:
986 * @canvas: an #AdgCanvas
988 * Gets the left padding (in global space) of @canvas.
990 * Returns: the requested padding or %0 on error
992 * Since: 1.0
994 gdouble
995 adg_canvas_get_left_padding(AdgCanvas *canvas)
997 AdgCanvasPrivate *data;
999 g_return_val_if_fail(ADG_IS_CANVAS(canvas), 0.);
1001 data = canvas->data;
1002 return data->left_padding;
1006 * adg_canvas_set_paddings:
1007 * @canvas: an #AdgCanvas
1008 * @top: top padding, in global space
1009 * @right: right padding, in global space
1010 * @bottom: bottom padding, in global space
1011 * @left: left padding, in global space
1013 * Convenient function to set all the paddings at once.
1015 * Since: 1.0
1017 void
1018 adg_canvas_set_paddings(AdgCanvas *canvas, gdouble top, gdouble right,
1019 gdouble bottom, gdouble left)
1021 g_return_if_fail(ADG_IS_CANVAS(canvas));
1022 g_object_set(canvas, "top-padding", top, "right-padding", right,
1023 "bottom-padding", bottom, "left-padding", left, NULL);
1027 static void
1028 _adg_global_changed(AdgEntity *entity)
1030 AdgCanvasPrivate *data = ((AdgCanvas *) entity)->data;
1032 if (_ADG_OLD_ENTITY_CLASS->global_changed)
1033 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
1035 if (data->title_block)
1036 adg_entity_global_changed((AdgEntity *) data->title_block);
1039 static void
1040 _adg_local_changed(AdgEntity *entity)
1042 AdgCanvasPrivate *data = ((AdgCanvas *) entity)->data;
1044 if (_ADG_OLD_ENTITY_CLASS->local_changed)
1045 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
1047 if (data->title_block)
1048 adg_entity_local_changed((AdgEntity *) data->title_block);
1051 static void
1052 _adg_invalidate(AdgEntity *entity)
1054 AdgCanvasPrivate *data = ((AdgCanvas *) entity)->data;
1056 if (_ADG_OLD_ENTITY_CLASS->invalidate)
1057 _ADG_OLD_ENTITY_CLASS->invalidate(entity);
1059 if (data->title_block)
1060 adg_entity_invalidate((AdgEntity *) data->title_block);
1063 static void
1064 _adg_arrange(AdgEntity *entity)
1066 AdgCanvasPrivate *data;
1067 CpmlExtents extents;
1069 if (_ADG_OLD_ENTITY_CLASS->arrange)
1070 _ADG_OLD_ENTITY_CLASS->arrange(entity);
1072 cpml_extents_copy(&extents, adg_entity_get_extents(entity));
1074 /* The extents should be defined, otherwise there is no drawing */
1075 g_return_if_fail(extents.is_defined);
1077 data = ((AdgCanvas *) entity)->data;
1079 if (data->size.x > 0 || data->size.y > 0) {
1080 const AdgMatrix *global = adg_entity_get_global_matrix(entity);
1081 CpmlExtents paper;
1083 paper.org.x = 0;
1084 paper.org.y = 0;
1085 paper.size.x = data->size.x;
1086 paper.size.y = data->size.y;
1088 cairo_matrix_transform_point(global, &paper.org.x, &paper.org.y);
1089 cairo_matrix_transform_distance(global, &paper.size.x, &paper.size.y);
1091 if (data->size.x > 0) {
1092 extents.org.x = paper.org.x;
1093 extents.size.x = paper.size.x;
1095 if (data->size.y > 0) {
1096 extents.org.y = paper.org.y;
1097 extents.size.y = paper.size.y;
1101 if (data->size.x == 0) {
1102 extents.org.x -= data->left_padding;
1103 extents.size.x += data->left_padding + data->right_padding;
1105 if (data->size.y == 0) {
1106 extents.org.y -= data->top_padding;
1107 extents.size.y += data->top_padding + data->bottom_padding;
1110 /* Impose the new extents */
1111 adg_entity_set_extents(entity, &extents);
1113 if (data->title_block) {
1114 AdgEntity *title_block_entity;
1115 const CpmlExtents *title_block_extents;
1116 AdgPair shift;
1118 title_block_entity = (AdgEntity *) data->title_block;
1119 adg_entity_arrange(title_block_entity);
1120 title_block_extents = adg_entity_get_extents(title_block_entity);
1122 shift.x = extents.org.x + extents.size.x - title_block_extents->org.x
1123 - title_block_extents->size.x;
1124 shift.y = extents.org.y + extents.size.y - title_block_extents->org.y
1125 - title_block_extents->size.y;
1127 /* The following block could be optimized by skipping tiny shift,
1128 * usually left by rounding errors */
1129 if (shift.x != 0 || shift.y != 0) {
1130 AdgMatrix unglobal, map;
1131 adg_matrix_copy(&unglobal, adg_entity_get_global_matrix(entity));
1132 cairo_matrix_invert(&unglobal);
1134 cairo_matrix_transform_distance(&unglobal, &shift.x, &shift.y);
1135 cairo_matrix_init_translate(&map, shift.x, shift.y);
1136 adg_entity_transform_global_map(title_block_entity, &map,
1137 ADG_TRANSFORM_AFTER);
1139 adg_entity_global_changed(title_block_entity);
1140 adg_entity_arrange(title_block_entity);
1145 static void
1146 _adg_render(AdgEntity *entity, cairo_t *cr)
1148 AdgCanvasPrivate *data;
1149 const CpmlExtents *extents;
1151 data = ((AdgCanvas *) entity)->data;
1152 extents = adg_entity_get_extents(entity);
1154 cairo_save(cr);
1156 /* Background fill */
1157 cairo_rectangle(cr, extents->org.x - data->left_margin,
1158 extents->org.y - data->top_margin,
1159 extents->size.x + data->left_margin + data->right_margin,
1160 extents->size.y + data->top_margin + data->bottom_margin);
1161 adg_entity_apply_dress(entity, data->background_dress, cr);
1162 cairo_fill(cr);
1164 /* Frame line */
1165 if (data->has_frame) {
1166 cairo_rectangle(cr, extents->org.x, extents->org.y,
1167 extents->size.x, extents->size.y);
1168 cairo_transform(cr, adg_entity_get_global_matrix(entity));
1169 adg_entity_apply_dress(entity, data->frame_dress, cr);
1170 cairo_stroke(cr);
1173 cairo_restore(cr);
1175 if (data->title_block)
1176 adg_entity_render((AdgEntity *) data->title_block, cr);
1178 if (_ADG_OLD_ENTITY_CLASS->render)
1179 _ADG_OLD_ENTITY_CLASS->render(entity, cr);
1182 #if GTK2_ENABLED
1185 * adg_canvas_set_paper:
1186 * @canvas: an #AdgCanvas
1187 * @paper_name: a paper name
1188 * @orientation: the page orientation
1190 * A convenient function to set the size of @canvas using a
1191 * @paper_name and an @orientation value. This should be a
1192 * PWG 5101.1-2002 paper name and it will be passed as is to
1193 * gtk_paper_size_new(), so use any valid name accepted by
1194 * that function.
1196 * To reset this size, you could use adg_canvas_set_size() with a
1197 * %NULL size: in this way the size will match the boundary boxes
1198 * of the entities contained by the canvas.
1200 * Furthermore, the margins will be set to their default values,
1201 * that is the margins returned by the #GtkPaperSize API.
1202 * If you want to use your own margins on a named paper size,
1203 * set them <emphasis>after</emphasis> the call to this function.
1205 * Since: 1.0
1207 void
1208 adg_canvas_set_paper(AdgCanvas *canvas, const gchar *paper_name,
1209 GtkPageOrientation orientation)
1211 GtkPageSetup *page_setup;
1212 GtkPaperSize *paper_size;
1214 g_return_if_fail(ADG_IS_CANVAS(canvas));
1215 g_return_if_fail(paper_name != NULL);
1217 page_setup = gtk_page_setup_new();
1218 paper_size = gtk_paper_size_new(paper_name);
1220 gtk_page_setup_set_paper_size(page_setup, paper_size);
1221 gtk_page_setup_set_orientation(page_setup, orientation);
1222 gtk_paper_size_free(paper_size);
1224 adg_canvas_set_page_setup(canvas, page_setup);
1225 g_object_unref(page_setup);
1229 * adg_canvas_set_page_setup:
1230 * @canvas: an #AdgCanvas
1231 * @page_setup: the page setup
1233 * A convenient function to setup the page of @canvas so it can
1234 * also be subsequentially used for printing. It is allowed to
1235 * pass %NULL for @page_setup to unset the setup data from @canvas.
1237 * A reference to @page_setup is added, so there is no need to keep
1238 * alive this object outside this function. The @page_setup pointer
1239 * is stored in the associative key %_adg_page_setup and can be
1240 * retrieved at any time with:
1242 * |[
1243 * page_setup = g_object_get_data(G_OBJECT(canvas), "_adg_page_setup");
1244 * ]|
1246 * The size and margins provided by @page_setup are used to set the
1247 * size and margins of @canvas much in the same way as what
1248 * adg_canvas_set_paper() does. This means if you set a page and
1249 * then unset it, the canvas will retain size and margins of the
1250 * original page although @page_setup will not be used for printing.
1251 * You must unset the size with adg_canvas_set_size() with a %NULL size.
1253 * |[
1254 * // By default, canvas does not have an explicit size
1255 * adg_canvas_set_page_setup(canvas, a4);
1256 * // Here canvas has the size and margins specified by a4
1257 * adg_canvas_set_page_setup(canvas, NULL);
1258 * // Now the only difference is that canvas is no more bound
1259 * // to the a4 page setup, so the following will return NULL:
1260 * page_setup = g_object_get_data(G_OBJECT(canvas), "_adg_page_setup");
1261 * // To restore the original status and have an autocomputed size:
1262 * adg_canvas_set_size(canvas, NULL);
1263 * ]|
1265 * Since: 1.0
1267 void
1268 adg_canvas_set_page_setup(AdgCanvas *canvas, GtkPageSetup *page_setup)
1270 gdouble top, right, bottom, left;
1271 AdgPair size;
1273 g_return_if_fail(ADG_IS_CANVAS(canvas));
1275 if (page_setup == NULL) {
1276 /* By convention, NULL resets the default page but
1277 * does not change any other property */
1278 g_object_set_data((GObject *) canvas, "_adg_page_setup", NULL);
1279 return;
1282 g_return_if_fail(GTK_IS_PAGE_SETUP(page_setup));
1284 top = gtk_page_setup_get_top_margin(page_setup, GTK_UNIT_POINTS);
1285 right = gtk_page_setup_get_right_margin(page_setup, GTK_UNIT_POINTS);
1286 bottom = gtk_page_setup_get_bottom_margin(page_setup, GTK_UNIT_POINTS);
1287 left = gtk_page_setup_get_left_margin(page_setup, GTK_UNIT_POINTS);
1288 size.x = gtk_page_setup_get_page_width(page_setup, GTK_UNIT_POINTS);
1289 size.y = gtk_page_setup_get_page_height(page_setup, GTK_UNIT_POINTS);
1291 adg_canvas_set_size(canvas, &size);
1292 adg_canvas_set_margins(canvas, top, right, bottom, left);
1294 g_object_ref(page_setup);
1295 g_object_set_data_full((GObject *) canvas, "_adg_page_setup",
1296 page_setup, g_object_unref);
1299 #endif