tests: additional checks on container types
[adg.git] / src / adg / adg-table-row.c
blobd7879fe4427bb3e7f9b01920ff3a8432e6a61745
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2015 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-row
23 * @Section_Id:AdgTableRow
24 * @title: AdgTableRow
25 * @short_description: A boxed type representing a table row
27 * The #AdgTableRow is a boxed type containing a single row of cells
28 * of an #AdgTable object.
30 * Every row is segmented into different cells. It must be populated
31 * by using the #AdgTableCell APIs, such as adg_table_cell_new() or
32 * adg_table_cell_new_before().
34 * Since: 1.0
35 **/
37 /**
38 * AdgTableRow:
40 * An opaque structure referring to a row of an #AdgTable. Any
41 * table can have an unlimited number of rows.
43 * Since: 1.0
44 **/
47 #include "adg-internal.h"
49 #include "adg-style.h"
50 #include "adg-table-style.h"
52 #include "adg-table.h"
53 #include "adg-table-row.h"
54 #include "adg-table-cell.h"
57 struct _AdgTableRow {
58 AdgTable *table;
59 GSList *cells;
60 gdouble height;
61 CpmlExtents extents;
65 static AdgTableRow * _adg_row_new (AdgTable *table);
68 GType
69 adg_table_row_get_type(void)
71 static GType row_type = 0;
73 if (G_UNLIKELY(row_type == 0))
74 row_type = g_boxed_type_register_static("AdgTableRow",
75 (GBoxedCopyFunc) adg_table_row_dup,
76 (GBoxedFreeFunc) adg_table_row_free);
78 return row_type;
82 /**
83 * adg_table_row_dup:
84 * @src: an #AdgTableRow structure
86 * Duplicates @src. The returned duplicate should be freed
87 * with adg_table_row_free() when no longer needed.
89 * Returns: (transfer full): a duplicate of @src.
91 * Since: 1.0
92 **/
93 AdgTableRow *
94 adg_table_row_dup(const AdgTableRow *src)
96 g_return_val_if_fail(src != NULL, NULL);
97 return g_memdup(src, sizeof(AdgTableRow));
101 * adg_table_row_new:
102 * @table: an #AdgTable
104 * Creates a new empty row and appends it at the end of the rows
105 * already present in @table. By default, the height of this new
106 * row will be the fallback value provided by the table style:
107 * you can override it by using adg_table_row_set_height().
109 * Returns: (transfer full): the newly created row or <constant>NULL</constant> on errors.
111 * Since: 1.0
113 AdgTableRow *
114 adg_table_row_new(AdgTable *table)
116 AdgTableRow *table_row;
118 g_return_val_if_fail(ADG_IS_TABLE(table), NULL);
120 table_row = _adg_row_new(table);
121 adg_table_insert(table, table_row, NULL);
122 adg_entity_invalidate((AdgEntity *) table);
124 return table_row;
128 * adg_table_row_new_before:
129 * @before_row: a valid #AdgTableRow
131 * Creates a new empty row with default height and inserts it
132 * just before @before_row.
134 * Returns: (transfer full): the newly created row or <constant>NULL</constant> on errors.
136 * Since: 1.0
138 AdgTableRow *
139 adg_table_row_new_before(AdgTableRow *before_row)
141 AdgTableRow *table_row;
142 AdgTable *table;
144 g_return_val_if_fail(before_row != NULL, NULL);
146 table = (AdgTable *) before_row->table;
147 g_return_val_if_fail(ADG_IS_TABLE(table), NULL);
149 table_row = _adg_row_new(table);
150 adg_table_insert(table, table_row, before_row);
151 adg_entity_invalidate((AdgEntity *) before_row->table);
153 return table_row;
158 * adg_table_row_free:
159 * @table_row: an #AdgTableRow structure
161 * Releases all the memory allocated by @table_row, itself included.
163 * Since: 1.0
165 void
166 adg_table_row_free(AdgTableRow *table_row)
168 AdgTable *table;
170 g_slist_foreach(table_row->cells, (GFunc) adg_table_cell_free, NULL);
171 g_slist_free(table_row->cells);
173 table = table_row->table;
174 if (table != NULL)
175 adg_table_remove(table, table_row);
177 g_free(table_row);
181 * adg_table_row_insert:
182 * @table_row: a valid #AdgTableRow
183 * @table_cell: the #AdgTableCell to insert
184 * @before_cell: (allow-none): an #AdgTableRow
186 * Inserts @table_cell inside @table_row. If @before_cell
187 * is specified, @table_cell is inserted before it.
189 * Since: 1.0
191 void
192 adg_table_row_insert(AdgTableRow *table_row, AdgTableCell *table_cell,
193 AdgTableCell *before_cell)
195 g_return_if_fail(table_row != NULL);
196 g_return_if_fail(table_cell != NULL);
198 if (before_cell == NULL) {
199 table_row->cells = g_slist_append(table_row->cells, table_cell);
200 } else {
201 GSList *before = g_slist_find(table_row->cells, before_cell);
203 /* This MUST be present, otherwise something really bad happened */
204 g_return_if_fail(before != NULL);
206 table_row->cells = g_slist_insert_before(table_row->cells,
207 before, table_cell);
212 * adg_table_row_remove:
213 * @table_row: a valid #AdgTableRow
214 * @table_cell: the #AdgTableCell to remove
216 * Removes @table_cell from list of cells of @table_row.
218 * Since: 1.0
220 void
221 adg_table_row_remove(AdgTableRow *table_row, AdgTableCell *table_cell)
223 g_return_if_fail(table_row != NULL);
224 g_return_if_fail(table_cell != NULL);
226 table_row->cells = g_slist_remove(table_row->cells, table_cell);
230 * adg_table_row_foreach:
231 * @table_row: an #AdgTableRow
232 * @callback: (scope call): a callback
233 * @user_data: callback user data
235 * Invokes @callback on each cell of @table_row.
236 * The callback should be declared as:
238 * <informalexample><programlisting language="C">
239 * void callback(AdgTableCell *table_cell, gpointer user_data);
240 * </programlisting></informalexample>
242 * Since: 1.0
244 void
245 adg_table_row_foreach(AdgTableRow *table_row,
246 GCallback callback, gpointer user_data)
248 g_return_if_fail(table_row != NULL);
249 g_return_if_fail(callback != NULL);
251 g_slist_foreach(table_row->cells, (GFunc) callback, user_data);
255 * adg_table_row_get_table:
256 * @table_row: a valid #AdgTableRow
258 * Returns the container table of @table_row. The returned table
259 * is owned by @table_row and must not be modified or freed.
261 * Returns: (transfer none): the requested table or <constant>NULL</constant> on errors.
263 * Since: 1.0
265 AdgTable *
266 adg_table_row_get_table(AdgTableRow *table_row)
268 g_return_val_if_fail(table_row != NULL, NULL);
270 return table_row->table;
274 * adg_table_row_set_height:
275 * @table_row: a valid #AdgTableRow
276 * @height: the new height
278 * Sets a new height on @table_row. The extents will be invalidated to
279 * recompute the whole layout of the table. Specifying 0 in
280 * @height will use the default height set in the table style.
282 * Since: 1.0
284 void
285 adg_table_row_set_height(AdgTableRow *table_row, gdouble height)
287 g_return_if_fail(table_row != NULL);
289 table_row->height = height;
291 adg_entity_invalidate((AdgEntity *) table_row->table);
295 * adg_table_row_get_height:
296 * @table_row: a valid #AdgTableRow
298 * Gets the height of @table_row.
300 * Returns: the requested height or 0 on errors.
302 * Since: 1.0
304 gdouble
305 adg_table_row_get_height(AdgTableRow *table_row)
307 g_return_val_if_fail(table_row != NULL, 0.);
309 return table_row->height;
313 * adg_table_row_get_extents:
314 * @table_row: a valid #AdgTableRow
316 * Gets the extents of @table_row. This function is useful only after
317 * the arrange() phase as in the other situation the extents will
318 * likely be not up to date.
320 * Returns: (transfer none): the extents of @table_row or <constant>NULL</constant> on errors.
322 * Since: 1.0
324 const CpmlExtents *
325 adg_table_row_get_extents(AdgTableRow *table_row)
327 g_return_val_if_fail(table_row != NULL, NULL);
329 return &table_row->extents;
333 * adg_table_row_size_request:
334 * @table_row: a valid #AdgTableRow
336 * Computes the minimum space needed to properly render @table_row
337 * and updates the size component of the internal #CpmlExtents struct,
338 * returning it to the caller. The returned #CpmlPair is owned by
339 * @table_row and should not be modified or freed.
341 * Returns: (transfer none): the minimum size required.
343 * Since: 1.0
345 const CpmlPair *
346 adg_table_row_size_request(AdgTableRow *table_row)
348 AdgTableStyle *table_style;
349 const CpmlPair *spacing;
350 CpmlExtents *extents;
351 CpmlVector *size;
352 AdgTableCell *cell;
353 GSList *cell_node;
354 const CpmlPair *cell_size;
356 g_return_val_if_fail(table_row != NULL, NULL);
358 table_style = (AdgTableStyle *) adg_table_get_table_style(table_row->table);
359 spacing = adg_table_style_get_cell_spacing(table_style);
360 extents = &table_row->extents;
361 size = &extents->size;
363 size->x = 0;
364 if (table_row->height == 0)
365 size->y = adg_table_style_get_row_height(table_style);
366 else
367 size->y = table_row->height;
369 /* Compute the row width by summing every cell width */
370 for (cell_node = table_row->cells; cell_node; cell_node = cell_node->next) {
371 cell = cell_node->data;
372 cell_size = adg_table_cell_size_request(cell, extents);
373 size->x += cell_size->x + spacing->x;
376 if (size->x > 0)
377 size->x += spacing->x;
379 return size;
383 * adg_table_row_arrange:
384 * @table_row: an #AdgTableRow
385 * @layout: the new extents to use
387 * Rearranges the underlying #AdgTableCell owned by @table_row using
388 * the new extents provided in @layout. If the x or y size component
389 * of @layout is negative, the value holded by the internal extents
390 * struct is not overriden.
392 * <note><para>
393 * table_row->extents must be up to date if @layout->size.x or
394 * @layout->size.y is negative in order to have a valid size.
395 * </para></note>
397 * Returns: (transfer none): the extents of @table_row or <constant>NULL</constant> on errors.
399 * Since: 1.0
401 const CpmlExtents *
402 adg_table_row_arrange(AdgTableRow *table_row, const CpmlExtents *layout)
404 CpmlExtents *extents;
405 CpmlExtents cell_layout;
406 const CpmlExtents *cell_extents;
407 AdgTableStyle *table_style;
408 const CpmlPair *spacing;
409 AdgTableCell *cell;
410 GSList *cell_node;
412 g_return_val_if_fail(table_row != NULL, NULL);
414 /* Set the new extents */
415 extents = &table_row->extents;
416 extents->org = layout->org;
417 if (layout->size.x > 0)
418 extents->size.x = layout->size.x;
419 if (layout->size.y > 0)
420 extents->size.y = layout->size.y;
421 extents->is_defined = TRUE;
423 table_style = (AdgTableStyle *) adg_table_get_table_style(table_row->table);
424 spacing = adg_table_style_get_cell_spacing(table_style);
426 /* Propagate the arrange to the table cells */
427 cell_layout.org.x = extents->org.x + spacing->x;
428 cell_layout.org.y = extents->org.y;
429 cell_layout.size.x = -1;
430 cell_layout.size.y = extents->size.y;
432 for (cell_node = table_row->cells; cell_node; cell_node = cell_node->next) {
433 cell = cell_node->data;
434 cell_extents = adg_table_cell_arrange(cell, &cell_layout);
435 cell_layout.org.x += cell_extents->size.x + spacing->x;
438 return extents;
442 static AdgTableRow *
443 _adg_row_new(AdgTable *table)
445 AdgTableRow *table_row = g_new(AdgTableRow, 1);
447 table_row->table = table;
448 table_row->cells = NULL;
449 table_row->height = 0;
450 table_row->extents.is_defined = FALSE;
452 return table_row;