1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010,2011,2012,2013 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.
22 * SECTION:adg-table-row
23 * @Section_Id: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 #AdgCell APIs, such as adg_table_cell_new() or
32 * adg_table_cell_new_before().
40 * An opaque structure referring to a row of an #AdgTable. Any
41 * table can have an unlimited number of rows.
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"
65 static AdgTableRow
* _adg_row_new (AdgTable
*table
);
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
);
84 * @table_row: an #AdgTableRow structure
86 * Duplicates @table_row. The returned duplicate should be freed
87 * with adg_table_row_free() when no longer needed.
89 * Returns: (transfer full): a duplicate of @table_row.
94 adg_table_row_dup(const AdgTableRow
*table_row
)
96 return g_memdup(table_row
, sizeof(AdgTableRow
));
101 * @table: an #AdgTable
103 * Creates a new empty row and appends it at the end of the rows
104 * yet present in @table. By default, the height of this new
105 * row will be the fallback value provided by the table style:
106 * you can override it by using adg_table_row_set_height().
108 * Returns: (transfer full): the newly created row or %NULL on errors.
113 adg_table_row_new(AdgTable
*table
)
115 AdgTableRow
*table_row
;
117 g_return_val_if_fail(ADG_IS_TABLE(table
), NULL
);
119 table_row
= _adg_row_new(table
);
120 adg_table_insert(table
, table_row
, NULL
);
121 adg_entity_invalidate((AdgEntity
*) table
);
127 * adg_table_row_new_before:
128 * @before_row: a valid #AdgTableRow
130 * Creates a new empty row with default height and inserts it
131 * just before @before_row.
133 * Returns: (transfer full): the newly created row or %NULL on errors.
138 adg_table_row_new_before(AdgTableRow
*before_row
)
140 AdgTableRow
*table_row
;
143 g_return_val_if_fail(before_row
!= NULL
, NULL
);
145 table
= (AdgTable
*) before_row
->table
;
146 g_return_val_if_fail(ADG_IS_TABLE(table
), NULL
);
148 table_row
= _adg_row_new(table
);
149 adg_table_insert(table
, table_row
, before_row
);
150 adg_entity_invalidate((AdgEntity
*) before_row
->table
);
157 * adg_table_row_free:
158 * @table_row: an #AdgTableRow structure
160 * Releases all the memory allocated by @table_row, itself included.
165 adg_table_row_free(AdgTableRow
*table_row
)
169 g_slist_foreach(table_row
->cells
, (GFunc
) adg_table_cell_free
, NULL
);
170 g_slist_free(table_row
->cells
);
172 table
= table_row
->table
;
174 adg_table_remove(table
, table_row
);
180 * adg_table_row_insert:
181 * @table_row: a valid #AdgTableRow
182 * @table_cell: the #AdgTableCell to insert
183 * @before_cell: (allow-none): an #AdgTableRow or %NULL
185 * Inserts @table_cell inside @table_row. If @before_cell
186 * is specified, @table_cell is inserted before it.
191 adg_table_row_insert(AdgTableRow
*table_row
, AdgTableCell
*table_cell
,
192 AdgTableCell
*before_cell
)
194 g_return_if_fail(table_row
!= NULL
);
195 g_return_if_fail(table_cell
!= NULL
);
197 if (before_cell
== NULL
) {
198 table_row
->cells
= g_slist_append(table_row
->cells
, table_cell
);
200 GSList
*before
= g_slist_find(table_row
->cells
, before_cell
);
202 /* This MUST be present, otherwise something really bad happened */
203 g_return_if_fail(before
!= NULL
);
205 table_row
->cells
= g_slist_insert_before(table_row
->cells
,
211 * adg_table_row_remove:
212 * @table_row: a valid #AdgTableRow
213 * @table_cell: the #AdgTableCell to remove
215 * Removes @table_cell from list of cells of @table_row.
220 adg_table_row_remove(AdgTableRow
*table_row
, AdgTableCell
*table_cell
)
222 g_return_if_fail(table_row
!= NULL
);
223 g_return_if_fail(table_cell
!= NULL
);
225 table_row
->cells
= g_slist_remove(table_row
->cells
, table_cell
);
229 * adg_table_row_foreach:
230 * @table_row: an #AdgTableRow
231 * @callback: (scope call): a callback
232 * @user_data: callback user data
234 * Invokes @callback on each cell of @table_row.
235 * The callback should be declared as:
238 * void callback(AdgTableCell *table_cell, gpointer user_data);
244 adg_table_row_foreach(AdgTableRow
*table_row
,
245 GCallback callback
, gpointer user_data
)
247 g_return_if_fail(table_row
!= NULL
);
248 g_return_if_fail(callback
!= NULL
);
250 g_slist_foreach(table_row
->cells
, (GFunc
) callback
, user_data
);
254 * adg_table_row_get_table:
255 * @table_row: a valid #AdgTableRow
257 * Returns the container table of @table_row. The returned table
258 * is owned by @table_row and must not be modified or freed.
260 * Returns: (transfer none): the requested table or %NULL on errors.
265 adg_table_row_get_table(AdgTableRow
*table_row
)
267 g_return_val_if_fail(table_row
!= NULL
, NULL
);
269 return table_row
->table
;
273 * adg_table_row_set_height:
274 * @table_row: a valid #AdgTableRow
275 * @height: the new height
277 * Sets a new height on @table_row. The extents will be invalidated to
278 * recompute the whole layout of the table. Specifying %0 in
279 * @height will use the default height set in the table style.
284 adg_table_row_set_height(AdgTableRow
*table_row
, gdouble height
)
286 g_return_if_fail(table_row
!= NULL
);
288 table_row
->height
= height
;
290 adg_entity_invalidate((AdgEntity
*) table_row
->table
);
294 * adg_table_row_get_height:
295 * @table_row: a valid #AdgTableRow
297 * Gets the height of @table_row.
299 * Returns: the requested height or %0 on errors
304 adg_table_row_get_height(AdgTableRow
*table_row
)
306 g_return_val_if_fail(table_row
!= NULL
, 0.);
308 return table_row
->height
;
312 * adg_table_row_get_extents:
313 * @table_row: a valid #AdgTableRow
315 * Gets the extents of @table_row. This function is useful only after
316 * the arrange() phase as in the other situation the extents will
317 * likely be not up to date.
319 * Returns: (transfer none): the extents of @table_row or %NULL on errors.
324 adg_table_row_get_extents(AdgTableRow
*table_row
)
326 g_return_val_if_fail(table_row
!= NULL
, NULL
);
328 return &table_row
->extents
;
332 * adg_table_row_size_request:
333 * @table_row: a valid #AdgTableRow
335 * Computes the minimum space needed to properly render @table_row
336 * and updates the size component of the internal #CpmlExtents struct,
337 * returning it to the caller. The returned #CpmlPair is owned by
338 * @table_row and should not be modified or freed.
340 * Returns: (transfer none): the minimum size required.
345 adg_table_row_size_request(AdgTableRow
*table_row
)
347 AdgTableStyle
*table_style
;
348 const CpmlPair
*spacing
;
349 CpmlExtents
*extents
;
353 const CpmlPair
*cell_size
;
355 g_return_val_if_fail(table_row
!= NULL
, NULL
);
357 table_style
= (AdgTableStyle
*) adg_table_get_table_style(table_row
->table
);
358 spacing
= adg_table_style_get_cell_spacing(table_style
);
359 extents
= &table_row
->extents
;
360 size
= &extents
->size
;
363 if (table_row
->height
== 0)
364 size
->y
= adg_table_style_get_row_height(table_style
);
366 size
->y
= table_row
->height
;
368 /* Compute the row width by summing every cell width */
369 for (cell_node
= table_row
->cells
; cell_node
; cell_node
= cell_node
->next
) {
370 cell
= cell_node
->data
;
371 cell_size
= adg_table_cell_size_request(cell
, extents
);
372 size
->x
+= cell_size
->x
+ spacing
->x
;
376 size
->x
+= spacing
->x
;
382 * adg_table_row_arrange:
383 * @table_row: an #AdgTableRow
384 * @layout: the new extents to use
386 * Rearranges the underlying #AdgTableCell owned by @table_row using
387 * the new extents provided in @layout. If the x or y size component
388 * of @layout is negative, the value holded by the internal extents
389 * struct is not overriden.
392 * table_row->extents must be up to date if @layout->size.x or
393 * @layout->size.y is negative in order to have a valid size.
396 * Returns: (transfer none): the extents of @table_row or %NULL on errors.
401 adg_table_row_arrange(AdgTableRow
*table_row
, const CpmlExtents
*layout
)
403 CpmlExtents
*extents
;
404 CpmlExtents cell_layout
;
405 const CpmlExtents
*cell_extents
;
406 AdgTableStyle
*table_style
;
407 const CpmlPair
*spacing
;
411 g_return_val_if_fail(table_row
!= NULL
, NULL
);
413 /* Set the new extents */
414 extents
= &table_row
->extents
;
415 extents
->org
= layout
->org
;
416 if (layout
->size
.x
> 0)
417 extents
->size
.x
= layout
->size
.x
;
418 if (layout
->size
.y
> 0)
419 extents
->size
.y
= layout
->size
.y
;
420 extents
->is_defined
= TRUE
;
422 table_style
= (AdgTableStyle
*) adg_table_get_table_style(table_row
->table
);
423 spacing
= adg_table_style_get_cell_spacing(table_style
);
425 /* Propagate the arrange to the table cells */
426 cell_layout
.org
.x
= extents
->org
.x
+ spacing
->x
;
427 cell_layout
.org
.y
= extents
->org
.y
;
428 cell_layout
.size
.x
= -1;
429 cell_layout
.size
.y
= extents
->size
.y
;
431 for (cell_node
= table_row
->cells
; cell_node
; cell_node
= cell_node
->next
) {
432 cell
= cell_node
->data
;
433 cell_extents
= adg_table_cell_arrange(cell
, &cell_layout
);
434 cell_layout
.org
.x
+= cell_extents
->size
.x
+ spacing
->x
;
442 _adg_row_new(AdgTable
*table
)
444 AdgTableRow
*table_row
= g_new(AdgTableRow
, 1);
446 table_row
->table
= table
;
447 table_row
->cells
= NULL
;
448 table_row
->height
= 0;
449 table_row
->extents
.is_defined
= FALSE
;