From 208ba9bb50227a2681515b9847c651dd943c7127 Mon Sep 17 00:00:00 2001 From: Tristan Van Berkom Date: Fri, 6 Aug 2010 15:58:12 -0400 Subject: [PATCH] Make GtkFrame allocate its label considering natural size requests Also like the GtkExpander, the label widget is allocated the minimum height for its allocated width and the remaining space is given to the child, test case included. --- gtk/gtkframe.c | 131 ++++++++++++++++++++++++++++++------- tests/testheightforwidth.c | 43 ++++++++++++ 2 files changed, 150 insertions(+), 24 deletions(-) diff --git a/gtk/gtkframe.c b/gtk/gtkframe.c index 7f6c0e209..76cf1fd95 100644 --- a/gtk/gtkframe.c +++ b/gtk/gtkframe.c @@ -47,6 +47,7 @@ struct _GtkFramePriv /* Properties */ GtkAllocation child_allocation; + GtkAllocation label_allocation; }; enum { @@ -99,6 +100,15 @@ static void gtk_frame_get_width (GtkSizeRequest *widget static void gtk_frame_get_height (GtkSizeRequest *widget, gint *minimum_size, gint *natural_size); +static void gtk_frame_get_height_for_width (GtkSizeRequest *layout, + gint width, + gint *minimum_height, + gint *natural_height); +static void gtk_frame_get_width_for_height (GtkSizeRequest *layout, + gint width, + gint *minimum_height, + gint *natural_height); + G_DEFINE_TYPE_WITH_CODE (GtkFrame, gtk_frame, GTK_TYPE_BIN, G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, @@ -597,24 +607,21 @@ gtk_frame_paint (GtkWidget *widget, if (priv->label_widget) { - GtkRequisition child_requisition; gfloat xalign; gint height_extra; gint x2; - gtk_widget_get_child_requisition (priv->label_widget, &child_requisition); - if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) xalign = priv->label_xalign; else xalign = 1 - priv->label_xalign; - height_extra = MAX (0, child_requisition.height - widget->style->ythickness) - - priv->label_yalign * child_requisition.height; + height_extra = MAX (0, priv->label_allocation.height - widget->style->ythickness) + - priv->label_yalign * priv->label_allocation.height; y -= height_extra; height += height_extra; - x2 = widget->style->xthickness + (priv->child_allocation.width - child_requisition.width - 2 * LABEL_PAD - 2 * LABEL_SIDE_PAD) * xalign + LABEL_SIDE_PAD; + x2 = widget->style->xthickness + (priv->child_allocation.width - priv->label_allocation.width - 2 * LABEL_PAD - 2 * LABEL_SIDE_PAD) * xalign + LABEL_SIDE_PAD; /* If the label is completely over or under the frame we can omit the gap */ if (priv->label_yalign == 0.0 || priv->label_yalign == 1.0) @@ -628,7 +635,7 @@ gtk_frame_paint (GtkWidget *widget, area, widget, "frame", x, y, width, height, GTK_POS_TOP, - x2, child_requisition.width + 2 * LABEL_PAD); + x2, priv->label_allocation.width + 2 * LABEL_PAD); } else gtk_paint_shadow (widget->style, widget->window, @@ -688,25 +695,32 @@ gtk_frame_size_allocate (GtkWidget *widget, if (priv->label_widget && gtk_widget_get_visible (priv->label_widget)) { - GtkRequisition child_requisition; - GtkAllocation child_allocation; + gint nat_width, width, height; gfloat xalign; - gtk_widget_get_child_requisition (priv->label_widget, &child_requisition); - if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) xalign = priv->label_xalign; else xalign = 1 - priv->label_xalign; - child_allocation.x = priv->child_allocation.x + LABEL_SIDE_PAD + - (priv->child_allocation.width - child_requisition.width - 2 * LABEL_PAD - 2 * LABEL_SIDE_PAD) * xalign + LABEL_PAD; - child_allocation.width = MIN (child_requisition.width, new_allocation.width - 2 * LABEL_PAD - 2 * LABEL_SIDE_PAD); + gtk_size_request_get_width (GTK_SIZE_REQUEST (priv->label_widget), NULL, &nat_width); + width = new_allocation.width - 2 * LABEL_PAD - 2 * LABEL_SIDE_PAD; + width = MIN (width, nat_width); + + gtk_size_request_get_height_for_width (GTK_SIZE_REQUEST (priv->label_widget), width, + &height, NULL); + + + priv->label_allocation.x = priv->child_allocation.x + LABEL_SIDE_PAD + + (new_allocation.width - width - 2 * LABEL_PAD - 2 * LABEL_SIDE_PAD) * xalign + LABEL_PAD; - child_allocation.y = priv->child_allocation.y - MAX (child_requisition.height, widget->style->ythickness); - child_allocation.height = child_requisition.height; + priv->label_allocation.width = width; - gtk_widget_size_allocate (priv->label_widget, &child_allocation); + + priv->label_allocation.y = priv->child_allocation.y - MAX (height, widget->style->ythickness); + priv->label_allocation.height = height; + + gtk_widget_size_allocate (priv->label_widget, &priv->label_allocation); } } @@ -727,19 +741,30 @@ gtk_frame_real_compute_child_allocation (GtkFrame *frame, GtkFramePriv *priv = frame->priv; GtkWidget *widget = GTK_WIDGET (frame); GtkAllocation *allocation = &widget->allocation; - GtkRequisition child_requisition; gint top_margin; guint border_width; + border_width = gtk_container_get_border_width (GTK_CONTAINER (frame)); + if (priv->label_widget) { - gtk_widget_get_child_requisition (priv->label_widget, &child_requisition); - top_margin = MAX (child_requisition.height, widget->style->ythickness); + gint nat_width, width, height; + + gtk_size_request_get_width (GTK_SIZE_REQUEST (priv->label_widget), NULL, &nat_width); + + width = widget->allocation.width; + width -= 2 * LABEL_PAD + 2 * LABEL_SIDE_PAD; + width -= (border_width + GTK_WIDGET (widget)->style->xthickness) * 2; + + width = MIN (width, nat_width); + + gtk_size_request_get_height_for_width (GTK_SIZE_REQUEST (priv->label_widget), width, + &height, NULL); + + top_margin = MAX (height, widget->style->ythickness); } else top_margin = widget->style->ythickness; - - border_width = gtk_container_get_border_width (GTK_CONTAINER (frame)); child_allocation->x = border_width + widget->style->xthickness; child_allocation->width = MAX(1, (gint)allocation->width - child_allocation->x * 2); @@ -846,9 +871,67 @@ gtk_frame_get_height (GtkSizeRequest *widget, gtk_frame_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size); } + +static void +gtk_frame_get_height_for_width (GtkSizeRequest *request, + gint width, + gint *minimum_height, + gint *natural_height) +{ + GtkWidget *widget = GTK_WIDGET (request); + GtkWidget *child; + GtkFrame *frame = GTK_FRAME (widget); + GtkFramePriv *priv = frame->priv; + GtkBin *bin = GTK_BIN (widget); + gint child_min, child_nat, label_width; + gint minimum, natural; + guint border_width; + + border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); + minimum = (border_width + GTK_WIDGET (widget)->style->ythickness) * 2; + natural = (border_width + GTK_WIDGET (widget)->style->ythickness) * 2; + + width -= (border_width + GTK_WIDGET (widget)->style->xthickness) * 2; + label_width = width - 2 * LABEL_PAD + 2 * LABEL_SIDE_PAD; + + if (priv->label_widget && gtk_widget_get_visible (priv->label_widget)) + { + gtk_size_request_get_height_for_width (GTK_SIZE_REQUEST (priv->label_widget), + label_width, &child_min, &child_nat); + minimum += child_min; + natural += child_nat; + } + + child = gtk_bin_get_child (bin); + if (child && gtk_widget_get_visible (child)) + { + gtk_size_request_get_height_for_width (GTK_SIZE_REQUEST (priv->label_widget), + width, &child_min, &child_nat); + minimum += child_min; + natural += child_nat; + } + + if (minimum_height) + *minimum_height = minimum; + + if (natural_height) + *natural_height = natural; +} + +static void +gtk_frame_get_width_for_height (GtkSizeRequest *widget, + gint height, + gint *minimum_width, + gint *natural_width) +{ + gtk_size_request_get_width (widget, minimum_width, natural_width); +} + static void gtk_frame_size_request_init (GtkSizeRequestIface *iface) { - iface->get_width = gtk_frame_get_width; - iface->get_height = gtk_frame_get_height; + iface->get_width = gtk_frame_get_width; + iface->get_height = gtk_frame_get_height; + iface->get_height_for_width = gtk_frame_get_height_for_width; + iface->get_width_for_height = gtk_frame_get_width_for_height; } diff --git a/tests/testheightforwidth.c b/tests/testheightforwidth.c index e59d3bb6f..f784864b6 100644 --- a/tests/testheightforwidth.c +++ b/tests/testheightforwidth.c @@ -615,6 +615,49 @@ TestInterface interfaces[] = { "", NULL }, + + { + "Wrapping Frame Label", + "This test demonstrates how the frame label can fill to its natural width " + "and also trade height for width.", + "" + "" + " " + " " + " " + " 400" + " 150" + " " + " " + " True" + " 8" + " 0" + " " + " " + " True" + " 12" + " " + " " + " True" + " some content" + " " + " " + " " + " " + " " + " " + " True" + " A frame label that's a little long and wraps" + " True" + " True" + " " + " " + " " + " " + " " + "", + NULL + }, }; -- 2.43.2