[gtk/wip/otte/wrapping-is-natural] label: Add gtk_label_set_natural_wrap_mode()
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/wrapping-is-natural] label: Add gtk_label_set_natural_wrap_mode()
- Date: Mon, 20 Dec 2021 01:28:46 +0000 (UTC)
commit 981ed22dff12f5c356faa67886a48d1b2ab18a84
Author: Benjamin Otte <otte redhat com>
Date: Sun Dec 19 19:22:31 2021 +0100
label: Add gtk_label_set_natural_wrap_mode()
Allows influencing natural size requests so that labels can request more
width than necessary for a given height.
Related: !4245
Related: #4535
gtk/gtkenums.h | 25 +++++
gtk/gtklabel.c | 106 +++++++++++++++++++--
gtk/gtklabel.h | 5 +
.../label-wrap-word-char-natural-size.ref.ui | 14 ++-
.../reftests/label-wrap-word-char-natural-size.ui | 17 +++-
5 files changed, 152 insertions(+), 15 deletions(-)
---
diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h
index d356a9154e..69faa56db8 100644
--- a/gtk/gtkenums.h
+++ b/gtk/gtkenums.h
@@ -285,6 +285,31 @@ typedef enum
GTK_MOVEMENT_HORIZONTAL_PAGES
} GtkMovementStep;
+/**
+ * GtkNaturalWrapMode:
+ * @GTK_NATURAL_WRAP_INHERIT: Inherit the minimum size request.
+ * In particular, this should be used with %PANGO_WRAP_CHAR.
+ * @GTK_NATURAL_WRAP_NONE: Try not to wrap the text. This mode is the
+ * closest to GTK3's behavior but can lead to a wide label leaving
+ * lots of empty space below the text.
+ * @GTK_NATURAL_WRAP_WORD: Attempt to wrap at word boundaries. This
+ * is useful in particular when using %PANGO_WRAP_WORD_CHAR as the
+ * wrap mode.
+ *
+ * Options for selecting a different wrap mode for natural size
+ * requests.
+ *
+ * See for example the [property@Gtk.Label:natural-wrap-mode] property.
+ *
+ * Since: 4.6
+ */
+typedef enum
+{
+ GTK_NATURAL_WRAP_INHERIT,
+ GTK_NATURAL_WRAP_NONE,
+ GTK_NATURAL_WRAP_WORD
+} GtkNaturalWrapMode;
+
/**
* GtkScrollStep:
* @GTK_SCROLL_STEPS: Scroll in steps.
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index 9af80f43a9..1f019fadaa 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -272,6 +272,7 @@ struct _GtkLabel
guint ellipsize : 3;
guint use_markup : 1;
guint wrap_mode : 3;
+ guint natural_wrap_mode : 3;
guint single_line_mode : 1;
guint in_click : 1;
guint track_links : 1;
@@ -380,6 +381,7 @@ enum {
PROP_JUSTIFY,
PROP_WRAP,
PROP_WRAP_MODE,
+ PROP_NATURAL_WRAP_MODE,
PROP_SELECTABLE,
PROP_MNEMONIC_KEYVAL,
PROP_MNEMONIC_WIDGET,
@@ -484,6 +486,9 @@ gtk_label_set_property (GObject *object,
case PROP_WRAP_MODE:
gtk_label_set_wrap_mode (self, g_value_get_enum (value));
break;
+ case PROP_NATURAL_WRAP_MODE:
+ gtk_label_set_natural_wrap_mode (self, g_value_get_enum (value));
+ break;
case PROP_SELECTABLE:
gtk_label_set_selectable (self, g_value_get_boolean (value));
break;
@@ -551,6 +556,9 @@ gtk_label_get_property (GObject *object,
case PROP_WRAP_MODE:
g_value_set_enum (value, self->wrap_mode);
break;
+ case PROP_NATURAL_WRAP_MODE:
+ g_value_set_enum (value, self->natural_wrap_mode);
+ break;
case PROP_SELECTABLE:
g_value_set_boolean (value, gtk_label_get_selectable (self));
break;
@@ -604,6 +612,7 @@ gtk_label_init (GtkLabel *self)
self->jtype = GTK_JUSTIFY_LEFT;
self->wrap = FALSE;
self->wrap_mode = PANGO_WRAP_WORD;
+ self->natural_wrap_mode = GTK_NATURAL_WRAP_INHERIT;
self->ellipsize = PANGO_ELLIPSIZE_NONE;
self->use_underline = FALSE;
@@ -1218,8 +1227,6 @@ get_width_for_height (GtkLabel *self,
gtk_label_ensure_layout (self);
layout = pango_layout_copy (self->layout);
pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE);
- if (self->wrap_mode == PANGO_WRAP_WORD_CHAR)
- pango_layout_set_wrap (layout, PANGO_WRAP_WORD);
/* binary search for the smallest width where the height doesn't
* eclipse the given height */
@@ -1228,8 +1235,19 @@ get_width_for_height (GtkLabel *self,
pango_layout_set_width (layout, -1);
pango_layout_get_size (layout, &max, NULL);
- *natural_width = my_pango_layout_get_width_for_height (layout, height, min, max);
+ /* first, do natural width */
+ if (self->natural_wrap_mode == GTK_NATURAL_WRAP_NONE)
+ {
+ *natural_width = max;
+ }
+ else
+ {
+ if (self->natural_wrap_mode == GTK_NATURAL_WRAP_WORD)
+ pango_layout_set_wrap (layout, PANGO_WRAP_WORD);
+ *natural_width = my_pango_layout_get_width_for_height (layout, height, min, max);
+ }
+ /* then, do minimum width */
if (self->ellipsize != PANGO_ELLIPSIZE_NONE)
{
g_object_unref (layout);
@@ -1237,14 +1255,14 @@ get_width_for_height (GtkLabel *self,
pango_layout_get_size (layout, minimum_width, NULL);
*minimum_width = MAX (*minimum_width, minimum_default);
}
- else if (self->wrap_mode == PANGO_WRAP_WORD_CHAR)
+ else if (self->natural_wrap_mode == GTK_NATURAL_WRAP_INHERIT)
{
- pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
- *minimum_width = my_pango_layout_get_width_for_height (layout, height, min, *natural_width);
+ *minimum_width = *natural_width;
}
else
{
- *minimum_width = *natural_width;
+ pango_layout_set_wrap (layout, self->wrap_mode);
+ *minimum_width = my_pango_layout_get_width_for_height (layout, height, min, *natural_width);
}
}
@@ -2375,6 +2393,9 @@ gtk_label_class_init (GtkLabelClass *class)
* This only affects the formatting if line wrapping is on (see the
* [property@Gtk.Label:wrap] property). The default is %PANGO_WRAP_WORD,
* which means wrap on word boundaries.
+ *
+ * For sizing behavior, also consider the [property@Gtk.Label:natural-wrap-mode]
+ * property.
*/
label_props[PROP_WRAP_MODE] =
g_param_spec_enum ("wrap-mode",
@@ -2384,6 +2405,27 @@ gtk_label_class_init (GtkLabelClass *class)
PANGO_WRAP_WORD,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+ /**
+ * GtkLabel:natural-wrap-mode: (attributes org.gtk.Property.get=gtk_label_get_natural_wrap_mode
org.gtk.Property.set=gtk_label_set_natural_wrap_mode)
+ *
+ * Select the line wrapping for the natural size request.
+ *
+ * This only affects the natural size requested. For the actual wrapping used,
+ * see the [property@Gtk.Label:wrap-mode] property.
+ *
+ * The default is %GTK_NATURAL_WRAP_INHERIT, which inherits the behavior of the
+ * [property@Gtk.Label:wrap-mode] property.
+ *
+ * Since: 4.6
+ */
+ label_props[PROP_NATURAL_WRAP_MODE] =
+ g_param_spec_enum ("natural-wrap-mode",
+ P_("Natrural wrap mode"),
+ P_("If wrap is set, controls linewrapping for natural size requests"),
+ GTK_TYPE_NATURAL_WRAP_MODE,
+ GTK_NATURAL_WRAP_INHERIT,
+ GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+
/**
* GtkLabel:selectable: (attributes org.gtk.Property.get=gtk_label_get_selectable
og.gtk.Property.set=gtk_label_set_selectable)
*
@@ -3998,6 +4040,9 @@ gtk_label_get_wrap (GtkLabel *self)
* This only affects the label if line wrapping is on. (See
* [method@Gtk.Label.set_wrap]) The default is %PANGO_WRAP_WORD
* which means wrap on word boundaries.
+ *
+ * For sizing behavior, also consider the [property@Gtk.Label:natural-wrap-mode]
+ * property.
*/
void
gtk_label_set_wrap_mode (GtkLabel *self,
@@ -4032,6 +4077,53 @@ gtk_label_get_wrap_mode (GtkLabel *self)
return self->wrap_mode;
}
+/**
+ * gtk_label_set_natural_wrap_mode: (attributes org.gtk.Method.set_property=natural-wrap-mode)
+ * @self: a `GtkLabel`
+ * @wrap_mode: the line wrapping mode
+ *
+ * Select the line wrapping for the natural size request.
+ *
+ * This only affects the natural size requested, for the actual wrapping used,
+ * see the [property@Gtk.Label:wrap-mode] property.
+ *
+ * Since: 4.6
+ */
+void
+gtk_label_set_natural_wrap_mode (GtkLabel *self,
+ GtkNaturalWrapMode wrap_mode)
+{
+ g_return_if_fail (GTK_IS_LABEL (self));
+
+ if (self->natural_wrap_mode != wrap_mode)
+ {
+ self->natural_wrap_mode = wrap_mode;
+ g_object_notify_by_pspec (G_OBJECT (self), label_props[PROP_NATURAL_WRAP_MODE]);
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+ }
+}
+
+/**
+ * gtk_label_get_natural_wrap_mode: (attributes org.gtk.Method.get_property=natural-wrap-mode)
+ * @self: a `GtkLabel`
+ *
+ * Returns line wrap mode used by the label.
+ *
+ * See [method@Gtk.Label.set_natural_wrap_mode].
+ *
+ * Returns: the natural line wrap mode
+ *
+ * Since: 4.6
+ */
+GtkNaturalWrapMode
+gtk_label_get_natural_wrap_mode (GtkLabel *self)
+{
+ g_return_val_if_fail (GTK_IS_LABEL (self), PANGO_WRAP_CHAR);
+
+ return self->natural_wrap_mode;
+}
+
static void
gtk_label_clear_layout (GtkLabel *self)
{
diff --git a/gtk/gtklabel.h b/gtk/gtklabel.h
index 36441a5fe9..4a42a4ba32 100644
--- a/gtk/gtklabel.h
+++ b/gtk/gtklabel.h
@@ -122,6 +122,11 @@ void gtk_label_set_wrap_mode (GtkLabel *self,
PangoWrapMode wrap_mode);
GDK_AVAILABLE_IN_ALL
PangoWrapMode gtk_label_get_wrap_mode (GtkLabel *self);
+GDK_AVAILABLE_IN_4_6
+void gtk_label_set_natural_wrap_mode (GtkLabel *self,
+ GtkNaturalWrapMode wrap_mode);
+GDK_AVAILABLE_IN_4_6
+GtkNaturalWrapMode gtk_label_get_natural_wrap_mode(GtkLabel *self);
GDK_AVAILABLE_IN_ALL
void gtk_label_set_selectable (GtkLabel *self,
gboolean setting);
diff --git a/testsuite/reftests/label-wrap-word-char-natural-size.ref.ui
b/testsuite/reftests/label-wrap-word-char-natural-size.ref.ui
index b8a08efc62..405064420c 100644
--- a/testsuite/reftests/label-wrap-word-char-natural-size.ref.ui
+++ b/testsuite/reftests/label-wrap-word-char-natural-size.ref.ui
@@ -1,21 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow">
- <property name="default-width">300</property>
+ <property name="default-width">600</property>
<property name="default-height">300</property>
<child>
<object class="GtkBox">
<property name="halign">center</property>
- <property name="valign">center</property>
<child>
<object class="GtkLabel">
- <property name="label">two
+ <property name="label">lots
+of
lines</property>
</object>
</child>
<child>
<object class="GtkLabel">
- <property name="label">unwrapped</property>
+ <property name="label">unwrappable
+words</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="label">single line of text</property>
</object>
</child>
</object>
diff --git a/testsuite/reftests/label-wrap-word-char-natural-size.ui
b/testsuite/reftests/label-wrap-word-char-natural-size.ui
index 929e5a3089..f70099651e 100644
--- a/testsuite/reftests/label-wrap-word-char-natural-size.ui
+++ b/testsuite/reftests/label-wrap-word-char-natural-size.ui
@@ -1,23 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow">
- <property name="default-width">300</property>
+ <property name="default-width">600</property>
<property name="default-height">300</property>
<child>
<object class="GtkBox">
<property name="halign">center</property>
- <property name="valign">center</property>
<child>
<object class="GtkLabel">
- <property name="label">two
+ <property name="label">lots
+of
lines</property>
</object>
</child>
<child>
<object class="GtkLabel">
- <property name="label">unwrapped</property>
+ <property name="label">unwrappable words</property>
<property name="wrap">1</property>
<property name="wrap-mode">word-char</property>
+ <property name="natural-wrap-mode">word</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="label">single line of text</property>
+ <property name="wrap">1</property>
+ <property name="wrap-mode">word-char</property>
+ <property name="natural-wrap-mode">none</property>
</object>
</child>
</object>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]