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.
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 #AdgTableCell 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 * @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.
94 adg_table_row_dup(const AdgTableRow
*src
)
96 g_return_val_if_fail(src
!= NULL
, NULL
);
97 return g_memdup(src
, sizeof(AdgTableRow
));
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.
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
);
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.
139 adg_table_row_new_before(AdgTableRow
*before_row
)
141 AdgTableRow
*table_row
;
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
);
158 * adg_table_row_free:
159 * @table_row: an #AdgTableRow structure
161 * Releases all the memory allocated by @table_row, itself included.
166 adg_table_row_free(AdgTableRow
*table_row
)
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
;
175 adg_table_remove(table
, 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.
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
);
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
,
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.
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>
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.
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.
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.
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.
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.
346 adg_table_row_size_request(AdgTableRow
*table_row
)
348 AdgTableStyle
*table_style
;
349 const CpmlPair
*spacing
;
350 CpmlExtents
*extents
;
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
;
364 if (table_row
->height
== 0)
365 size
->y
= adg_table_style_get_row_height(table_style
);
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
;
377 size
->x
+= spacing
->x
;
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.
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.
397 * Returns: (transfer none): the extents of @table_row or <constant>NULL</constant> on errors.
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
;
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
;
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
;