[gtk/avoid-label-resizes] wip: Add a bin with slack



commit c640e4a4ccf3f6f228676127429015706bb5fa09
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon May 18 21:18:36 2020 -0400

    wip: Add a bin with slack
    
    Just an experiment: Make a bin that adds 'slack' around
    its child, and avoids resizing unless the child size changes
    more than the slack allows.

 tests/meson.build |   1 +
 tests/testslack.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 272 insertions(+)
---
diff --git a/tests/meson.build b/tests/meson.build
index 5cb5a04d92..6de29e1d6d 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -82,6 +82,7 @@ gtk_tests = [
   ['testscrolledge'],
   ['testscrolltofocus'],
   ['testcellarea'],
+  ['testslack'],
   ['testswitch'],
   ['testtreepos'],
   ['testsensitive'],
diff --git a/tests/testslack.c b/tests/testslack.c
new file mode 100644
index 0000000000..529748d1f8
--- /dev/null
+++ b/tests/testslack.c
@@ -0,0 +1,271 @@
+#include <gtk/gtk.h>
+
+#define GTK_TYPE_SLACK (gtk_slack_get_type ())
+G_DECLARE_FINAL_TYPE (GtkSlack, gtk_slack, GTK, SLACK, GtkWidget)
+
+struct _GtkSlack {
+  GtkWidget parent;
+
+  GtkWidget *child;
+
+  gboolean has_width;
+  gboolean has_height;
+  int width;
+  int height;
+  int hslack;
+  int vslack;
+};
+
+struct _GtkSlackClass {
+  GtkWidgetClass parent_class;
+};
+
+enum {
+  PROP_HSLACK = 1,
+  PROP_VSLACK,
+  LAST_PROP
+};
+
+static GParamSpec *props[LAST_PROP];
+
+G_DEFINE_TYPE (GtkSlack, gtk_slack, GTK_TYPE_WIDGET)
+
+static void
+gtk_slack_init (GtkSlack *slack)
+{
+  slack->has_width = FALSE;
+  slack->has_height = FALSE;
+  slack->hslack = 0;
+  slack->vslack = 0;
+}
+
+static void
+gtk_slack_measure (GtkWidget      *widget,
+                   GtkOrientation  orientation,
+                   gint            for_size,
+                   gint            *minimum,
+                   gint            *natural,
+                   gint            *minimum_baseline,
+                   gint            *natural_baseline)
+{
+  GtkSlack *slack = GTK_SLACK (widget);
+  int child_min, child_nat;
+
+  if (slack->child && gtk_widget_get_visible (slack->child))
+    {
+      gtk_widget_measure (slack->child,
+                          orientation, for_size,
+                          &child_min, &child_nat,
+                          NULL, NULL);
+    }
+  else
+    {
+      child_min = 0;
+      child_nat = 0;
+    }
+
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      if (!slack->has_width)
+        {
+          slack->width = child_nat + slack->hslack;
+          slack->has_width = TRUE;
+        }
+      else if (abs (slack->width - child_nat) > slack->hslack)
+        {
+          slack->width = child_nat + slack->hslack;
+        }
+      else
+        {
+          slack->width = MAX (slack->width, child_min);
+        }
+
+      *minimum = child_min;
+      *natural = slack->width;
+    }
+  else
+    {
+      if (!slack->has_height)
+        {
+          slack->height = child_nat + slack->vslack;
+          slack->has_height = TRUE;
+        }
+      else if(abs (slack->height - child_nat) > slack->vslack)
+        {
+          slack->height = child_nat + slack->vslack;
+        }
+      else
+        {
+          slack->height = MAX (slack->height, child_min);
+        }
+
+      *minimum = child_min;
+      *natural = slack->height;
+    }
+}
+
+static void
+gtk_slack_size_allocate (GtkWidget *widget,
+                         int        width,
+                         int        height,
+                         int        baseline)
+{
+  GtkSlack *slack = GTK_SLACK (widget);
+  GtkAllocation allocation;
+
+  allocation.x = 0;
+  allocation.y = 0;
+  allocation.width = width;
+  allocation.height = height;
+
+  gtk_widget_size_allocate (slack->child, &allocation, -1);
+}
+
+static void
+gtk_slack_set_property (GObject         *object,
+                        guint            prop_id,
+                        const GValue    *value,
+                        GParamSpec      *pspec)
+{
+  GtkSlack *slack = GTK_SLACK (object);
+
+  switch (prop_id)
+    {
+    case PROP_HSLACK:
+      if (slack->hslack != g_value_get_int (value))
+        {
+          slack->hslack = g_value_get_int (value);
+          slack->has_width = FALSE;
+          gtk_widget_queue_resize (GTK_WIDGET (slack));
+        }
+      break;
+    case PROP_VSLACK:
+      if (slack->vslack != g_value_get_int (value))
+        {
+          slack->vslack = g_value_get_int (value);
+          slack->has_height = FALSE;
+          gtk_widget_queue_resize (GTK_WIDGET (slack));
+        }
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_slack_get_property (GObject         *object,
+                        guint            prop_id,
+                        GValue          *value,
+                        GParamSpec      *pspec)
+{
+  GtkSlack *slack = GTK_SLACK (object);
+
+  switch (prop_id)
+    {
+    case PROP_HSLACK:
+      g_value_set_int (value, slack->hslack);
+      break;
+    case PROP_VSLACK:
+      g_value_set_int (value, slack->vslack);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_slack_class_init (GtkSlackClass *class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+  gobject_class->get_property = gtk_slack_get_property;
+  gobject_class->set_property = gtk_slack_set_property;
+
+  widget_class->measure = gtk_slack_measure;
+  widget_class->size_allocate = gtk_slack_size_allocate;
+
+  props[PROP_HSLACK] =
+    g_param_spec_int ("hslack", "Horizontal Slack", "Horizontal Slack",
+                      0, 100, 0,
+                      G_PARAM_READWRITE);
+  props[PROP_VSLACK] =
+    g_param_spec_int ("vslack", "Vertical Slack", "Vertical Slack",
+                      0, 100, 0,
+                      G_PARAM_READWRITE);
+
+  g_object_class_install_properties (gobject_class, LAST_PROP, props);
+
+  gtk_widget_class_set_css_name (widget_class, "slack");
+}
+
+static GtkWidget *
+gtk_slack_new (void)
+{
+  return g_object_new (GTK_TYPE_SLACK, NULL);
+}
+
+static void
+gtk_slack_set_child (GtkSlack  *slack,
+                     GtkWidget *widget)
+{
+  slack->child = widget;
+  gtk_widget_set_parent (widget, GTK_WIDGET (slack));
+}
+
+static gboolean
+close_cb (GtkWindow *window, gpointer data)
+{
+  *((gboolean *)data) = TRUE;
+
+  g_main_context_wakeup (NULL);
+
+  return TRUE;
+}
+
+static const char css[] =
+"window {"
+"  background: blue; "
+"}"
+".label {"
+"  background: yellow;"
+"}";
+
+int
+main (int argc, char *argv[])
+{
+  gboolean done = FALSE;
+  GtkWidget *window;
+  GtkWidget *slack;
+  GtkWidget *label;
+  GtkCssProvider *provider;
+
+  gtk_init ();
+
+  provider = gtk_css_provider_new ();
+  gtk_css_provider_load_from_data (provider, css, -1);
+  gtk_style_context_add_provider_for_display (gdk_display_get_default (),
+                                              GTK_STYLE_PROVIDER (provider),
+                                              800);
+
+  window = gtk_window_new ();
+  g_signal_connect (window, "close-request", G_CALLBACK (close_cb), &done);
+
+  slack = gtk_slack_new ();
+  gtk_widget_set_halign (slack, GTK_ALIGN_CENTER);
+  gtk_widget_set_valign (slack, GTK_ALIGN_CENTER);
+  gtk_window_set_child (GTK_WINDOW (window), slack);
+
+  label = gtk_label_new ("Test");
+  gtk_widget_add_css_class (label, "label");
+  gtk_slack_set_child (GTK_SLACK (slack), label);
+
+  gtk_window_present (GTK_WINDOW (window));
+
+  while (!done)
+    g_main_context_iteration (NULL, TRUE);
+
+  gtk_window_destroy (GTK_WINDOW (window));
+}


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