doc: update copyright line for 2021
[adg.git] / src / adg / adg-table-cell.c
blob786a9d822145d35ce8d0c41d75e951346b3c2d82
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2021 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-table-cell
23 * @Section_Id:AdgTableCell
24 * @title: AdgTableCell
25 * @short_description: A single cell of a table
27 * The #AdgTableCell is a boxed type, the basic component of an
28 * #AdgTable entity. It must be added to an #AdgTableRow that,
29 * in cascade, will be added to an #AdgTable entity.
31 * Any cell can be filled with a title and a value: the font to be
32 * used will be picked up from the #AdgTableStyle got by resolving
33 * the #AdgTable:table-dress property.
35 * The default title is placed at the upper left corner of the cell
36 * while the value is centered up to the bottom edge of the cell.
37 * Anyway the text positioning can be customized by using the
38 * adg_table_cell_set_value_pos() method.
40 * Some convenient functions to easily create title and value entities
41 * with plain text are provided: adg_table_cell_new_full(),
42 * adg_table_cell_set_text_title() and adg_table_cell_set_text_value().
43 * When using these methods keep in mind the underlying #AdgToyText
44 * entities will be displaced accordingly to the
45 * #AdgTableStyle:cell-padding value, not used when setting the
46 * entities through other APIs.
48 * Since: 1.0
49 **/
51 /**
52 * AdgTableCell:
54 * An opaque structure referring to the cell of an #AdgTableRow.
55 * Any row can have an unlimited number of cells.
57 * Since: 1.0
58 **/
61 #include "adg-internal.h"
62 #include "adg-text-internal.h"
64 #include "adg-container.h"
65 #include "adg-alignment.h"
66 #include "adg-textual.h"
67 #include "adg-style.h"
68 #include "adg-table-style.h"
70 #include "adg-table.h"
71 #include "adg-table-row.h"
72 #include "adg-table-cell.h"
75 struct _AdgTableCell {
76 AdgTableRow *row;
77 gdouble width;
78 gboolean has_frame;
79 AdgEntity *title;
80 AdgEntity *value;
81 CpmlPair value_factor;
82 CpmlExtents extents;
86 static AdgTableCell * _adg_cell_new (void);
87 static void _adg_cell_invalidate (AdgTableCell *table_cell);
88 static gboolean _adg_cell_set_title (AdgTableCell *table_cell,
89 AdgEntity *title);
90 static gboolean _adg_cell_set_value (AdgTableCell *table_cell,
91 AdgEntity *value);
92 static void _adg_cell_set_value_pos (AdgTableCell *table_cell,
93 const CpmlPair *from_factor,
94 const CpmlPair *to_factor);
97 GType
98 adg_table_cell_get_type(void)
100 static GType cell_type = 0;
102 if (G_UNLIKELY(cell_type == 0))
103 cell_type = g_boxed_type_register_static("AdgTableCell",
104 (GBoxedCopyFunc) adg_table_cell_dup,
105 (GBoxedFreeFunc) adg_table_cell_free);
107 return cell_type;
112 * adg_table_cell_dup:
113 * @src: an #AdgTableCell structure
115 * Duplicates @src. The returned duplicate should be freed
116 * with adg_table_cell_free() when no longer needed.
118 * Returns: (transfer full): a duplicate of @src.
120 * Since: 1.0
122 AdgTableCell *
123 adg_table_cell_dup(const AdgTableCell *src)
125 g_return_val_if_fail(src != NULL, NULL);
126 return cpml_memdup(src, sizeof(AdgTableCell));
130 * adg_table_cell_new:
131 * @table_row: a valid #AdgTableRow
133 * Creates a new empty cell without a frame and appends it at the
134 * end of the cells yet present in @table_row. You can add content
135 * to the cell by using adg_table_cell_set_title() and
136 * adg_table_cell_set_value() or enable the frame with
137 * adg_table_cell_switch_frame().
139 * Returns: (transfer full): the newly created cell or <constant>NULL</constant> on errors.
141 * Since: 1.0
143 AdgTableCell *
144 adg_table_cell_new(AdgTableRow *table_row)
146 AdgTableCell *table_cell;
148 g_return_val_if_fail(table_row != NULL, NULL);
150 table_cell = _adg_cell_new();
151 table_cell->row = table_row;
153 adg_table_row_insert(table_row, table_cell, NULL);
154 _adg_cell_invalidate(table_cell);
156 return table_cell;
160 * adg_table_cell_new_before:
161 * @before_cell: a valid #AdgTableCell
163 * Creates a new cell and inserts it rigthly before the @table_cell cell.
165 * Returns: (transfer full): the newly created cell or <constant>NULL</constant> on errors.
167 * Since: 1.0
169 AdgTableCell *
170 adg_table_cell_new_before(AdgTableCell *before_cell)
172 AdgTableRow *table_row;
173 AdgTableCell *table_cell;
175 g_return_val_if_fail(before_cell != NULL, NULL);
177 table_row = before_cell->row;
178 g_return_val_if_fail(table_row != NULL, NULL);
180 table_cell = _adg_cell_new();
181 table_cell->row = table_row;
183 adg_table_row_insert(table_row, table_cell, NULL);
184 _adg_cell_invalidate(table_cell);
186 return table_cell;
190 * adg_table_cell_new_with_width:
191 * @table_row: a valid #AdgTableRow
192 * @width: the cell width
194 * A convenient wrapper to adg_table_cell_new() that allows to
195 * specify the @width of @table_row all at once.
197 * Returns: (transfer full): the newly created cell or <constant>NULL</constant> on errors.
199 * Since: 1.0
201 AdgTableCell *
202 adg_table_cell_new_with_width(AdgTableRow *table_row, gdouble width)
204 AdgTableCell *table_cell;
206 g_return_val_if_fail(width >= 0, NULL);
208 table_cell = adg_table_cell_new(table_row);
209 if (table_cell != NULL)
210 adg_table_cell_set_width(table_cell, width);
212 return table_cell;
216 * adg_table_cell_new_full:
217 * @table_row: a valid #AdgTableRow
218 * @width: the cell width
219 * @name: (nullable): the name to bound to this cell
220 * @title: (nullable): the title text
221 * @has_frame: whether to draw or not the frame
223 * A convenient function to add a cell and specifies some common
224 * used properties at once.
226 * If @name is <constant>NULL</constant>, the created cell will
227 * not be a named cell. Check adg_table_set_cell() for further
228 * details on what a named cell is supposed to be.
230 * @title can be <constant>NULL</constant>, in which case no
231 * title entity will be created.
233 * Returns: (transfer full): the newly created cell or <constant>NULL</constant> on errors.
235 * Since: 1.0
237 AdgTableCell *
238 adg_table_cell_new_full(AdgTableRow *table_row, gdouble width,
239 const gchar *name, const gchar *title,
240 gboolean has_frame)
242 AdgTableCell *table_cell;
244 g_return_val_if_fail(width >= 0, NULL);
246 table_cell = adg_table_cell_new(table_row);
247 if (table_cell == NULL)
248 return NULL;
250 adg_table_cell_set_width(table_cell, width);
251 adg_table_cell_switch_frame(table_cell, has_frame);
253 if (title) {
254 adg_table_cell_set_text_title(table_cell, title);
256 if (name) {
257 AdgTable *table = adg_table_row_get_table(table_row);
258 adg_table_set_cell(table, name, table_cell);
261 return table_cell;
265 * adg_table_cell_dispose:
266 * @table_cell: a valid #AdgTableCell struct
268 * Disposes @table_cell.
270 * Since: 1.0
272 void
273 adg_table_cell_dispose(AdgTableCell *table_cell)
275 g_return_if_fail(table_cell != NULL);
277 _adg_cell_set_title(table_cell, NULL);
278 _adg_cell_set_value(table_cell, NULL);
282 * adg_table_cell_free:
283 * @table_cell: an #AdgTableCell structure
285 * Releases all the memory allocated by @table_cell, itself included.
287 * Since: 1.0
289 void
290 adg_table_cell_free(AdgTableCell *table_cell)
292 AdgTableRow *table_row;
294 g_return_if_fail(table_cell != NULL);
296 table_row = table_cell->row;
298 if (table_cell->row != NULL) {
299 AdgTable *table = adg_table_row_get_table(table_row);
300 adg_table_row_remove(table_row, table_cell);
301 if (table)
302 adg_table_set_cell(table, NULL, table_cell);
305 adg_table_cell_dispose(table_cell);
306 g_free(table_cell);
310 * adg_table_cell_get_row:
311 * @table_cell: a valid #AdgTableCell
313 * Gets the row container of @table_cell. The returned #AdgTableRow
314 * is owned by @table_cell and must not be modified or freed.
316 * Returns: (transfer none): the container row.
318 * Since: 1.0
320 AdgTableRow *
321 adg_table_cell_get_row(AdgTableCell *table_cell)
323 g_return_val_if_fail(table_cell != NULL, NULL);
324 return table_cell->row;
328 * adg_table_cell_get_table:
329 * @table_cell: a valid #AdgTableCell
331 * A convenient function that gets the table that contains
332 * @table_cell. The returned #AdgTable is owned by @table_cell
333 * and must not be modified or freed.
335 * Returns: (transfer none): the container table.
337 * Since: 1.0
339 AdgTable *
340 adg_table_cell_get_table(AdgTableCell *table_cell)
342 AdgTableRow *table_row = adg_table_cell_get_row(table_cell);
343 if (table_row == NULL)
344 return NULL;
346 return adg_table_row_get_table(table_row);
350 * adg_table_cell_set_title:
351 * @table_cell: a valid #AdgTableCell
352 * @title: (nullable): the new title entity
354 * Sets @title as the new title entity of @table_cell. The top left
355 * corner of the bounding box of @title will be cohincident to
356 * the top left corner of the cell extents, taking into accounts
357 * eventual padding spaces specified by the table style.
359 * The old internal entity is unrefenrenced while the @title (if
360 * not <constant>NULL</constant>) is refenenced with
361 * g_object_ref_sink().
363 * @title can be <constant>NULL</constant>, in which case the old
364 * entity is removed.
366 * Since: 1.0
368 void
369 adg_table_cell_set_title(AdgTableCell *table_cell, AdgEntity *title)
371 g_return_if_fail(table_cell != NULL);
372 g_return_if_fail(title == NULL || ADG_IS_ENTITY(title));
374 if (_adg_cell_set_title(table_cell, title))
375 _adg_cell_invalidate(table_cell);
379 * adg_table_cell_set_text_title:
380 * @table_cell: a valid #AdgTableCell
381 * @title: a text string
383 * Convenient function to set a the title of a cell using an #AdgToyText
384 * entity with the font dress picked from #AdgTable:table-dress with
385 * a call to adg_table_style_get_title_dress().
387 * Since: 1.0
389 void
390 adg_table_cell_set_text_title(AdgTableCell *table_cell, const gchar *title)
392 AdgTable *table;
393 AdgEntity *entity;
394 AdgTableStyle *table_style;
395 const CpmlPair *padding;
396 AdgDress table_dress, font_dress;
397 cairo_matrix_t map;
399 g_return_if_fail(table_cell != NULL);
401 if (title == NULL)
402 adg_table_cell_set_title(table_cell, NULL);
404 if (table_cell->title) {
405 gchar *old_title;
406 gboolean unchanged;
408 if (ADG_IS_TEXTUAL(table_cell->title))
409 old_title = adg_textual_dup_text((AdgTextual *) table_cell->title);
410 else
411 old_title = NULL;
413 unchanged = g_strcmp0(title, old_title) == 0;
414 g_free(old_title);
416 if (unchanged)
417 return;
420 table = adg_table_cell_get_table(table_cell);
421 table_dress = adg_table_get_table_dress(table);
422 table_style = (AdgTableStyle *) adg_entity_style((AdgEntity *) table,
423 table_dress);
424 padding = adg_table_style_get_cell_padding(table_style);
425 font_dress = adg_table_style_get_title_dress(table_style);
426 entity = g_object_new(ADG_TYPE_BEST_TEXT, "text", title,
427 "font-dress", font_dress, NULL);
429 cairo_matrix_init_translate(&map, padding->x, padding->y);
430 adg_entity_set_global_map(entity, &map);
432 adg_table_cell_set_title(table_cell, entity);
436 * adg_table_cell_title:
437 * @table_cell: a valid #AdgTableCell
439 * Gets the current title of @table_cell. The returned string is owned
440 * by @table_cell and must not be modified or freed.
442 * Returns: (transfer none): the title entity or <constant>NULL</constant> for undefined title.
444 * Since: 1.0
446 AdgEntity *
447 adg_table_cell_title(AdgTableCell *table_cell)
449 g_return_val_if_fail(table_cell != NULL, NULL);
451 return table_cell->title;
455 * adg_table_cell_set_value:
456 * @table_cell: a valid #AdgTableCell
457 * @value: the new value entity
459 * Sets @value as the new value entity of @table_cell. The bottom middle
460 * point of the bounding box of @value will be cohincident to the
461 * bottom middle point of the cell extents, taking into accounts
462 * eventual padding spaces specified by the table style.
464 * The old internal entity is unrefenrenced while the @value (if
465 * not <constant>NULL</constant>) is referenced with
466 * g_object_ref_sink().
468 * @value can be <constant>NULL</constant>, in which case the old entity
469 * is removed.
471 * Since: 1.0
473 void
474 adg_table_cell_set_value(AdgTableCell *table_cell, AdgEntity *value)
476 g_return_if_fail(table_cell != NULL);
477 g_return_if_fail(value == NULL || ADG_IS_ENTITY(value));
479 if (_adg_cell_set_value(table_cell, value))
480 _adg_cell_invalidate(table_cell);
484 * adg_table_cell_set_text_value:
485 * @table_cell: a valid #AdgTableCell
486 * @value: (nullable): a text string
488 * Convenient function to set a the value of a cell using an #AdgToyText
489 * entity with a value font dress picked from #AdgTable:table-dress with
490 * a call to adg_table_style_get_value_dress().
492 * @value can be <constant>NULL</constant>, in which case the old entity
493 * is removed.
495 * Since: 1.0
497 void
498 adg_table_cell_set_text_value(AdgTableCell *table_cell, const gchar *value)
500 AdgTable *table;
501 AdgEntity *entity;
502 AdgTableStyle *table_style;
503 const CpmlPair *padding;
504 AdgDress table_dress, font_dress;
505 cairo_matrix_t map;
507 g_return_if_fail(table_cell != NULL);
509 if (value == NULL) {
510 adg_table_cell_set_value(table_cell, NULL);
511 return;
514 if (table_cell->value) {
515 gchar *old_value;
516 gboolean unchanged;
518 if (ADG_IS_TEXTUAL(table_cell->value))
519 old_value = adg_textual_dup_text((AdgTextual *) table_cell->value);
520 else
521 old_value = NULL;
523 unchanged = g_strcmp0(value, old_value) == 0;
524 g_free(old_value);
525 if (unchanged)
526 return;
529 table = adg_table_cell_get_table(table_cell);
530 table_dress = adg_table_get_table_dress(table);
531 table_style = (AdgTableStyle *) adg_entity_style((AdgEntity *) table,
532 table_dress);
533 padding = adg_table_style_get_cell_padding(table_style);
534 font_dress = adg_table_style_get_value_dress(table_style);
535 entity = g_object_new(ADG_TYPE_BEST_TEXT, "text", value,
536 "font-dress", font_dress, NULL);
538 cairo_matrix_init_translate(&map, 0, -padding->y);
539 adg_entity_set_global_map(entity, &map);
541 adg_table_cell_set_value(table_cell, entity);
545 * adg_table_cell_value:
546 * @table_cell: a valid #AdgTableCell
548 * Gets the current value of @table_cell. The returned string is owned
549 * by @table_cell and must not be modified or freed.
551 * Returns: (transfer none): the value entity or <constant>NULL</constant> for undefined value.
553 * Since: 1.0
555 AdgEntity *
556 adg_table_cell_value(AdgTableCell *table_cell)
558 g_return_val_if_fail(table_cell != NULL, NULL);
560 return table_cell->value;
564 * adg_table_cell_set_value_pos:
565 * @table_cell: a valid #AdgTableCell
566 * @from_factor: the alignment factor on the value entity
567 * @to_factor: the alignment factor on the cell
569 * Sets a new custom position for the value entity of @table_cell. The
570 * @from_factor specifies the source point (as a fraction of the
571 * value extents) while the @to_factor is the destination point
572 * (specified as a fraction of the cell extents) the source point
573 * must be moved to.
575 * Since: 1.0
577 void
578 adg_table_cell_set_value_pos(AdgTableCell *table_cell,
579 const CpmlPair *from_factor,
580 const CpmlPair *to_factor)
582 g_return_if_fail(table_cell != NULL);
583 _adg_cell_set_value_pos(table_cell, from_factor, to_factor);
587 * adg_table_cell_set_value_pos_explicit:
588 * @table_cell: a valid #AdgTableCell
589 * @from_x: the x alignment factor on the entity
590 * @from_y: the y alignment factor on the entity
591 * @to_x: the x alignment factor on the cell
592 * @to_y: the y alignment factor on the cell
594 * A convenient wrapper around adg_table_cell_set_value_pos()
595 * that uses explicit factors instead of #CpmlPair.
597 * Since: 1.0
599 void
600 adg_table_cell_set_value_pos_explicit(AdgTableCell *table_cell,
601 gdouble from_x, gdouble from_y,
602 gdouble to_x, gdouble to_y)
604 CpmlPair from, to;
606 from.x = from_x;
607 from.y = from_y;
608 to.x = to_x;
609 to.y = to_y;
611 adg_table_cell_set_value_pos(table_cell, &from, &to);
615 * adg_table_cell_set_width:
616 * @table_cell: a valid #AdgTableCell
617 * @width: the new width
619 * Sets a new width on @table_cell. The extents on the whole table
620 * will be invalidated, so will be recomputed in the next
621 * arrange() phase.
623 * A positive @width value specifies the width of this cell in global
624 * space: if the width of its content (that is, either the title or the
625 * value entity) will be greater than @width, it will be rendered
626 * outside the cell boundary box, luckely overwriting the adiacent
627 * cells.
629 * Using 0 as @width means the width of the cell will be automatically
630 * adjusted to the maximum width of its content.
632 * Negative width values are not allowed: this condition will raise
633 * a warning without any further processing.
635 * Since: 1.0
637 void
638 adg_table_cell_set_width(AdgTableCell *table_cell, gdouble width)
640 g_return_if_fail(table_cell != NULL);
641 g_return_if_fail(width >= 0);
643 if (table_cell->width != width) {
644 table_cell->width = width;
645 _adg_cell_invalidate(table_cell);
650 * adg_table_cell_get_width:
651 * @table_cell: a valid #AdgTableCell
653 * Gets the width of @table_cell.
655 * Returns: the requested width or 0 on errors.
657 * Since: 1.0
659 gdouble
660 adg_table_cell_get_width(AdgTableCell *table_cell)
662 g_return_val_if_fail(table_cell != NULL, 0.);
664 return table_cell->width;
668 * adg_table_cell_switch_frame:
669 * @table_cell: a valid #AdgTableCell
670 * @has_frame: whether to draw or not the frame
672 * Sets the frame flag of @table_cell: if @has_frame is
673 * <constant>TRUE</constant>, a frame around @table_cell
674 * will be rendered using the #AdgTableStyle:frame-dress
675 * dress of the table style.
677 * Since: 1.0
679 void
680 adg_table_cell_switch_frame(AdgTableCell *table_cell, gboolean has_frame)
682 g_return_if_fail(table_cell != NULL);
684 if (table_cell->has_frame != has_frame) {
685 AdgTable *table = adg_table_cell_get_table(table_cell);
686 table_cell->has_frame = has_frame;
687 adg_table_invalidate_grid(table);
692 * adg_table_cell_has_frame:
693 * @table_cell: a valid #AdgTableCell
695 * Gets the frame flag of @table_cell.
697 * Returns: the frame flag.
699 * Since: 1.0
701 gboolean
702 adg_table_cell_has_frame(AdgTableCell *table_cell)
704 g_return_val_if_fail(table_cell != NULL, FALSE);
706 return table_cell->has_frame;
710 * adg_table_cell_get_extents:
711 * @table_cell: a valid #AdgTableCell
713 * Gets the extents of @table_cell. This function is useful only after the
714 * arrange() phase as in the other situation the extents will likely
715 * be not up to date.
717 * Returns: the extents of @table_cell or <constant>NULL</constant> on errors.
719 * Since: 1.0
721 const CpmlExtents *
722 adg_table_cell_get_extents(AdgTableCell *table_cell)
724 g_return_val_if_fail(table_cell != NULL, NULL);
726 return &table_cell->extents;
730 * adg_table_cell_size_request:
731 * @table_cell: a valid #AdgTableCell
732 * @row_extents: the extents of the container #AdgTableRow
734 * Computes the minimum space needed to properly render @table_cell
735 * and updates the size component of the internal #CpmlExtents struct,
736 * returning it to the caller. The returned #CpmlPair is owned by
737 * @table_cell and should not be modified or freed.
739 * Returns: (transfer none): the minimum size required.
741 * Since: 1.0
743 const CpmlPair *
744 adg_table_cell_size_request(AdgTableCell *table_cell,
745 const CpmlExtents *row_extents)
747 CpmlVector *size;
748 AdgAlignment *title_alignment;
749 AdgAlignment *value_alignment;
750 AdgTable *table;
752 size = &table_cell->extents.size;
754 if (table_cell->title) {
755 title_alignment = (AdgAlignment *) adg_entity_get_parent(table_cell->title);
756 adg_entity_arrange((AdgEntity *) title_alignment);
757 } else {
758 title_alignment = NULL;
761 if (table_cell->value) {
762 value_alignment = (AdgAlignment *) adg_entity_get_parent(table_cell->value);
763 adg_entity_arrange((AdgEntity *) value_alignment);
764 } else {
765 value_alignment = NULL;
768 table = adg_table_cell_get_table(table_cell);
769 size->y = row_extents->size.y;
771 if (table_cell->width == 0) {
772 AdgTableStyle *table_style = (AdgTableStyle *) adg_table_get_table_style(table);
773 const CpmlExtents *extents;
775 /* The width depends on the cell content (default = 0) */
776 size->x = 0;
778 if (title_alignment) {
779 extents = adg_entity_get_extents((AdgEntity *) title_alignment);
780 size->x = extents->size.x;
783 if (value_alignment) {
784 extents = adg_entity_get_extents((AdgEntity *) value_alignment);
785 if (extents->size.x > size->x)
786 size->x = extents->size.x;
789 size->x += adg_table_style_get_cell_spacing(table_style)->x * 2;
790 } else {
791 size->x = table_cell->width;
794 return size;
798 * adg_table_cell_arrange:
799 * @table_cell: an #AdgTableCell
800 * @layout: the new extents to use
802 * Rearranges the underlying #AdgTableCell owned by @table_cell using
803 * the new extents provided in @layout. If the x or y size component
804 * of @layout is negative, the value holded by the internal extents
805 * struct is not overriden.
807 * <note><para>
808 * table_cell->extents must be up to date if @layout->size.x or
809 * @layout->size.y is negative in order to have a valid size.
810 * </para></note>
812 * Returns: the extents of @table_cell or <constant>NULL</constant> on errors.
814 * Since: 1.0
816 const CpmlExtents *
817 adg_table_cell_arrange(AdgTableCell *table_cell, const CpmlExtents *layout)
819 CpmlExtents *extents;
820 AdgAlignment *alignment;
821 cairo_matrix_t map;
823 /* Set the new extents */
824 extents = &table_cell->extents;
825 extents->org = layout->org;
826 if (layout->size.x > 0)
827 extents->size.x = layout->size.x;
828 if (layout->size.y > 0)
829 extents->size.y = layout->size.y;
830 extents->is_defined = TRUE;
832 if (table_cell->title) {
833 alignment = (AdgAlignment *) adg_entity_get_parent(table_cell->title);
835 cairo_matrix_init_translate(&map, extents->org.x, extents->org.y);
836 adg_entity_set_global_map((AdgEntity *) alignment, &map);
839 if (table_cell->value) {
840 CpmlPair to;
842 alignment = (AdgAlignment *) adg_entity_get_parent(table_cell->value);
843 to.x = extents->size.x * table_cell->value_factor.x + extents->org.x;
844 to.y = extents->size.y * table_cell->value_factor.y + extents->org.y;
846 cairo_matrix_init_translate(&map, to.x, to.y);
847 adg_entity_set_global_map((AdgEntity *) alignment, &map);
850 return extents;
854 static AdgTableCell *
855 _adg_cell_new(void)
857 AdgTableCell *table_cell;
859 table_cell = g_new(AdgTableCell, 1);
860 table_cell->row = NULL;
861 table_cell->width = 0.;
862 table_cell->has_frame = FALSE;
863 table_cell->title = NULL;
864 table_cell->value = NULL;
865 table_cell->extents.is_defined = FALSE;
866 table_cell->value_factor.x = 0.5;
867 table_cell->value_factor.y = 1;
869 return table_cell;
872 static void
873 _adg_cell_invalidate(AdgTableCell *table_cell)
875 AdgTable *table = adg_table_cell_get_table(table_cell);
877 if (table)
878 adg_entity_invalidate((AdgEntity *) table);
881 static gboolean
882 _adg_cell_set_title(AdgTableCell *table_cell, AdgEntity *title)
884 AdgEntity *alignment;
886 if (table_cell->title == title)
887 return FALSE;
889 if (table_cell->title) {
890 alignment = adg_entity_get_parent(table_cell->title);
891 g_object_unref(alignment);
894 table_cell->title = title;
896 if (title) {
897 AdgEntity *table = (AdgEntity *) adg_table_cell_get_table(table_cell);
898 alignment = (AdgEntity *) adg_alignment_new_explicit(0, -1);
899 g_object_ref_sink(alignment);
900 adg_entity_set_parent(alignment, table);
901 adg_container_add((AdgContainer *) alignment, title);
904 return TRUE;
907 static gboolean
908 _adg_cell_set_value(AdgTableCell *table_cell, AdgEntity *value)
910 AdgEntity *alignment;
912 if (table_cell->value == value)
913 return FALSE;
915 if (table_cell->value) {
916 alignment = adg_entity_get_parent(table_cell->value);
917 adg_container_remove((AdgContainer *) alignment, table_cell->value);
918 g_object_unref(alignment);
921 table_cell->value = value;
923 if (value) {
924 AdgEntity *table = (AdgEntity *) adg_table_cell_get_table(table_cell);
925 alignment = (AdgEntity *) adg_alignment_new_explicit(0.5, 0);
926 g_object_ref_sink(alignment);
927 adg_entity_set_parent(alignment, table);
928 adg_container_add((AdgContainer *) alignment, value);
931 return TRUE;
934 static void
935 _adg_cell_set_value_pos(AdgTableCell *table_cell,
936 const CpmlPair *from_factor, const CpmlPair *to_factor)
938 AdgAlignment *alignment;
940 if (table_cell->value == NULL)
941 return;
943 alignment = (AdgAlignment *) adg_entity_get_parent(table_cell->value);
945 if (from_factor)
946 adg_alignment_set_factor(alignment, from_factor);
948 if (to_factor)
949 table_cell->value_factor = *to_factor;