1 | /* GTK - The GIMP Toolkit |
2 | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
3 | * |
4 | * GtkAspectFrame: Ensure that the child window has a specified aspect ratio |
5 | * or, if obey_child, has the same aspect ratio as its requested size |
6 | * |
7 | * Copyright Owen Taylor 4/9/97 |
8 | * |
9 | * This library is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU Lesser General Public |
11 | * License as published by the Free Software Foundation; either |
12 | * version 2 of the License, or (at your option) any later version. |
13 | * |
14 | * This library is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | * Lesser General Public License for more details. |
18 | * |
19 | * You should have received a copy of the GNU Lesser General Public |
20 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
21 | */ |
22 | |
23 | /* |
24 | * Modified by the GTK+ Team and others 1997-2001. See the AUTHORS |
25 | * file for a list of people on the GTK+ Team. See the ChangeLog |
26 | * files for a list of changes. These files are distributed with |
27 | * GTK+ at ftp://ftp.gtk.org/pub/gtk/. |
28 | */ |
29 | |
30 | /** |
31 | * GtkAspectFrame: |
32 | * |
33 | * `GtkAspectFrame` preserves the aspect ratio of its child. |
34 | * |
35 | * The frame can respect the aspect ratio of the child widget, |
36 | * or use its own aspect ratio. |
37 | * |
38 | * # CSS nodes |
39 | * |
40 | * `GtkAspectFrame` uses a CSS node with name `frame`. |
41 | */ |
42 | |
43 | #include "config.h" |
44 | |
45 | #include "gtkaspectframe.h" |
46 | |
47 | #include "gtksizerequest.h" |
48 | |
49 | #include "gtkbuildable.h" |
50 | |
51 | #include "gtkwidgetprivate.h" |
52 | #include "gtkprivate.h" |
53 | #include "gtkintl.h" |
54 | |
55 | |
56 | typedef struct _GtkAspectFrameClass GtkAspectFrameClass; |
57 | |
58 | struct _GtkAspectFrame |
59 | { |
60 | GtkWidget parent_instance; |
61 | |
62 | GtkWidget *child; |
63 | gboolean obey_child; |
64 | float xalign; |
65 | float yalign; |
66 | float ratio; |
67 | }; |
68 | |
69 | struct _GtkAspectFrameClass |
70 | { |
71 | GtkWidgetClass parent_class; |
72 | }; |
73 | |
74 | enum { |
75 | PROP_0, |
76 | PROP_XALIGN, |
77 | PROP_YALIGN, |
78 | PROP_RATIO, |
79 | PROP_OBEY_CHILD, |
80 | PROP_CHILD |
81 | }; |
82 | |
83 | static void gtk_aspect_frame_dispose (GObject *object); |
84 | static void gtk_aspect_frame_set_property (GObject *object, |
85 | guint prop_id, |
86 | const GValue *value, |
87 | GParamSpec *pspec); |
88 | static void gtk_aspect_frame_get_property (GObject *object, |
89 | guint prop_id, |
90 | GValue *value, |
91 | GParamSpec *pspec); |
92 | static void gtk_aspect_frame_size_allocate (GtkWidget *widget, |
93 | int width, |
94 | int height, |
95 | int baseline); |
96 | static void gtk_aspect_frame_measure (GtkWidget *widget, |
97 | GtkOrientation orientation, |
98 | int for_size, |
99 | int *minimum, |
100 | int *natural, |
101 | int *minimum_baseline, |
102 | int *natural_baseline); |
103 | |
104 | static void gtk_aspect_frame_compute_expand (GtkWidget *widget, |
105 | gboolean *hexpand, |
106 | gboolean *vexpand); |
107 | static GtkSizeRequestMode |
108 | gtk_aspect_frame_get_request_mode (GtkWidget *widget); |
109 | |
110 | static void gtk_aspect_frame_buildable_init (GtkBuildableIface *iface); |
111 | |
112 | #define MAX_RATIO 10000.0 |
113 | #define MIN_RATIO 0.0001 |
114 | |
115 | |
116 | G_DEFINE_TYPE_WITH_CODE (GtkAspectFrame, gtk_aspect_frame, GTK_TYPE_WIDGET, |
117 | G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, |
118 | gtk_aspect_frame_buildable_init)) |
119 | |
120 | |
121 | static void |
122 | gtk_aspect_frame_class_init (GtkAspectFrameClass *class) |
123 | { |
124 | GObjectClass *gobject_class = G_OBJECT_CLASS (class); |
125 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); |
126 | |
127 | gobject_class->dispose = gtk_aspect_frame_dispose; |
128 | gobject_class->set_property = gtk_aspect_frame_set_property; |
129 | gobject_class->get_property = gtk_aspect_frame_get_property; |
130 | |
131 | widget_class->measure = gtk_aspect_frame_measure; |
132 | widget_class->size_allocate = gtk_aspect_frame_size_allocate; |
133 | widget_class->compute_expand = gtk_aspect_frame_compute_expand; |
134 | widget_class->get_request_mode = gtk_aspect_frame_get_request_mode; |
135 | |
136 | /** |
137 | * GtkAspectFrame:xalign: (attributes org.gtk.Property.get=gtk_aspect_frame_get_xalign org.gtk.Property.set=gtk_aspect_frame_set_xalign) |
138 | * |
139 | * The horizontal alignment of the child. |
140 | */ |
141 | g_object_class_install_property (oclass: gobject_class, |
142 | property_id: PROP_XALIGN, |
143 | pspec: g_param_spec_float (name: "xalign" , |
144 | P_("Horizontal Alignment" ), |
145 | P_("X alignment of the child" ), |
146 | minimum: 0.0, maximum: 1.0, default_value: 0.5, |
147 | GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); |
148 | /** |
149 | * GtkAspectFrame:yalign: (attributes org.gtk.Property.get=gtk_aspect_frame_get_yalign org.gtk.Property.set=gtk_aspect_frame_set_yalign) |
150 | * |
151 | * The vertical alignment of the child. |
152 | */ |
153 | g_object_class_install_property (oclass: gobject_class, |
154 | property_id: PROP_YALIGN, |
155 | pspec: g_param_spec_float (name: "yalign" , |
156 | P_("Vertical Alignment" ), |
157 | P_("Y alignment of the child" ), |
158 | minimum: 0.0, maximum: 1.0, default_value: 0.5, |
159 | GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); |
160 | /** |
161 | * GtkAspectFrame:ratio: (attributes org.gtk.Property.get=gtk_aspect_frame_get_ratio org.gtk.Property.set=gtk_aspect_frame_set_ratio) |
162 | * |
163 | * The aspect ratio to be used by the `GtkAspectFrame`. |
164 | * |
165 | * This property is only used if |
166 | * [property@Gtk.AspectFrame:obey-child] is set to %FALSE. |
167 | */ |
168 | g_object_class_install_property (oclass: gobject_class, |
169 | property_id: PROP_RATIO, |
170 | pspec: g_param_spec_float (name: "ratio" , |
171 | P_("Ratio" ), |
172 | P_("Aspect ratio if obey_child is FALSE" ), |
173 | MIN_RATIO, MAX_RATIO, default_value: 1.0, |
174 | GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); |
175 | /** |
176 | * GtkAspectFrame:obey-child: (attributes org.gtk.Property.get=gtk_aspect_frame_get_obey_child org.gtk.Property.set=gtk_aspect_frame_set_obey_child) |
177 | * |
178 | * Whether the `GtkAspectFrame` should use the aspect ratio of its child. |
179 | */ |
180 | g_object_class_install_property (oclass: gobject_class, |
181 | property_id: PROP_OBEY_CHILD, |
182 | pspec: g_param_spec_boolean (name: "obey-child" , |
183 | P_("Obey child" ), |
184 | P_("Force aspect ratio to match that of the frame’s child" ), |
185 | TRUE, |
186 | GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); |
187 | /** |
188 | * GtkAspectFrame:child: (attributes org.gtk.Property.get=gtk_aspect_frame_get_child org.gtk.Property.set=gtk_aspect_frame_set_child) |
189 | * |
190 | * The child widget. |
191 | */ |
192 | g_object_class_install_property (oclass: gobject_class, |
193 | property_id: PROP_CHILD, |
194 | pspec: g_param_spec_object (name: "child" , |
195 | P_("Child" ), |
196 | P_("The child widget" ), |
197 | GTK_TYPE_WIDGET, |
198 | GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); |
199 | |
200 | gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), I_("aspectframe" )); |
201 | gtk_widget_class_set_accessible_role (GTK_WIDGET_CLASS (class), accessible_role: GTK_ACCESSIBLE_ROLE_GROUP); |
202 | } |
203 | |
204 | static void |
205 | gtk_aspect_frame_init (GtkAspectFrame *self) |
206 | { |
207 | self->xalign = 0.5; |
208 | self->yalign = 0.5; |
209 | self->ratio = 1.0; |
210 | self->obey_child = TRUE; |
211 | } |
212 | |
213 | static void |
214 | gtk_aspect_frame_dispose (GObject *object) |
215 | { |
216 | GtkAspectFrame *self = GTK_ASPECT_FRAME (object); |
217 | |
218 | g_clear_pointer (&self->child, gtk_widget_unparent); |
219 | |
220 | G_OBJECT_CLASS (gtk_aspect_frame_parent_class)->dispose (object); |
221 | } |
222 | |
223 | static void |
224 | gtk_aspect_frame_set_property (GObject *object, |
225 | guint prop_id, |
226 | const GValue *value, |
227 | GParamSpec *pspec) |
228 | { |
229 | GtkAspectFrame *self = GTK_ASPECT_FRAME (object); |
230 | |
231 | switch (prop_id) |
232 | { |
233 | /* g_object_notify is handled by the _frame_set function */ |
234 | case PROP_XALIGN: |
235 | gtk_aspect_frame_set_xalign (self, xalign: g_value_get_float (value)); |
236 | break; |
237 | case PROP_YALIGN: |
238 | gtk_aspect_frame_set_yalign (self, yalign: g_value_get_float (value)); |
239 | break; |
240 | case PROP_RATIO: |
241 | gtk_aspect_frame_set_ratio (self, ratio: g_value_get_float (value)); |
242 | break; |
243 | case PROP_OBEY_CHILD: |
244 | gtk_aspect_frame_set_obey_child (self, obey_child: g_value_get_boolean (value)); |
245 | break; |
246 | case PROP_CHILD: |
247 | gtk_aspect_frame_set_child (self, child: g_value_get_object (value)); |
248 | break; |
249 | default: |
250 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
251 | break; |
252 | } |
253 | } |
254 | |
255 | static void |
256 | gtk_aspect_frame_get_property (GObject *object, |
257 | guint prop_id, |
258 | GValue *value, |
259 | GParamSpec *pspec) |
260 | { |
261 | GtkAspectFrame *self = GTK_ASPECT_FRAME (object); |
262 | |
263 | switch (prop_id) |
264 | { |
265 | case PROP_XALIGN: |
266 | g_value_set_float (value, v_float: self->xalign); |
267 | break; |
268 | case PROP_YALIGN: |
269 | g_value_set_float (value, v_float: self->yalign); |
270 | break; |
271 | case PROP_RATIO: |
272 | g_value_set_float (value, v_float: self->ratio); |
273 | break; |
274 | case PROP_OBEY_CHILD: |
275 | g_value_set_boolean (value, v_boolean: self->obey_child); |
276 | break; |
277 | case PROP_CHILD: |
278 | g_value_set_object (value, v_object: gtk_aspect_frame_get_child (self)); |
279 | break; |
280 | default: |
281 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
282 | break; |
283 | } |
284 | } |
285 | |
286 | static GtkBuildableIface *parent_buildable_iface; |
287 | |
288 | static void |
289 | gtk_aspect_frame_buildable_add_child (GtkBuildable *buildable, |
290 | GtkBuilder *builder, |
291 | GObject *child, |
292 | const char *type) |
293 | { |
294 | if (GTK_IS_WIDGET (child)) |
295 | gtk_aspect_frame_set_child (GTK_ASPECT_FRAME (buildable), GTK_WIDGET (child)); |
296 | else |
297 | parent_buildable_iface->add_child (buildable, builder, child, type); |
298 | } |
299 | |
300 | static void |
301 | gtk_aspect_frame_buildable_init (GtkBuildableIface *iface) |
302 | { |
303 | parent_buildable_iface = g_type_interface_peek_parent (g_iface: iface); |
304 | |
305 | iface->add_child = gtk_aspect_frame_buildable_add_child; |
306 | } |
307 | |
308 | /** |
309 | * gtk_aspect_frame_new: |
310 | * @xalign: Horizontal alignment of the child within the parent. |
311 | * Ranges from 0.0 (left aligned) to 1.0 (right aligned) |
312 | * @yalign: Vertical alignment of the child within the parent. |
313 | * Ranges from 0.0 (top aligned) to 1.0 (bottom aligned) |
314 | * @ratio: The desired aspect ratio. |
315 | * @obey_child: If %TRUE, @ratio is ignored, and the aspect |
316 | * ratio is taken from the requistion of the child. |
317 | * |
318 | * Create a new `GtkAspectFrame`. |
319 | * |
320 | * Returns: the new `GtkAspectFrame`. |
321 | */ |
322 | GtkWidget * |
323 | gtk_aspect_frame_new (float xalign, |
324 | float yalign, |
325 | float ratio, |
326 | gboolean obey_child) |
327 | { |
328 | GtkAspectFrame *self; |
329 | |
330 | self = g_object_new (GTK_TYPE_ASPECT_FRAME, NULL); |
331 | |
332 | self->xalign = CLAMP (xalign, 0.0, 1.0); |
333 | self->yalign = CLAMP (yalign, 0.0, 1.0); |
334 | self->ratio = CLAMP (ratio, MIN_RATIO, MAX_RATIO); |
335 | self->obey_child = obey_child != FALSE; |
336 | |
337 | return GTK_WIDGET (self); |
338 | } |
339 | |
340 | /** |
341 | * gtk_aspect_frame_set_xalign: (attributes org.gtk.Method.set_property=xalign) |
342 | * @self: a `GtkAspectFrame` |
343 | * @xalign: horizontal alignment, from 0.0 (left aligned) to 1.0 (right aligned) |
344 | * |
345 | * Sets the horizontal alignment of the child within the allocation |
346 | * of the `GtkAspectFrame`. |
347 | */ |
348 | void |
349 | gtk_aspect_frame_set_xalign (GtkAspectFrame *self, |
350 | float xalign) |
351 | { |
352 | g_return_if_fail (GTK_IS_ASPECT_FRAME (self)); |
353 | |
354 | xalign = CLAMP (xalign, 0.0, 1.0); |
355 | |
356 | if (self->xalign == xalign) |
357 | return; |
358 | |
359 | self->xalign = xalign; |
360 | |
361 | g_object_notify (G_OBJECT (self), property_name: "xalign" ); |
362 | gtk_widget_queue_resize (GTK_WIDGET (self)); |
363 | } |
364 | |
365 | /** |
366 | * gtk_aspect_frame_get_xalign: (attributes org.gtk.Method.get_property=xalign) |
367 | * @self: a `GtkAspectFrame` |
368 | * |
369 | * Returns the horizontal alignment of the child within the |
370 | * allocation of the `GtkAspectFrame`. |
371 | * |
372 | * Returns: the horizontal alignment |
373 | */ |
374 | float |
375 | gtk_aspect_frame_get_xalign (GtkAspectFrame *self) |
376 | { |
377 | g_return_val_if_fail (GTK_IS_ASPECT_FRAME (self), 0.5); |
378 | |
379 | return self->xalign; |
380 | } |
381 | |
382 | /** |
383 | * gtk_aspect_frame_set_yalign: (attributes org.gtk.Method.set_property=yalign) |
384 | * @self: a `GtkAspectFrame` |
385 | * @yalign: horizontal alignment, from 0.0 (top aligned) to 1.0 (bottom aligned) |
386 | * |
387 | * Sets the vertical alignment of the child within the allocation |
388 | * of the `GtkAspectFrame`. |
389 | */ |
390 | void |
391 | gtk_aspect_frame_set_yalign (GtkAspectFrame *self, |
392 | float yalign) |
393 | { |
394 | g_return_if_fail (GTK_IS_ASPECT_FRAME (self)); |
395 | |
396 | yalign = CLAMP (yalign, 0.0, 1.0); |
397 | |
398 | if (self->yalign == yalign) |
399 | return; |
400 | |
401 | self->yalign = yalign; |
402 | |
403 | g_object_notify (G_OBJECT (self), property_name: "yalign" ); |
404 | gtk_widget_queue_resize (GTK_WIDGET (self)); |
405 | } |
406 | |
407 | /** |
408 | * gtk_aspect_frame_get_yalign: (attributes org.gtk.Method.get_property=yalign) |
409 | * @self: a `GtkAspectFrame` |
410 | * |
411 | * Returns the vertical alignment of the child within the |
412 | * allocation of the `GtkAspectFrame`. |
413 | * |
414 | * Returns: the vertical alignment |
415 | */ |
416 | float |
417 | gtk_aspect_frame_get_yalign (GtkAspectFrame *self) |
418 | { |
419 | g_return_val_if_fail (GTK_IS_ASPECT_FRAME (self), 0.5); |
420 | |
421 | return self->xalign; |
422 | } |
423 | |
424 | /** |
425 | * gtk_aspect_frame_set_ratio: (attributes org.gtk.Method.set_property=ratio) |
426 | * @self: a `GtkAspectFrame` |
427 | * @ratio: aspect ratio of the child |
428 | * |
429 | * Sets the desired aspect ratio of the child. |
430 | */ |
431 | void |
432 | gtk_aspect_frame_set_ratio (GtkAspectFrame *self, |
433 | float ratio) |
434 | { |
435 | g_return_if_fail (GTK_IS_ASPECT_FRAME (self)); |
436 | |
437 | ratio = CLAMP (ratio, MIN_RATIO, MAX_RATIO); |
438 | |
439 | if (self->ratio == ratio) |
440 | return; |
441 | |
442 | self->ratio = ratio; |
443 | |
444 | g_object_notify (G_OBJECT (self), property_name: "ratio" ); |
445 | gtk_widget_queue_resize (GTK_WIDGET (self)); |
446 | } |
447 | |
448 | /** |
449 | * gtk_aspect_frame_get_ratio: (attributes org.gtk.Method.get_property=ratio) |
450 | * @self: a `GtkAspectFrame` |
451 | * |
452 | * Returns the desired aspect ratio of the child. |
453 | * |
454 | * Returns: the desired aspect ratio |
455 | */ |
456 | float |
457 | gtk_aspect_frame_get_ratio (GtkAspectFrame *self) |
458 | { |
459 | g_return_val_if_fail (GTK_IS_ASPECT_FRAME (self), 1.0); |
460 | |
461 | return self->ratio; |
462 | } |
463 | |
464 | /** |
465 | * gtk_aspect_frame_set_obey_child: (attributes org.gtk.Method.set_propery=obey-child) |
466 | * @self: a `GtkAspectFrame` |
467 | * @obey_child: If %TRUE, @ratio is ignored, and the aspect |
468 | * ratio is taken from the requistion of the child. |
469 | * |
470 | * Sets whether the aspect ratio of the child's size |
471 | * request should override the set aspect ratio of |
472 | * the `GtkAspectFrame`. |
473 | */ |
474 | void |
475 | gtk_aspect_frame_set_obey_child (GtkAspectFrame *self, |
476 | gboolean obey_child) |
477 | { |
478 | g_return_if_fail (GTK_IS_ASPECT_FRAME (self)); |
479 | |
480 | if (self->obey_child == obey_child) |
481 | return; |
482 | |
483 | self->obey_child = obey_child; |
484 | |
485 | g_object_notify (G_OBJECT (self), property_name: "obey-child" ); |
486 | gtk_widget_queue_resize (GTK_WIDGET (self)); |
487 | |
488 | } |
489 | |
490 | /** |
491 | * gtk_aspect_frame_get_obey_child: (attributes org.gtk.Method.get_property=obey-child) |
492 | * @self: a `GtkAspectFrame` |
493 | * |
494 | * Returns whether the child's size request should override |
495 | * the set aspect ratio of the `GtkAspectFrame`. |
496 | * |
497 | * Returns: whether to obey the child's size request |
498 | */ |
499 | gboolean |
500 | gtk_aspect_frame_get_obey_child (GtkAspectFrame *self) |
501 | { |
502 | g_return_val_if_fail (GTK_IS_ASPECT_FRAME (self), TRUE); |
503 | |
504 | return self->obey_child; |
505 | } |
506 | |
507 | static void |
508 | get_full_allocation (GtkAspectFrame *self, |
509 | GtkAllocation *child_allocation) |
510 | { |
511 | child_allocation->x = 0; |
512 | child_allocation->y = 0; |
513 | child_allocation->width = gtk_widget_get_width (GTK_WIDGET (self)); |
514 | child_allocation->height = gtk_widget_get_height (GTK_WIDGET (self)); |
515 | } |
516 | |
517 | static void |
518 | compute_child_allocation (GtkAspectFrame *self, |
519 | GtkAllocation *child_allocation) |
520 | { |
521 | double ratio; |
522 | |
523 | if (self->child && gtk_widget_get_visible (widget: self->child)) |
524 | { |
525 | GtkAllocation full_allocation; |
526 | |
527 | if (self->obey_child) |
528 | { |
529 | GtkRequisition child_requisition; |
530 | |
531 | gtk_widget_get_preferred_size (widget: self->child, minimum_size: &child_requisition, NULL); |
532 | if (child_requisition.height != 0) |
533 | { |
534 | ratio = ((double) child_requisition.width / |
535 | child_requisition.height); |
536 | if (ratio < MIN_RATIO) |
537 | ratio = MIN_RATIO; |
538 | } |
539 | else if (child_requisition.width != 0) |
540 | ratio = MAX_RATIO; |
541 | else |
542 | ratio = 1.0; |
543 | } |
544 | else |
545 | ratio = self->ratio; |
546 | |
547 | get_full_allocation (self, child_allocation: &full_allocation); |
548 | |
549 | if (ratio * full_allocation.height > full_allocation.width) |
550 | { |
551 | child_allocation->width = full_allocation.width; |
552 | child_allocation->height = full_allocation.width / ratio + 0.5; |
553 | } |
554 | else |
555 | { |
556 | child_allocation->width = ratio * full_allocation.height + 0.5; |
557 | child_allocation->height = full_allocation.height; |
558 | } |
559 | |
560 | child_allocation->x = full_allocation.x + self->xalign * (full_allocation.width - child_allocation->width); |
561 | child_allocation->y = full_allocation.y + self->yalign * (full_allocation.height - child_allocation->height); |
562 | } |
563 | else |
564 | get_full_allocation (self, child_allocation); |
565 | } |
566 | |
567 | static void |
568 | gtk_aspect_frame_measure (GtkWidget *widget, |
569 | GtkOrientation orientation, |
570 | int for_size, |
571 | int *minimum, |
572 | int *natural, |
573 | int *minimum_baseline, |
574 | int *natural_baseline) |
575 | { |
576 | GtkAspectFrame *self = GTK_ASPECT_FRAME (widget); |
577 | |
578 | if (self->child && gtk_widget_get_visible (widget: self->child)) |
579 | { |
580 | int child_min, child_nat; |
581 | |
582 | gtk_widget_measure (widget: self->child, |
583 | orientation, for_size, |
584 | minimum: &child_min, natural: &child_nat, |
585 | NULL, NULL); |
586 | |
587 | *minimum = child_min; |
588 | *natural = child_nat; |
589 | } |
590 | else |
591 | { |
592 | *minimum = 0; |
593 | *natural = 0; |
594 | } |
595 | } |
596 | |
597 | static void |
598 | gtk_aspect_frame_size_allocate (GtkWidget *widget, |
599 | int width, |
600 | int height, |
601 | int baseline) |
602 | { |
603 | GtkAspectFrame *self = GTK_ASPECT_FRAME (widget); |
604 | GtkAllocation new_allocation; |
605 | |
606 | compute_child_allocation (self, child_allocation: &new_allocation); |
607 | |
608 | if (self->child && gtk_widget_get_visible (widget: self->child)) |
609 | gtk_widget_size_allocate (widget: self->child, allocation: &new_allocation, baseline: -1); |
610 | } |
611 | |
612 | static void |
613 | gtk_aspect_frame_compute_expand (GtkWidget *widget, |
614 | gboolean *hexpand, |
615 | gboolean *vexpand) |
616 | { |
617 | GtkAspectFrame *self = GTK_ASPECT_FRAME (widget); |
618 | |
619 | if (self->child) |
620 | { |
621 | *hexpand = gtk_widget_compute_expand (widget: self->child, orientation: GTK_ORIENTATION_HORIZONTAL); |
622 | *vexpand = gtk_widget_compute_expand (widget: self->child, orientation: GTK_ORIENTATION_VERTICAL); |
623 | } |
624 | else |
625 | { |
626 | *hexpand = FALSE; |
627 | *vexpand = FALSE; |
628 | } |
629 | } |
630 | |
631 | static GtkSizeRequestMode |
632 | gtk_aspect_frame_get_request_mode (GtkWidget *widget) |
633 | { |
634 | GtkAspectFrame *self = GTK_ASPECT_FRAME (widget); |
635 | |
636 | if (self->child) |
637 | return gtk_widget_get_request_mode (widget: self->child); |
638 | else |
639 | return GTK_SIZE_REQUEST_CONSTANT_SIZE; |
640 | } |
641 | |
642 | /** |
643 | * gtk_aspect_frame_set_child: (attributes org.gtk.Method.set_property=child) |
644 | * @self: a `GtkAspectFrame` |
645 | * @child: (nullable): the child widget |
646 | * |
647 | * Sets the child widget of @self. |
648 | */ |
649 | void |
650 | gtk_aspect_frame_set_child (GtkAspectFrame *self, |
651 | GtkWidget *child) |
652 | { |
653 | g_return_if_fail (GTK_IS_ASPECT_FRAME (self)); |
654 | g_return_if_fail (child == NULL || GTK_IS_WIDGET (child)); |
655 | |
656 | if (self->child == child) |
657 | return; |
658 | |
659 | g_clear_pointer (&self->child, gtk_widget_unparent); |
660 | |
661 | if (child) |
662 | { |
663 | self->child = child; |
664 | gtk_widget_set_parent (widget: child, GTK_WIDGET (self)); |
665 | } |
666 | |
667 | g_object_notify (G_OBJECT (self), property_name: "child" ); |
668 | } |
669 | |
670 | /** |
671 | * gtk_aspect_frame_get_child: (attributes org.gtk.Method.get_property=child) |
672 | * @self: a `GtkAspectFrame` |
673 | * |
674 | * Gets the child widget of @self. |
675 | * |
676 | * Returns: (nullable) (transfer none): the child widget of self@ |
677 | */ |
678 | GtkWidget * |
679 | gtk_aspect_frame_get_child (GtkAspectFrame *self) |
680 | { |
681 | g_return_val_if_fail (GTK_IS_ASPECT_FRAME (self), NULL); |
682 | |
683 | return self->child; |
684 | } |
685 | |