1 | /* GTK - The GIMP Toolkit |
2 | * Copyright (C) 2010 Red Hat, Inc. |
3 | * Author: Matthias Clasen |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Lesser General Public |
16 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | #include "config.h" |
20 | |
21 | #include <string.h> |
22 | |
23 | #include "gtkgrid.h" |
24 | |
25 | #include "gtkbuildable.h" |
26 | #include "gtkcsspositionvalueprivate.h" |
27 | #include "gtkgridlayout.h" |
28 | #include "gtkintl.h" |
29 | #include "gtkorientable.h" |
30 | #include "gtkprivate.h" |
31 | #include "gtksizerequest.h" |
32 | #include "gtkcssnodeprivate.h" |
33 | #include "gtkwidgetprivate.h" |
34 | |
35 | |
36 | /** |
37 | * GtkGrid: |
38 | * |
39 | * `GtkGrid` is a container which arranges its child widgets in |
40 | * rows and columns. |
41 | * |
42 | *  |
43 | * |
44 | * It supports arbitrary positions and horizontal/vertical spans. |
45 | * |
46 | * Children are added using [method@Gtk.Grid.attach]. They can span multiple |
47 | * rows or columns. It is also possible to add a child next to an existing |
48 | * child, using [method@Gtk.Grid.attach_next_to]. To remove a child from the |
49 | * grid, use [method@Gtk.Grid.remove]. |
50 | * |
51 | * The behaviour of `GtkGrid` when several children occupy the same grid |
52 | * cell is undefined. |
53 | * |
54 | * # GtkGrid as GtkBuildable |
55 | * |
56 | * Every child in a `GtkGrid` has access to a custom [iface@Gtk.Buildable] |
57 | * element, called `<layout>`. It can by used to specify a position in the |
58 | * grid and optionally spans. All properties that can be used in the `<layout>` |
59 | * element are implemented by [class@Gtk.GridLayoutChild]. |
60 | * |
61 | * It is implemented by `GtkWidget` using [class@Gtk.LayoutManager]. |
62 | * |
63 | * To showcase it, here is a simple example: |
64 | * |
65 | * ```xml |
66 | * <object class="GtkGrid" id="my_grid"> |
67 | * <child> |
68 | * <object class="GtkButton" id="button1"> |
69 | * <property name="label">Button 1</property> |
70 | * <layout> |
71 | * <property name="column">0</property> |
72 | * <property name="row">0</property> |
73 | * </layout> |
74 | * </object> |
75 | * </child> |
76 | * <child> |
77 | * <object class="GtkButton" id="button2"> |
78 | * <property name="label">Button 2</property> |
79 | * <layout> |
80 | * <property name="column">1</property> |
81 | * <property name="row">0</property> |
82 | * </layout> |
83 | * </object> |
84 | * </child> |
85 | * <child> |
86 | * <object class="GtkButton" id="button3"> |
87 | * <property name="label">Button 3</property> |
88 | * <layout> |
89 | * <property name="column">2</property> |
90 | * <property name="row">0</property> |
91 | * <property name="row-span">2</property> |
92 | * </layout> |
93 | * </object> |
94 | * </child> |
95 | * <child> |
96 | * <object class="GtkButton" id="button4"> |
97 | * <property name="label">Button 4</property> |
98 | * <layout> |
99 | * <property name="column">0</property> |
100 | * <property name="row">1</property> |
101 | * <property name="column-span">2</property> |
102 | * </layout> |
103 | * </object> |
104 | * </child> |
105 | * </object> |
106 | * ``` |
107 | * |
108 | * It organizes the first two buttons side-by-side in one cell each. |
109 | * The third button is in the last column but spans across two rows. |
110 | * This is defined by the `row-span` property. The last button is |
111 | * located in the second row and spans across two columns, which is |
112 | * defined by the `column-span` property. |
113 | * |
114 | * # CSS nodes |
115 | * |
116 | * `GtkGrid` uses a single CSS node with name `grid`. |
117 | * |
118 | * # Accessibility |
119 | * |
120 | * `GtkGrid` uses the %GTK_ACCESSIBLE_ROLE_GROUP role. |
121 | */ |
122 | |
123 | typedef struct |
124 | { |
125 | GtkLayoutManager *layout_manager; |
126 | |
127 | GtkOrientation orientation; |
128 | } GtkGridPrivate; |
129 | |
130 | enum |
131 | { |
132 | PROP_0, |
133 | PROP_ROW_SPACING, |
134 | PROP_COLUMN_SPACING, |
135 | PROP_ROW_HOMOGENEOUS, |
136 | PROP_COLUMN_HOMOGENEOUS, |
137 | PROP_BASELINE_ROW, |
138 | N_PROPERTIES, |
139 | |
140 | /* GtkOrientable */ |
141 | PROP_ORIENTATION |
142 | }; |
143 | |
144 | static void gtk_grid_buildable_iface_init (GtkBuildableIface *iface); |
145 | |
146 | static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; |
147 | |
148 | G_DEFINE_TYPE_WITH_CODE (GtkGrid, gtk_grid, GTK_TYPE_WIDGET, |
149 | G_ADD_PRIVATE (GtkGrid) |
150 | G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL) |
151 | G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, |
152 | gtk_grid_buildable_iface_init)) |
153 | |
154 | |
155 | static void |
156 | gtk_grid_get_property (GObject *object, |
157 | guint prop_id, |
158 | GValue *value, |
159 | GParamSpec *pspec) |
160 | { |
161 | GtkGrid *grid = GTK_GRID (object); |
162 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
163 | |
164 | switch (prop_id) |
165 | { |
166 | case PROP_ORIENTATION: |
167 | g_value_set_enum (value, v_enum: priv->orientation); |
168 | break; |
169 | |
170 | case PROP_ROW_SPACING: |
171 | g_value_set_int (value, v_int: gtk_grid_layout_get_row_spacing (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager))); |
172 | break; |
173 | |
174 | case PROP_COLUMN_SPACING: |
175 | g_value_set_int (value, v_int: gtk_grid_layout_get_column_spacing (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager))); |
176 | break; |
177 | |
178 | case PROP_ROW_HOMOGENEOUS: |
179 | g_value_set_boolean (value, v_boolean: gtk_grid_layout_get_row_homogeneous (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager))); |
180 | break; |
181 | |
182 | case PROP_COLUMN_HOMOGENEOUS: |
183 | g_value_set_boolean (value, v_boolean: gtk_grid_layout_get_column_homogeneous (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager))); |
184 | break; |
185 | |
186 | case PROP_BASELINE_ROW: |
187 | g_value_set_int (value, v_int: gtk_grid_layout_get_baseline_row (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager))); |
188 | break; |
189 | |
190 | default: |
191 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
192 | break; |
193 | } |
194 | } |
195 | |
196 | static void |
197 | gtk_grid_set_orientation (GtkGrid *grid, |
198 | GtkOrientation orientation) |
199 | { |
200 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
201 | |
202 | if (priv->orientation != orientation) |
203 | { |
204 | priv->orientation = orientation; |
205 | |
206 | gtk_widget_update_orientation (GTK_WIDGET (grid), orientation: priv->orientation); |
207 | |
208 | g_object_notify (G_OBJECT (grid), property_name: "orientation" ); |
209 | } |
210 | } |
211 | |
212 | static void |
213 | gtk_grid_set_property (GObject *object, |
214 | guint prop_id, |
215 | const GValue *value, |
216 | GParamSpec *pspec) |
217 | { |
218 | GtkGrid *grid = GTK_GRID (object); |
219 | |
220 | switch (prop_id) |
221 | { |
222 | case PROP_ORIENTATION: |
223 | gtk_grid_set_orientation (grid, orientation: g_value_get_enum (value)); |
224 | break; |
225 | |
226 | case PROP_ROW_SPACING: |
227 | gtk_grid_set_row_spacing (grid, spacing: g_value_get_int (value)); |
228 | break; |
229 | |
230 | case PROP_COLUMN_SPACING: |
231 | gtk_grid_set_column_spacing (grid, spacing: g_value_get_int (value)); |
232 | break; |
233 | |
234 | case PROP_ROW_HOMOGENEOUS: |
235 | gtk_grid_set_row_homogeneous (grid, homogeneous: g_value_get_boolean (value)); |
236 | break; |
237 | |
238 | case PROP_COLUMN_HOMOGENEOUS: |
239 | gtk_grid_set_column_homogeneous (grid, homogeneous: g_value_get_boolean (value)); |
240 | break; |
241 | |
242 | case PROP_BASELINE_ROW: |
243 | gtk_grid_set_baseline_row (grid, row: g_value_get_int (value)); |
244 | break; |
245 | |
246 | default: |
247 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
248 | break; |
249 | } |
250 | } |
251 | |
252 | static void |
253 | grid_attach (GtkGrid *grid, |
254 | GtkWidget *widget, |
255 | int column, |
256 | int row, |
257 | int width, |
258 | int height) |
259 | { |
260 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
261 | GtkGridLayoutChild *grid_child; |
262 | |
263 | gtk_widget_set_parent (widget, GTK_WIDGET (grid)); |
264 | |
265 | grid_child = GTK_GRID_LAYOUT_CHILD (ptr: gtk_layout_manager_get_layout_child (manager: priv->layout_manager, child: widget)); |
266 | gtk_grid_layout_child_set_column (child: grid_child, column); |
267 | gtk_grid_layout_child_set_row (child: grid_child, row); |
268 | gtk_grid_layout_child_set_column_span (child: grid_child, span: width); |
269 | gtk_grid_layout_child_set_row_span (child: grid_child, span: height); |
270 | } |
271 | |
272 | /* Find the position 'touching' existing |
273 | * children. @orientation and @max determine |
274 | * from which direction to approach (horizontal |
275 | * + max = right, vertical + !max = top, etc). |
276 | * @op_pos, @op_span determine the rows/columns |
277 | * in which the touching has to happen. |
278 | */ |
279 | static int |
280 | find_attach_position (GtkGrid *grid, |
281 | GtkOrientation orientation, |
282 | int op_pos, |
283 | int op_span, |
284 | gboolean max) |
285 | { |
286 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
287 | GtkWidget *child; |
288 | gboolean hit; |
289 | int pos; |
290 | |
291 | if (max) |
292 | pos = -G_MAXINT; |
293 | else |
294 | pos = G_MAXINT; |
295 | |
296 | hit = FALSE; |
297 | |
298 | for (child = gtk_widget_get_first_child (GTK_WIDGET (grid)); |
299 | child != NULL; |
300 | child = gtk_widget_get_next_sibling (widget: child)) |
301 | { |
302 | GtkGridLayoutChild *grid_child; |
303 | int attach_pos = 0, attach_span = 0; |
304 | int opposite_pos = 0, opposite_span = 0; |
305 | |
306 | grid_child = GTK_GRID_LAYOUT_CHILD (ptr: gtk_layout_manager_get_layout_child (manager: priv->layout_manager, child)); |
307 | |
308 | switch (orientation) |
309 | { |
310 | case GTK_ORIENTATION_HORIZONTAL: |
311 | attach_pos = gtk_grid_layout_child_get_column (child: grid_child); |
312 | attach_span = gtk_grid_layout_child_get_column_span (child: grid_child); |
313 | opposite_pos = gtk_grid_layout_child_get_row (child: grid_child); |
314 | opposite_span = gtk_grid_layout_child_get_row_span (child: grid_child); |
315 | break; |
316 | |
317 | case GTK_ORIENTATION_VERTICAL: |
318 | attach_pos = gtk_grid_layout_child_get_row (child: grid_child); |
319 | attach_span = gtk_grid_layout_child_get_row_span (child: grid_child); |
320 | opposite_pos = gtk_grid_layout_child_get_column (child: grid_child); |
321 | opposite_span = gtk_grid_layout_child_get_column_span (child: grid_child); |
322 | break; |
323 | |
324 | default: |
325 | break; |
326 | } |
327 | |
328 | /* check if the ranges overlap */ |
329 | if (opposite_pos <= op_pos + op_span && op_pos <= opposite_pos + opposite_span) |
330 | { |
331 | hit = TRUE; |
332 | |
333 | if (max) |
334 | pos = MAX (pos, attach_pos + attach_span); |
335 | else |
336 | pos = MIN (pos, attach_pos); |
337 | } |
338 | } |
339 | |
340 | if (!hit) |
341 | pos = 0; |
342 | |
343 | return pos; |
344 | } |
345 | |
346 | static void |
347 | gtk_grid_compute_expand (GtkWidget *widget, |
348 | gboolean *hexpand_p, |
349 | gboolean *vexpand_p) |
350 | { |
351 | GtkWidget *w; |
352 | gboolean hexpand = FALSE; |
353 | gboolean vexpand = FALSE; |
354 | |
355 | for (w = gtk_widget_get_first_child (widget); |
356 | w != NULL; |
357 | w = gtk_widget_get_next_sibling (widget: w)) |
358 | { |
359 | hexpand = hexpand || gtk_widget_compute_expand (widget: w, orientation: GTK_ORIENTATION_HORIZONTAL); |
360 | vexpand = vexpand || gtk_widget_compute_expand (widget: w, orientation: GTK_ORIENTATION_VERTICAL); |
361 | } |
362 | |
363 | *hexpand_p = hexpand; |
364 | *vexpand_p = vexpand; |
365 | } |
366 | |
367 | static GtkSizeRequestMode |
368 | gtk_grid_get_request_mode (GtkWidget *widget) |
369 | { |
370 | GtkWidget *w; |
371 | int wfh = 0, hfw = 0; |
372 | |
373 | for (w = gtk_widget_get_first_child (widget); |
374 | w != NULL; |
375 | w = gtk_widget_get_next_sibling (widget: w)) |
376 | { |
377 | GtkSizeRequestMode mode = gtk_widget_get_request_mode (widget: w); |
378 | |
379 | switch (mode) |
380 | { |
381 | case GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH: |
382 | hfw ++; |
383 | break; |
384 | case GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT: |
385 | wfh ++; |
386 | break; |
387 | case GTK_SIZE_REQUEST_CONSTANT_SIZE: |
388 | default: |
389 | break; |
390 | } |
391 | } |
392 | |
393 | if (hfw == 0 && wfh == 0) |
394 | return GTK_SIZE_REQUEST_CONSTANT_SIZE; |
395 | else |
396 | return wfh > hfw ? |
397 | GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT : |
398 | GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; |
399 | } |
400 | |
401 | static void |
402 | gtk_grid_dispose (GObject *object) |
403 | { |
404 | GtkWidget *child; |
405 | |
406 | while ((child = gtk_widget_get_first_child (GTK_WIDGET (object)))) |
407 | gtk_grid_remove (GTK_GRID (object), child); |
408 | |
409 | G_OBJECT_CLASS (gtk_grid_parent_class)->dispose (object); |
410 | } |
411 | |
412 | static void |
413 | gtk_grid_class_init (GtkGridClass *class) |
414 | { |
415 | GObjectClass *object_class = G_OBJECT_CLASS (class); |
416 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); |
417 | |
418 | object_class->dispose = gtk_grid_dispose; |
419 | object_class->get_property = gtk_grid_get_property; |
420 | object_class->set_property = gtk_grid_set_property; |
421 | |
422 | widget_class->compute_expand = gtk_grid_compute_expand; |
423 | widget_class->get_request_mode = gtk_grid_get_request_mode; |
424 | |
425 | g_object_class_override_property (oclass: object_class, property_id: PROP_ORIENTATION, name: "orientation" ); |
426 | |
427 | /** |
428 | * GtkGrid:row-spacing: (attributes org.gtk.Property.get=gtk_grid_get_row_spacing org.gtk.Property.set=gtk_grid_set_row_spacing) |
429 | * |
430 | * The amount of space between two consecutive rows. |
431 | */ |
432 | obj_properties[PROP_ROW_SPACING] = |
433 | g_param_spec_int (name: "row-spacing" , |
434 | P_("Row spacing" ), |
435 | P_("The amount of space between two consecutive rows" ), |
436 | minimum: 0, G_MAXINT16, default_value: 0, |
437 | GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); |
438 | |
439 | /** |
440 | * GtkGrid:column-spacing: (attributes org.gtk.Property.get=gtk_grid_get_column_spacing org.gtk.Property.set=gtk_grid_set_column_spacing) |
441 | * |
442 | * The amount of space between two consecutive columns. |
443 | */ |
444 | obj_properties[PROP_COLUMN_SPACING] = |
445 | g_param_spec_int (name: "column-spacing" , |
446 | P_("Column spacing" ), |
447 | P_("The amount of space between two consecutive columns" ), |
448 | minimum: 0, G_MAXINT16, default_value: 0, |
449 | GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); |
450 | |
451 | /** |
452 | * GtkGrid:row-homogeneous: (attributes org.gtk.Property.get=gtk_grid_get_row_homogeneous org.gtk.Property.set=gtk_grid_set_row_homogeneous) |
453 | * |
454 | * If %TRUE, the rows are all the same height. |
455 | */ |
456 | obj_properties[PROP_ROW_HOMOGENEOUS] = |
457 | g_param_spec_boolean (name: "row-homogeneous" , |
458 | P_("Row Homogeneous" ), |
459 | P_("If TRUE, the rows are all the same height" ), |
460 | FALSE, |
461 | GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); |
462 | |
463 | /** |
464 | * GtkGrid:column-homogeneous: (attributes org.gtk.Property.get=gtk_grid_get_column_homogeneous org.gtk.Property.set=gtk_grid_set_column_homogeneous) |
465 | * |
466 | * If %TRUE, the columns are all the same width. |
467 | */ |
468 | obj_properties[PROP_COLUMN_HOMOGENEOUS] = |
469 | g_param_spec_boolean (name: "column-homogeneous" , |
470 | P_("Column Homogeneous" ), |
471 | P_("If TRUE, the columns are all the same width" ), |
472 | FALSE, |
473 | GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); |
474 | |
475 | /** |
476 | * GtkGrid:baseline-row: (attributes org.gtk.Property.get=gtk_grid_get_baseline_row org.gtk.Property.set=gtk_grid_set_baseline_row) |
477 | * |
478 | * The row to align to the baseline when valign is %GTK_ALIGN_BASELINE. |
479 | */ |
480 | obj_properties[PROP_BASELINE_ROW] = |
481 | g_param_spec_int (name: "baseline-row" , |
482 | P_("Baseline Row" ), |
483 | P_("The row to align the to the baseline when valign is GTK_ALIGN_BASELINE" ), |
484 | minimum: 0, G_MAXINT, default_value: 0, |
485 | GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); |
486 | |
487 | g_object_class_install_properties (oclass: object_class, n_pspecs: N_PROPERTIES, pspecs: obj_properties); |
488 | |
489 | gtk_widget_class_set_css_name (widget_class, I_("grid" )); |
490 | gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_GRID_LAYOUT); |
491 | gtk_widget_class_set_accessible_role (widget_class, accessible_role: GTK_ACCESSIBLE_ROLE_GROUP); |
492 | } |
493 | |
494 | static GtkBuildableIface *parent_buildable_iface; |
495 | |
496 | static void |
497 | gtk_grid_buildable_add_child (GtkBuildable *buildable, |
498 | GtkBuilder *builder, |
499 | GObject *child, |
500 | const char *type) |
501 | { |
502 | if (GTK_IS_WIDGET (child)) |
503 | { |
504 | GtkGrid *grid = GTK_GRID ( buildable); |
505 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
506 | int pos[2] = { 0, 0 }; |
507 | |
508 | pos[priv->orientation] = find_attach_position (grid, orientation: priv->orientation, op_pos: 0, op_span: 1, TRUE); |
509 | grid_attach (grid, GTK_WIDGET (child), column: pos[0], row: pos[1], width: 1, height: 1); |
510 | } |
511 | else |
512 | parent_buildable_iface->add_child (buildable, builder, child, type); |
513 | } |
514 | |
515 | static void |
516 | gtk_grid_buildable_iface_init (GtkBuildableIface *iface) |
517 | { |
518 | parent_buildable_iface = g_type_interface_peek_parent (g_iface: iface); |
519 | |
520 | iface->add_child = gtk_grid_buildable_add_child; |
521 | } |
522 | |
523 | static void |
524 | gtk_grid_init (GtkGrid *grid) |
525 | { |
526 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
527 | |
528 | priv->layout_manager = gtk_widget_get_layout_manager (GTK_WIDGET (grid)); |
529 | |
530 | priv->orientation = GTK_ORIENTATION_HORIZONTAL; |
531 | gtk_widget_update_orientation (GTK_WIDGET (grid), orientation: priv->orientation); |
532 | } |
533 | |
534 | /** |
535 | * gtk_grid_new: |
536 | * |
537 | * Creates a new grid widget. |
538 | * |
539 | * Returns: the new `GtkGrid` |
540 | */ |
541 | GtkWidget * |
542 | gtk_grid_new (void) |
543 | { |
544 | return g_object_new (GTK_TYPE_GRID, NULL); |
545 | } |
546 | |
547 | /** |
548 | * gtk_grid_attach: |
549 | * @grid: a `GtkGrid` |
550 | * @child: the widget to add |
551 | * @column: the column number to attach the left side of @child to |
552 | * @row: the row number to attach the top side of @child to |
553 | * @width: the number of columns that @child will span |
554 | * @height: the number of rows that @child will span |
555 | * |
556 | * Adds a widget to the grid. |
557 | * |
558 | * The position of @child is determined by @column and @row. |
559 | * The number of “cells” that @child will occupy is determined |
560 | * by @width and @height. |
561 | */ |
562 | void |
563 | gtk_grid_attach (GtkGrid *grid, |
564 | GtkWidget *child, |
565 | int column, |
566 | int row, |
567 | int width, |
568 | int height) |
569 | { |
570 | g_return_if_fail (GTK_IS_GRID (grid)); |
571 | g_return_if_fail (GTK_IS_WIDGET (child)); |
572 | g_return_if_fail (_gtk_widget_get_parent (child) == NULL); |
573 | g_return_if_fail (width > 0); |
574 | g_return_if_fail (height > 0); |
575 | |
576 | grid_attach (grid, widget: child, column, row, width, height); |
577 | } |
578 | |
579 | /** |
580 | * gtk_grid_attach_next_to: |
581 | * @grid: a `GtkGrid` |
582 | * @child: the widget to add |
583 | * @sibling: (nullable): the child of @grid that @child will be placed |
584 | * next to, or %NULL to place @child at the beginning or end |
585 | * @side: the side of @sibling that @child is positioned next to |
586 | * @width: the number of columns that @child will span |
587 | * @height: the number of rows that @child will span |
588 | * |
589 | * Adds a widget to the grid. |
590 | * |
591 | * The widget is placed next to @sibling, on the side determined by |
592 | * @side. When @sibling is %NULL, the widget is placed in row (for |
593 | * left or right placement) or column 0 (for top or bottom placement), |
594 | * at the end indicated by @side. |
595 | * |
596 | * Attaching widgets labeled `[1]`, `[2]`, `[3]` with `@sibling == %NULL` and |
597 | * `@side == %GTK_POS_LEFT` yields a layout of `[3][2][1]`. |
598 | */ |
599 | void |
600 | gtk_grid_attach_next_to (GtkGrid *grid, |
601 | GtkWidget *child, |
602 | GtkWidget *sibling, |
603 | GtkPositionType side, |
604 | int width, |
605 | int height) |
606 | { |
607 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
608 | GtkGridLayoutChild *grid_sibling; |
609 | int left, top; |
610 | |
611 | g_return_if_fail (GTK_IS_GRID (grid)); |
612 | g_return_if_fail (GTK_IS_WIDGET (child)); |
613 | g_return_if_fail (_gtk_widget_get_parent (child) == NULL); |
614 | g_return_if_fail (sibling == NULL || _gtk_widget_get_parent (sibling) == (GtkWidget*)grid); |
615 | g_return_if_fail (width > 0); |
616 | g_return_if_fail (height > 0); |
617 | |
618 | if (sibling != NULL) |
619 | { |
620 | grid_sibling = GTK_GRID_LAYOUT_CHILD (ptr: gtk_layout_manager_get_layout_child (manager: priv->layout_manager, child: sibling)); |
621 | |
622 | switch (side) |
623 | { |
624 | case GTK_POS_LEFT: |
625 | left = gtk_grid_layout_child_get_column (child: grid_sibling) - width; |
626 | top = gtk_grid_layout_child_get_row (child: grid_sibling); |
627 | break; |
628 | case GTK_POS_RIGHT: |
629 | left = gtk_grid_layout_child_get_column (child: grid_sibling) + |
630 | gtk_grid_layout_child_get_column_span (child: grid_sibling); |
631 | top = gtk_grid_layout_child_get_row (child: grid_sibling); |
632 | break; |
633 | case GTK_POS_TOP: |
634 | left = gtk_grid_layout_child_get_column (child: grid_sibling); |
635 | top = gtk_grid_layout_child_get_row (child: grid_sibling) - height; |
636 | break; |
637 | case GTK_POS_BOTTOM: |
638 | left = gtk_grid_layout_child_get_column (child: grid_sibling); |
639 | top = gtk_grid_layout_child_get_row (child: grid_sibling) + |
640 | gtk_grid_layout_child_get_row_span (child: grid_sibling); |
641 | break; |
642 | default: |
643 | g_assert_not_reached (); |
644 | } |
645 | } |
646 | else |
647 | { |
648 | switch (side) |
649 | { |
650 | case GTK_POS_LEFT: |
651 | left = find_attach_position (grid, orientation: GTK_ORIENTATION_HORIZONTAL, op_pos: 0, op_span: height, FALSE); |
652 | left -= width; |
653 | top = 0; |
654 | break; |
655 | case GTK_POS_RIGHT: |
656 | left = find_attach_position (grid, orientation: GTK_ORIENTATION_HORIZONTAL, op_pos: 0, op_span: height, TRUE); |
657 | top = 0; |
658 | break; |
659 | case GTK_POS_TOP: |
660 | left = 0; |
661 | top = find_attach_position (grid, orientation: GTK_ORIENTATION_VERTICAL, op_pos: 0, op_span: width, FALSE); |
662 | top -= height; |
663 | break; |
664 | case GTK_POS_BOTTOM: |
665 | left = 0; |
666 | top = find_attach_position (grid, orientation: GTK_ORIENTATION_VERTICAL, op_pos: 0, op_span: width, TRUE); |
667 | break; |
668 | default: |
669 | g_assert_not_reached (); |
670 | } |
671 | } |
672 | |
673 | grid_attach (grid, widget: child, column: left, row: top, width, height); |
674 | } |
675 | |
676 | /** |
677 | * gtk_grid_get_child_at: |
678 | * @grid: a `GtkGrid` |
679 | * @column: the left edge of the cell |
680 | * @row: the top edge of the cell |
681 | * |
682 | * Gets the child of @grid whose area covers the grid |
683 | * cell at @column, @row. |
684 | * |
685 | * Returns: (transfer none) (nullable): the child at the given position |
686 | */ |
687 | GtkWidget * |
688 | gtk_grid_get_child_at (GtkGrid *grid, |
689 | int column, |
690 | int row) |
691 | { |
692 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
693 | GtkWidget *child; |
694 | |
695 | g_return_val_if_fail (GTK_IS_GRID (grid), NULL); |
696 | |
697 | for (child = gtk_widget_get_first_child (GTK_WIDGET (grid)); |
698 | child != NULL; |
699 | child = gtk_widget_get_next_sibling (widget: child)) |
700 | { |
701 | GtkGridLayoutChild *grid_child; |
702 | int child_column, child_row, child_width, child_height; |
703 | |
704 | grid_child = GTK_GRID_LAYOUT_CHILD (ptr: gtk_layout_manager_get_layout_child (manager: priv->layout_manager, child)); |
705 | child_column = gtk_grid_layout_child_get_column (child: grid_child); |
706 | child_row = gtk_grid_layout_child_get_row (child: grid_child); |
707 | child_width = gtk_grid_layout_child_get_column_span (child: grid_child); |
708 | child_height = gtk_grid_layout_child_get_row_span (child: grid_child); |
709 | |
710 | if (child_column <= column && child_column + child_width > column && |
711 | child_row <= row && child_row + child_height > row) |
712 | return child; |
713 | } |
714 | |
715 | return NULL; |
716 | } |
717 | |
718 | /** |
719 | * gtk_grid_remove: |
720 | * @grid: a `GtkGrid` |
721 | * @child: the child widget to remove |
722 | * |
723 | * Removes a child from @grid. |
724 | * |
725 | * The child must have been added with |
726 | * [method@Gtk.Grid.attach] or [method@Gtk.Grid.attach_next_to]. |
727 | */ |
728 | void |
729 | gtk_grid_remove (GtkGrid *grid, |
730 | GtkWidget *child) |
731 | { |
732 | g_return_if_fail (GTK_IS_GRID (grid)); |
733 | g_return_if_fail (GTK_IS_WIDGET (child)); |
734 | g_return_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (grid)); |
735 | |
736 | gtk_widget_unparent (widget: child); |
737 | } |
738 | |
739 | /** |
740 | * gtk_grid_insert_row: |
741 | * @grid: a `GtkGrid` |
742 | * @position: the position to insert the row at |
743 | * |
744 | * Inserts a row at the specified position. |
745 | * |
746 | * Children which are attached at or below this position |
747 | * are moved one row down. Children which span across this |
748 | * position are grown to span the new row. |
749 | */ |
750 | void |
751 | gtk_grid_insert_row (GtkGrid *grid, |
752 | int position) |
753 | { |
754 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
755 | GtkWidget *child; |
756 | int top, height; |
757 | |
758 | g_return_if_fail (GTK_IS_GRID (grid)); |
759 | |
760 | for (child = gtk_widget_get_first_child (GTK_WIDGET (grid)); |
761 | child != NULL; |
762 | child = gtk_widget_get_next_sibling (widget: child)) |
763 | { |
764 | GtkGridLayoutChild *grid_child; |
765 | |
766 | grid_child = GTK_GRID_LAYOUT_CHILD (ptr: gtk_layout_manager_get_layout_child (manager: priv->layout_manager, child)); |
767 | top = gtk_grid_layout_child_get_row (child: grid_child); |
768 | height = gtk_grid_layout_child_get_row_span (child: grid_child); |
769 | |
770 | if (top >= position) |
771 | gtk_grid_layout_child_set_row (child: grid_child, row: top + 1); |
772 | else if (top + height > position) |
773 | gtk_grid_layout_child_set_row_span (child: grid_child, span: height + 1); |
774 | } |
775 | } |
776 | |
777 | /** |
778 | * gtk_grid_remove_row: |
779 | * @grid: a `GtkGrid` |
780 | * @position: the position of the row to remove |
781 | * |
782 | * Removes a row from the grid. |
783 | * |
784 | * Children that are placed in this row are removed, |
785 | * spanning children that overlap this row have their |
786 | * height reduced by one, and children below the row |
787 | * are moved up. |
788 | */ |
789 | void |
790 | gtk_grid_remove_row (GtkGrid *grid, |
791 | int position) |
792 | { |
793 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
794 | GtkWidget *child; |
795 | |
796 | g_return_if_fail (GTK_IS_GRID (grid)); |
797 | |
798 | child = gtk_widget_get_first_child (GTK_WIDGET (grid)); |
799 | while (child) |
800 | { |
801 | GtkWidget *next = gtk_widget_get_next_sibling (widget: child); |
802 | GtkGridLayoutChild *grid_child; |
803 | int top, height; |
804 | |
805 | grid_child = GTK_GRID_LAYOUT_CHILD (ptr: gtk_layout_manager_get_layout_child (manager: priv->layout_manager, child)); |
806 | top = gtk_grid_layout_child_get_row (child: grid_child); |
807 | height = gtk_grid_layout_child_get_row_span (child: grid_child); |
808 | |
809 | if (top <= position && top + height > position) |
810 | height--; |
811 | if (top > position) |
812 | top--; |
813 | |
814 | if (height <= 0) |
815 | { |
816 | gtk_grid_remove (grid, child); |
817 | } |
818 | else |
819 | { |
820 | gtk_grid_layout_child_set_row_span (child: grid_child, span: height); |
821 | gtk_grid_layout_child_set_row (child: grid_child, row: top); |
822 | } |
823 | |
824 | child = next; |
825 | } |
826 | } |
827 | |
828 | /** |
829 | * gtk_grid_insert_column: |
830 | * @grid: a `GtkGrid` |
831 | * @position: the position to insert the column at |
832 | * |
833 | * Inserts a column at the specified position. |
834 | * |
835 | * Children which are attached at or to the right of this position |
836 | * are moved one column to the right. Children which span across this |
837 | * position are grown to span the new column. |
838 | */ |
839 | void |
840 | gtk_grid_insert_column (GtkGrid *grid, |
841 | int position) |
842 | { |
843 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
844 | GtkWidget *child; |
845 | |
846 | g_return_if_fail (GTK_IS_GRID (grid)); |
847 | |
848 | for (child = gtk_widget_get_first_child (GTK_WIDGET (grid)); |
849 | child != NULL; |
850 | child = gtk_widget_get_next_sibling (widget: child)) |
851 | { |
852 | GtkGridLayoutChild *grid_child; |
853 | int left, width; |
854 | |
855 | grid_child = GTK_GRID_LAYOUT_CHILD (ptr: gtk_layout_manager_get_layout_child (manager: priv->layout_manager, child)); |
856 | left = gtk_grid_layout_child_get_column (child: grid_child); |
857 | width = gtk_grid_layout_child_get_column_span (child: grid_child); |
858 | |
859 | if (left >= position) |
860 | gtk_grid_layout_child_set_column (child: grid_child, column: left + 1); |
861 | else if (left + width > position) |
862 | gtk_grid_layout_child_set_column_span (child: grid_child, span: width + 1); |
863 | } |
864 | } |
865 | |
866 | /** |
867 | * gtk_grid_remove_column: |
868 | * @grid: a `GtkGrid` |
869 | * @position: the position of the column to remove |
870 | * |
871 | * Removes a column from the grid. |
872 | * |
873 | * Children that are placed in this column are removed, |
874 | * spanning children that overlap this column have their |
875 | * width reduced by one, and children after the column |
876 | * are moved to the left. |
877 | */ |
878 | void |
879 | gtk_grid_remove_column (GtkGrid *grid, |
880 | int position) |
881 | { |
882 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
883 | GtkWidget *child; |
884 | |
885 | g_return_if_fail (GTK_IS_GRID (grid)); |
886 | |
887 | child = gtk_widget_get_first_child (GTK_WIDGET (grid)); |
888 | while (child) |
889 | { |
890 | GtkWidget *next = gtk_widget_get_next_sibling (widget: child); |
891 | GtkGridLayoutChild *grid_child; |
892 | int left, width; |
893 | |
894 | grid_child = GTK_GRID_LAYOUT_CHILD (ptr: gtk_layout_manager_get_layout_child (manager: priv->layout_manager, child)); |
895 | |
896 | left = gtk_grid_layout_child_get_column (child: grid_child); |
897 | width = gtk_grid_layout_child_get_column_span (child: grid_child); |
898 | |
899 | if (left <= position && left + width > position) |
900 | width--; |
901 | if (left > position) |
902 | left--; |
903 | |
904 | if (width <= 0) |
905 | { |
906 | gtk_grid_remove (grid, child); |
907 | } |
908 | else |
909 | { |
910 | gtk_grid_layout_child_set_column_span (child: grid_child, span: width); |
911 | gtk_grid_layout_child_set_column (child: grid_child, column: left); |
912 | } |
913 | |
914 | child = next; |
915 | } |
916 | } |
917 | |
918 | /** |
919 | * gtk_grid_insert_next_to: |
920 | * @grid: a `GtkGrid` |
921 | * @sibling: the child of @grid that the new row or column will be |
922 | * placed next to |
923 | * @side: the side of @sibling that @child is positioned next to |
924 | * |
925 | * Inserts a row or column at the specified position. |
926 | * |
927 | * The new row or column is placed next to @sibling, on the side |
928 | * determined by @side. If @side is %GTK_POS_TOP or %GTK_POS_BOTTOM, |
929 | * a row is inserted. If @side is %GTK_POS_LEFT of %GTK_POS_RIGHT, |
930 | * a column is inserted. |
931 | */ |
932 | void |
933 | gtk_grid_insert_next_to (GtkGrid *grid, |
934 | GtkWidget *sibling, |
935 | GtkPositionType side) |
936 | { |
937 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
938 | GtkGridLayoutChild *child; |
939 | |
940 | g_return_if_fail (GTK_IS_GRID (grid)); |
941 | g_return_if_fail (GTK_IS_WIDGET (sibling)); |
942 | g_return_if_fail (_gtk_widget_get_parent (sibling) == (GtkWidget*)grid); |
943 | |
944 | child = GTK_GRID_LAYOUT_CHILD (ptr: gtk_layout_manager_get_layout_child (manager: priv->layout_manager, child: sibling)); |
945 | |
946 | switch (side) |
947 | { |
948 | case GTK_POS_LEFT: |
949 | gtk_grid_insert_column (grid, position: gtk_grid_layout_child_get_column (child)); |
950 | break; |
951 | case GTK_POS_RIGHT: |
952 | { |
953 | int col = gtk_grid_layout_child_get_column (child) + |
954 | gtk_grid_layout_child_get_column_span (child); |
955 | gtk_grid_insert_column (grid, position: col); |
956 | } |
957 | break; |
958 | case GTK_POS_TOP: |
959 | gtk_grid_insert_row (grid, position: gtk_grid_layout_child_get_row (child)); |
960 | break; |
961 | case GTK_POS_BOTTOM: |
962 | { |
963 | int row = gtk_grid_layout_child_get_row (child) + |
964 | gtk_grid_layout_child_get_row_span (child); |
965 | gtk_grid_insert_row (grid, position: row); |
966 | } |
967 | break; |
968 | default: |
969 | g_assert_not_reached (); |
970 | } |
971 | } |
972 | |
973 | /** |
974 | * gtk_grid_set_row_homogeneous: (attributes org.gtk.Method.set_property=row-homogeneous) |
975 | * @grid: a `GtkGrid` |
976 | * @homogeneous: %TRUE to make rows homogeneous |
977 | * |
978 | * Sets whether all rows of @grid will have the same height. |
979 | */ |
980 | void |
981 | gtk_grid_set_row_homogeneous (GtkGrid *grid, |
982 | gboolean homogeneous) |
983 | { |
984 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
985 | gboolean old_val; |
986 | |
987 | g_return_if_fail (GTK_IS_GRID (grid)); |
988 | |
989 | old_val = gtk_grid_layout_get_row_homogeneous (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager)); |
990 | if (old_val != !!homogeneous) |
991 | { |
992 | gtk_grid_layout_set_row_homogeneous (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager), homogeneous); |
993 | g_object_notify_by_pspec (G_OBJECT (grid), pspec: obj_properties [PROP_ROW_HOMOGENEOUS]); |
994 | } |
995 | } |
996 | |
997 | /** |
998 | * gtk_grid_get_row_homogeneous: (attributes org.gtk.Method.get_property=row-homogeneous) |
999 | * @grid: a `GtkGrid` |
1000 | * |
1001 | * Returns whether all rows of @grid have the same height. |
1002 | * |
1003 | * Returns: whether all rows of @grid have the same height. |
1004 | */ |
1005 | gboolean |
1006 | gtk_grid_get_row_homogeneous (GtkGrid *grid) |
1007 | { |
1008 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
1009 | |
1010 | g_return_val_if_fail (GTK_IS_GRID (grid), FALSE); |
1011 | |
1012 | return gtk_grid_layout_get_row_homogeneous (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager)); |
1013 | } |
1014 | |
1015 | /** |
1016 | * gtk_grid_set_column_homogeneous: (attributes org.gtk.Method.set_property=column-homogeneous) |
1017 | * @grid: a `GtkGrid` |
1018 | * @homogeneous: %TRUE to make columns homogeneous |
1019 | * |
1020 | * Sets whether all columns of @grid will have the same width. |
1021 | */ |
1022 | void |
1023 | gtk_grid_set_column_homogeneous (GtkGrid *grid, |
1024 | gboolean homogeneous) |
1025 | { |
1026 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
1027 | gboolean old_val; |
1028 | |
1029 | g_return_if_fail (GTK_IS_GRID (grid)); |
1030 | |
1031 | old_val = gtk_grid_layout_get_column_homogeneous (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager)); |
1032 | if (old_val != !!homogeneous) |
1033 | { |
1034 | gtk_grid_layout_set_column_homogeneous (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager), homogeneous); |
1035 | g_object_notify_by_pspec (G_OBJECT (grid), pspec: obj_properties [PROP_COLUMN_HOMOGENEOUS]); |
1036 | } |
1037 | } |
1038 | |
1039 | /** |
1040 | * gtk_grid_get_column_homogeneous: (attributes org.gtk.Method.get_property=column-homogeneous) |
1041 | * @grid: a `GtkGrid` |
1042 | * |
1043 | * Returns whether all columns of @grid have the same width. |
1044 | * |
1045 | * Returns: whether all columns of @grid have the same width. |
1046 | */ |
1047 | gboolean |
1048 | gtk_grid_get_column_homogeneous (GtkGrid *grid) |
1049 | { |
1050 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
1051 | |
1052 | g_return_val_if_fail (GTK_IS_GRID (grid), FALSE); |
1053 | |
1054 | return gtk_grid_layout_get_column_homogeneous (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager)); |
1055 | } |
1056 | |
1057 | /** |
1058 | * gtk_grid_set_row_spacing: (attributes org.gtk.Method.set_property=row-spacing) |
1059 | * @grid: a `GtkGrid` |
1060 | * @spacing: the amount of space to insert between rows |
1061 | * |
1062 | * Sets the amount of space between rows of @grid. |
1063 | */ |
1064 | void |
1065 | gtk_grid_set_row_spacing (GtkGrid *grid, |
1066 | guint spacing) |
1067 | { |
1068 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
1069 | guint old_spacing; |
1070 | |
1071 | g_return_if_fail (GTK_IS_GRID (grid)); |
1072 | g_return_if_fail (spacing <= G_MAXINT16); |
1073 | |
1074 | old_spacing = gtk_grid_layout_get_row_spacing (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager)); |
1075 | if (old_spacing != spacing) |
1076 | { |
1077 | gtk_grid_layout_set_row_spacing (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager), spacing); |
1078 | g_object_notify_by_pspec (G_OBJECT (grid), pspec: obj_properties [PROP_ROW_SPACING]); |
1079 | } |
1080 | } |
1081 | |
1082 | /** |
1083 | * gtk_grid_get_row_spacing: (attributes org.gtk.Method.get_property=row-spacing) |
1084 | * @grid: a `GtkGrid` |
1085 | * |
1086 | * Returns the amount of space between the rows of @grid. |
1087 | * |
1088 | * Returns: the row spacing of @grid |
1089 | */ |
1090 | guint |
1091 | gtk_grid_get_row_spacing (GtkGrid *grid) |
1092 | { |
1093 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
1094 | |
1095 | g_return_val_if_fail (GTK_IS_GRID (grid), 0); |
1096 | |
1097 | return gtk_grid_layout_get_row_spacing (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager)); |
1098 | } |
1099 | |
1100 | /** |
1101 | * gtk_grid_set_column_spacing: (attributes org.gtk.Method.set_property=column-spacing) |
1102 | * @grid: a `GtkGrid` |
1103 | * @spacing: the amount of space to insert between columns |
1104 | * |
1105 | * Sets the amount of space between columns of @grid. |
1106 | */ |
1107 | void |
1108 | gtk_grid_set_column_spacing (GtkGrid *grid, |
1109 | guint spacing) |
1110 | { |
1111 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
1112 | guint old_spacing; |
1113 | |
1114 | g_return_if_fail (GTK_IS_GRID (grid)); |
1115 | g_return_if_fail (spacing <= G_MAXINT16); |
1116 | |
1117 | old_spacing = gtk_grid_layout_get_column_spacing (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager)); |
1118 | if (old_spacing != spacing) |
1119 | { |
1120 | gtk_grid_layout_set_column_spacing (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager), spacing); |
1121 | g_object_notify_by_pspec (G_OBJECT (grid), pspec: obj_properties [PROP_COLUMN_SPACING]); |
1122 | } |
1123 | } |
1124 | |
1125 | /** |
1126 | * gtk_grid_get_column_spacing: (attributes org.gtk.Method.get_property=column-spacing) |
1127 | * @grid: a `GtkGrid` |
1128 | * |
1129 | * Returns the amount of space between the columns of @grid. |
1130 | * |
1131 | * Returns: the column spacing of @grid |
1132 | */ |
1133 | guint |
1134 | gtk_grid_get_column_spacing (GtkGrid *grid) |
1135 | { |
1136 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
1137 | |
1138 | g_return_val_if_fail (GTK_IS_GRID (grid), 0); |
1139 | |
1140 | return gtk_grid_layout_get_column_spacing (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager)); |
1141 | } |
1142 | |
1143 | /** |
1144 | * gtk_grid_set_row_baseline_position: |
1145 | * @grid: a `GtkGrid` |
1146 | * @row: a row index |
1147 | * @pos: a `GtkBaselinePosition` |
1148 | * |
1149 | * Sets how the baseline should be positioned on @row of the |
1150 | * grid, in case that row is assigned more space than is requested. |
1151 | * |
1152 | * The default baseline position is %GTK_BASELINE_POSITION_CENTER. |
1153 | */ |
1154 | void |
1155 | gtk_grid_set_row_baseline_position (GtkGrid *grid, |
1156 | int row, |
1157 | GtkBaselinePosition pos) |
1158 | { |
1159 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
1160 | |
1161 | g_return_if_fail (GTK_IS_GRID (grid)); |
1162 | |
1163 | gtk_grid_layout_set_row_baseline_position (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager), |
1164 | row, |
1165 | pos); |
1166 | } |
1167 | |
1168 | /** |
1169 | * gtk_grid_get_row_baseline_position: |
1170 | * @grid: a `GtkGrid` |
1171 | * @row: a row index |
1172 | * |
1173 | * Returns the baseline position of @row. |
1174 | * |
1175 | * See [method@Gtk.Grid.set_row_baseline_position]. |
1176 | * |
1177 | * Returns: the baseline position of @row |
1178 | */ |
1179 | GtkBaselinePosition |
1180 | gtk_grid_get_row_baseline_position (GtkGrid *grid, |
1181 | int row) |
1182 | { |
1183 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
1184 | |
1185 | g_return_val_if_fail (GTK_IS_GRID (grid), GTK_BASELINE_POSITION_CENTER); |
1186 | |
1187 | return gtk_grid_layout_get_row_baseline_position (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager), row); |
1188 | } |
1189 | |
1190 | /** |
1191 | * gtk_grid_set_baseline_row: (attributes org.gtk.Method.set_property=baseline-row) |
1192 | * @grid: a `GtkGrid` |
1193 | * @row: the row index |
1194 | * |
1195 | * Sets which row defines the global baseline for the entire grid. |
1196 | * |
1197 | * Each row in the grid can have its own local baseline, but only |
1198 | * one of those is global, meaning it will be the baseline in the |
1199 | * parent of the @grid. |
1200 | */ |
1201 | void |
1202 | gtk_grid_set_baseline_row (GtkGrid *grid, |
1203 | int row) |
1204 | { |
1205 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
1206 | int old_row; |
1207 | |
1208 | g_return_if_fail (GTK_IS_GRID (grid)); |
1209 | |
1210 | old_row = gtk_grid_layout_get_baseline_row (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager)); |
1211 | if (old_row != row) |
1212 | { |
1213 | gtk_grid_layout_set_baseline_row (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager), row); |
1214 | g_object_notify (G_OBJECT (grid), property_name: "baseline-row" ); |
1215 | } |
1216 | } |
1217 | |
1218 | /** |
1219 | * gtk_grid_get_baseline_row: (attributes org.gtk.Method.get_property=baseline-row) |
1220 | * @grid: a `GtkGrid` |
1221 | * |
1222 | * Returns which row defines the global baseline of @grid. |
1223 | * |
1224 | * Returns: the row index defining the global baseline |
1225 | */ |
1226 | int |
1227 | gtk_grid_get_baseline_row (GtkGrid *grid) |
1228 | { |
1229 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
1230 | |
1231 | g_return_val_if_fail (GTK_IS_GRID (grid), 0); |
1232 | |
1233 | return gtk_grid_layout_get_baseline_row (grid: GTK_GRID_LAYOUT (ptr: priv->layout_manager)); |
1234 | } |
1235 | |
1236 | /** |
1237 | * gtk_grid_query_child: |
1238 | * @grid: a `GtkGrid` |
1239 | * @child: a `GtkWidget` child of @grid |
1240 | * @column: (out) (optional): the column used to attach the left side of @child |
1241 | * @row: (out) (optional): the row used to attach the top side of @child |
1242 | * @width: (out) (optional): the number of columns @child spans |
1243 | * @height: (out) (optional): the number of rows @child spans |
1244 | * |
1245 | * Queries the attach points and spans of @child inside the given `GtkGrid`. |
1246 | */ |
1247 | void |
1248 | gtk_grid_query_child (GtkGrid *grid, |
1249 | GtkWidget *child, |
1250 | int *column, |
1251 | int *row, |
1252 | int *width, |
1253 | int *height) |
1254 | { |
1255 | GtkGridPrivate *priv = gtk_grid_get_instance_private (self: grid); |
1256 | GtkGridLayoutChild *grid_child; |
1257 | |
1258 | g_return_if_fail (GTK_IS_GRID (grid)); |
1259 | g_return_if_fail (GTK_IS_WIDGET (child)); |
1260 | g_return_if_fail (_gtk_widget_get_parent (child) == (GtkWidget *) grid); |
1261 | |
1262 | grid_child = GTK_GRID_LAYOUT_CHILD (ptr: gtk_layout_manager_get_layout_child (manager: priv->layout_manager, child)); |
1263 | |
1264 | if (column != NULL) |
1265 | *column = gtk_grid_layout_child_get_column (child: grid_child); |
1266 | if (row != NULL) |
1267 | *row = gtk_grid_layout_child_get_row (child: grid_child); |
1268 | if (width != NULL) |
1269 | *width = gtk_grid_layout_child_get_column_span (child: grid_child); |
1270 | if (height != NULL) |
1271 | *height = gtk_grid_layout_child_get_row_span (child: grid_child); |
1272 | } |
1273 | |