[gtk/wip/ebassi/constraint-layout] Add custom parser for guides defined in GtkBuilder UI files



commit 8ab609e4e7824e8150f4620c41f1d62c092ebb05
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Mon Jul 1 19:22:48 2019 +0100

    Add custom parser for guides defined in GtkBuilder UI files
    
    Like we describe constraints, we can also define guides.

 gtk/gtkconstraintlayout.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 160 insertions(+)
---
diff --git a/gtk/gtkconstraintlayout.c b/gtk/gtkconstraintlayout.c
index ccca990f93..4623798b5e 100644
--- a/gtk/gtkconstraintlayout.c
+++ b/gtk/gtkconstraintlayout.c
@@ -103,6 +103,27 @@
  * The "source" and "target" attributes can be set to "super" to indicate
  * that the constraint target is the widget using the GtkConstraintLayout.
  *
+ * Additionally, the "constraints" element can also contain a description
+ * of the #GtkConstraintGuides used by the layout:
+ *
+ * |[
+ *   <constraints>
+ *     <guide min-width="100" max-width="500" name="hspace"/>
+ *     <guide min-height="64" nat-height="128" name="vspace" strength="strong"/>
+ *   </constraints>
+ * ]|
+ *
+ * The "guide" element has the following optional attributes:
+ *
+ *   - "min-width", "nat-width", and "max-width", describe the minimum,
+ *     natural, and maximum width of the guide, respectively
+ *   - "min-height", "nat-height", and "max-height", describe the minimum,
+ *     natural, and maximum height of the guide, respectively
+ *   - "strength" describes the strength of the constraint on the natural
+ *     size of the guide; if not specified, the constraint is assumed to
+ *     have a medium strength
+ *   - "name" describes a name for the guide, useful when debugging
+ *
  * # Using the Visual Format Language
  *
  * Complex constraints can be described using a compact syntax called VFL,
@@ -1187,6 +1208,7 @@ typedef struct {
   GtkConstraintLayout *layout;
   GtkBuilder *builder;
   GList *constraints;
+  GList *guides;
 } ConstraintsParserData;
 
 typedef struct {
@@ -1200,6 +1222,14 @@ typedef struct {
   double multiplier;
 } ConstraintData;
 
+typedef struct {
+  char *name;
+  char *strength;
+  struct {
+    int min, nat, max;
+  } sizes[2];
+} GuideData;
+
 static void
 constraint_data_free (gpointer _data)
 {
@@ -1215,6 +1245,17 @@ constraint_data_free (gpointer _data)
   g_free (data);
 }
 
+static void
+guide_data_free (gpointer _data)
+{
+  GuideData *data = _data;
+
+  g_free (data->name);
+  g_free (data->strength);
+
+  g_free (data);
+}
+
 static void
 parse_double (const char *string,
               double     *value_p,
@@ -1241,6 +1282,32 @@ parse_double (const char *string,
   errno = saved_errno;
 }
 
+static void
+parse_int (const char *string,
+           int        *value_p,
+           int         default_value)
+{
+  gint64 value;
+  char *endptr;
+  int saved_errno;
+
+  if (string == NULL || string[0] == '\0')
+    {
+      *value_p = default_value;
+      return;
+    }
+
+  saved_errno = errno;
+  errno = 0;
+  value = g_ascii_strtoll (string, &endptr, 10);
+  if (errno == 0 && endptr != string)
+    *value_p = (int) value;
+  else
+    *value_p = default_value;
+
+  errno = saved_errno;
+}
+
 static GtkConstraint *
 constraint_data_to_constraint (const ConstraintData *data,
                                GtkBuilder           *builder,
@@ -1322,6 +1389,8 @@ constraint_data_to_constraint (const ConstraintData *data,
                                            data->strength,
                                            &strength,
                                            error);
+      if (!res)
+        return NULL;
     }
   else
     strength = GTK_CONSTRAINT_STRENGTH_REQUIRED;
@@ -1340,6 +1409,38 @@ constraint_data_to_constraint (const ConstraintData *data,
                                       strength);
 }
 
+static GtkConstraintGuide *
+guide_data_to_guide (const GuideData *data,
+                     GtkBuilder      *builder,
+                     GError         **error)
+{
+  int strength;
+  gboolean res;
+
+  if (data->strength != NULL)
+    {
+      res = _gtk_builder_enum_from_string (GTK_TYPE_CONSTRAINT_STRENGTH,
+                                           data->strength,
+                                           &strength,
+                                           error);
+      if (!res)
+        return NULL;
+    }
+  else
+    strength = GTK_CONSTRAINT_STRENGTH_MEDIUM;
+
+  return g_object_new (GTK_TYPE_CONSTRAINT_GUIDE,
+                       "min-width", data->sizes[GTK_ORIENTATION_HORIZONTAL].min,
+                       "nat-width", data->sizes[GTK_ORIENTATION_HORIZONTAL].nat,
+                       "max-width", data->sizes[GTK_ORIENTATION_HORIZONTAL].max,
+                       "min-height", data->sizes[GTK_ORIENTATION_VERTICAL].min,
+                       "nat-height", data->sizes[GTK_ORIENTATION_VERTICAL].nat,
+                       "max-height", data->sizes[GTK_ORIENTATION_VERTICAL].max,
+                       "strength", strength,
+                       "name", data->name,
+                       NULL);
+}
+
 static void
 constraints_start_element (GMarkupParseContext  *context,
                            const char           *element_name,
@@ -1399,6 +1500,44 @@ constraints_start_element (GMarkupParseContext  *context,
 
       data->constraints = g_list_prepend (data->constraints, cdata);
     }
+  else if (strcmp (element_name, "guide") == 0)
+    {
+      const char *min_width, *nat_width, *max_width;
+      const char *min_height, *nat_height, *max_height;
+      const char *strength_str;
+      const char *name;
+      GuideData *gdata;
+
+      if (!_gtk_builder_check_parent (data->builder, context, "constraints", error))
+        return;
+
+      if (!g_markup_collect_attributes (element_name, attr_names, attr_values, error,
+                                        G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "min-width", 
&min_width,
+                                        G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "nat-width", 
&nat_width,
+                                        G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "max-width", 
&max_width,
+                                        G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "min-height", 
&min_height,
+                                        G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "nat-height", 
&nat_height,
+                                        G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "max-height", 
&max_height,
+                                        G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "strength", 
&strength_str,
+                                        G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "name", &name,
+                                        G_MARKUP_COLLECT_INVALID))
+        {
+          _gtk_builder_prefix_error (data->builder, context, error);
+          return;
+        }
+
+      gdata = g_new0 (GuideData, 1);
+      parse_int (min_width, &(gdata->sizes[GTK_ORIENTATION_HORIZONTAL].min), 0);
+      parse_int (nat_width, &(gdata->sizes[GTK_ORIENTATION_HORIZONTAL].nat), 0);
+      parse_int (max_width, &(gdata->sizes[GTK_ORIENTATION_HORIZONTAL].max), G_MAXINT);
+      parse_int (min_height, &(gdata->sizes[GTK_ORIENTATION_VERTICAL].min), 0);
+      parse_int (nat_height, &(gdata->sizes[GTK_ORIENTATION_VERTICAL].nat), 0);
+      parse_int (max_height, &(gdata->sizes[GTK_ORIENTATION_VERTICAL].max), G_MAXINT);
+      gdata->name = g_strdup (name);
+      gdata->strength = g_strdup (strength_str);
+
+      data->guides = g_list_prepend (data->guides, gdata);
+    }
   else
     {
       _gtk_builder_error_unhandled_tag (data->builder, context,
@@ -1436,6 +1575,7 @@ gtk_constraint_layout_custom_tag_start (GtkBuildable  *buildable,
       data->layout = g_object_ref (GTK_CONSTRAINT_LAYOUT (buildable));
       data->builder = builder;
       data->constraints = NULL;
+      data->guides = NULL;
 
       *parser = constraints_parser;
       *parser_data = data;
@@ -1468,6 +1608,25 @@ gtk_constraint_layout_custom_finished (GtkBuildable *buildable,
     {
       GList *l;
 
+      data->guides = g_list_reverse (data->guides);
+      for (l = data->guides; l != NULL; l = l->next)
+        {
+          const GuideData *gdata = l->data;
+          GtkConstraintGuide *g;
+          GError *error = NULL;
+
+          g = guide_data_to_guide (gdata, builder, &error);
+          if (error != NULL)
+            {
+              g_critical ("Unable to parse guide definition: %s",
+                          error->message);
+              g_error_free (error);
+              continue;
+            }
+
+          gtk_constraint_layout_add_guide (data->layout, g);
+        }
+
       data->constraints = g_list_reverse (data->constraints);
       for (l = data->constraints; l != NULL; l = l->next)
         {
@@ -1493,6 +1652,7 @@ gtk_constraint_layout_custom_finished (GtkBuildable *buildable,
         }
 
       g_list_free_full (data->constraints, constraint_data_free);
+      g_list_free_full (data->guides, guide_data_free);
       g_object_unref (data->layout);
       g_free (data);
     }


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