doc: update copyright line for 2019
[adg.git] / src / adg / adg-table-row.c
bloba2ce315b89859ec3d7e73d262efd08b27d6f8572
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2019 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_return_if_fail(table_row != NULL);
172 g_slist_foreach(table_row->cells, (GFunc) adg_table_cell_free, NULL);
173 g_slist_free(table_row->cells);
175 table = table_row->table;
176 if (table != NULL)
177 adg_table_remove(table, table_row);
179 g_free(table_row);
183 * adg_table_row_insert:
184 * @table_row: a valid #AdgTableRow
185 * @table_cell: the #AdgTableCell to insert
186 * @before_cell: (allow-none): an #AdgTableRow
188 * Inserts @table_cell inside @table_row. If @before_cell
189 * is specified, @table_cell is inserted before it.
191 * Since: 1.0
193 void
194 adg_table_row_insert(AdgTableRow *table_row, AdgTableCell *table_cell,
195 AdgTableCell *before_cell)
197 g_return_if_fail(table_row != NULL);
198 g_return_if_fail(table_cell != NULL);
200 if (before_cell == NULL) {
201 table_row->cells = g_slist_append(table_row->cells, table_cell);
202 } else {
203 GSList *before = g_slist_find(table_row->cells, before_cell);
205 /* This MUST be present, otherwise something really bad happened */
206 g_return_if_fail(before != NULL);
208 table_row->cells = g_slist_insert_before(table_row->cells,
209 before, table_cell);
214 * adg_table_row_remove:
215 * @table_row: a valid #AdgTableRow
216 * @table_cell: the #AdgTableCell to remove
218 * Removes @table_cell from list of cells of @table_row.
220 * Since: 1.0
222 void
223 adg_table_row_remove(AdgTableRow *table_row, AdgTableCell *table_cell)
225 g_return_if_fail(table_row != NULL);
226 g_return_if_fail(table_cell != NULL);
228 table_row->cells = g_slist_remove(table_row->cells, table_cell);
232 * adg_table_row_foreach:
233 * @table_row: an #AdgTableRow
234 * @callback: (scope call): a callback
235 * @user_data: callback user data
237 * Invokes @callback on each cell of @table_row.
238 * The callback should be declared as:
240 * <informalexample><programlisting language="C">
241 * void callback(AdgTableCell *table_cell, gpointer user_data);
242 * </programlisting></informalexample>
244 * Since: 1.0
246 void
247 adg_table_row_foreach(AdgTableRow *table_row,
248 GCallback callback, gpointer user_data)
250 g_return_if_fail(table_row != NULL);
251 g_return_if_fail(callback != NULL);
253 g_slist_foreach(table_row->cells, (GFunc) callback, user_data);
257 * adg_table_row_get_table:
258 * @table_row: a valid #AdgTableRow
260 * Returns the container table of @table_row. The returned table
261 * is owned by @table_row and must not be modified or freed.
263 * Returns: (transfer none): the requested table or <constant>NULL</constant> on errors.
265 * Since: 1.0
267 AdgTable *
268 adg_table_row_get_table(AdgTableRow *table_row)
270 g_return_val_if_fail(table_row != NULL, NULL);
272 return table_row->table;
276 * adg_table_row_set_height:
277 * @table_row: a valid #AdgTableRow
278 * @height: the new height
280 * Sets a new height on @table_row. The extents will be invalidated to
281 * recompute the whole layout of the table. Specifying 0 in
282 * @height will use the default height set in the table style.
284 * Since: 1.0
286 void
287 adg_table_row_set_height(AdgTableRow *table_row, gdouble height)
289 g_return_if_fail(table_row != NULL);
291 table_row->height = height;
293 adg_entity_invalidate((AdgEntity *) table_row->table);
297 * adg_table_row_get_height:
298 * @table_row: a valid #AdgTableRow
300 * Gets the height of @table_row.
302 * Returns: the requested height or 0 on errors.
304 * Since: 1.0
306 gdouble
307 adg_table_row_get_height(AdgTableRow *table_row)
309 g_return_val_if_fail(table_row != NULL, 0.);
311 return table_row->height;
315 * adg_table_row_get_extents:
316 * @table_row: a valid #AdgTableRow
318 * Gets the extents of @table_row. This function is useful only after
319 * the arrange() phase as in the other situation the extents will
320 * likely be not up to date.
322 * Returns: (transfer none): the extents of @table_row or <constant>NULL</constant> on errors.
324 * Since: 1.0
326 const CpmlExtents *
327 adg_table_row_get_extents(AdgTableRow *table_row)
329 g_return_val_if_fail(table_row != NULL, NULL);
331 return &table_row->extents;
335 * adg_table_row_size_request:
336 * @table_row: a valid #AdgTableRow
338 * Computes the minimum space needed to properly render @table_row
339 * and updates the size component of the internal #CpmlExtents struct,
340 * returning it to the caller. The returned #CpmlPair is owned by
341 * @table_row and should not be modified or freed.
343 * Returns: (transfer none): the minimum size required.
345 * Since: 1.0
347 const CpmlPair *
348 adg_table_row_size_request(AdgTableRow *table_row)
350 AdgTableStyle *table_style;
351 const CpmlPair *spacing;
352 gdouble xpad;
353 CpmlExtents *extents;
354 CpmlVector *size;
355 AdgTableCell *cell;
356 GSList *cell_node;
357 const CpmlPair *cell_size;
359 g_return_val_if_fail(table_row != NULL, NULL);
361 table_style = (AdgTableStyle *) adg_table_get_table_style(table_row->table);
362 spacing = adg_table_style_get_cell_spacing(table_style);
363 xpad = spacing ? spacing->x : 0;
364 extents = &table_row->extents;
365 size = &extents->size;
367 size->x = 0;
368 if (table_row->height == 0)
369 size->y = adg_table_style_get_row_height(table_style);
370 else
371 size->y = table_row->height;
373 /* Compute the row width by summing every cell width */
374 for (cell_node = table_row->cells; cell_node; cell_node = cell_node->next) {
375 cell = cell_node->data;
376 cell_size = adg_table_cell_size_request(cell, extents);
377 size->x += cell_size->x + xpad;
380 if (size->x > 0)
381 size->x += xpad;
383 return size;
387 * adg_table_row_arrange:
388 * @table_row: an #AdgTableRow
389 * @layout: the new extents to use
391 * Rearranges the underlying #AdgTableCell owned by @table_row using
392 * the new extents provided in @layout. If the x or y size component
393 * of @layout is negative, the value holded by the internal extents
394 * struct is not overriden.
396 * <note><para>
397 * table_row->extents must be up to date if @layout->size.x or
398 * @layout->size.y is negative in order to have a valid size.
399 * </para></note>
401 * Returns: (transfer none): the extents of @table_row or <constant>NULL</constant> on errors.
403 * Since: 1.0
405 const CpmlExtents *
406 adg_table_row_arrange(AdgTableRow *table_row, const CpmlExtents *layout)
408 CpmlExtents *extents;
409 CpmlExtents cell_layout;
410 const CpmlExtents *cell_extents;
411 AdgTableStyle *table_style;
412 const CpmlPair *spacing;
413 gdouble xpad;
414 AdgTableCell *cell;
415 GSList *cell_node;
417 g_return_val_if_fail(table_row != NULL, NULL);
418 g_return_val_if_fail(layout != NULL, NULL);
419 g_return_val_if_fail(layout->is_defined, NULL);
421 /* Set the new extents */
422 extents = &table_row->extents;
423 extents->org = layout->org;
424 if (layout->size.x > 0)
425 extents->size.x = layout->size.x;
426 if (layout->size.y > 0)
427 extents->size.y = layout->size.y;
428 extents->is_defined = TRUE;
430 table_style = (AdgTableStyle *) adg_table_get_table_style(table_row->table);
431 spacing = adg_table_style_get_cell_spacing(table_style);
432 xpad = spacing ? spacing->x : 0;
434 /* Propagate the arrange to the table cells */
435 cell_layout.org.x = extents->org.x + xpad;
436 cell_layout.org.y = extents->org.y;
437 cell_layout.size.x = -1;
438 cell_layout.size.y = extents->size.y;
440 for (cell_node = table_row->cells; cell_node; cell_node = cell_node->next) {
441 cell = cell_node->data;
442 cell_extents = adg_table_cell_arrange(cell, &cell_layout);
443 cell_layout.org.x += cell_extents->size.x + xpad;
446 return extents;
450 static AdgTableRow *
451 _adg_row_new(AdgTable *table)
453 AdgTableRow *table_row = g_new(AdgTableRow, 1);
455 table_row->table = table;
456 table_row->cells = NULL;
457 table_row->height = 0;
458 table_row->extents.is_defined = FALSE;
460 return table_row;