[gtk/wip/otte/inscription: 2/6] Add GtkInscription




commit 7980904ea3002f38dfcd6ae230c0eed44fc30d65
Author: Benjamin Otte <otte redhat com>
Date:   Thu May 19 06:44:23 2022 +0200

    Add GtkInscription
    
    A label alternative that renders itself into a given rectangle.
    
    The main use case is cells in column view.

 gtk/gtk.h            |   1 +
 gtk/gtkinscription.c | 890 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkinscription.h |  79 +++++
 gtk/meson.build      |   2 +
 4 files changed, 972 insertions(+)
---
diff --git a/gtk/gtk.h b/gtk/gtk.h
index 0d4521e4ac..bac384a2e0 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -155,6 +155,7 @@
 #include <gtk/gtkimcontextsimple.h>
 #include <gtk/gtkimmulticontext.h>
 #include <gtk/gtkinfobar.h>
+#include <gtk/gtkinscription.h>
 #include <gtk/gtklabel.h>
 #include <gtk/gtklayoutmanager.h>
 #include <gtk/gtklayoutchild.h>
diff --git a/gtk/gtkinscription.c b/gtk/gtkinscription.c
new file mode 100644
index 0000000000..6dce790ae6
--- /dev/null
+++ b/gtk/gtkinscription.c
@@ -0,0 +1,890 @@
+/*
+ * Copyright © 2022 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gtkinscription.h"
+
+#include "gtkcssstylechangeprivate.h"
+#include "gtksnapshot.h"
+#include "gtkwidgetprivate.h"
+
+/**
+ * GtkInscription:
+ *
+ * `GtkInscription` is a widget to show text in a predefined area.
+ *
+ * You likely want to use `GtkLabel` instead as this widget is intended only for
+ * a small subset of use cases. The main use case is usage inside lists
+ * such as `GtkColumnView`.
+ *
+ * While a `GtkLabel` sizes itself according to the text that is displayed,
+ * `GtkInscription` is given a size and inscribes the given text into that space
+ * as good as it can.
+ *
+ * As it is a common occurence that text doesn't fit, users of this widget should
+ * plan for that case.
+ */
+
+/* 3 chars are enough to display ellipsizing "..." */
+#define DEFAULT_MIN_CHARS 3
+/* This means we request no natural size and fall back to min size */
+#define DEFAULT_NAT_CHARS 0
+/* 1 line is what people want in 90% of cases */
+#define DEFAULT_MIN_LINES 1
+/* This means we request no natural size and fall back to min size */
+#define DEFAULT_NAT_LINES 0
+/* Unlike GtkLabel, we default to not centering text */
+#define DEFAULT_XALIGN 0.f
+/* But just like GtkLabel, we center vertically */
+#define DEFAULT_YALIGN 0.5f
+
+struct _GtkInscription
+{
+  GtkWidget parent_instance;
+
+  char *text;
+  guint min_chars;
+  guint nat_chars;
+  guint min_lines;
+  guint nat_lines;
+  float xalign;
+  float yalign;
+
+  PangoLayout *layout;
+};
+
+enum
+{
+  PROP_0,
+  PROP_MIN_CHARS,
+  PROP_MIN_LINES,
+  PROP_NAT_CHARS,
+  PROP_NAT_LINES,
+  PROP_TEXT,
+  PROP_XALIGN,
+  PROP_YALIGN,
+
+  N_PROPS
+};
+
+G_DEFINE_TYPE (GtkInscription, gtk_inscription, GTK_TYPE_WIDGET)
+
+static GParamSpec *properties[N_PROPS] = { NULL, };
+
+static void
+gtk_inscription_dispose (GObject *object)
+{
+  GtkInscription *self = GTK_INSCRIPTION (object);
+
+  g_clear_pointer (&self->text, g_free);
+
+  G_OBJECT_CLASS (gtk_inscription_parent_class)->dispose (object);
+}
+
+static void
+gtk_inscription_finalize (GObject *object)
+{
+  GtkInscription *self = GTK_INSCRIPTION (object);
+
+  g_clear_object (&self->layout);
+
+  G_OBJECT_CLASS (gtk_inscription_parent_class)->finalize (object);
+}
+
+static void
+gtk_inscription_get_property (GObject    *object,
+                              guint       property_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+  GtkInscription *self = GTK_INSCRIPTION (object);
+
+  switch (property_id)
+    {
+    case PROP_MIN_CHARS:
+      g_value_set_uint (value, self->min_chars);
+      break;
+
+    case PROP_MIN_LINES:
+      g_value_set_uint (value, self->min_chars);
+      break;
+
+    case PROP_NAT_CHARS:
+      g_value_set_uint (value, self->min_chars);
+      break;
+
+    case PROP_NAT_LINES:
+      g_value_set_uint (value, self->min_chars);
+      break;
+
+    case PROP_TEXT:
+      g_value_set_string (value, self->text);
+      break;
+
+    case PROP_XALIGN:
+      g_value_set_float (value, self->xalign);
+      break;
+
+    case PROP_YALIGN:
+      g_value_set_float (value, self->yalign);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_inscription_set_property (GObject      *object,
+                              guint         property_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+  GtkInscription *self = GTK_INSCRIPTION (object);
+
+  switch (property_id)
+    {
+    case PROP_MIN_CHARS:
+      gtk_inscription_set_min_chars (self, g_value_get_uint (value));
+      break;
+
+    case PROP_MIN_LINES:
+      gtk_inscription_set_min_lines (self, g_value_get_uint (value));
+      break;
+
+    case PROP_NAT_CHARS:
+      gtk_inscription_set_min_lines (self, g_value_get_uint (value));
+      break;
+
+    case PROP_NAT_LINES:
+      gtk_inscription_set_nat_lines (self, g_value_get_uint (value));
+      break;
+
+    case PROP_TEXT:
+      gtk_inscription_set_text (self, g_value_get_string (value));
+      break;
+
+    case PROP_XALIGN:
+      gtk_inscription_set_xalign (self, g_value_get_float (value));
+      break;
+
+    case PROP_YALIGN:
+      gtk_inscription_set_yalign (self, g_value_get_float (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_inscription_css_changed (GtkWidget         *widget,
+                             GtkCssStyleChange *change)
+{
+  GtkInscription *self = GTK_INSCRIPTION (widget);
+
+  GTK_WIDGET_CLASS (gtk_inscription_parent_class)->css_changed (widget, change);
+
+  if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_TEXT_ATTRS))
+    {
+      PangoAttrList *new_attrs;
+
+      new_attrs = gtk_css_style_get_pango_attributes (gtk_css_style_change_get_new_style (change));
+      pango_layout_set_attributes (self->layout, new_attrs);
+      pango_attr_list_unref (new_attrs);
+
+      gtk_widget_queue_draw (widget);
+    }
+}
+
+static PangoFontMetrics *
+gtk_inscription_get_font_metrics (GtkInscription *self)
+{
+  PangoContext *context;
+
+  context = gtk_widget_get_pango_context (GTK_WIDGET (self));
+
+  return pango_context_get_metrics (context, NULL, NULL);
+}
+
+static int
+get_char_pixels (GtkInscription *self)
+{
+  int char_width, digit_width;
+  PangoFontMetrics *metrics;
+
+  metrics = gtk_inscription_get_font_metrics (self);
+  char_width = pango_font_metrics_get_approximate_char_width (metrics);
+  digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
+  pango_font_metrics_unref (metrics);
+
+  return MAX (char_width, digit_width);
+}
+
+static void
+gtk_inscription_measure_width (GtkInscription *self,
+                               int            *minimum,
+                               int            *natural)
+{
+  int char_pixels = get_char_pixels (self);
+
+  if (self->min_chars == 0 && self->nat_chars == 0)
+    return;
+
+  *minimum = self->min_chars * char_pixels;
+  *natural = MAX (self->min_chars, self->nat_chars) * char_pixels;
+}
+
+static int
+get_line_pixels (GtkInscription *self,
+                 int            *baseline)
+{
+  PangoFontMetrics *metrics;
+  int ascent, descent;
+
+  metrics = gtk_inscription_get_font_metrics (self);
+
+  ascent = pango_font_metrics_get_ascent (metrics);
+  descent = pango_font_metrics_get_descent (metrics);
+
+  if (baseline)
+    *baseline = ascent;
+
+  return ascent + descent;
+}
+
+static void
+gtk_inscription_measure_height (GtkInscription *self,
+                                int            *minimum,
+                                int            *natural,
+                                int            *minimum_baseline,
+                                int            *natural_baseline)
+{
+  int line_pixels, baseline;
+
+  if (self->min_lines == 0 && self->nat_lines == 0)
+    return;
+
+  line_pixels = get_line_pixels (self, &baseline);
+
+  *minimum = self->min_lines * line_pixels;
+  *natural = MAX (self->min_lines, self->nat_lines) * line_pixels;
+
+  if (minimum_baseline)
+    *minimum_baseline = self->min_lines ? baseline : 0;
+  if (natural_baseline)
+    *natural_baseline = (self->min_lines || self->nat_lines) ? baseline : 0;
+}
+
+static void
+gtk_inscription_measure (GtkWidget      *widget,
+                         GtkOrientation  orientation,
+                         int             for_size,
+                         int            *minimum,
+                         int            *natural,
+                         int            *minimum_baseline,
+                         int            *natural_baseline)
+{
+  GtkInscription *self = GTK_INSCRIPTION (widget);
+
+  /* We split this into 2 functions explicitly, so nobody gets the idea
+   * of adding height-for-width to this.
+   * This is meant to be fast, so that is a big no-no.
+   */
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    gtk_inscription_measure_width (self, minimum, natural);
+  else
+    gtk_inscription_measure_height (self, minimum, natural, minimum_baseline, natural_baseline);
+
+  *minimum = PANGO_PIXELS_CEIL (*minimum);
+  *natural = PANGO_PIXELS_CEIL (*natural);
+  if (*minimum_baseline > 0)
+    *minimum_baseline = PANGO_PIXELS_CEIL (*minimum_baseline);
+  if (*natural_baseline > 0)
+    *natural_baseline = PANGO_PIXELS_CEIL (*natural_baseline);
+}
+
+static void
+gtk_inscription_get_layout_location (GtkInscription *self,
+                                     int            *x_out,
+                                     int            *y_out)
+{
+  GtkWidget *widget = GTK_WIDGET (self);
+  const int widget_width = gtk_widget_get_width (widget);
+  const int widget_height = gtk_widget_get_height (widget);
+  PangoRectangle logical;
+  float xalign;
+  int baseline;
+  int x, y;
+
+  g_assert (x_out);
+  g_assert (y_out);
+
+  xalign = self->xalign;
+  if (_gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR)
+    xalign = 1.0 - xalign;
+
+  pango_layout_get_pixel_extents (self->layout, NULL, &logical);
+  x = floor ((xalign * (widget_width - logical.width)) - logical.x);
+
+  baseline = gtk_widget_get_allocated_baseline (widget);
+  if (baseline != -1)
+    {
+      int layout_baseline = pango_layout_get_baseline (self->layout) / PANGO_SCALE;
+      /* yalign is 0 because we can't support yalign while baseline aligning */
+      y = baseline - layout_baseline;
+    }
+  else
+    {
+      y = floor ((widget_height - logical.height) * self->yalign);
+    }
+
+  *x_out = x;
+  *y_out = y;
+}
+
+static void
+gtk_inscription_snapshot (GtkWidget   *widget,
+                          GtkSnapshot *snapshot)
+{
+  GtkInscription *self = GTK_INSCRIPTION (widget);
+  GtkStyleContext *context;
+  int lx, ly;
+
+  if (!self->text || (*self->text == '\0'))
+    return;
+
+  context = _gtk_widget_get_style_context (widget);
+
+  gtk_inscription_get_layout_location (self, &lx, &ly);
+  gtk_snapshot_render_layout (snapshot, context, lx, ly, self->layout);
+}
+
+static void
+gtk_inscription_class_init (GtkInscriptionClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  gobject_class->dispose = gtk_inscription_dispose;
+  gobject_class->finalize = gtk_inscription_finalize;
+  gobject_class->get_property = gtk_inscription_get_property;
+  gobject_class->set_property = gtk_inscription_set_property;
+
+  widget_class->css_changed = gtk_inscription_css_changed;
+  widget_class->measure = gtk_inscription_measure;
+  widget_class->snapshot = gtk_inscription_snapshot;
+
+  /**
+   * GtkInscription:min-chars: (attributes org.gtk.Property.get=gtk_inscription_get_min_chars 
org.gtk.Property.set=gtk_inscription_set_min_chars)
+   *
+   * The number of characters that should fit into the inscription at minimum.
+   *
+   * This influences the requested width, not the width actually given to the widget,
+   * which might turn out to be larger.
+   *
+   * Note that this is an approximate character width, so some characters might be
+   * wider and some might be thinner, so do not expect the number of characters to
+   * exactly match.
+   *
+   * If you set this property to 0, the inscription will not request any width at all
+   * and its width will be determined entirely by its surroundings.
+   *
+   * Since: 4.8
+   */
+  properties[PROP_MIN_CHARS] =
+      g_param_spec_uint ("min-chars", NULL, NULL,
+                         0, G_MAXUINT,
+                         DEFAULT_MIN_CHARS,
+                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GtkInscription:min-lines: (attributes org.gtk.Property.get=gtk_inscription_get_min_lines 
org.gtk.Property.set=gtk_inscription_set_min_lines)
+   *
+   * The number of lines that should fit into the inscription at minimum.
+   *
+   * This influences the requested height, not the height actually given to the widget,
+   * which might turn out to be larger.
+   *
+   * Note that this is an approximate line height, so if the text uses things like fancy
+   * Unicode or attribute that influence the height, the text might not fit.
+   *
+   * If you set this property to 0, the inscription will not request any height at all
+   * and its height will be determined entirely by its surroundings.
+   *
+   * Since: 4.8
+   */
+  properties[PROP_MIN_LINES] =
+      g_param_spec_uint ("min-lines", NULL, NULL,
+                         0, G_MAXUINT,
+                         DEFAULT_MIN_LINES,
+                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GtkInscription:nat-chars: (attributes org.gtk.Property.get=gtk_inscription_get_nat_chars 
org.gtk.Property.set=gtk_inscription_set_nat_chars)
+   *
+   * The number of characters that should ideally fit into the inscription.
+   *
+   * This influences the requested width, not the width actually given to the widget.
+   * The widget might turn out larger as well as smaller.
+   *
+   * If this property is set to a value smaller than [property@Gtk.Inscription:min-chars], and
+   * in particular its default value of 0, that value will be used instead.
+   *
+   * Since: 4.8
+   */
+  properties[PROP_NAT_CHARS] =
+      g_param_spec_uint ("nat-chars", NULL, NULL,
+                         0, G_MAXUINT,
+                         DEFAULT_NAT_CHARS,
+                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GtkInscription:nat-lines: (attributes org.gtk.Property.get=gtk_inscription_get_nat_lines 
org.gtk.Property.set=gtk_inscription_set_nat_lines)
+   *
+   * The number of lines that should ideally fit into the inscription.
+   *
+   * This influences the requested height, not the height actually given to the widget.
+   * The widget might turn out larger as well as smaller.
+   *
+   * If this property is set to a value smaller than [property@Gtk.Inscription:min-lines], and
+   * in particular its default value of 0, that value will be used instead.
+   *
+   * Since: 4.8
+   */
+  properties[PROP_NAT_LINES] =
+      g_param_spec_uint ("nat-lines", NULL, NULL,
+                         0, G_MAXUINT,
+                         DEFAULT_NAT_LINES,
+                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GtkInscription:text: (attributes org.gtk.Property.get=gtk_inscription_get_text 
org.gtk.Property.set=gtk_inscription_set_text)
+   *
+   * The displayed text.
+   *
+   * Since: 4.8
+   */
+  properties[PROP_TEXT] =
+    g_param_spec_string ("text", NULL, NULL,
+                         NULL,
+                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GtkInscription:xalign: (attributes org.gtk.Property.get=gtk_inscription_get_xalign 
org.gtk.Property.set=gtk_inscription_set_xalign)
+   *
+   * The horizontal alignment of the text inside the allocated size.
+   *
+   * Compare this to [property@Gtk.Widget:halign], which determines how the
+   * inscription's size allocation is positioned in the available space.
+   *
+   * Since: 4.8
+   */
+  properties[PROP_XALIGN] =
+      g_param_spec_float ("xalign", NULL, NULL,
+                          0.0, 1.0,
+                          DEFAULT_XALIGN,
+                          G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GtkInscription:yalign: (attributes org.gtk.Property.get=gtk_inscription_get_yalign 
org.gtk.Property.set=gtk_inscription_set_yalign)
+   *
+   * The vertical alignment of the text inside the allocated size.
+   *
+   * Compare this to [property@Gtk.Widget:valign], which determines how the
+   * inscription's size allocation is positioned in the available space.
+   *
+   * Since: 4.8
+   */
+  properties[PROP_YALIGN] =
+      g_param_spec_float ("yalign", NULL, NULL,
+                          0.0, 1.0,
+                          DEFAULT_YALIGN,
+                          G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (gobject_class, N_PROPS, properties);
+}
+
+static void
+gtk_inscription_init (GtkInscription *self)
+{
+  self->min_chars = DEFAULT_MIN_CHARS;
+  self->nat_chars = DEFAULT_NAT_CHARS;
+  self->min_lines = DEFAULT_MIN_LINES;
+  self->nat_lines = DEFAULT_NAT_LINES;
+  self->xalign = DEFAULT_XALIGN;
+  self->yalign = DEFAULT_YALIGN;
+
+  self->layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), NULL);
+}
+
+/**
+ * gtk_inscription_new:
+ * @text: (nullable): The text to display.
+ *
+ * Creates a new `GtkInscription` with the given text.
+ *
+ * Returns: a new `GtkInscription`
+ *
+ * Since: 4.8
+ */
+GtkWidget *
+gtk_inscription_new (const char *text)
+{
+  return g_object_new (GTK_TYPE_INSCRIPTION,
+                       "text", text,
+                       NULL);
+}
+
+/**
+ * gtk_inscription_set_text: (attributes org.gtk.Method.set_property=text)
+ * @self: a `GtkInscription`
+ * @text: (nullable): The text to display
+ *
+ * Sets the text to be displayed.
+ *
+ * Since: 4.8
+ */
+void
+gtk_inscription_set_text (GtkInscription *self,
+                          const char  *text)
+{
+  g_return_if_fail (GTK_IS_INSCRIPTION (self));
+
+  if (g_strcmp0 (self->text, text) == 0)
+    return;
+
+  g_free (self->text);
+  self->text = g_strdup (text);
+
+  pango_layout_set_text (self->layout, self->text, -1);
+
+  /* This here not being a gtk_widget_queue_resize() is why this widget exists */
+  gtk_widget_queue_draw (GTK_WIDGET (self));
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TEXT]);
+}
+
+/**
+ * gtk_inscription_get_text: (attributes org.gtk.Method.get_property=text)
+ * @self: a `GtkInscription`
+ *
+ * Gets the text that is displayed.
+ *
+ * Returns: (nullable) (transfer none): The displayed text
+ *
+ * Since: 4.8
+ */
+const char *
+gtk_inscription_get_text (GtkInscription *self)
+{
+  g_return_val_if_fail (GTK_IS_INSCRIPTION (self), NULL);
+
+  return self->text;
+}
+
+/**
+ * gtk_inscription_set_min_chars: (attributes org.gtk.Method.set_property=min-chars)
+ * @self: a `GtkInscription`
+ * @min_chars: the minimum number of characters that should fit, approximately
+ *
+ * Sets the `min-chars` of the inscription.
+ *
+ * See the [property@Gtk.Inscription:min-chars] property.
+ *
+ * Since: 4.8
+ */
+void
+gtk_inscription_set_min_chars (GtkInscription *self,
+                               guint           min_chars)
+{
+  g_return_if_fail (GTK_IS_INSCRIPTION (self));
+
+  if (self->min_chars == min_chars)
+    return;
+
+  self->min_chars = min_chars;
+
+  gtk_widget_queue_resize (GTK_WIDGET (self));
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MIN_CHARS]);
+}
+
+/**
+ * gtk_inscription_get_min_chars: (attributes org.gtk.Method.get_property=min-chars)
+ * @self: a `GtkInscription`
+ *
+ * Gets the `min-chars` of the inscription.
+ *
+ * See the [property@Gtk.Inscription:min-chars] property.
+ *
+ * Returns: the min-chars property
+ *
+ * Since: 4.8
+ */
+guint
+gtk_inscription_get_min_chars (GtkInscription *self)
+{
+  g_return_val_if_fail (GTK_IS_INSCRIPTION (self), DEFAULT_MIN_CHARS);
+
+  return self->min_chars;
+}
+
+/**
+ * gtk_inscription_set_nat_chars: (attributes org.gtk.Method.set_property=nat-chars)
+ * @self: a `GtkInscription`
+ * @nat_chars: the number of characters that should ideally fit, approximately
+ *
+ * Sets the `nat-chars` of the inscription.
+ *
+ * See the [property@Gtk.Inscription:nat-chars] property.
+ *
+ * Since: 4.8
+ */
+void
+gtk_inscription_set_nat_chars (GtkInscription *self,
+                               guint           nat_chars)
+{
+  g_return_if_fail (GTK_IS_INSCRIPTION (self));
+
+  if (self->nat_chars == nat_chars)
+    return;
+
+  self->nat_chars = nat_chars;
+
+  gtk_widget_queue_resize (GTK_WIDGET (self));
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MIN_CHARS]);
+}
+
+/**
+ * gtk_inscription_get_nat_chars: (attributes org.gtk.Method.get_property=nat-chars)
+ * @self: a `GtkInscription`
+ *
+ * Gets the `nat-chars` of the inscription.
+ *
+ * See the [property@Gtk.Inscription:nat-chars] property.
+ *
+ * Returns: the nat-chars property
+ *
+ * Since: 4.8
+ */
+guint
+gtk_inscription_get_nat_chars (GtkInscription *self)
+{
+  g_return_val_if_fail (GTK_IS_INSCRIPTION (self), DEFAULT_NAT_CHARS);
+
+  return self->nat_chars;
+}
+
+/**
+ * gtk_inscription_set_min_lines: (attributes org.gtk.Method.set_property=min-lines)
+ * @self: a `GtkInscription`
+ * @min_lines: the minimum number of lines that should fit, approximately
+ *
+ * Sets the `min-lines` of the inscription.
+ *
+ * See the [property@Gtk.Inscription:min-lines] property.
+ *
+ * Since: 4.8
+ */
+void
+gtk_inscription_set_min_lines (GtkInscription *self,
+                               guint           min_lines)
+{
+  g_return_if_fail (GTK_IS_INSCRIPTION (self));
+
+  if (self->min_lines == min_lines)
+    return;
+
+  self->min_lines = min_lines;
+
+  gtk_widget_queue_resize (GTK_WIDGET (self));
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MIN_CHARS]);
+}
+
+/**
+ * gtk_inscription_get_min_lines: (attributes org.gtk.Method.get_property=min-lines)
+ * @self: a `GtkInscription`
+ *
+ * Gets the `min-lines` of the inscription.
+ *
+ * See the [property@Gtk.Inscription:min-lines] property.
+ *
+ * Returns: the min-lines property
+ *
+ * Since: 4.8
+ */
+guint
+gtk_inscription_get_min_lines (GtkInscription *self)
+{
+  g_return_val_if_fail (GTK_IS_INSCRIPTION (self), DEFAULT_MIN_LINES);
+
+  return self->min_lines;
+}
+
+/**
+ * gtk_inscription_set_nat_lines: (attributes org.gtk.Method.set_property=nat-lines)
+ * @self: a `GtkInscription`
+ * @nat_lines: the number of lines that should ideally fit
+ *
+ * Sets the `nat-lines` of the inscription.
+ *
+ * See the [property@Gtk.Inscription:nat-lines] property.
+ *
+ * Since: 4.8
+ */
+void
+gtk_inscription_set_nat_lines (GtkInscription *self,
+                               guint           nat_lines)
+{
+  g_return_if_fail (GTK_IS_INSCRIPTION (self));
+
+  if (self->nat_lines == nat_lines)
+    return;
+
+  self->nat_lines = nat_lines;
+
+  gtk_widget_queue_resize (GTK_WIDGET (self));
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MIN_CHARS]);
+}
+
+/**
+ * gtk_inscription_get_nat_lines: (attributes org.gtk.Method.get_property=nat-lines)
+ * @self: a `GtkInscription`
+ *
+ * Gets the `nat-lines` of the inscription.
+ *
+ * See the [property@Gtk.Inscription:nat-lines] property.
+ *
+ * Returns: the nat-lines property
+ *
+ * Since: 4.8
+ */
+guint
+gtk_inscription_get_nat_lines (GtkInscription *self)
+{
+  g_return_val_if_fail (GTK_IS_INSCRIPTION (self), DEFAULT_NAT_LINES);
+
+  return self->nat_lines;
+}
+
+/**
+ * gtk_inscription_set_xalign: (attributes org.gtk.Method.set_property=xalign)
+ * @self: a `GtkInscription`
+ * @xalign: the new xalign value, between 0 and 1
+ *
+ * Sets the `xalign` of the inscription.
+ *
+ * See the [property@Gtk.Inscription:xalign] property.
+ *
+ * Since: 4.8
+ */
+void
+gtk_inscription_set_xalign (GtkInscription *self,
+                            float           xalign)
+{
+  g_return_if_fail (GTK_IS_INSCRIPTION (self));
+
+  xalign = CLAMP (xalign, 0.0, 1.0);
+
+  if (self->xalign == xalign)
+    return;
+
+  self->xalign = xalign;
+
+  gtk_widget_queue_draw (GTK_WIDGET (self));
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_XALIGN]);
+}
+
+/**
+ * gtk_inscription_get_xalign: (attributes org.gtk.Method.get_property=xalign)
+ * @self: a `GtkInscription`
+ *
+ * Gets the `xalign` of the inscription.
+ *
+ * See the [property@Gtk.Inscription:xalign] property.
+ *
+ * Returns: the xalign property
+ *
+ * Since: 4.8
+ */
+float
+gtk_inscription_get_xalign (GtkInscription *self)
+{
+  g_return_val_if_fail (GTK_IS_INSCRIPTION (self), DEFAULT_XALIGN);
+
+  return self->xalign;
+}
+
+/**
+ * gtk_inscription_set_yalign: (attributes org.gtk.Method.set_property=yalign)
+ * @self: a `GtkInscription`
+ * @yalign: the new yalign value, between 0 and 1
+ *
+ * Sets the `yalign` of the inscription.
+ *
+ * See the [property@Gtk.Inscription:yalign] property.
+ *
+ * Since: 4.8
+ */
+void
+gtk_inscription_set_yalign (GtkInscription *self,
+                            float           yalign)
+{
+  g_return_if_fail (GTK_IS_INSCRIPTION (self));
+
+  yalign = CLAMP (yalign, 0.0, 1.0);
+
+  if (self->yalign == yalign)
+    return;
+
+  self->yalign = yalign;
+
+  gtk_widget_queue_draw (GTK_WIDGET (self));
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_YALIGN]);
+}
+
+/**
+ * gtk_inscription_get_yalign: (attributes org.gtk.Method.get_property=yalign)
+ * @self: a `GtkInscription`
+ *
+ * Gets the `yalign` of the inscription.
+ *
+ * See the [property@Gtk.Inscription:yalign] property.
+ *
+ * Returns: the yalign property
+ *
+ * Since: 4.8
+ */
+float
+gtk_inscription_get_yalign (GtkInscription *self)
+{
+  g_return_val_if_fail (GTK_IS_INSCRIPTION (self), DEFAULT_YALIGN);
+
+  return self->yalign;
+}
+
diff --git a/gtk/gtkinscription.h b/gtk/gtkinscription.h
new file mode 100644
index 0000000000..83e7eeb81e
--- /dev/null
+++ b/gtk/gtkinscription.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2022 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GTK_INSCRIPTION_H__
+#define __GTK_INSCRIPTION_H__
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtkwidget.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_INSCRIPTION         (gtk_inscription_get_type ())
+
+GDK_AVAILABLE_IN_4_8
+G_DECLARE_FINAL_TYPE (GtkInscription, gtk_inscription, GTK, INSCRIPTION, GtkWidget)
+
+GDK_AVAILABLE_IN_4_8
+GtkWidget *             gtk_inscription_new                     (const char             *text);
+
+GDK_AVAILABLE_IN_4_8
+const char *            gtk_inscription_get_text                (GtkInscription         *self);
+GDK_AVAILABLE_IN_4_8
+void                    gtk_inscription_set_text                (GtkInscription         *self,
+                                                                 const char             *text);
+
+GDK_AVAILABLE_IN_4_8
+guint                   gtk_inscription_get_min_chars           (GtkInscription         *self);
+GDK_AVAILABLE_IN_4_8
+void                    gtk_inscription_set_min_chars           (GtkInscription         *self,
+                                                                 guint                   min_chars);
+GDK_AVAILABLE_IN_4_8
+guint                   gtk_inscription_get_nat_chars           (GtkInscription         *self);
+GDK_AVAILABLE_IN_4_8
+void                    gtk_inscription_set_nat_chars           (GtkInscription         *self,
+                                                                 guint                   nat_chars);
+GDK_AVAILABLE_IN_4_8
+guint                   gtk_inscription_get_min_lines           (GtkInscription         *self);
+GDK_AVAILABLE_IN_4_8
+void                    gtk_inscription_set_min_lines           (GtkInscription         *self,
+                                                                 guint                   min_lines);
+GDK_AVAILABLE_IN_4_8
+guint                   gtk_inscription_get_nat_lines           (GtkInscription         *self);
+GDK_AVAILABLE_IN_4_8
+void                    gtk_inscription_set_nat_lines           (GtkInscription         *self,
+                                                                 guint                   nat_lines);
+
+GDK_AVAILABLE_IN_4_8
+float                   gtk_inscription_get_xalign              (GtkInscription         *self);
+GDK_AVAILABLE_IN_4_8
+void                    gtk_inscription_set_xalign              (GtkInscription         *self,
+                                                                 float                   xalign);
+GDK_AVAILABLE_IN_4_8
+float                   gtk_inscription_get_yalign              (GtkInscription         *self);
+GDK_AVAILABLE_IN_4_8
+void                    gtk_inscription_set_yalign              (GtkInscription         *self,
+                                                                 float                   yalign);
+
+G_END_DECLS
+
+#endif  /* __GTK_INSCRIPTION_H__ */
diff --git a/gtk/meson.build b/gtk/meson.build
index 322badc1ad..2e404f2ac4 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -283,6 +283,7 @@ gtk_public_sources = files([
   'gtkimmodule.c',
   'gtkimmulticontext.c',
   'gtkinfobar.c',
+  'gtkinscription.c',
   'gtklabel.c',
   'gtklayoutchild.c',
   'gtklayoutmanager.c',
@@ -570,6 +571,7 @@ gtk_public_headers = files([
   'gtkimmodule.h',
   'gtkimmulticontext.h',
   'gtkinfobar.h',
+  'gtkinscription.h',
   'gtklabel.h',
   'gtklayoutchild.h',
   'gtklayoutmanager.h',


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