State of natural size, Havoc/Behdad style
- From: "Mathias Hasselmann" <Mathias Hasselmann gmx de>
- To: Gtk+ Developers <gtk-devel-list gnome org>
- Subject: State of natural size, Havoc/Behdad style
- Date: Tue, 08 Jan 2008 19:17:44 +0100
Attached the current state of natural size, with an API similiar to Havoc's wishes and implementing the natural size allocation they both suggested.
Havoc suggest to have two methods: get_desired_width() and get_desired_height(), but I implemented get_desired_size(), since I do not see how to implement this for GtkLabel, without recalculating the entire layout four times on each desired size request.
--
GMX FreeMail: 1 GB Postfach, 5 E-Mail-Adressen, 10 Free SMS.
Alle Infos und kostenlose Anmeldung: http://www.gmx.net/de/go/freemail
--
Mathias Hasselmann
http://taschenorakel.de/mathias/
Ist Ihr Browser Vista-kompatibel? Jetzt die neuesten
Browser-Versionen downloaden: http://www.gmx.net/de/go/browser
>From 1a64cd913c90ce8dd3ce4f17de714741a3db1b33 Mon Sep 17 00:00:00 2001
From: Mathias Hasselmann <mathias openismus com>
Date: Sat, 5 Jan 2008 11:36:29 +0100
Subject: =?utf-8?q?*=20tests/testellipsise.c:=20Extend=20the=20test=20to=20support=20rotations.
=20*=20gtk/gtklabel.c:=20Support=20ellipsizing=20and=20wrapping=20on=20labels
=20rotated=20by=20multiples=20of=2090=C2=B0.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
---
ChangeLog | 6 ++
gtk/gtk.symbols | 2 +
gtk/gtklabel.c | 223 +++++++++++++++++++++++++++++++++++++------------
gtk/gtklabel.h | 3 +
tests/testellipsise.c | 112 +++++++++++++++++++++++--
5 files changed, 285 insertions(+), 61 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 69119de..fb5f18d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2008-01-02 Mathias Hasselmann <mathias openismus com>
+
+ * tests/testellipsise.c: Extend the test to support rotations.
+ * gtk/gtklabel.c: Support ellipsizing and wrapping on labels
+ rotated by multiples of 90°.
+
2008-01-04 Mathias Hasselmann <mathias openismus com>
Avoid some compiler warnings (#507000).
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index f5de635..e353959 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -2065,6 +2065,7 @@ gtk_label_get_type G_GNUC_CONST
gtk_label_get_use_markup
gtk_label_get_use_underline
gtk_label_get_width_chars
+gtk_label_get_full_size
gtk_label_new
gtk_label_new_with_mnemonic
gtk_label_select_region
@@ -2087,6 +2088,7 @@ gtk_label_set_text_with_mnemonic
gtk_label_set_use_markup
gtk_label_set_use_underline
gtk_label_set_width_chars
+gtk_label_set_full_size
#endif
#endif
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index cfe3df4..b3fe927 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -48,11 +48,16 @@
#define GTK_LABEL_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_LABEL, GtkLabelPrivate))
+#ifndef INFINITY /* Why again don't we use C99? */
+#define INFINITY HUGE_VAL
+#endif
+
typedef struct
{
gint wrap_width;
gint width_chars;
gint max_width_chars;
+ gboolean full_size;
}
GtkLabelPrivate;
@@ -95,7 +100,8 @@ enum {
PROP_WIDTH_CHARS,
PROP_SINGLE_LINE_MODE,
PROP_ANGLE,
- PROP_MAX_WIDTH_CHARS
+ PROP_MAX_WIDTH_CHARS,
+ PROP_FULL_SIZE
};
static guint signals[LAST_SIGNAL] = { 0 };
@@ -512,6 +518,23 @@ gtk_label_class_init (GtkLabelClass *class)
G_MAXINT,
-1,
GTK_PARAM_READWRITE));
+
+ /**
+ * GtkLabel:full-size:
+ *
+ * Use the entire space the widget got assigned for text wrapping. Overrides
+ * any #GtkLabel:width-chars, #GtkLabel:max-width-chars and screen size based
+ * constraints. Requires #GtkLabel:angle to be 0°, 90°, 180° or 270°.
+ *
+ * Since: 2.14
+ **/
+ g_object_class_install_property (gobject_class,
+ PROP_FULL_SIZE,
+ g_param_spec_boolean ("full-size",
+ P_("Full size"),
+ P_("Use the entire size of the widget to wrap text"),
+ FALSE,
+ GTK_PARAM_READWRITE));
/*
* Key bindings
*/
@@ -688,6 +711,9 @@ gtk_label_set_property (GObject *object,
case PROP_MAX_WIDTH_CHARS:
gtk_label_set_max_width_chars (label, g_value_get_int (value));
break;
+ case PROP_FULL_SIZE:
+ gtk_label_set_full_size (label, g_value_get_boolean (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -771,6 +797,9 @@ gtk_label_get_property (GObject *object,
case PROP_MAX_WIDTH_CHARS:
g_value_set_int (value, gtk_label_get_max_width_chars (label));
break;
+ case PROP_FULL_SIZE:
+ g_value_set_int (value, gtk_label_get_full_size (label));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -2005,14 +2034,14 @@ gtk_label_ensure_layout (GtkLabel *label)
PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
gdouble angle = gtk_label_get_angle (label);
- if (angle != 0.0 && !label->wrap && !label->ellipsize && !label->select_info)
+ if (angle != 0.0 && !label->select_info)
{
+ PangoMatrix matrix = PANGO_MATRIX_INIT;
+
/* We rotate the standard singleton PangoContext for the widget,
* depending on the fact that it's meant pretty much exclusively
* for our use.
*/
- PangoMatrix matrix = PANGO_MATRIX_INIT;
-
pango_matrix_rotate (&matrix, angle);
pango_context_set_matrix (gtk_widget_get_pango_context (widget), &matrix);
@@ -2056,8 +2085,8 @@ gtk_label_ensure_layout (GtkLabel *label)
pango_layout_set_single_paragraph_mode (label->layout, label->single_line_mode);
if (label->ellipsize)
- pango_layout_set_width (label->layout,
- widget->allocation.width * PANGO_SCALE);
+ pango_layout_set_width (label->layout,
+ widget->allocation.width * PANGO_SCALE);
else if (label->wrap)
{
GtkWidgetAuxInfo *aux_info;
@@ -2086,12 +2115,12 @@ gtk_label_ensure_layout (GtkLabel *label)
width = MIN (width, wrap_width);
width = MIN (width,
PANGO_SCALE * (gdk_screen_get_width (screen) + 1) / 2);
-
+
pango_layout_set_width (label->layout, width);
pango_layout_get_extents (label->layout, NULL, &logical_rect);
width = logical_rect.width;
height = logical_rect.height;
-
+
/* Unfortunately, the above may leave us with a very unbalanced looking paragraph,
* so we try short search for a narrower width that leaves us with the same height
*/
@@ -2138,8 +2167,8 @@ gtk_label_size_request (GtkWidget *widget,
{
GtkLabel *label;
GtkLabelPrivate *priv;
- gint width, height;
PangoRectangle logical_rect;
+ PangoRectangle required_rect;
GtkWidgetAuxInfo *aux_info;
g_return_if_fail (GTK_IS_LABEL (widget));
@@ -2166,39 +2195,21 @@ gtk_label_size_request (GtkWidget *widget,
gtk_label_ensure_layout (label);
- width = label->misc.xpad * 2;
- height = label->misc.ypad * 2;
-
aux_info = _gtk_widget_get_aux_info (widget, FALSE);
- if (label->have_transform)
- {
- PangoRectangle rect;
- PangoContext *context = pango_layout_get_context (label->layout);
- const PangoMatrix *matrix = pango_context_get_matrix (context);
-
- pango_layout_get_extents (label->layout, NULL, &rect);
- pango_matrix_transform_rectangle (matrix, &rect);
- pango_extents_to_pixels (&rect, NULL);
-
- requisition->width = width + rect.width;
- requisition->height = height + rect.height;
-
- return;
- }
- else
- pango_layout_get_extents (label->layout, NULL, &logical_rect);
+ pango_layout_get_extents (label->layout, NULL, &logical_rect);
+ required_rect.x = required_rect.y = 0;
if ((label->wrap || label->ellipsize ||
priv->width_chars > 0 || priv->max_width_chars > 0) &&
aux_info && aux_info->width > 0)
- width += aux_info->width;
+ required_rect.width = aux_info->width;
else if (label->ellipsize || priv->width_chars > 0 || priv->max_width_chars > 0)
{
- width += PANGO_PIXELS (get_label_char_width (label));
+ required_rect.width = PANGO_PIXELS (get_label_char_width (label));
}
else
- width += PANGO_PIXELS (logical_rect.width);
+ required_rect.width = PANGO_PIXELS (logical_rect.width);
if (label->single_line_mode)
{
@@ -2214,39 +2225,102 @@ gtk_label_size_request (GtkWidget *widget,
descent = pango_font_metrics_get_descent (metrics);
pango_font_metrics_unref (metrics);
- height += PANGO_PIXELS (ascent + descent);
+ required_rect.height = PANGO_PIXELS (ascent + descent);
}
else
- height += PANGO_PIXELS (logical_rect.height);
+ required_rect.height = PANGO_PIXELS (logical_rect.height);
- requisition->width = width;
- requisition->height = height;
+ if (label->have_transform)
+ {
+ PangoContext *context = pango_layout_get_context (label->layout);
+ const PangoMatrix *matrix = pango_context_get_matrix (context);
+ pango_matrix_transform_pixel_rectangle (matrix, &required_rect);
+ }
+
+ requisition->width = required_rect.width + label->misc.xpad * 2;
+ requisition->height = required_rect.height + label->misc.ypad * 2;
}
static void
gtk_label_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
- GtkLabel *label;
-
- label = GTK_LABEL (widget);
+ GtkLabel *label = GTK_LABEL (widget);
(* GTK_WIDGET_CLASS (gtk_label_parent_class)->size_allocate) (widget, allocation);
- if (label->ellipsize)
+ if (label->ellipsize || GTK_LABEL_GET_PRIVATE (label)->full_size)
{
if (label->layout)
{
- gint width;
PangoRectangle logical;
+ PangoRectangle bounds;
- width = (allocation->width - label->misc.xpad * 2) * PANGO_SCALE;
+ bounds.x = bounds.y = 0;
+ bounds.width = allocation->width - label->misc.xpad * 2;
+ bounds.height = allocation->height - label->misc.ypad * 2;
pango_layout_set_width (label->layout, -1);
- pango_layout_get_extents (label->layout, NULL, &logical);
+ pango_layout_get_pixel_extents (label->layout, NULL, &logical);
+
+ if (label->have_transform)
+ {
+ PangoContext *context = gtk_widget_get_pango_context (widget);
+ const PangoMatrix *matrix = pango_context_get_matrix (context);
+
+ const gdouble dx = matrix->xx; /* cos (M_PI * angle / 180) */
+ const gdouble dy = matrix->xy; /* sin (M_PI * angle / 180) */
+
+ if (fabs (dy) < 0.01)
+ {
+ if (logical.width > bounds.width)
+ pango_layout_set_width (label->layout, bounds.width * PANGO_SCALE);
+ }
+ else if (fabs (dx) < 0.01)
+ {
+ if (logical.width > bounds.height)
+ pango_layout_set_width (label->layout, bounds.height * PANGO_SCALE);
+ }
+ else
+ {
+ gdouble x0, y0, x1, y1, length;
+ gboolean vertical;
+ gint cy;
+
+ x0 = bounds.width / 2;
+ y0 = dx ? x0 * dy / dx : dy * INFINITY;
+ vertical = fabs (y0) > bounds.height / 2;
- if (logical.width > width)
- pango_layout_set_width (label->layout, width);
+ if (vertical)
+ {
+ y0 = bounds.height/2;
+ x0 = dy ? y0 * dx / dy : dx * INFINITY;
+ }
+
+ length = 2 * sqrt (x0 * x0 + y0 * y0);
+ pango_layout_set_width (label->layout, rint (length * PANGO_SCALE));
+ pango_layout_get_pixel_size (label->layout, NULL, &cy);
+
+ x1 = +dy * cy/2;
+ y1 = -dx * cy/2;
+
+ if (vertical)
+ {
+ y0 = bounds.height/2 + y1 - y0;
+ x0 = -y0 * dx/dy;
+ }
+ else
+ {
+ x0 = bounds.width/2 + x1 - x0;
+ y0 = -x0 * dy/dx;
+ }
+
+ length = length - sqrt (x0 * x0 + y0 * y0) * 2;
+ pango_layout_set_width (label->layout, rint (length * PANGO_SCALE));
+ }
+ }
+ else if (logical.width > bounds.width)
+ pango_layout_set_width (label->layout, bounds.width * PANGO_SCALE);
}
}
@@ -2327,7 +2401,9 @@ get_layout_location (GtkLabel *label,
GtkWidget *widget;
GtkLabelPrivate *priv;
gfloat xalign;
- gint req_width, x, y;
+ gint req_width;
+ gint req_height;
+ gint x, y;
misc = GTK_MISC (label);
widget = GTK_WIDGET (label);
@@ -2338,33 +2414,48 @@ get_layout_location (GtkLabel *label,
else
xalign = 1.0 - misc->xalign;
- if (label->ellipsize || priv->width_chars > 0)
+ if (label->ellipsize || priv->width_chars > 0 || GTK_LABEL_GET_PRIVATE (label)->full_size)
{
int width;
PangoRectangle logical;
width = pango_layout_get_width (label->layout);
- pango_layout_get_pixel_extents (label->layout, NULL, &logical);
+ pango_layout_get_extents (label->layout, NULL, &logical);
+
+ if (label->have_transform)
+ {
+ PangoContext *context = gtk_widget_get_pango_context (widget);
+ const PangoMatrix *matrix = pango_context_get_matrix (context);
+ pango_matrix_transform_rectangle (matrix, &logical);
+ }
+
+ pango_extents_to_pixels (&logical, NULL);
req_width = logical.width;
+ req_height = logical.height;
+
if (width != -1)
req_width = MIN(PANGO_PIXELS (width), req_width);
+
req_width += 2 * misc->xpad;
+ req_height += 2 * misc->ypad;
}
else
- req_width = widget->requisition.width;
+ {
+ req_width = widget->requisition.width;
+ req_height = widget->requisition.height;
+ }
x = floor (widget->allocation.x + (gint)misc->xpad +
- xalign * (widget->allocation.width - req_width));
+ xalign * (widget->allocation.width - req_width));
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
x = MAX (x, widget->allocation.x + misc->xpad);
else
x = MIN (x, widget->allocation.x + widget->allocation.width - misc->xpad);
- y = floor (widget->allocation.y + (gint)misc->ypad
- + MAX (((widget->allocation.height - widget->requisition.height) * misc->yalign),
- 0));
+ y = floor (widget->allocation.y + (gint)misc->ypad +
+ misc->yalign * (widget->allocation.height - req_height));
if (xp)
*xp = x;
@@ -3676,6 +3767,32 @@ gtk_label_set_use_underline (GtkLabel *label,
gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
}
+gboolean
+gtk_label_get_full_size (GtkLabel *label)
+{
+ g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
+ return GTK_LABEL_GET_PRIVATE (label)->full_size;
+}
+
+void
+gtk_label_set_full_size (GtkLabel *label,
+ gboolean setting)
+{
+ GtkLabelPrivate *priv;
+
+ g_return_if_fail (GTK_IS_LABEL (label));
+ priv = GTK_LABEL_GET_PRIVATE (label);
+
+ if (priv->full_size != setting)
+ {
+ priv->full_size = setting;
+
+ g_object_notify (G_OBJECT (label), "full-size");
+ gtk_label_invalidate_wrap_width (label);
+ gtk_widget_queue_resize (GTK_WIDGET (label));
+ }
+}
+
/**
* gtk_label_get_use_underline:
* @label: a #GtkLabel
diff --git a/gtk/gtklabel.h b/gtk/gtklabel.h
index 5656ebb..ac90f1d 100644
--- a/gtk/gtklabel.h
+++ b/gtk/gtklabel.h
@@ -119,6 +119,9 @@ gboolean gtk_label_get_use_markup (GtkLabel *label);
void gtk_label_set_use_underline (GtkLabel *label,
gboolean setting);
gboolean gtk_label_get_use_underline (GtkLabel *label);
+void gtk_label_set_full_size (GtkLabel *label,
+ gboolean setting);
+gboolean gtk_label_get_full_size (GtkLabel *label);
void gtk_label_set_markup_with_mnemonic (GtkLabel *label,
const gchar *str);
diff --git a/tests/testellipsise.c b/tests/testellipsise.c
index 0783d61..157884a 100644
--- a/tests/testellipsise.c
+++ b/tests/testellipsise.c
@@ -26,6 +26,21 @@
#include <gtk/gtk.h>
static void
+redraw_event_box (GtkWidget *widget)
+{
+ while (widget)
+ {
+ if (GTK_IS_EVENT_BOX (widget))
+ {
+ gtk_widget_queue_draw (widget);
+ break;
+ }
+
+ widget = gtk_widget_get_parent (widget);
+ }
+}
+
+static void
combo_changed_cb (GtkWidget *combo,
gpointer data)
{
@@ -33,33 +48,114 @@ combo_changed_cb (GtkWidget *combo,
gint active;
active = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
-
gtk_label_set_ellipsize (GTK_LABEL (label), (PangoEllipsizeMode)active);
+ redraw_event_box (label);
+}
+
+static void
+scale_changed_cb (GtkRange *range,
+ gpointer data)
+{
+ double angle = gtk_range_get_value (range);
+ GtkWidget *label = GTK_WIDGET (data);
+
+ gtk_label_set_angle (GTK_LABEL (label), angle);
+ redraw_event_box (label);
+}
+
+static gboolean
+ebox_expose_event_cb (GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer data)
+{
+ PangoLayout *layout;
+ const double dashes[] = { 6, 18 };
+ GtkWidget *label = data;
+ gint x, y, dx, dy;
+ cairo_t *cr;
+
+ gtk_widget_translate_coordinates (label, widget, 0, 0, &x, &y);
+
+ cr = gdk_cairo_create (widget->window);
+ cairo_translate (cr, -0.5, -0.5);
+ cairo_set_line_width (cr, 1);
+
+ cairo_rectangle (cr,
+ x + 0.5 * (label->allocation.width - label->requisition.width),
+ y + 0.5 * (label->allocation.height - label->requisition.height),
+ label->requisition.width, label->requisition.height);
+ cairo_set_source_rgb (cr, 0.8, 0.2, 0.2);
+ cairo_set_dash (cr, NULL, 0, 0);
+ cairo_stroke (cr);
+
+ cairo_rectangle (cr, x, y, label->allocation.width, label->allocation.height);
+ cairo_set_source_rgb (cr, 0.2, 0.2, 0.8);
+ cairo_set_dash (cr, dashes, 2, 0.5);
+ cairo_stroke (cr);
+
+ layout = gtk_widget_create_pango_layout (widget, NULL);
+
+ pango_layout_set_markup (layout,
+ "<span color='#c33'>\342\200\242 requisition</span>\n"
+ "<span color='#33c'>\342\200\242 allocation</span>", -1);
+
+ pango_layout_get_pixel_size (layout, &dx, &dy);
+
+ cairo_set_source_rgba (cr, 1, 1, 1, 0.8);
+ cairo_rectangle (cr, 0, 0, dx + 12, dy + 8);
+ cairo_fill (cr);
+
+ cairo_translate (cr, 6, 4);
+ pango_cairo_show_layout (cr, layout);
+
+ g_object_unref (layout);
+ cairo_destroy (cr);
+
+ return FALSE;
}
int
main (int argc, char *argv[])
{
- GtkWidget *window, *vbox, *hbox, *label, *combo;
+ GtkWidget *window, *vbox, *label;
+ GtkWidget *combo, *scale, *align, *ebox;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_container_set_border_width (GTK_CONTAINER (window), 12);
+ gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
- vbox = gtk_vbox_new (0, FALSE);
+
+ vbox = gtk_vbox_new (FALSE, 6);
gtk_container_add (GTK_CONTAINER (window), vbox);
- hbox = gtk_hbox_new (0, FALSE);
- gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
- label = gtk_label_new ("This label may be ellipsized\nto make it fit.");
- gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+
combo = gtk_combo_box_new_text ();
+ scale = gtk_hscale_new_with_range (0, 360, 1);
+ label = gtk_label_new ("This label may be ellipsized\nto make it fit.");
+
gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "NONE");
gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "START");
gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "MIDDLE");
gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "END");
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
- gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
+
+ align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
+ gtk_container_add (GTK_CONTAINER (align), label);
+
+ ebox = gtk_event_box_new ();
+ gtk_widget_set_app_paintable (ebox, TRUE);
+ gtk_container_add (GTK_CONTAINER (ebox), align);
+
+ gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), ebox, TRUE, TRUE, 0);
+
+ g_object_set_data (G_OBJECT (label), "combo", combo);
+
g_signal_connect (combo, "changed", G_CALLBACK (combo_changed_cb), label);
+ g_signal_connect (scale, "value-changed", G_CALLBACK (scale_changed_cb), label);
+ g_signal_connect_after (ebox, "expose-event", G_CALLBACK (ebox_expose_event_cb), label);
gtk_widget_show_all (window);
--
1.5.3.7
>From 7012c88d5c645b45277d75c873fffb12af4a71cc Mon Sep 17 00:00:00 2001
From: Mathias Hasselmann <mathias openismus com>
Date: Sat, 5 Jan 2008 11:37:48 +0100
Subject: Merge nearly identical size-allocation loops for start and end packing.
* gtk/gtkhbox.c: Merge loops in gtk_hbox_size_allocate.
---
ChangeLog | 6 ++
gtk/gtkhbox.c | 174 +++++++++++++++++++++------------------------------------
2 files changed, 69 insertions(+), 111 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index fb5f18d..aebf3c5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
2008-01-02 Mathias Hasselmann <mathias openismus com>
+ Merge nearly identical size-allocation loops for start and end packing.
+
+ * gtk/gtkhbox.c: Merge loops in gtk_hbox_size_allocate.
+
+2008-01-02 Mathias Hasselmann <mathias openismus com>
+
* tests/testellipsise.c: Extend the test to support rotations.
* gtk/gtklabel.c: Support ellipsizing and wrapping on labels
rotated by multiples of 90°.
diff --git a/gtk/gtkhbox.c b/gtk/gtkhbox.c
index 3140cac..c949251 100644
--- a/gtk/gtkhbox.c
+++ b/gtk/gtkhbox.c
@@ -138,6 +138,7 @@ gtk_hbox_size_allocate (GtkWidget *widget,
gint extra;
gint x;
GtkTextDirection direction;
+ GtkPackType packing;
box = GTK_BOX (widget);
widget->allocation = *allocation;
@@ -163,10 +164,11 @@ gtk_hbox_size_allocate (GtkWidget *widget,
if (nvis_children > 0)
{
+ gint border_width = GTK_CONTAINER (box)->border_width;
+
if (box->homogeneous)
{
- width = (allocation->width -
- GTK_CONTAINER (box)->border_width * 2 -
+ width = (allocation->width - border_width * 2 -
(nvis_children - 1) * box->spacing);
extra = width / nvis_children;
}
@@ -181,129 +183,79 @@ gtk_hbox_size_allocate (GtkWidget *widget,
extra = 0;
}
- x = allocation->x + GTK_CONTAINER (box)->border_width;
- 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);
-
- children = box->children;
- while (children)
- {
- child = children->data;
- children = children->next;
-
- if ((child->pack == GTK_PACK_START) && GTK_WIDGET_VISIBLE (child->widget))
- {
- if (box->homogeneous)
- {
- if (nvis_children == 1)
- child_width = width;
- else
- child_width = extra;
-
- nvis_children -= 1;
- width -= extra;
- }
- else
- {
- GtkRequisition child_requisition;
-
- gtk_widget_get_child_requisition (child->widget, &child_requisition);
-
- child_width = child_requisition.width + child->padding * 2;
-
- if (child->expand)
- {
- if (nexpand_children == 1)
- child_width += width;
- else
- child_width += extra;
-
- nexpand_children -= 1;
- width -= extra;
- }
- }
-
- if (child->fill)
- {
- child_allocation.width = MAX (1, (gint) child_width - (gint) child->padding * 2);
- child_allocation.x = x + child->padding;
- }
- else
- {
- GtkRequisition child_requisition;
-
- gtk_widget_get_child_requisition (child->widget, &child_requisition);
- child_allocation.width = child_requisition.width;
- child_allocation.x = x + (child_width - child_allocation.width) / 2;
- }
-
- if (direction == GTK_TEXT_DIR_RTL)
- child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
-
- gtk_widget_size_allocate (child->widget, &child_allocation);
-
- x += child_width + box->spacing;
- }
- }
-
- x = allocation->x + allocation->width - GTK_CONTAINER (box)->border_width;
+ child_allocation.y = allocation->y + border_width;
+ child_allocation.height = MAX (1, allocation->height - border_width * 2);
- children = box->children;
- while (children)
- {
- child = children->data;
- children = children->next;
-
- if ((child->pack == GTK_PACK_END) && GTK_WIDGET_VISIBLE (child->widget))
- {
- GtkRequisition child_requisition;
- gtk_widget_get_child_requisition (child->widget, &child_requisition);
+ for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing)
+ {
+ if (GTK_PACK_START == packing)
+ x = allocation->x + GTK_CONTAINER (box)->border_width;
+ else
+ x = allocation->x + allocation->width - border_width;;
- if (box->homogeneous)
- {
- if (nvis_children == 1)
- child_width = width;
- else
- child_width = extra;
+ children = box->children;
+ while (children)
+ {
+ child = children->data;
+ children = children->next;
- nvis_children -= 1;
- width -= extra;
- }
- else
+ if ((child->pack == packing) && GTK_WIDGET_VISIBLE (child->widget))
{
- child_width = child_requisition.width + child->padding * 2;
+ GtkRequisition child_requisition;
+ gtk_widget_get_child_requisition (child->widget, &child_requisition);
- if (child->expand)
+ if (box->homogeneous)
{
- if (nexpand_children == 1)
- child_width += width;
+ if (nvis_children == 1)
+ child_width = width;
else
- child_width += extra;
+ child_width = extra;
- nexpand_children -= 1;
+ nvis_children -= 1;
width -= extra;
}
- }
+ else
+ {
+ child_width = child_requisition.width + child->padding * 2;
+
+ if (child->expand)
+ {
+ if (nexpand_children == 1)
+ child_width += width;
+ else
+ child_width += extra;
+
+ nexpand_children -= 1;
+ width -= extra;
+ }
+ }
- if (child->fill)
- {
- child_allocation.width = MAX (1, (gint)child_width - (gint)child->padding * 2);
- child_allocation.x = x + child->padding - child_width;
- }
- else
- {
- child_allocation.width = child_requisition.width;
- child_allocation.x = x + (child_width - child_allocation.width) / 2 - child_width;
- }
+ if (child->fill)
+ {
+ child_allocation.width = MAX (1, (gint) child_width - (gint) child->padding * 2);
+ child_allocation.x = x + child->padding;
+ }
+ else
+ {
+ child_allocation.width = child_requisition.width;
+ child_allocation.x = x + (child_width - child_allocation.width) / 2;
+ }
- if (direction == GTK_TEXT_DIR_RTL)
- child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
+ if (GTK_PACK_END == packing)
+ child_allocation.x -= child_width;
- gtk_widget_size_allocate (child->widget, &child_allocation);
+ if (direction == GTK_TEXT_DIR_RTL)
+ child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
- x -= (child_width + box->spacing);
- }
- }
+ gtk_widget_size_allocate (child->widget, &child_allocation);
+
+ if (GTK_PACK_START == packing)
+ x += child_width + box->spacing;
+ else
+ x -= child_width + box->spacing;
+ }
+ }
+ }
}
}
--
1.5.3.7
>From 8c04efe87e1d3c7e43e0f89b1762255598b34639 Mon Sep 17 00:00:00 2001
From: Mathias Hasselmann <mathias openismus com>
Date: Tue, 8 Jan 2008 19:05:49 +0100
Subject: Introduce GtkExtendedLayout interface.
---
ChangeLog | 4 +
gtk/Makefile.am | 2 +
gtk/gtk.h | 1 +
gtk/gtk.symbols | 12 ++
gtk/gtkalignment.c | 14 ++-
gtk/gtkextendedlayout.c | 146 +++++++++++++++++++++++++++
gtk/gtkextendedlayout.h | 74 ++++++++++++++
gtk/gtkhbox.c | 235 ++++++++++++++++++++++++++++++++-----------
gtk/gtklabel.c | 239 ++++++++++++++++++++++++++++++++++----------
gtk/gtksizegroup.c | 221 ++++++++++++++++++++++++++++------------
gtk/gtksizegroup.h | 5 +-
gtk/gtkwidget.c | 124 +++++++++++++++++++++--
gtk/gtkwidget.h | 14 +++
tests/Makefile.am | 5 +-
tests/testellipsise.c | 29 +++++-
tests/testextendedlayout.c | 120 ++++++++++++++++++++++
16 files changed, 1049 insertions(+), 196 deletions(-)
create mode 100644 gtk/gtkextendedlayout.c
create mode 100644 gtk/gtkextendedlayout.h
create mode 100644 tests/testextendedlayout.c
diff --git a/ChangeLog b/ChangeLog
index aebf3c5..c299a61 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2008-01-03 Mathias Hasselmann <mathias openismus com>
+
+ Introduce GtkExtendedLayout interface.
+
2008-01-02 Mathias Hasselmann <mathias openismus com>
Merge nearly identical size-allocation loops for start and end packing.
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 5a19467..d614794 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -183,6 +183,7 @@ gtk_public_h_sources = \
gtkenums.h \
gtkeventbox.h \
gtkexpander.h \
+ gtkextendedlayout.h \
gtkfilechooser.h \
gtkfilechooserbutton.h \
gtkfilechooserdialog.h \
@@ -447,6 +448,7 @@ gtk_base_c_sources = \
gtkentrycompletion.c \
gtkeventbox.c \
gtkexpander.c \
+ gtkextendedlayout.c \
gtkfilechooser.c \
gtkfilechooserbutton.c \
gtkfilechooserdefault.c \
diff --git a/gtk/gtk.h b/gtk/gtk.h
index 0ce693c..36670bb 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -81,6 +81,7 @@
#include <gtk/gtkenums.h>
#include <gtk/gtkeventbox.h>
#include <gtk/gtkexpander.h>
+#include <gtk/gtkextendedlayout.h>
#include <gtk/gtkfilesel.h>
#include <gtk/gtkfixed.h>
#include <gtk/gtkfilechooserbutton.h>
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index e353959..2a00927 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -1326,6 +1326,15 @@ gtk_expander_set_use_underline
#endif
#endif
+#if IN_HEADER(__GTK_EXTENDED_LAYOUT_H__)
+#if IN_FILE(__GTK_EXTENDED_LAYOUT_C__)
+gtk_extended_layout_get_type G_GNUC_CONST
+gtk_extended_layout_get_desired_size
+gtk_extended_layout_get_height_for_width
+gtk_extended_layout_get_width_for_height
+#endif
+#endif
+
#if IN_HEADER(__GTK_FILE_CHOOSER_H__)
#if IN_FILE(__GTK_FILE_CHOOSER_C__)
gtk_file_chooser_add_filter
@@ -4793,6 +4802,9 @@ gtk_widget_show_all
gtk_widget_show_now
gtk_widget_size_allocate
gtk_widget_size_request
+gtk_widget_get_desired_size
+gtk_widget_get_height_for_width
+gtk_widget_get_width_for_height
gtk_widget_style_get G_GNUC_NULL_TERMINATED
gtk_widget_style_get_property
gtk_widget_style_get_valist
diff --git a/gtk/gtkalignment.c b/gtk/gtkalignment.c
index 5f852d0..9e2b70c 100644
--- a/gtk/gtkalignment.c
+++ b/gtk/gtkalignment.c
@@ -26,6 +26,7 @@
#include <config.h>
#include "gtkalignment.h"
+#include "gtkextendedlayout.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include "gtkalias.h"
@@ -460,7 +461,9 @@ gtk_alignment_size_allocate (GtkWidget *widget,
if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
{
- gtk_widget_get_child_requisition (bin->child, &child_requisition);
+ GtkExtendedLayout *layout = GTK_EXTENDED_LAYOUT (bin->child);
+
+ gtk_extended_layout_get_desired_size (layout, NULL, &child_requisition);
border_width = GTK_CONTAINER (alignment)->border_width;
@@ -470,7 +473,14 @@ gtk_alignment_size_allocate (GtkWidget *widget,
width = allocation->width - padding_horizontal - 2 * border_width;
height = allocation->height - padding_vertical - 2 * border_width;
-
+
+ if (child_requisition.width > width)
+ gtk_extended_layout_get_height_for_width (layout, width, NULL,
+ &child_requisition.height);
+ else if (child_requisition.height > height)
+ gtk_extended_layout_get_width_for_height (layout, height, NULL,
+ &child_requisition.width);
+
if (width > child_requisition.width)
child_allocation.width = (child_requisition.width *
(1.0 - alignment->xscale) +
diff --git a/gtk/gtkextendedlayout.c b/gtk/gtkextendedlayout.c
new file mode 100644
index 0000000..b9d35c7
--- /dev/null
+++ b/gtk/gtkextendedlayout.c
@@ -0,0 +1,146 @@
+/* gtkextendedlayout.c
+ * Copyright (C) 2007 Openismus GmbH
+ *
+ * Author:
+ * Mathias Hasselmann <mathias openismus com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include <config.h>
+#include "gtkextendedlayout.h"
+#include "gtkintl.h"
+#include "gtkalias.h"
+
+GType
+gtk_extended_layout_get_type (void)
+{
+ static GType extended_layout_type = 0;
+
+ if (G_UNLIKELY(!extended_layout_type))
+ extended_layout_type =
+ g_type_register_static_simple (G_TYPE_INTERFACE, I_("GtkExtendedLayout"),
+ sizeof (GtkExtendedLayoutIface),
+ NULL, 0, NULL, 0);
+
+ return extended_layout_type;
+}
+
+/**
+ * gtk_extended_layout_get_desired_size:
+ * @layout: a #GtkExtendedLayout instance
+ * @minimum_size: location for storing the minimum size, or %NULL
+ * @natural_size: location for storing the preferred size, or %NULL
+ *
+ * Retreives an extended layout item's desired size.
+ *
+ * Since: 2.16
+ */
+void
+gtk_extended_layout_get_desired_size (GtkExtendedLayout *layout,
+ GtkRequisition *minimum_size,
+ GtkRequisition *natural_size)
+{
+ GtkExtendedLayoutIface *iface;
+
+ g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (layout));
+ g_return_if_fail (NULL != minimum_size || NULL != natural_size);
+
+ iface = GTK_EXTENDED_LAYOUT_GET_IFACE (layout);
+ iface->get_desired_size (layout, minimum_size, natural_size);
+}
+
+/**
+ * gtk_extended_layout_get_width_for_height:
+ * @layout: a #GtkExtendedLayout instance
+ * @height: the size which is available for allocation
+ * @minimum_size: location for storing the minimum size, or %NULL
+ * @natural_size: location for storing the preferred size, or %NULL
+ *
+ * Retreives an extended layout item's desired width if it would given
+ * the size specified in @height.
+ *
+ * Since: 2.16
+ */
+void
+gtk_extended_layout_get_width_for_height (GtkExtendedLayout *layout,
+ gint height,
+ gint *minimum_width,
+ gint *natural_width)
+{
+ GtkExtendedLayoutIface *iface;
+
+ g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (layout));
+ iface = GTK_EXTENDED_LAYOUT_GET_IFACE (layout);
+
+ if (iface->get_width_for_height)
+ iface->get_width_for_height (layout, height, minimum_width, natural_width);
+ else
+ {
+ GtkRequisition minimum_size;
+ GtkRequisition natural_size;
+
+ iface->get_desired_size (layout, &minimum_size, &natural_size);
+
+ if (minimum_width)
+ *minimum_width = minimum_size.width;
+ if (natural_width)
+ *natural_width = natural_size.width;
+ }
+}
+
+/**
+ * gtk_extended_layout_get_height_for_width:
+ * @layout: a #GtkExtendedLayout instance
+ * @width: the size which is available for allocation
+ * @minimum_size: location for storing the minimum size, or %NULL
+ * @natural_size: location for storing the preferred size, or %NULL
+ *
+ * Retreives an extended layout item's desired height if it would given
+ * the size specified in @width.
+ *
+ * Since: 2.16
+ */
+void
+gtk_extended_layout_get_height_for_width (GtkExtendedLayout *layout,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height)
+{
+ GtkExtendedLayoutIface *iface;
+
+ g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (layout));
+ iface = GTK_EXTENDED_LAYOUT_GET_IFACE (layout);
+
+ if (iface->get_height_for_width)
+ iface->get_height_for_width (layout, width, minimum_height, natural_height);
+ else
+ {
+ GtkRequisition minimum_size;
+ GtkRequisition natural_size;
+
+ iface->get_desired_size (layout, &minimum_size, &natural_size);
+
+ if (minimum_height)
+ *minimum_height = minimum_size.height;
+ if (natural_height)
+ *natural_height = natural_size.height;
+ }
+}
+
+#define __GTK_EXTENDED_LAYOUT_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkextendedlayout.h b/gtk/gtkextendedlayout.h
new file mode 100644
index 0000000..9944fed
--- /dev/null
+++ b/gtk/gtkextendedlayout.h
@@ -0,0 +1,74 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2007 Openismus GmbH
+ *
+ * Author:
+ * Mathias Hasselmann <mathias openismus com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_EXTENDED_LAYOUT_H__
+#define __GTK_EXTENDED_LAYOUT_H__
+
+#include <gtk/gtkwidget.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_EXTENDED_LAYOUT (gtk_extended_layout_get_type ())
+#define GTK_EXTENDED_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_EXTENDED_LAYOUT, GtkExtendedLayout))
+#define GTK_EXTENDED_LAYOUT_CLASS(klass) ((GtkExtendedLayoutIface*)g_type_interface_peek ((klass), GTK_TYPE_EXTENDED_LAYOUT))
+#define GTK_IS_EXTENDED_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_EXTENDED_LAYOUT))
+#define GTK_EXTENDED_LAYOUT_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GTK_TYPE_EXTENDED_LAYOUT, GtkExtendedLayoutIface))
+
+typedef struct _GtkExtendedLayout GtkExtendedLayout;
+typedef struct _GtkExtendedLayoutIface GtkExtendedLayoutIface;
+
+struct _GtkExtendedLayoutIface
+{
+ GTypeInterface g_iface;
+
+ /* virtual table */
+
+ void (*get_desired_size) (GtkExtendedLayout *layout,
+ GtkRequisition *minimum_size,
+ GtkRequisition *natural_size);
+ void (*get_width_for_height) (GtkExtendedLayout *layout,
+ gint height,
+ gint *minimum_width,
+ gint *natural_width);
+ void (*get_height_for_width) (GtkExtendedLayout *layout,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height);
+};
+
+GType gtk_extended_layout_get_type (void) G_GNUC_CONST;
+
+void gtk_extended_layout_get_desired_size (GtkExtendedLayout *layout,
+ GtkRequisition *minimum_size,
+ GtkRequisition *natural_size);
+void gtk_extended_layout_get_width_for_height (GtkExtendedLayout *layout,
+ gint height,
+ gint *minimum_width,
+ gint *natural_width);
+void gtk_extended_layout_get_height_for_width (GtkExtendedLayout *layout,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height);
+
+G_END_DECLS
+
+#endif /* __GTK_EXTENDED_LAYOUT_H__ */
diff --git a/gtk/gtkhbox.c b/gtk/gtkhbox.c
index c949251..bb5d199 100644
--- a/gtk/gtkhbox.c
+++ b/gtk/gtkhbox.c
@@ -26,18 +26,36 @@
#include <config.h>
#include "gtkhbox.h"
+#include "gtkextendedlayout.h"
#include "gtkintl.h"
#include "gtkalias.h"
+typedef struct _GtkBoxDesiredSizes GtkBoxDesiredSizes;
+typedef struct _GtkBoxSpreading GtkBoxSpreading;
-static void gtk_hbox_size_request (GtkWidget *widget,
- GtkRequisition *requisition);
-static void gtk_hbox_size_allocate (GtkWidget *widget,
- GtkAllocation *allocation);
+struct _GtkBoxDesiredSizes
+{
+ gint minimum_size;
+ gint natural_size;
+};
+struct _GtkBoxSpreading
+{
+ GtkBoxChild *child;
+ gint index;
+};
-G_DEFINE_TYPE (GtkHBox, gtk_hbox, GTK_TYPE_BOX)
+static void gtk_hbox_get_desired_size (GtkExtendedLayout *layout,
+ GtkRequisition *minimum_size,
+ GtkRequisition *natural_size);
+static void gtk_hbox_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+static void gtk_hbox_layout_interface_init (GtkExtendedLayoutIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GtkHBox, gtk_hbox, GTK_TYPE_BOX,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
+ gtk_hbox_layout_interface_init))
static void
gtk_hbox_class_init (GtkHBoxClass *class)
{
@@ -45,11 +63,16 @@ gtk_hbox_class_init (GtkHBoxClass *class)
widget_class = (GtkWidgetClass*) class;
- widget_class->size_request = gtk_hbox_size_request;
widget_class->size_allocate = gtk_hbox_size_allocate;
}
static void
+gtk_hbox_layout_interface_init (GtkExtendedLayoutIface *iface)
+{
+ iface->get_desired_size = gtk_hbox_get_desired_size;
+}
+
+static void
gtk_hbox_init (GtkHBox *hbox)
{
}
@@ -70,57 +93,103 @@ gtk_hbox_new (gboolean homogeneous,
static void
-gtk_hbox_size_request (GtkWidget *widget,
- GtkRequisition *requisition)
+gtk_hbox_get_desired_size (GtkExtendedLayout *layout,
+ GtkRequisition *minimum_size,
+ GtkRequisition *natural_size)
{
GtkBox *box;
- GtkBoxChild *child;
GList *children;
gint nvis_children;
- gint width;
+ gint border_width;
- box = GTK_BOX (widget);
- requisition->width = 0;
- requisition->height = 0;
- nvis_children = 0;
+ box = GTK_BOX (layout);
+ border_width = GTK_CONTAINER (box)->border_width;
+
+ minimum_size->width = minimum_size->height = 0;
+ natural_size->width = natural_size->height = 0;
+ nvis_children = 0;
children = box->children;
while (children)
{
+ GtkBoxChild *child;
+
child = children->data;
children = children->next;
if (GTK_WIDGET_VISIBLE (child->widget))
- {
- GtkRequisition child_requisition;
+ {
+ GtkRequisition child_minimum_size;
+ GtkRequisition child_natural_size;
- gtk_widget_size_request (child->widget, &child_requisition);
+ gtk_widget_get_desired_size (child->widget,
+ &child_minimum_size,
+ &child_natural_size);
- if (box->homogeneous)
- {
- width = child_requisition.width + child->padding * 2;
- requisition->width = MAX (requisition->width, width);
- }
- else
- {
- requisition->width += child_requisition.width + child->padding * 2;
- }
+ if (box->homogeneous)
+ {
+ gint width;
- requisition->height = MAX (requisition->height, child_requisition.height);
+ width = child_minimum_size.width + child->padding * 2;
+ minimum_size->width = MAX (minimum_size->width, width);
- nvis_children += 1;
- }
+ width = child_natural_size.width + child->padding * 2;
+ natural_size->width = MAX (natural_size->width, width);
+ }
+ else
+ {
+ minimum_size->width += child_minimum_size.width + child->padding * 2;
+ natural_size->width += child_natural_size.width + child->padding * 2;
+ }
+
+ minimum_size->height = MAX (minimum_size->height, child_minimum_size.height);
+ natural_size->height = MAX (natural_size->height, child_natural_size.height);
+
+ nvis_children += 1;
+ }
}
if (nvis_children > 0)
{
if (box->homogeneous)
- requisition->width *= nvis_children;
- requisition->width += (nvis_children - 1) * box->spacing;
+ {
+ minimum_size->width *= nvis_children;
+ natural_size->width *= nvis_children;
+ }
+
+ minimum_size->width += (nvis_children - 1) * box->spacing;
+ natural_size->width += (nvis_children - 1) * box->spacing;
}
- requisition->width += GTK_CONTAINER (box)->border_width * 2;
- requisition->height += GTK_CONTAINER (box)->border_width * 2;
+ minimum_size->width += border_width * 2;
+ minimum_size->height += border_width * 2;
+
+ natural_size->width += border_width * 2;
+ natural_size->height += border_width * 2;
+}
+
+static gint
+gtk_vbox_compare_gap (gconstpointer p1,
+ gconstpointer p2,
+ gpointer data)
+{
+ GtkBoxDesiredSizes *sizes = data;
+ const GtkBoxSpreading *c1 = p1;
+ const GtkBoxSpreading *c2 = p2;
+
+ const gint d1 = MAX (sizes[c1->index].natural_size -
+ sizes[c1->index].minimum_size,
+ 0);
+ const gint d2 = MAX (sizes[c2->index].natural_size -
+ sizes[c2->index].minimum_size,
+ 0);
+
+ gint delta = (d1 - d2);
+
+ if (0 == delta)
+ delta = (c1->index - c2->index);
+
+ return delta;
}
static void
@@ -130,21 +199,12 @@ gtk_hbox_size_allocate (GtkWidget *widget,
GtkBox *box;
GtkBoxChild *child;
GList *children;
- GtkAllocation child_allocation;
gint nvis_children;
gint nexpand_children;
- gint child_width;
- gint width;
- gint extra;
- gint x;
- GtkTextDirection direction;
- GtkPackType packing;
box = GTK_BOX (widget);
widget->allocation = *allocation;
- direction = gtk_widget_get_direction (widget);
-
nvis_children = 0;
nexpand_children = 0;
children = box->children;
@@ -165,23 +225,78 @@ gtk_hbox_size_allocate (GtkWidget *widget,
if (nvis_children > 0)
{
gint border_width = GTK_CONTAINER (box)->border_width;
+ GtkTextDirection direction = gtk_widget_get_direction (widget);
+ GtkAllocation child_allocation;
+
+ GtkBoxSpreading *spreading = g_newa (GtkBoxSpreading, nvis_children);
+ GtkBoxDesiredSizes *sizes = g_newa (GtkBoxDesiredSizes, nvis_children);
+
+ GtkPackType packing;
+ gint child_width;
+
+ gint width;
+ gint extra;
+ gint x, i;
+
+ width = (allocation->width - border_width * 2 -
+ (nvis_children - 1) * box->spacing);
if (box->homogeneous)
{
- width = (allocation->width - border_width * 2 -
- (nvis_children - 1) * box->spacing);
extra = width / nvis_children;
}
- else if (nexpand_children > 0)
- {
- width = (gint) allocation->width - (gint) widget->requisition.width;
- extra = width / nexpand_children;
- }
else
- {
- width = 0;
- extra = 0;
- }
+ {
+ /* Retreive desired size for visible children */
+
+ for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing)
+ {
+ i = 0;
+ children = box->children;
+ while (children)
+ {
+ child = children->data;
+ children = children->next;
+
+ if (child->pack == packing && GTK_WIDGET_VISIBLE (child->widget))
+ {
+ gtk_widget_get_width_for_height (child->widget,
+ allocation->height,
+ &sizes[i].minimum_size,
+ &sizes[i].natural_size);
+
+ width -= sizes[i].minimum_size;
+
+ spreading[i].index = i;
+ spreading[i].child = child;
+
+ i += 1;
+ }
+ }
+ }
+
+ /* Sort children by difference between natural and minimum size */
+
+ g_qsort_with_data (spreading,
+ nvis_children, sizeof (GtkBoxSpreading),
+ gtk_vbox_compare_gap, sizes);
+
+ for (i = 0; width > 0 && i < nvis_children; ++i)
+ {
+ extra = sizes[spreading[i].index].natural_size
+ - sizes[spreading[i].index].minimum_size;
+
+ extra = MIN (width, extra);
+ width -= extra;
+
+ sizes[spreading[i].index].minimum_size += extra;
+ }
+
+ if (nexpand_children > 0)
+ extra = width / nexpand_children;
+ else
+ extra = 0;
+ }
child_allocation.y = allocation->y + border_width;
child_allocation.height = MAX (1, allocation->height - border_width * 2);
@@ -193,17 +308,17 @@ gtk_hbox_size_allocate (GtkWidget *widget,
else
x = allocation->x + allocation->width - border_width;;
+ /* Allocate child positions */
+
+ i = 0;
children = box->children;
while (children)
{
child = children->data;
children = children->next;
- if ((child->pack == packing) && GTK_WIDGET_VISIBLE (child->widget))
+ if (child->pack == packing && GTK_WIDGET_VISIBLE (child->widget))
{
- GtkRequisition child_requisition;
- gtk_widget_get_child_requisition (child->widget, &child_requisition);
-
if (box->homogeneous)
{
if (nvis_children == 1)
@@ -216,7 +331,7 @@ gtk_hbox_size_allocate (GtkWidget *widget,
}
else
{
- child_width = child_requisition.width + child->padding * 2;
+ child_width = sizes[i].minimum_size + child->padding * 2;
if (child->expand)
{
@@ -237,7 +352,7 @@ gtk_hbox_size_allocate (GtkWidget *widget,
}
else
{
- child_allocation.width = child_requisition.width;
+ child_allocation.width = sizes[i].minimum_size;
child_allocation.x = x + (child_width - child_allocation.width) / 2;
}
@@ -253,6 +368,8 @@ gtk_hbox_size_allocate (GtkWidget *widget,
x += child_width + box->spacing;
else
x -= child_width + box->spacing;
+
+ i += 1;
}
}
}
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index b3fe927..4f73664 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -43,6 +43,7 @@
#include "gtknotebook.h"
#include "gtkstock.h"
#include "gtkbindings.h"
+#include "gtkextendedlayout.h"
#include "gtkprivate.h"
#include "gtkalias.h"
@@ -67,7 +68,7 @@ struct _GtkLabelSelectionInfo
gint selection_anchor;
gint selection_end;
GtkWidget *popup_menu;
-
+
gint drag_start_x;
gint drag_start_y;
@@ -116,8 +117,6 @@ static void gtk_label_get_property (GObject *object,
GParamSpec *pspec);
static void gtk_label_destroy (GtkObject *object);
static void gtk_label_finalize (GObject *object);
-static void gtk_label_size_request (GtkWidget *widget,
- GtkRequisition *requisition);
static void gtk_label_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static void gtk_label_state_changed (GtkWidget *widget,
@@ -201,10 +200,25 @@ static gint gtk_label_move_forward_word (GtkLabel *label,
static gint gtk_label_move_backward_word (GtkLabel *label,
gint start);
-static GQuark quark_angle = 0;
+static void gtk_label_layout_interface_init (GtkExtendedLayoutIface *iface);
-G_DEFINE_TYPE (GtkLabel, gtk_label, GTK_TYPE_MISC)
+static void gtk_label_get_desired_size (GtkExtendedLayout *layout,
+ GtkRequisition *minimum_size,
+ GtkRequisition *natural_size);
+static void gtk_label_get_width_for_height (GtkExtendedLayout *layout,
+ gint height,
+ gint *minimum_width,
+ gint *natural_width);
+static void gtk_label_get_height_for_width (GtkExtendedLayout *layout,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height);
+static GQuark quark_angle = 0;
+
+G_DEFINE_TYPE_WITH_CODE (GtkLabel, gtk_label, GTK_TYPE_MISC,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
+ gtk_label_layout_interface_init))
static void
add_move_binding (GtkBindingSet *binding_set,
guint keyval,
@@ -229,6 +243,14 @@ add_move_binding (GtkBindingSet *binding_set,
}
static void
+gtk_label_layout_interface_init (GtkExtendedLayoutIface *iface)
+{
+ iface->get_desired_size = gtk_label_get_desired_size;
+ iface->get_width_for_height = gtk_label_get_width_for_height;
+ iface->get_height_for_width = gtk_label_get_height_for_width;
+}
+
+static void
gtk_label_class_init (GtkLabelClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
@@ -243,8 +265,7 @@ gtk_label_class_init (GtkLabelClass *class)
gobject_class->finalize = gtk_label_finalize;
object_class->destroy = gtk_label_destroy;
-
- widget_class->size_request = gtk_label_size_request;
+
widget_class->size_allocate = gtk_label_size_allocate;
widget_class->state_changed = gtk_label_state_changed;
widget_class->style_set = gtk_label_style_set;
@@ -2161,23 +2182,35 @@ gtk_label_ensure_layout (GtkLabel *label)
}
}
+static gint
+get_single_line_height (GtkWidget *widget,
+ PangoLayout *layout)
+{
+ PangoContext *context;
+ PangoFontMetrics *metrics;
+ gint ascent, descent;
+
+ context = pango_layout_get_context (layout);
+ metrics = pango_context_get_metrics (context, widget->style->font_desc,
+ pango_context_get_language (context));
+
+ ascent = pango_font_metrics_get_ascent (metrics);
+ descent = pango_font_metrics_get_descent (metrics);
+ pango_font_metrics_unref (metrics);
+
+ return PANGO_PIXELS (ascent + descent);
+}
+
static void
-gtk_label_size_request (GtkWidget *widget,
- GtkRequisition *requisition)
+gtk_label_get_desired_size (GtkExtendedLayout *layout,
+ GtkRequisition *minimum_size,
+ GtkRequisition *natural_size)
{
- GtkLabel *label;
- GtkLabelPrivate *priv;
- PangoRectangle logical_rect;
+ GtkLabelPrivate *priv = GTK_LABEL_GET_PRIVATE (layout);
+ GtkLabel *label = GTK_LABEL (layout);
PangoRectangle required_rect;
- GtkWidgetAuxInfo *aux_info;
-
- g_return_if_fail (GTK_IS_LABEL (widget));
- g_return_if_fail (requisition != NULL);
-
- label = GTK_LABEL (widget);
- priv = GTK_LABEL_GET_PRIVATE (widget);
- /*
+ /*
* If word wrapping is on, then the height requisition can depend
* on:
*
@@ -2195,50 +2228,152 @@ gtk_label_size_request (GtkWidget *widget,
gtk_label_ensure_layout (label);
- aux_info = _gtk_widget_get_aux_info (widget, FALSE);
+ if (minimum_size)
+ {
+ GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (GTK_WIDGET (label), FALSE);
- pango_layout_get_extents (label->layout, NULL, &logical_rect);
- required_rect.x = required_rect.y = 0;
+ pango_layout_get_extents (label->layout, NULL, &required_rect);
+ required_rect.x = required_rect.y = 0;
- if ((label->wrap || label->ellipsize ||
- priv->width_chars > 0 || priv->max_width_chars > 0) &&
- aux_info && aux_info->width > 0)
- required_rect.width = aux_info->width;
- else if (label->ellipsize || priv->width_chars > 0 || priv->max_width_chars > 0)
- {
- required_rect.width = PANGO_PIXELS (get_label_char_width (label));
+ if (label->ellipsize || priv->width_chars > 0 || priv->max_width_chars > 0)
+ {
+ /* backup the Pango layout, as get_label_char_width() scrambles it */
+
+ PangoLayout *backup = label->layout;
+ label->layout = pango_layout_copy (label->layout);
+
+ required_rect.width = get_label_char_width (label);
+
+ g_object_unref (label->layout);
+ label->layout = backup;
+ }
+
+ if (label->single_line_mode)
+ required_rect.height = get_single_line_height (GTK_WIDGET (label), label->layout);
+
+ if (label->have_transform)
+ {
+ PangoContext *context = pango_layout_get_context (label->layout);
+ const PangoMatrix *matrix = pango_context_get_matrix (context);
+ pango_matrix_transform_rectangle (matrix, &required_rect);
+ }
+
+ required_rect.width = PANGO_PIXELS_CEIL (required_rect.width);
+ required_rect.height = PANGO_PIXELS_CEIL (required_rect.height);
+
+ if ((label->wrap || label->ellipsize ||
+ priv->width_chars > 0 || priv->max_width_chars > 0) &&
+ aux_info && aux_info->width > 0)
+ required_rect.width = aux_info->width;
+
+ minimum_size->width = required_rect.width + label->misc.xpad * 2;
+ minimum_size->height = required_rect.height + label->misc.ypad * 2;
}
- else
- required_rect.width = PANGO_PIXELS (logical_rect.width);
- if (label->single_line_mode)
+ if (natural_size)
{
- PangoContext *context;
- PangoFontMetrics *metrics;
- gint ascent, descent;
+ PangoLayout *natural_layout = pango_layout_copy (label->layout);
- context = pango_layout_get_context (label->layout);
- metrics = pango_context_get_metrics (context, widget->style->font_desc,
- pango_context_get_language (context));
+ pango_layout_set_width (natural_layout, -1);
+ pango_layout_set_ellipsize (natural_layout, PANGO_ELLIPSIZE_NONE);
- ascent = pango_font_metrics_get_ascent (metrics);
- descent = pango_font_metrics_get_descent (metrics);
- pango_font_metrics_unref (metrics);
-
- required_rect.height = PANGO_PIXELS (ascent + descent);
+ pango_layout_get_extents (natural_layout, NULL, &required_rect);
+ required_rect.x = required_rect.y = 0;
+
+ if (label->single_line_mode)
+ required_rect.height = get_single_line_height (GTK_WIDGET (label), label->layout);
+
+ if (label->have_transform)
+ {
+ PangoContext *context = pango_layout_get_context (natural_layout);
+ const PangoMatrix *matrix = pango_context_get_matrix (context);
+ pango_matrix_transform_rectangle (matrix, &required_rect);
+ }
+
+ required_rect.width = PANGO_PIXELS_CEIL (required_rect.width);
+ required_rect.height = PANGO_PIXELS_CEIL (required_rect.height);
+
+ natural_size->width = required_rect.width + label->misc.xpad * 2;
+ natural_size->height = required_rect.height + label->misc.ypad * 2;
+
+ g_object_unref (natural_layout);
}
- else
- required_rect.height = PANGO_PIXELS (logical_rect.height);
+}
+
+static void
+get_size_for_allocation (GtkLabel *label,
+ gint allocation,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ PangoLayout *layout;
+
+ gtk_label_ensure_layout (label);
+ layout = pango_layout_copy (label->layout);
+ pango_layout_set_width (layout, PANGO_SCALE * allocation);
- if (label->have_transform)
+ if (minimum_size)
+ pango_layout_get_pixel_size (layout, NULL, minimum_size);
+
+ if (natural_size)
{
- PangoContext *context = pango_layout_get_context (label->layout);
- const PangoMatrix *matrix = pango_context_get_matrix (context);
- pango_matrix_transform_pixel_rectangle (matrix, &required_rect);
+// pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE);
+ pango_layout_get_pixel_size (layout, NULL, natural_size);
}
- requisition->width = required_rect.width + label->misc.xpad * 2;
- requisition->height = required_rect.height + label->misc.ypad * 2;
+ g_object_unref (layout);
+}
+
+static void
+gtk_label_get_width_for_height (GtkExtendedLayout *layout,
+ gint height,
+ gint *minimum_width,
+ gint *natural_width)
+{
+ GtkLabel *label = GTK_LABEL (layout);
+ gdouble angle = gtk_label_get_angle (label);
+
+ if (90 == angle || 270 == angle)
+ get_size_for_allocation (label, height, minimum_width, natural_width);
+ else
+ {
+ GtkRequisition minimum_size, natural_size;
+
+ gtk_extended_layout_get_desired_size (layout,
+ minimum_width ? &minimum_size : NULL,
+ natural_width ? &natural_size : NULL);
+
+ if (minimum_width)
+ *minimum_width = minimum_size.width;
+ if (natural_width)
+ *natural_width = natural_size.width;
+ }
+}
+
+static void
+gtk_label_get_height_for_width (GtkExtendedLayout *layout,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height)
+{
+ GtkLabel *label = GTK_LABEL (layout);
+ gdouble angle = gtk_label_get_angle (label);
+
+ if (0 == angle || 180 == angle)
+ get_size_for_allocation (label, width, minimum_height, natural_height);
+ else
+ {
+ GtkRequisition minimum_size, natural_size;
+
+ gtk_extended_layout_get_desired_size (layout,
+ minimum_height ? &minimum_size : NULL,
+ natural_height ? &natural_size : NULL);
+
+ if (minimum_height)
+ *minimum_height = minimum_size.height;
+ if (natural_height)
+ *natural_height = natural_size.height;
+ }
}
static void
diff --git a/gtk/gtksizegroup.c b/gtk/gtksizegroup.c
index 477c45f..2cd431b 100644
--- a/gtk/gtksizegroup.c
+++ b/gtk/gtksizegroup.c
@@ -25,8 +25,18 @@
#include "gtkprivate.h"
#include "gtksizegroup.h"
#include "gtkbuildable.h"
+#include "gtkextendedlayout.h"
#include "gtkalias.h"
+#define GTK_SIZE_GROUP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_SIZE_GROUP, GtkSizeGroupPrivate))
+
+typedef struct _GtkSizeGroupPrivate GtkSizeGroupPrivate;
+
+struct _GtkSizeGroupPrivate
+{
+ GtkRequisition natural_size;
+};
+
enum {
PROP_0,
PROP_MODE,
@@ -314,6 +324,7 @@ gtk_size_group_class_init (GtkSizeGroupClass *klass)
GTK_PARAM_READWRITE));
initialize_size_group_quarks ();
+ g_type_class_add_private (klass, sizeof (GtkSizeGroupPrivate));
}
static void
@@ -588,25 +599,49 @@ gtk_size_group_get_widgets (GtkSizeGroup *size_group)
return size_group->widgets;
}
-static gint
-get_base_dimension (GtkWidget *widget,
- GtkSizeGroupMode mode)
+static void
+get_base_dimensions (GtkWidget *widget,
+ GtkSizeGroupMode mode,
+ gint *minimum_size,
+ gint *natural_size)
{
GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (widget, FALSE);
if (mode == GTK_SIZE_GROUP_HORIZONTAL)
{
- if (aux_info && aux_info->width > 0)
- return aux_info->width;
- else
- return widget->requisition.width;
+ if (minimum_size)
+ {
+ if (aux_info && aux_info->width > 0)
+ *minimum_size = aux_info->width;
+ else
+ *minimum_size = widget->requisition.width;
+ }
+
+ if (natural_size)
+ {
+ if (aux_info)
+ *natural_size = aux_info->natural_size.width;
+ else
+ *natural_size = widget->requisition.width;
+ }
}
else
{
- if (aux_info && aux_info->height > 0)
- return aux_info->height;
- else
- return widget->requisition.height;
+ if (minimum_size)
+ {
+ if (aux_info && aux_info->height > 0)
+ *minimum_size = aux_info->height;
+ else
+ *minimum_size = widget->requisition.height;
+ }
+
+ if (natural_size)
+ {
+ if (aux_info)
+ *natural_size = aux_info->natural_size.height;
+ else
+ *natural_size = widget->requisition.height;
+ }
}
}
@@ -615,31 +650,39 @@ do_size_request (GtkWidget *widget)
{
if (GTK_WIDGET_REQUEST_NEEDED (widget))
{
- gtk_widget_ensure_style (widget);
+ GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (widget, TRUE);
+
+ gtk_widget_ensure_style (widget);
GTK_PRIVATE_UNSET_FLAG (widget, GTK_REQUEST_NEEDED);
- g_signal_emit_by_name (widget,
- "size_request",
- &widget->requisition);
+
+ gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (widget),
+ &widget->requisition,
+ &aux_info->natural_size);
+
+ g_assert (widget->requisition.width <= aux_info->natural_size.width);
+ g_assert (widget->requisition.height <= aux_info->natural_size.height);
}
}
-static gint
-compute_base_dimension (GtkWidget *widget,
- GtkSizeGroupMode mode)
+static void
+compute_base_dimensions (GtkWidget *widget,
+ GtkSizeGroupMode mode,
+ gint *minimum_size,
+ gint *natural_size)
{
do_size_request (widget);
-
- return get_base_dimension (widget, mode);
+ get_base_dimensions (widget, mode, minimum_size, natural_size);
}
-static gint
+static void
compute_dimension (GtkWidget *widget,
- GtkSizeGroupMode mode)
+ GtkSizeGroupMode mode,
+ gint *minimum_size,
+ gint *natural_size)
{
GSList *widgets = NULL;
GSList *groups = NULL;
GSList *tmp_list;
- gint result = 0;
add_widget_to_closure (widget, mode, &groups, &widgets);
@@ -650,16 +693,26 @@ compute_dimension (GtkWidget *widget,
if (!groups)
{
- result = compute_base_dimension (widget, mode);
+ compute_base_dimensions (widget, mode, minimum_size, natural_size);
}
else
{
GtkSizeGroup *group = groups->data;
+ GtkSizeGroupPrivate *priv = GTK_SIZE_GROUP_GET_PRIVATE (group);
+
+ gint result_minimum_size = 0;
+ gint result_natural_size = 0;
if (mode == GTK_SIZE_GROUP_HORIZONTAL && group->have_width)
- result = group->requisition.width;
+ {
+ result_minimum_size = group->requisition.width;
+ result_natural_size = priv->natural_size.width;
+ }
else if (mode == GTK_SIZE_GROUP_VERTICAL && group->have_height)
- result = group->requisition.height;
+ {
+ result_minimum_size = group->requisition.height;
+ result_natural_size = priv->natural_size.height;
+ }
else
{
tmp_list = widgets;
@@ -667,13 +720,20 @@ compute_dimension (GtkWidget *widget,
{
GtkWidget *tmp_widget = tmp_list->data;
- gint dimension = compute_base_dimension (tmp_widget, mode);
+ gint tmp_widget_minimum_size;
+ gint tmp_widget_natural_size;
- if (GTK_WIDGET_MAPPED (tmp_widget) || !group->ignore_hidden)
- {
- if (dimension > result)
- result = dimension;
- }
+ compute_base_dimensions (tmp_widget, mode,
+ &tmp_widget_minimum_size,
+ &tmp_widget_natural_size);
+
+ if (GTK_WIDGET_MAPPED (tmp_widget) || !group->ignore_hidden)
+ {
+ if (result_minimum_size < tmp_widget_minimum_size)
+ result_minimum_size = tmp_widget_minimum_size;
+ if (result_natural_size < tmp_widget_natural_size)
+ result_natural_size = tmp_widget_natural_size;
+ }
tmp_list = tmp_list->next;
}
@@ -682,38 +742,45 @@ compute_dimension (GtkWidget *widget,
while (tmp_list)
{
GtkSizeGroup *tmp_group = tmp_list->data;
+ GtkSizeGroupPrivate *tmp_priv = GTK_SIZE_GROUP_GET_PRIVATE (tmp_group);
if (mode == GTK_SIZE_GROUP_HORIZONTAL)
{
tmp_group->have_width = TRUE;
- tmp_group->requisition.width = result;
+ tmp_group->requisition.width = result_minimum_size;
+ tmp_priv->natural_size.width = result_natural_size;
}
else
{
tmp_group->have_height = TRUE;
- tmp_group->requisition.height = result;
+ tmp_group->requisition.height = result_minimum_size;
+ tmp_priv->natural_size.height = result_natural_size;
}
tmp_list = tmp_list->next;
}
}
+
+ if (minimum_size)
+ *minimum_size = result_minimum_size;
+ if (natural_size)
+ *natural_size = result_natural_size;
}
g_slist_foreach (widgets, (GFunc)g_object_unref, NULL);
g_slist_free (widgets);
g_slist_free (groups);
-
- return result;
}
-static gint
-get_dimension (GtkWidget *widget,
- GtkSizeGroupMode mode)
+static void
+get_dimensions (GtkWidget *widget,
+ GtkSizeGroupMode mode,
+ gint *minimum_size,
+ gint *natural_size)
{
GSList *widgets = NULL;
GSList *groups = NULL;
- gint result = 0;
add_widget_to_closure (widget, mode, &groups, &widgets);
@@ -722,22 +789,31 @@ get_dimension (GtkWidget *widget,
if (!groups)
{
- result = get_base_dimension (widget, mode);
+ get_base_dimensions (widget, mode, minimum_size, natural_size);
}
else
{
GtkSizeGroup *group = groups->data;
+ GtkSizeGroupPrivate *priv = GTK_SIZE_GROUP_GET_PRIVATE (group);
if (mode == GTK_SIZE_GROUP_HORIZONTAL && group->have_width)
- result = group->requisition.width;
+ {
+ if (minimum_size)
+ *minimum_size = group->requisition.width;
+ if (natural_size)
+ *natural_size = priv->natural_size.width;
+ }
else if (mode == GTK_SIZE_GROUP_VERTICAL && group->have_height)
- result = group->requisition.height;
+ {
+ if (minimum_size)
+ *minimum_size = group->requisition.height;
+ if (natural_size)
+ *natural_size = priv->natural_size.height;
+ }
}
g_slist_free (widgets);
g_slist_free (groups);
-
- return result;
}
static void
@@ -752,11 +828,23 @@ get_fast_child_requisition (GtkWidget *widget,
{
if (aux_info->width > 0)
requisition->width = aux_info->width;
- if (aux_info && aux_info->height > 0)
+ if (aux_info->height > 0)
requisition->height = aux_info->height;
}
}
+static void
+get_fast_natural_size (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (widget, FALSE);
+
+ if (aux_info)
+ *requisition = aux_info->natural_size;
+ else
+ *requisition = widget->requisition;
+}
+
/**
* _gtk_size_group_get_child_requisition:
* @widget: a #GtkWidget
@@ -775,8 +863,8 @@ _gtk_size_group_get_child_requisition (GtkWidget *widget,
{
if (get_size_groups (widget))
{
- requisition->width = get_dimension (widget, GTK_SIZE_GROUP_HORIZONTAL);
- requisition->height = get_dimension (widget, GTK_SIZE_GROUP_VERTICAL);
+ get_dimensions (widget, GTK_SIZE_GROUP_HORIZONTAL, &requisition->width, NULL);
+ get_dimensions (widget, GTK_SIZE_GROUP_VERTICAL, &requisition->height, NULL);
/* Only do the full computation if we actually have size groups */
}
@@ -786,41 +874,40 @@ _gtk_size_group_get_child_requisition (GtkWidget *widget,
}
/**
- * _gtk_size_group_compute_requisition:
+ * _gtk_size_group_compute_desired_size:
* @widget: a #GtkWidget
- * @requisition: location to store computed requisition.
+ * @minimum_size: location to store computed minimum size
+ * @natural_size: location to store computed natural size
*
- * Compute the requisition of a widget taking into account grouping of
+ * Compute the desired size of a widget taking into account grouping of
* the widget's requisition with other widgets.
**/
void
-_gtk_size_group_compute_requisition (GtkWidget *widget,
- GtkRequisition *requisition)
+_gtk_size_group_compute_desired_size (GtkWidget *widget,
+ GtkRequisition *minimum_size,
+ GtkRequisition *natural_size)
{
- gint width;
- gint height;
-
initialize_size_group_quarks ();
if (get_size_groups (widget))
{
/* Only do the full computation if we actually have size groups */
-
- width = compute_dimension (widget, GTK_SIZE_GROUP_HORIZONTAL);
- height = compute_dimension (widget, GTK_SIZE_GROUP_VERTICAL);
- if (requisition)
- {
- requisition->width = width;
- requisition->height = height;
- }
+ compute_dimension (widget, GTK_SIZE_GROUP_HORIZONTAL,
+ minimum_size ? &minimum_size->width : NULL,
+ natural_size ? &natural_size->width : NULL);
+ compute_dimension (widget, GTK_SIZE_GROUP_VERTICAL,
+ minimum_size ? &minimum_size->height : NULL,
+ natural_size ? &natural_size->height : NULL);
}
else
{
do_size_request (widget);
-
- if (requisition)
- get_fast_child_requisition (widget, requisition);
+
+ if (minimum_size)
+ get_fast_child_requisition (widget, minimum_size);
+ if (natural_size)
+ get_fast_natural_size (widget, natural_size);
}
}
diff --git a/gtk/gtksizegroup.h b/gtk/gtksizegroup.h
index 4a83153..1bcb164 100644
--- a/gtk/gtksizegroup.h
+++ b/gtk/gtksizegroup.h
@@ -98,8 +98,9 @@ GSList * gtk_size_group_get_widgets (GtkSizeGroup *size_group);
void _gtk_size_group_get_child_requisition (GtkWidget *widget,
GtkRequisition *requisition);
-void _gtk_size_group_compute_requisition (GtkWidget *widget,
- GtkRequisition *requisition);
+void _gtk_size_group_compute_desired_size (GtkWidget *widget,
+ GtkRequisition *minimum_size,
+ GtkRequisition *natural_size);
void _gtk_size_group_queue_resize (GtkWidget *widget);
G_END_DECLS
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 1aa1bba..738a668 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -53,6 +53,7 @@
#include "gtkinvisible.h"
#include "gtkbuildable.h"
#include "gtkbuilderprivate.h"
+#include "gtkextendedlayout.h"
#include "gtkalias.h"
#define WIDGET_CLASS(w) GTK_WIDGET_GET_CLASS (w)
@@ -269,7 +270,11 @@ static void gtk_widget_buildable_custom_finished (GtkBuildable
static void gtk_widget_buildable_parser_finished (GtkBuildable *buildable,
GtkBuilder *builder);
-
+static void gtk_widget_layout_interface_init (GtkExtendedLayoutIface *iface);
+static void gtk_widget_real_get_desired_size (GtkExtendedLayout *layout,
+ GtkRequisition *minimum_size,
+ GtkRequisition *natural_size);
+
static void gtk_widget_set_usize_internal (GtkWidget *widget,
gint width,
gint height);
@@ -342,6 +347,13 @@ gtk_widget_get_type (void)
NULL /* interface data */
};
+ const GInterfaceInfo layout_info =
+ {
+ (GInterfaceInitFunc) gtk_widget_layout_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL /* interface data */
+ };
+
widget_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkWidget",
&widget_info, G_TYPE_FLAG_ABSTRACT);
@@ -349,7 +361,8 @@ gtk_widget_get_type (void)
&accessibility_info) ;
g_type_add_interface_static (widget_type, GTK_TYPE_BUILDABLE,
&buildable_info) ;
-
+ g_type_add_interface_static (widget_type, GTK_TYPE_EXTENDED_LAYOUT,
+ &layout_info) ;
}
return widget_type;
@@ -3629,10 +3642,11 @@ gtk_widget_size_request (GtkWidget *widget,
#ifdef G_ENABLE_DEBUG
if (requisition == &widget->requisition)
- g_warning ("gtk_widget_size_request() called on child widget with request equal\n to widget->requisition. gtk_widget_set_usize() may not work properly.");
+ g_warning ("gtk_widget_size_request() called on child widget with request equal\n"
+ "to widget->requisition. gtk_widget_set_usize() may not work properly.");
#endif /* G_ENABLE_DEBUG */
- _gtk_size_group_compute_requisition (widget, requisition);
+ _gtk_size_group_compute_desired_size (widget, requisition, NULL);
}
/**
@@ -8137,14 +8151,11 @@ _gtk_widget_get_aux_info (GtkWidget *widget,
aux_info = g_object_get_qdata (G_OBJECT (widget), quark_aux_info);
if (!aux_info && create)
{
- aux_info = g_slice_new (GtkWidgetAuxInfo);
+ aux_info = g_slice_new0 (GtkWidgetAuxInfo);
aux_info->width = -1;
aux_info->height = -1;
- aux_info->x = 0;
- aux_info->y = 0;
- aux_info->x_set = FALSE;
- aux_info->y_set = FALSE;
+
g_object_set_qdata (G_OBJECT (widget), quark_aux_info, aux_info);
}
@@ -8907,6 +8918,101 @@ gtk_widget_buildable_parser_finished (GtkBuildable *buildable,
gtk_widget_grab_focus (GTK_WIDGET (buildable));
}
+/*
+ * GtkExtendedLayout implementation
+ */
+static void
+gtk_widget_real_get_desired_size (GtkExtendedLayout *layout,
+ GtkRequisition *minimum_size,
+ GtkRequisition *natural_size)
+{
+ GtkWidget *widget = GTK_WIDGET (layout);
+ GtkRequisition requisition = widget->requisition;
+
+ g_signal_emit (widget, widget_signals[SIZE_REQUEST], 0, &requisition);
+
+ if (minimum_size)
+ *minimum_size = requisition;
+ if (natural_size)
+ *natural_size = requisition;
+}
+
+/**
+ * gtk_widget_get_desired_size:
+ * @widget: a #GtkWidget
+ * @minimum_size: location for storing the @widget's minimum size, or %NULL
+ * @natural_size: location for storing the @widget's preferred size, or %NULL
+ *
+ * Retreives a widget's desired size, considering restrictions imposed by
+ * #GtkSizeGroup<!-- -->s. See also: gtk_extended_layout_get_desired_size().
+ *
+ * Since: 2.16
+ */
+void
+gtk_widget_get_desired_size (GtkWidget *widget,
+ GtkRequisition *minimum_size,
+ GtkRequisition *natural_size)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ _gtk_size_group_compute_desired_size (widget, minimum_size, natural_size);
+}
+
+void
+gtk_widget_get_height_for_width (GtkWidget *widget,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height)
+{
+ GtkRequisition minimum_size;
+ GtkRequisition natural_size;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+#if 0
+ TODO: integrate height-for-width with size-groups
+#else
+ gtk_widget_get_desired_size (widget,
+ minimum_height ? &minimum_size : NULL,
+ natural_height ? &natural_size : NULL);
+
+ if (minimum_height)
+ *minimum_height = minimum_size.height;
+ if (natural_height)
+ *natural_height = natural_size.height;
+#endif
+}
+
+void
+gtk_widget_get_width_for_height (GtkWidget *widget,
+ gint height,
+ gint *minimum_width,
+ gint *natural_width)
+{
+ GtkRequisition minimum_size;
+ GtkRequisition natural_size;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+#if 0
+ TODO: integrate width-for-height with size-groups
+#else
+ gtk_widget_get_desired_size (widget,
+ minimum_width ? &minimum_size : NULL,
+ natural_width ? &natural_size : NULL);
+
+ if (minimum_width)
+ *minimum_width = minimum_size.width;
+ if (natural_width)
+ *natural_width = natural_size.width;
+#endif
+}
+
+static void
+gtk_widget_layout_interface_init (GtkExtendedLayoutIface *iface)
+{
+ iface->get_desired_size = gtk_widget_real_get_desired_size;
+}
+
typedef struct {
GObject *object;
guint key;
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index b7f889a..cd11c99 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -429,8 +429,11 @@ struct _GtkWidgetAuxInfo
gint y;
gint width;
gint height;
+
guint x_set : 1;
guint y_set : 1;
+
+ GtkRequisition natural_size;
};
struct _GtkWidgetShapeInfo
@@ -495,6 +498,17 @@ void gtk_widget_size_request (GtkWidget *widget,
GtkRequisition *requisition);
void gtk_widget_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
+void gtk_widget_get_desired_size (GtkWidget *widget,
+ GtkRequisition *minimum_size,
+ GtkRequisition *natural_size);
+void gtk_widget_get_height_for_width(GtkWidget *widget,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height);
+void gtk_widget_get_width_for_height(GtkWidget *widget,
+ gint height,
+ gint *minimum_width,
+ gint *natural_width);
void gtk_widget_get_child_requisition (GtkWidget *widget,
GtkRequisition *requisition);
void gtk_widget_add_accelerator (GtkWidget *widget,
diff --git a/tests/Makefile.am b/tests/Makefile.am
index fd75f47..737a4bf 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -58,7 +58,8 @@ noinst_PROGRAMS = $(TEST_PROGS) \
testcellrenderertext \
testdnd \
testellipsise \
- testentrycompletion \
+ testentrycompletion \
+ testextendedlayout \
testfilechooser \
testfilechooserbutton \
testframe \
@@ -136,6 +137,7 @@ testcellrenderertext_DEPENDENCIES = $(TEST_DEPS)
testdnd_DEPENDENCIES = $(TEST_DEPS)
testellipsise_DEPENDENCIES = $(TEST_DEPS)
testentrycompletion_DEPENDENCIES = $(TEST_DEPS)
+testextendedlayout_DEPENDENCIES = $(TEST_DEPS)
testfilechooser_DEPENDENCIES = $(TEST_DEPS)
testfilechooserbutton_DEPENDENCIES = $(TEST_DEPS)
testgtk_DEPENDENCIES = $(TEST_DEPS)
@@ -188,6 +190,7 @@ testcellrenderertext_LDADD = $(LDADDS)
testdnd_LDADD = $(LDADDS)
testellipsise_LDADD = $(LDADDS)
testentrycompletion_LDADD = $(LDADDS)
+testextendedlayout_LDADD = $(LDADDS)
testfilechooser_LDADD = $(LDADDS)
testfilechooserbutton_LDADD = $(LDADDS)
testgtk_LDADD = $(LDADDS)
diff --git a/tests/testellipsise.c b/tests/testellipsise.c
index 157884a..5b8b46d 100644
--- a/tests/testellipsise.c
+++ b/tests/testellipsise.c
@@ -70,8 +70,10 @@ ebox_expose_event_cb (GtkWidget *widget,
{
PangoLayout *layout;
const double dashes[] = { 6, 18 };
+ GtkRequisition natural_size;
GtkWidget *label = data;
gint x, y, dx, dy;
+ gchar *markup;
cairo_t *cr;
gtk_widget_translate_coordinates (label, widget, 0, 0, &x, &y);
@@ -93,14 +95,33 @@ ebox_expose_event_cb (GtkWidget *widget,
cairo_set_dash (cr, dashes, 2, 0.5);
cairo_stroke (cr);
- layout = gtk_widget_create_pango_layout (widget, NULL);
+ gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (label),
+ NULL, &natural_size);
+
+ cairo_rectangle (cr,
+ x + 0.5 * (label->allocation.width - natural_size.width),
+ y + 0.5 * (label->allocation.height - natural_size.height),
+ natural_size.width, natural_size.height);
+ cairo_set_source_rgb (cr, 0.2, 0.8, 0.2);
+ cairo_set_dash (cr, dashes, 2, 12.5);
+ cairo_stroke (cr);
- pango_layout_set_markup (layout,
- "<span color='#c33'>\342\200\242 requisition</span>\n"
- "<span color='#33c'>\342\200\242 allocation</span>", -1);
+ markup = g_strdup_printf (
+ "<span color='#c33'>\342\200\242 requisition:\t%dx%d</span>\n"
+ "<span color='#3c3'>\342\200\242 natural size:\t%dx%d</span>\n"
+ "<span color='#33c'>\342\200\242 allocation:\t%dx%d</span>",
+ label->requisition.width, label->requisition.height,
+ natural_size.width, natural_size.height,
+ label->allocation.width, label->allocation.height);
+ layout = gtk_widget_create_pango_layout (widget, NULL);
+ pango_layout_set_markup (layout, markup, -1);
pango_layout_get_pixel_size (layout, &dx, &dy);
+ g_free (markup);
+
+ cairo_translate (cr, 0, widget->allocation.height - dy - 8);
+
cairo_set_source_rgba (cr, 1, 1, 1, 0.8);
cairo_rectangle (cr, 0, 0, dx + 12, dy + 8);
cairo_fill (cr);
diff --git a/tests/testextendedlayout.c b/tests/testextendedlayout.c
new file mode 100644
index 0000000..497ccaf
--- /dev/null
+++ b/tests/testextendedlayout.c
@@ -0,0 +1,120 @@
+#include <gtk/gtk.h>
+#include <math.h>
+
+static void
+size_group_toggled_cb (GtkToggleButton *button,
+ GtkSizeGroup *group)
+{
+ if (gtk_toggle_button_get_active (button))
+ gtk_size_group_set_mode (group, GTK_SIZE_GROUP_HORIZONTAL);
+ else
+ gtk_size_group_set_mode (group, GTK_SIZE_GROUP_NONE);
+}
+
+static void
+ellipsize_toggled_cb (GtkToggleButton *button,
+ GtkWidget *vbox)
+{
+ GList *rows, *row_iter, *cells, *cell_iter;
+ PangoEllipsizeMode mode;
+
+ if (gtk_toggle_button_get_active (button))
+ mode = PANGO_ELLIPSIZE_END;
+ else
+ mode = PANGO_ELLIPSIZE_NONE;
+
+ rows = gtk_container_get_children (GTK_CONTAINER (vbox));
+ for (row_iter = rows; row_iter; row_iter = row_iter->next)
+ {
+ if (!GTK_IS_CONTAINER (row_iter->data))
+ break;
+
+ cells = gtk_container_get_children (row_iter->data);
+
+ for (cell_iter = cells; cell_iter; cell_iter = cell_iter->next)
+ if (GTK_IS_LABEL (cell_iter->data))
+ gtk_label_set_ellipsize (cell_iter->data, mode);
+
+ g_list_free (cells);
+ }
+
+ g_list_free (rows);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ GtkWidget *window, *vbox, *button;
+ GtkSizeGroup *groups[5];
+ gint x, y;
+
+ gtk_init (&argc, &argv);
+
+ for (x = 0; x < G_N_ELEMENTS (groups); ++x)
+ groups[x] = gtk_size_group_new (GTK_SIZE_GROUP_NONE);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+
+ for (y = 0; y < 4; ++y)
+ {
+ GtkWidget *hbox = gtk_hbox_new (FALSE, 6);
+
+ for (x = 0; x < G_N_ELEMENTS (groups); ++x)
+ {
+ gchar *text = g_strdup_printf ("Label #%.0f.%d", pow(10, y), x + 1);
+ GtkWidget *label = gtk_label_new (text);
+ g_free (text);
+
+ text = g_strdup_printf ("label/%d/%d", y, x);
+ gtk_widget_set_name (label, text);
+ g_free (text);
+
+ if (1 != x)
+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+ if (x > 0)
+ gtk_box_pack_start (GTK_BOX (hbox), gtk_vseparator_new (), FALSE, TRUE, 0);
+
+ gtk_box_pack_start (GTK_BOX (hbox), label, 1 == x, TRUE, 0);
+ gtk_size_group_add_widget (groups[x], label);
+ }
+
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
+ }
+
+ gtk_box_pack_start (GTK_BOX (vbox), gtk_hseparator_new (), FALSE, TRUE, 0);
+
+ for (x = 0; x < G_N_ELEMENTS (groups); ++x)
+ {
+ gchar *text = g_strdup_printf ("Size Group #%d", x + 1);
+
+ button = gtk_check_button_new_with_label (text);
+ gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0);
+ g_free (text);
+
+ g_signal_connect (button, "toggled", G_CALLBACK (size_group_toggled_cb), groups[x]);
+ }
+
+ gtk_box_pack_start (GTK_BOX (vbox), gtk_hseparator_new (), FALSE, TRUE, 0);
+
+ button = gtk_check_button_new_with_label ("Ellipsize");
+ gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
+
+ g_signal_connect (button, "toggled",
+ G_CALLBACK (ellipsize_toggled_cb),
+ vbox);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+ gtk_widget_show_all (window);
+
+ g_signal_connect (window, "destroy",
+ G_CALLBACK (gtk_main_quit),
+ NULL);
+
+ gtk_main ();
+
+ return 0;
+}
--
1.5.3.7
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]