[gtk+/native-layout] Make GtkFrame allocate its label considering natural size requests



commit 360e2c4dd531c9f3ed719f634a4530d681625939
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Fri Aug 6 15:58:12 2010 -0400

    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 7f6c0e2..76cf1fd 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 2c27047..dba3da9 100644
--- a/tests/testheightforwidth.c
+++ b/tests/testheightforwidth.c
@@ -617,6 +617,49 @@ TestInterface interfaces[] = {
   },
 
   {
+    "Wrapping Frame Label",
+    "This test demonstrates how the frame label can fill to its natural width "
+    "and also trade height for width.",
+    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+    "<interface>"
+    "  <requires lib=\"gtk+\" version=\"2.20\"/>"
+    "  <!-- interface-naming-policy project-wide -->"
+    "  <object class=\"GtkWindow\" id=\"window\">"
+    "    <property name=\"default_width\">400</property>"
+    "    <property name=\"default_height\">150</property>"
+    "    <child>"
+    "      <object class=\"GtkFrame\" id=\"frame1\">"
+    "        <property name=\"visible\">True</property>"
+    "        <property name=\"border_width\">8</property>"
+    "        <property name=\"label_xalign\">0</property>"
+    "        <child>"
+    "          <object class=\"GtkAlignment\" id=\"alignment1\">"
+    "            <property name=\"visible\">True</property>"
+    "            <property name=\"left_padding\">12</property>"
+    "            <child>"
+    "              <object class=\"GtkLabel\" id=\"label2\">"
+    "                <property name=\"visible\">True</property>"
+    "                <property name=\"label\" translatable=\"yes\">some content</property>"
+    "              </object>"
+    "            </child>"
+    "          </object>"
+    "        </child>"
+    "        <child type=\"label\">"
+    "          <object class=\"GtkLabel\" id=\"label1\">"
+    "            <property name=\"visible\">True</property>"
+    "            <property name=\"label\" translatable=\"yes\">A frame label that's a little long and wraps</property>"
+    "            <property name=\"use_markup\">True</property>"
+    "            <property name=\"wrap\">True</property>"
+    "          </object>"
+    "        </child>"
+    "      </object>"
+    "    </child>"
+    "  </object>"
+    "</interface>",
+    NULL
+  },
+
+  {
     "Ellipsizing Treeview",
     "Demonstrates how natural size can be shared across treeview columns and renderers.",
     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]