diff --git a/ChangeLog.gtk-extended-layout b/ChangeLog.gtk-extended-layout index 1a19bd6c10..e3295f1798 100644 --- a/ChangeLog.gtk-extended-layout +++ b/ChangeLog.gtk-extended-layout @@ -1,3 +1,14 @@ +2007-07-02 Mathias Hasselmann + + * gtk/gtkbin.c: Properly evaluate natural size. + * gtk/gtkhbox.c: Consider natural size for child placement. + * gtk/gtklabel.c: Drop any PangoLayout width assigned during the + size allocation process to get proper natural size readings. + * tests/testextendedlayout.c: Add some GtkHPaned to the natural + size test for dynamic evaluation of the algorithm. Create guides for + the button of the height-for-width test for debugging, as it is + affected by natural sizing of GtkHBox. + 2007-07-01 Mathias Hasselmann * gtk/gtk.symbols, gtk/gtkextendedlayout.c, gtk/gtkextendedlayout.h: diff --git a/gtk/gtkbin.c b/gtk/gtkbin.c index fdc7b21552..a7ffce21fb 100644 --- a/gtk/gtkbin.c +++ b/gtk/gtkbin.c @@ -73,8 +73,8 @@ gtk_bin_child_type (GtkContainer *container) { if (!GTK_BIN (container)->child) return GTK_TYPE_WIDGET; - else - return G_TYPE_NONE; + + return G_TYPE_NONE; } static void @@ -195,11 +195,22 @@ gtk_bin_extended_layout_get_natural_size (GtkExtendedLayout *layout, GtkRequisition *requisition) { GtkBin *bin = GTK_BIN (layout); + GtkExtendedLayout *child_layout; g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (bin->child)); - layout = GTK_EXTENDED_LAYOUT (bin->child); - return gtk_extended_layout_get_natural_size (layout, requisition); + child_layout = GTK_EXTENDED_LAYOUT (bin->child); + gtk_extended_layout_get_natural_size (child_layout, requisition); + + if (GTK_EXTENDED_LAYOUT_HAS_PADDING (layout)) + { + GtkBorder padding; + + gtk_extended_layout_get_padding (layout, &padding); + + requisition->width += padding.left + padding.right; + requisition->height += padding.top + padding.bottom; + } } static gint @@ -222,9 +233,7 @@ gtk_bin_extended_layout_get_baselines (GtkExtendedLayout *layout, GtkBorder padding; if (GTK_EXTENDED_LAYOUT_HAS_PADDING (bin)) - { - gtk_extended_layout_get_padding (layout, &padding); - } + gtk_extended_layout_get_padding (layout, &padding); else padding.top = GTK_CONTAINER (bin)->border_width; diff --git a/gtk/gtkhbox.c b/gtk/gtkhbox.c index b885185cf8..683fd36f09 100644 --- a/gtk/gtkhbox.c +++ b/gtk/gtkhbox.c @@ -173,13 +173,12 @@ gtk_hbox_size_request (GtkWidget *widget, if (nvis_children > 0) { GtkHBoxPrivate *priv = GTK_HBOX_GET_PRIVATE (widget); - gint effective_baseline, i; + gint effective_baseline = 0, i; gint *baselines = NULL; if (priv->baseline_policy != GTK_BASELINE_NONE) { baselines = g_newa (gint, nvis_children); - effective_baseline = 0; i = 0; children = box->children; @@ -265,13 +264,9 @@ gtk_hbox_size_allocate (GtkWidget *widget, GtkBoxChild *child; GList *children; - GtkTextDirection direction; - box = GTK_BOX (widget); widget->allocation = *allocation; - direction = gtk_widget_get_direction (widget); - nvis_children = 0; nexpand_children = 0; children = box->children; @@ -292,46 +287,103 @@ gtk_hbox_size_allocate (GtkWidget *widget, if (nvis_children > 0) { GtkHBoxPrivate *priv = GTK_HBOX_GET_PRIVATE (widget); - GtkAllocation child_allocation; - gint effective_baseline, i; + + gint effective_baseline; GtkPackType packing; gint *baselines; - gint width; - gint extra; + GtkTextDirection direction; + gint border_width; - baselines = g_newa (gint, nvis_children); - effective_baseline = 0; + GtkAllocation child_allocation; + + gint *natural_requisitions; + gint *minimum_requisitions; + + gint natural_width; + gint minimum_width; + + gint available, natural, extra; + gint i; + + direction = gtk_widget_get_direction (widget); + border_width = GTK_CONTAINER (box)->border_width; + + natural_width = 0; + natural_requisitions = g_newa (gint, nvis_children); + minimum_requisitions = g_newa (gint, nvis_children); + + children = box->children; + i = 0; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + GtkRequisition child_requisition; + + gtk_widget_size_request (child->widget, &child_requisition); + minimum_requisitions[i] = child_requisition.width; + + if (GTK_IS_EXTENDED_LAYOUT (child->widget) && + GTK_EXTENDED_LAYOUT_HAS_NATURAL_SIZE (child->widget)) + { + gtk_extended_layout_get_natural_size ( + GTK_EXTENDED_LAYOUT (child->widget), + &child_requisition); + natural_requisitions[i] = + child_requisition.width - + minimum_requisitions[i]; + } + else + natural_requisitions[i] = 0; + + natural_width += natural_requisitions[i++]; + } + } + + minimum_width = widget->requisition.width - border_width * 2 - + (nvis_children - 1) * box->spacing; if (box->homogeneous) { - width = (allocation->width - - GTK_CONTAINER (box)->border_width * 2 - - (nvis_children - 1) * box->spacing); - extra = width / nvis_children; + available = (allocation->width - border_width * 2 - + (nvis_children - 1) * box->spacing); + extra = available / nvis_children; + natural = 0; } else if (nexpand_children > 0) { - width = (gint) allocation->width - (gint) widget->requisition.width; - extra = width / nexpand_children; + available = (gint)allocation->width - widget->requisition.width; + natural = MAX (0, MIN (available, natural_width)); + available -= natural; + + extra = MAX (0, available / nexpand_children); } else { - width = 0; + available = 0; + natural = 0; extra = 0; } - child_allocation.y = allocation->y + GTK_CONTAINER (box)->border_width; - child_allocation.height = MAX (1, (gint) allocation->height - (gint) GTK_CONTAINER (box)->border_width * 2); + effective_baseline = 0; + baselines = g_newa (gint, nvis_children); + + child_allocation.y = allocation->y + border_width; + child_allocation.height = MAX (1, (gint) allocation->height - (gint) border_width * 2); for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing) { gint x; if (GTK_PACK_START == packing) - x = allocation->x + GTK_CONTAINER (box)->border_width; + x = allocation->x + border_width; else - x = allocation->x + allocation->width - GTK_CONTAINER (box)->border_width; + x = allocation->x + allocation->width - border_width; i = 0; children = box->children; @@ -344,37 +396,37 @@ gtk_hbox_size_allocate (GtkWidget *widget, { if ((child->pack == packing)) { - GtkRequisition child_requisition; gint child_width; - gtk_widget_get_child_requisition (child->widget, &child_requisition); - if (box->homogeneous) { if (nvis_children == 1) - child_width = width; + child_width = available; else child_width = extra; nvis_children -= 1; - width -= extra; + available -= extra; } else { - child_width = child_requisition.width + child->padding * 2; + child_width = minimum_requisitions[i] + child->padding * 2; if (child->expand) { if (nexpand_children == 1) - child_width += width; + child_width += available; else child_width += extra; nexpand_children -= 1; - width -= extra; + available -= extra; } } + if (natural_width > 0) + child_width += natural * natural_requisitions[i] / natural_width; + if (child->fill) { child_allocation.width = MAX (1, (gint) child_width - (gint) child->padding * 2); @@ -382,7 +434,7 @@ gtk_hbox_size_allocate (GtkWidget *widget, } else { - child_allocation.width = child_requisition.width; + child_allocation.width = minimum_requisitions[i]; child_allocation.x = x + (child_width - child_allocation.width) / 2; } @@ -498,8 +550,8 @@ gtk_hbox_extended_layout_get_natural_size (GtkExtendedLayout *layout, GtkBoxChild *child; GList *children; - requisition->width = 0; - requisition->height = 0; + requisition->width = GTK_CONTAINER (box)->border_width * 2; + requisition->height = GTK_CONTAINER (box)->border_width * 2; children = box->children; while (children) diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c index 24ac08e19c..10c790a970 100644 --- a/gtk/gtklabel.c +++ b/gtk/gtklabel.c @@ -4276,14 +4276,21 @@ gtk_label_extended_layout_get_natural_size (GtkExtendedLayout *layout, { GtkLabel *label; gboolean ellipsize; + PangoLayout *tmp; label = GTK_LABEL (layout); ellipsize = label->ellipsize; label->ellipsize = PANGO_ELLIPSIZE_NONE; + tmp = label->layout; + label->layout = pango_layout_copy (tmp); + + pango_layout_set_width (label->layout, -1); gtk_label_size_request (GTK_WIDGET (label), requisition); + g_object_unref (label->layout); label->ellipsize = ellipsize; + label->layout = tmp; } static gint diff --git a/tests/testextendedlayout.c b/tests/testextendedlayout.c index bfba76695b..3777cdfa48 100644 --- a/tests/testextendedlayout.c +++ b/tests/testextendedlayout.c @@ -193,6 +193,7 @@ test_case_append_guide (TestCase *self, static void append_natural_size_box (TestCase *test, + GtkWidget *vbox, const gchar *caption, PangoEllipsizeMode ellipsize) { @@ -218,32 +219,98 @@ append_natural_size_box (TestCase *test, gtk_label_set_markup (GTK_LABEL (label), caption); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (test->widget), label, FALSE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (test->widget), hbox, FALSE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); +} +static gboolean +restore_paned (gpointer data) +{ + GtkPaned *paned; + GtkWidget *hint; + gint pos; + + + paned = GTK_PANED (data); + hint = gtk_paned_get_child2 (paned); + gtk_widget_set_sensitive (hint, TRUE); + + pos = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (paned), "initial-position")); + gtk_paned_set_position (paned, pos); + + return FALSE; +} + +static gboolean +shrink_paned_timeout (gpointer data) +{ + GtkPaned *paned; + gint pos; + + paned = GTK_PANED (data); + pos = gtk_paned_get_position (paned); + + if (pos < 20) + { + g_timeout_add (1000, restore_paned, paned); + return FALSE; + } + + gtk_paned_set_position (paned, pos - 5); + return TRUE; +} + +static void +shrink_paned (GtkWidget *button, + gpointer data) +{ + GtkPaned *paned; + GtkWidget *hint; + + paned = GTK_PANED (data); + hint = gtk_paned_get_child2 (paned); + gtk_widget_set_sensitive (hint, FALSE); + + g_object_set_data (G_OBJECT (paned), "initial-position", + GINT_TO_POINTER (gtk_paned_get_position (paned))); + g_timeout_add (50, shrink_paned_timeout, paned); } static TestCase* create_natural_size_test (TestSuite *suite) { + GtkWidget *vbox, *hint, *button; + TestCase *test = test_case_new (suite, "Natural Size", NULL, - gtk_vbox_new (FALSE, 12)); + gtk_hpaned_new ()); + gtk_container_set_border_width (GTK_CONTAINER (test->widget), 6); - gtk_container_set_border_width (GTK_CONTAINER (test->widget), 12); + vbox = gtk_vbox_new (FALSE, 12); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 6); + gtk_paned_pack1 (GTK_PANED (test->widget), vbox, TRUE, TRUE); - append_natural_size_box (test, + append_natural_size_box (test, vbox, "No ellipsizing", PANGO_ELLIPSIZE_NONE); - append_natural_size_box (test, + append_natural_size_box (test, vbox, "Ellipsizing at start", PANGO_ELLIPSIZE_START); - append_natural_size_box (test, + append_natural_size_box (test, vbox, "Ellipsizing in the middle", PANGO_ELLIPSIZE_MIDDLE); - append_natural_size_box (test, + append_natural_size_box (test, vbox, "Ellipsizing at end", PANGO_ELLIPSIZE_END); + button = gtk_button_new_with_label ("Shrink to check ellipsing"); + gtk_label_set_angle (GTK_LABEL (GTK_BIN (button)->child), -90); + g_signal_connect (button, "clicked", G_CALLBACK (shrink_paned), test->widget); + + hint = gtk_alignment_new (1.0, 0.5, 0.0, 1.0); + gtk_container_set_border_width (GTK_CONTAINER (hint), 6); + gtk_container_add (GTK_CONTAINER (hint), button); + gtk_paned_pack2 (GTK_PANED (test->widget), hint, FALSE, FALSE); + return test; } @@ -278,6 +345,8 @@ create_height_for_width_test (TestSuite *suite) GTK_ICON_SIZE_DIALOG)); gtk_box_pack_start (GTK_BOX (test->widget), child, FALSE, TRUE, 0); + test_case_append_guide (test, child, GUIDE_EXTERIOUR_BOTH, 1); + return test; }