[gtk/simple-label] gtk-demo: Speed up characters scrolling




commit db2025bb242d69ac8480a37b4c256104a408482a
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Nov 14 00:09:23 2020 -0500

    gtk-demo: Speed up characters scrolling
    
    Use a simple label widget that does not queue a
    resize when the text is changed.

 demos/gtk-demo/listview_ucd.c |  31 ++---
 demos/gtk-demo/meson.build    |   1 +
 demos/gtk-demo/simplelabel.c  | 256 ++++++++++++++++++++++++++++++++++++++++++
 demos/gtk-demo/simplelabel.h  |  15 +++
 4 files changed, 289 insertions(+), 14 deletions(-)
---
diff --git a/demos/gtk-demo/listview_ucd.c b/demos/gtk-demo/listview_ucd.c
index 418e7ca418..987346208d 100644
--- a/demos/gtk-demo/listview_ucd.c
+++ b/demos/gtk-demo/listview_ucd.c
@@ -9,6 +9,7 @@
 #include <gtk/gtk.h>
 #include "script-names.h"
 #include "unicode-names.h"
+#include "simplelabel.h"
 
 
 #define UCD_TYPE_ITEM (ucd_item_get_type ())
@@ -102,7 +103,9 @@ setup_centered_label (GtkSignalListItemFactory *factory,
                       GObject                  *listitem)
 {
   GtkWidget *label;
-  label = gtk_label_new ("");
+  label = simple_label_new ();
+  simple_label_set_min_chars (SIMPLE_LABEL (label), 3);
+  simple_label_set_nat_chars (SIMPLE_LABEL (label), 20);
   gtk_list_item_set_child (GTK_LIST_ITEM (listitem), label);
 }
 
@@ -111,8 +114,9 @@ setup_label (GtkSignalListItemFactory *factory,
              GObject                  *listitem)
 {
   GtkWidget *label;
-  label = gtk_label_new ("");
-  gtk_label_set_xalign (GTK_LABEL (label), 0);
+  label = simple_label_new ();
+  simple_label_set_min_chars (SIMPLE_LABEL (label), 3);
+  simple_label_set_nat_chars (SIMPLE_LABEL (label), 20);
   gtk_list_item_set_child (GTK_LIST_ITEM (listitem), label);
 }
 
@@ -121,10 +125,9 @@ setup_ellipsizing_label (GtkSignalListItemFactory *factory,
                          GObject                  *listitem)
 {
   GtkWidget *label;
-  label = gtk_label_new ("");
-  gtk_label_set_xalign (GTK_LABEL (label), 0);
-  gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
-  gtk_label_set_width_chars (GTK_LABEL (label), 20);
+  label = simple_label_new ();
+  simple_label_set_min_chars (SIMPLE_LABEL (label), 3);
+  simple_label_set_nat_chars (SIMPLE_LABEL (label), 20);
   gtk_list_item_set_child (GTK_LIST_ITEM (listitem), label);
 }
 
@@ -142,7 +145,7 @@ bind_codepoint (GtkSignalListItemFactory *factory,
   codepoint = ucd_item_get_codepoint (UCD_ITEM (item));
 
   g_snprintf (buffer, 10, "%#06x", codepoint);
-  gtk_label_set_label (GTK_LABEL (label), buffer);
+  simple_label_set_text (SIMPLE_LABEL (label), buffer);
 }
 
 static void
@@ -161,7 +164,7 @@ bind_char (GtkSignalListItemFactory *factory,
   if (g_unichar_isprint (codepoint))
     g_unichar_to_utf8 (codepoint, buffer);
 
-  gtk_label_set_label (GTK_LABEL (label), buffer);
+  simple_label_set_text (SIMPLE_LABEL (label), buffer);
 }
 
 static void
@@ -176,7 +179,7 @@ bind_name (GtkSignalListItemFactory *factory,
   item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem));
   name = ucd_item_get_name (UCD_ITEM (item));
 
-  gtk_label_set_label (GTK_LABEL (label), name);
+  simple_label_set_text (SIMPLE_LABEL (label), name);
 }
 
 static void
@@ -191,7 +194,7 @@ bind_type (GtkSignalListItemFactory *factory,
   item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem));
   codepoint = ucd_item_get_codepoint (UCD_ITEM (item));
 
-  gtk_label_set_label (GTK_LABEL (label), get_unicode_type_name (g_unichar_type (codepoint)));
+  simple_label_set_text (SIMPLE_LABEL (label), get_unicode_type_name (g_unichar_type (codepoint)));
 }
 
 static void
@@ -206,7 +209,7 @@ bind_break_type (GtkSignalListItemFactory *factory,
   item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem));
   codepoint = ucd_item_get_codepoint (UCD_ITEM (item));
 
-  gtk_label_set_label (GTK_LABEL (label), get_break_type_name (g_unichar_break_type (codepoint)));
+  simple_label_set_text (SIMPLE_LABEL (label), get_break_type_name (g_unichar_break_type (codepoint)));
 }
 
 static void
@@ -221,7 +224,7 @@ bind_combining_class (GtkSignalListItemFactory *factory,
   item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem));
   codepoint = ucd_item_get_codepoint (UCD_ITEM (item));
 
-  gtk_label_set_label (GTK_LABEL (label), get_combining_class_name (g_unichar_combining_class (codepoint)));
+  simple_label_set_text (SIMPLE_LABEL (label), get_combining_class_name (g_unichar_combining_class 
(codepoint)));
 }
 
 static void
@@ -238,7 +241,7 @@ bind_script (GtkSignalListItemFactory *factory,
   codepoint = ucd_item_get_codepoint (UCD_ITEM (item));
   script = g_unichar_get_script (codepoint);
 
-  gtk_label_set_label (GTK_LABEL (label), get_script_name (script));
+  simple_label_set_text (SIMPLE_LABEL (label), get_script_name (script));
 }
 
 static void
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index 1347baf2aa..1faf185952 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -130,6 +130,7 @@ extra_demo_sources = files([
   'unicode-names.c',
   'suggestionentry.c',
   'language-names.c',
+  'simple-label.c',
 ])
 
 if os_unix
diff --git a/demos/gtk-demo/simplelabel.c b/demos/gtk-demo/simplelabel.c
new file mode 100644
index 0000000000..65978ebbfe
--- /dev/null
+++ b/demos/gtk-demo/simplelabel.c
@@ -0,0 +1,256 @@
+#include "simplelabel.h"
+
+struct _SimpleLabel
+{
+  GtkWidget parent_instance;
+
+  PangoLayout *layout;
+  int min_chars;
+  int nat_chars;
+
+  int min_width;
+  int nat_width;
+  int height;
+};
+
+struct _SimpleLabelClass
+{
+  GtkWidgetClass parent_class;
+};
+
+enum {
+  PROP_TEXT = 1,
+  PROP_MIN_CHARS,
+  PROP_NAT_CHARS,
+  NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
+
+G_DEFINE_TYPE (SimpleLabel, simple_label, GTK_TYPE_WIDGET)
+
+static void
+simple_label_init (SimpleLabel *self)
+{
+  self->layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), "");
+  pango_layout_set_ellipsize (self->layout, PANGO_ELLIPSIZE_END);
+  pango_layout_set_wrap (self->layout, FALSE);
+}
+
+static void
+simple_label_dispose (GObject *object)
+{
+  SimpleLabel *self = SIMPLE_LABEL (object);
+
+  g_clear_object (&self->layout);
+
+  G_OBJECT_CLASS (simple_label_parent_class)->dispose (object);
+}
+
+static void
+simple_label_set_property (GObject      *object,
+                           guint         prop_id,
+                           const GValue *value,
+                           GParamSpec   *pspec)
+{
+  SimpleLabel *self = SIMPLE_LABEL (object);
+
+  switch (prop_id)
+    {
+    case PROP_TEXT:
+      simple_label_set_text (self, g_value_get_string (value));
+      break;
+
+    case PROP_MIN_CHARS:
+      simple_label_set_min_chars (self, g_value_get_int (value));
+      break;
+
+    case PROP_NAT_CHARS:
+      simple_label_set_nat_chars (self, g_value_get_int (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+simple_label_get_property (GObject     *object,
+                           guint        prop_id,
+                           GValue      *value,
+                           GParamSpec  *pspec)
+{
+  SimpleLabel *self = SIMPLE_LABEL (object);
+
+  switch (prop_id)
+    {
+    case PROP_TEXT:
+      g_value_set_string (value, pango_layout_get_text (self->layout));
+      break;
+
+    case PROP_MIN_CHARS:
+      g_value_set_int (value, self->min_chars);
+      break;
+
+    case PROP_NAT_CHARS:
+      g_value_set_int (value, self->nat_chars);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+simple_label_measure (GtkWidget      *widget,
+                      GtkOrientation  orientation,
+                      int             for_size,
+                      int            *minimum,
+                      int            *natural,
+                      int            *minimum_baseline,
+                      int            *natural_baseline)
+{
+  SimpleLabel *self = SIMPLE_LABEL (widget);
+
+  if (orientation == GTK_ORIENTATION_VERTICAL)
+    {
+      *minimum = *natural = self->height;
+    }
+  else
+    {
+      *minimum = self->min_width;
+      *natural = self->nat_width;
+    }
+}
+
+static void
+simple_label_size_allocate (GtkWidget *widget,
+                            int        width,
+                            int        height,
+                            int        baseline)
+{
+  SimpleLabel *self = SIMPLE_LABEL (widget);
+
+  pango_layout_set_width (self->layout, width * PANGO_SCALE);
+}
+
+static void
+simple_label_snapshot (GtkWidget   *widget,
+                       GtkSnapshot *snapshot)
+{
+  SimpleLabel *self = SIMPLE_LABEL (widget);
+  GtkStyleContext *context;
+
+  context = gtk_widget_get_style_context (widget);
+
+  gtk_snapshot_render_layout (snapshot, context, 0, 0, self->layout);
+}
+
+static void
+simple_label_class_init (SimpleLabelClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+  object_class->dispose = simple_label_dispose;
+  object_class->set_property = simple_label_set_property;
+  object_class->get_property = simple_label_get_property;
+
+  widget_class->measure = simple_label_measure;
+  widget_class->size_allocate = simple_label_size_allocate;
+  widget_class->snapshot = simple_label_snapshot;
+
+  properties[PROP_TEXT] =
+    g_param_spec_string ("text", "Text", "Text",
+                         NULL,
+                         G_PARAM_READWRITE);
+
+  properties[PROP_MIN_CHARS] =
+    g_param_spec_int ("min-chars", "Minimum Characters", "Minimum Characters",
+                      0, G_MAXINT, 0,
+                      G_PARAM_READWRITE);
+
+  properties[PROP_NAT_CHARS] =
+    g_param_spec_int ("nat-chars", "Natural Characters", "Natural Characters",
+                      0, G_MAXINT, 0,
+                      G_PARAM_READWRITE);
+
+  g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
+}
+
+GtkWidget *
+simple_label_new (void)
+{
+  return g_object_new (SIMPLE_TYPE_LABEL, NULL);
+}
+
+void
+simple_label_set_text (SimpleLabel *self,
+                       const char  *text)
+{
+  pango_layout_set_text (self->layout, text, -1);
+
+  gtk_widget_queue_draw (GTK_WIDGET (self));
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TEXT]);
+}
+
+static void
+recalculate (SimpleLabel *self)
+{
+  PangoContext *context;
+  PangoFontMetrics *metrics;
+  int char_width;
+  int digit_width;
+  int width;
+  int ascent;
+  int descent;
+
+  context = gtk_widget_get_pango_context (GTK_WIDGET (self));
+  metrics = pango_context_get_metrics (context,
+                                       pango_context_get_font_description (context),
+                                       pango_context_get_language (context));
+  char_width = pango_font_metrics_get_approximate_char_width (metrics);
+  digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
+  ascent = pango_font_metrics_get_ascent (metrics);
+  descent = pango_font_metrics_get_descent (metrics);
+  pango_font_metrics_unref (metrics);
+
+  width = MAX (char_width, digit_width);
+
+  self->min_width = (width * self->min_chars) / PANGO_SCALE;
+  self->nat_width = (width * self->nat_chars) / PANGO_SCALE;
+  self->height = (ascent + descent) / PANGO_SCALE;
+}
+
+void
+simple_label_set_min_chars (SimpleLabel *self,
+                            int          min_chars)
+{
+  if (self->min_chars == min_chars)
+    return;
+
+  self->min_chars = min_chars;
+
+  recalculate (self);
+  gtk_widget_queue_resize (GTK_WIDGET (self));
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MIN_CHARS]);
+}
+
+void
+simple_label_set_nat_chars (SimpleLabel *self,
+                            int          nat_chars)
+{
+  if (self->nat_chars == nat_chars)
+    return;
+
+  self->nat_chars = nat_chars;
+
+  recalculate (self);
+  gtk_widget_queue_resize (GTK_WIDGET (self));
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_NAT_CHARS]);
+}
diff --git a/demos/gtk-demo/simplelabel.h b/demos/gtk-demo/simplelabel.h
new file mode 100644
index 0000000000..04ef3ea8e8
--- /dev/null
+++ b/demos/gtk-demo/simplelabel.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <gtk/gtk.h>
+
+#define SIMPLE_TYPE_LABEL (simple_label_get_type ())
+G_DECLARE_FINAL_TYPE (SimpleLabel, simple_label, SIMPLE, LABEL, GtkWidget)
+
+GtkWidget * simple_label_new           (void);
+
+void        simple_label_set_text      (SimpleLabel *self,
+                                        const char  *text);
+void        simple_label_set_min_chars (SimpleLabel *self,
+                                        int          min_chars);
+void        simple_label_set_nat_chars (SimpleLabel *self,
+                                        int          nat_chars);


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