[gtk/wip/layout-manager: 430/431] WIP: GtkGridLayout



commit 0340a8f1521e9e1f22239c17c491251b2157972d
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Tue Feb 5 14:14:14 2019 +0100

    WIP: GtkGridLayout

 gtk/gtkgridlayout.c        | 334 +++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkgridlayout.h        |  66 +++++++++
 gtk/gtkgridlayoutchild.c   | 175 ++++++++++++++++++++++++
 gtk/gtkgridlayoutprivate.h |  27 ++++
 4 files changed, 602 insertions(+)
---
diff --git a/gtk/gtkgridlayout.c b/gtk/gtkgridlayout.c
new file mode 100644
index 0000000000..38641643f3
--- /dev/null
+++ b/gtk/gtkgridlayout.c
@@ -0,0 +1,334 @@
+#include "config.h"
+
+#include "gtkgridlayoutprivate.h"
+
+#include "gtkcsspositionvalueprivate.h"
+#include "gtkenums.h"
+#include "gtkintl.h"
+#include "gtkorientableprivate.h"
+#include "gtkprivate.h"
+#include "gtksizerequest.h"
+#include "gtkstylecontextprivate.h"
+#include "gtkwidgetprivate.h"
+
+#include <string.h>
+
+/**
+ * SECTION:gtkgridlayout
+ * @Short_description: Pack widgets in rows and columns
+ * @Title: GtkGridLayout
+ * @See_also: #GtkBoxLayout
+ *
+ * GtkGridLayout is a layout manager which arranges its child widgets in
+ * rows and columns, with arbitrary positions and horizontal/vertical spans.
+ *
+ * Children can span multiple rows or columns. The behaviour of GtkGridLayout
+ * when several children occupy the same grid cell is undefined.
+ *
+ * If you do not specify the attach points for each widget, GtkGridLayout
+ * behaves like a #GtkBoxLayout, and will lay out children in a single row
+ * or column, using the the #GtkOrientable:orientation property. However, if
+ * all you want is a single row or column, then #GtkBoxLayout is the preferred
+ * layout manager.
+ */
+
+typedef struct _GridRowProperties       GridRowProperties;
+typedef struct _GridLineData            GridLineData;
+typedef struct _GridLine                GridLine;
+typedef struct _GridLines               GridLines;
+
+struct _GridRowProperties
+{
+  int row;
+  GtkBaselinePosition baseline_position;
+};
+
+/* A GtkGridLineData struct contains row/column specific parts
+ * of the grid.
+ */
+struct _GridLineData
+{
+  gint16 spacing;
+  guint homogeneous : 1;
+};
+
+#define ROWS(layout)    (&(layout)->linedata[GTK_ORIENTATION_HORIZONTAL])
+#define COLUMNS(layout) (&(layout)->linedata[GTK_ORIENTATION_VERTICAL])
+
+/* A GridLine struct represents a single row or column
+ * during size requests
+ */
+struct _GridLine
+{
+  int minimum;
+  int natural;
+  int minimum_above;
+  int minimum_below;
+  int natural_above;
+  int natural_below;
+
+  int position;
+  int allocation;
+  int allocated_baseline;
+
+  guint need_expand : 1;
+  guint expand      : 1;
+  guint empty       : 1;
+};
+
+struct _GridLines
+{
+  GridLine *lines;
+  int min, max;
+};
+
+struct _GtkGridRequest
+{
+  GtkGridLayout *grid;
+
+  GridLines lines[2];
+};
+
+struct _GtkGridLayout
+{
+  GtkLayoutManager parent_instance;
+
+  GList *row_properties;
+
+  GtkOrientation orientation;
+  int baseline_row;
+
+  GridLineData linedata[2];
+};
+
+enum
+{
+  PROP_ROW_SPACING = 1,
+  PROP_COLUMN_SPACING,
+  PROP_ROW_HOMOGENEOUS,
+  PROP_COLUMN_HOMOGENEOUS,
+  PROP_BASELINE_ROW,
+
+  N_PROPERTIES,
+
+  /* from GtkOrientable */
+  PROP_ORIENTATION
+};
+
+static const GridRowProperties grid_row_properties_default = {
+  0,
+  GTK_BASELINE_POSITION_CENTER
+};
+
+static GParamSpec *grid_layout_props[N_PROPERTIES];
+
+G_DEFINE_TYPE_WITH_CODE (GtkGridLayout, gtk_grid_layout, GTK_TYPE_LAYOUT_MANAGER,
+  G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
+
+static void
+gtk_grid_layout_create_layout_child (GtkLayoutManager *manager,
+                                     GtkWidget        *child)
+{
+  return g_object_new (GTK_TYPE_GRID_LAYOUT_CHILD,
+                       "layout-manager", manager,
+                       "child-widget", child,
+                       NULL);
+}
+
+static void
+gtk_grid_layout_finalize (GObject *gobject)
+{
+  G_OBJECT_CLASS (gtk_grid_layout_parent_class)->finalize (gobject);
+}
+
+static void
+gtk_grid_layout_get_property (GObject    *gobject,
+                              guint       prop_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+  GtkGridLayout *self = GTK_GRID_LAYOUT (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_ORIENTATION:
+      g_value_set_enum (value, self->orientation);
+      break;
+
+    case PROP_ROW_SPACING:
+      g_value_set_int (value, COLUMNS (self)->spacing);
+      break;
+
+    case PROP_COLUMN_SPACING:
+      g_value_set_int (value, ROWS (self)->spacing);
+      break;
+
+    case PROP_ROW_HOMOGENEOUS:
+      g_value_set_boolean (value, COLUMNS (self)->homogeneous);
+      break;
+
+    case PROP_COLUMN_HOMOGENEOUS:
+      g_value_set_boolean (value, ROWS (self)->homogeneous);
+      break;
+
+    case PROP_BASELINE_ROW:
+      g_value_set_int (value, self->baseline_row);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_grid_layout_set_orientation (GtkGridLayout  *self,
+                                 GtkOrientation  orientation)
+{
+  GtkLayoutManager *layout_manager = GTK_LAYOUT_MANAGER (self);
+  GtkWidget *widget;
+
+  if (self->orientation == orientation)
+    return;
+
+  self->orientation = orientation;
+
+  widget = gtk_layout_manager_get_widget (GTK_LAYOUT_MANAGER (self));
+  if (widget != NULL && GTK_IS_ORIENTABLE (widget))
+    _gtk_orientable_set_style_classes (GTK_ORIENTABLE (widget));
+
+  gtk_layout_manager_layout_changed (layout_manager);
+}
+
+static void
+gtk_grid_layout_set_property (GObject      *gobject,
+                              guint         prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+  GtkGridLayout *self = GTK_GRID_LAYOUT (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_ORIENTATION:
+      gtk_grid_layout_set_orientation (self, g_value_get_enum (value));
+      break;
+
+    case PROP_ROW_SPACING:
+      gtk_grid_layout_set_row_spacing (self, g_value_get_int (value));
+      break;
+
+    case PROP_COLUMN_SPACING:
+      gtk_grid_layout_set_column_spacing (self, g_value_get_int (value));
+      break;
+
+    case PROP_ROW_HOMOGENEOUS:
+      gtk_grid_layout_set_row_homogeneous (self, g_value_get_boolean (value));
+      break;
+
+    case PROP_COLUMN_HOMOGENEOUS:
+      gtk_grid_layout_set_column_homogeneous (self, g_value_get_boolean (value));
+      break;
+
+    case PROP_BASELINE_ROW:
+      gtk_grid_layout_set_baseline_row (self, g_value_get_int (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_grid_layout_class_init (GtkGridLayoutClass *klass)
+{
+  GtkLayoutManagerClass *manager_class = GTK_LAYOUT_MANAGER_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  manager_class->create_layout_child = gtk_grid_layout_create_layout_child;
+
+  gobject_class->set_property = gtk_grid_layout_set_property;
+  gobject_class->get_property = gtk_grid_layout_get_property;
+
+  g_object_class_install_properties (gobject_class, N_PROPERTIES, grid_layout_props);
+}
+
+static void
+gtk_grid_layout_init (GtkGridLayout *self)
+{
+}
+
+GtkLayoutManager *
+gtk_grid_layout_new (void)
+{
+  return g_object_new (GTK_TYPE_GRID_LAYOUT, NULL);
+}
+
+void
+gtk_grid_layout_set_row_homogeneous (GtkGridLayout *grid_layout,
+                                     gboolean       homogeneous)
+{
+}
+
+gboolean
+gtk_grid_layout_get_row_homogeneous (GtkGridLayout *grid_layout)
+{
+}
+
+void
+gtk_grid_layout_set_row_spacing (GtkGridLayout *grid_layout,
+                                 guint          spacing)
+{
+}
+
+guint
+gtk_grid_layout_get_row_spacing (GtkGridLayout *grid_layout)
+{
+}
+
+void
+gtk_grid_layout_set_column_homogeneous (GtkGridLayout *grid_layout,
+                                        gboolean       homogeneous)
+{
+}
+
+gboolean
+gtk_grid_layout_get_column_homogeneous (GtkGridLayout *grid_layout)
+{
+}
+
+void
+gtk_grid_layout_set_column_spacing (GtkGridLayout *grid_layout,
+                                    guint          spacing)
+{
+}
+
+guint
+gtk_grid_layout_get_column_spacing (GtkGridLayout *grid_layout)
+{
+}
+
+void
+gtk_grid_layout_set_row_baseline_position (GtkGridLayout       *grid_layout,
+                                           int                  row,
+                                           GtkBaselinePosition  pos)
+{
+}
+
+GtkBaselinePosition
+gtk_grid_layout_get_row_baseline_position (GtkGridLayout *grid_layout,
+                                           int            row)
+{
+}
+
+void
+gtk_grid_layout_set_baseline_row (GtkGridLayout *grid_layout,
+                                  int            row)
+{
+}
+
+int
+gtk_grid_layout_get_baseline_row (GtkGridLayout *grid_layout)
+{
+}
diff --git a/gtk/gtkgridlayout.h b/gtk/gtkgridlayout.h
new file mode 100644
index 0000000000..4fadfd928b
--- /dev/null
+++ b/gtk/gtkgridlayout.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtklayoutmanager.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_GRID_LAYOUT (gtk_grid_layout_get_type())
+
+GDK_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (GtkGridLayout, gtk_grid_layout, GTK, GRID_LAYOUT, GtkLayoutManager)
+
+GDK_AVAILABLE_IN_ALL
+GtkLayoutManager *      gtk_grid_layout_new                             (void);
+
+GDK_AVAILABLE_IN_ALL
+void                    gtk_grid_layout_set_row_homogeneous             (GtkGridLayout       *grid_layout,
+                                                                         gboolean             homogeneous);
+GDK_AVAILABLE_IN_ALL
+gboolean                gtk_grid_layout_get_row_homogeneous             (GtkGridLayout       *grid_layout);
+GDK_AVAILABLE_IN_ALL
+void                    gtk_grid_layout_set_row_spacing                 (GtkGridLayout       *grid_layout,
+                                                                         guint                spacing);
+GDK_AVAILABLE_IN_ALL
+guint                   gtk_grid_layout_get_row_spacing                 (GtkGridLayout       *grid_layout);
+GDK_AVAILABLE_IN_ALL
+void                    gtk_grid_layout_set_column_homogeneous          (GtkGridLayout       *grid_layout,
+                                                                         gboolean             homogeneous);
+GDK_AVAILABLE_IN_ALL
+gboolean                gtk_grid_layout_get_column_homogeneous          (GtkGridLayout       *grid_layout);
+GDK_AVAILABLE_IN_ALL
+void                    gtk_grid_layout_set_column_spacing              (GtkGridLayout       *grid_layout,
+                                                                         guint                spacing);
+GDK_AVAILABLE_IN_ALL
+guint                   gtk_grid_layout_get_column_spacing              (GtkGridLayout       *grid_layout);
+GDK_AVAILABLE_IN_ALL
+void                    gtk_grid_layout_set_row_baseline_position       (GtkGridLayout       *grid_layout,
+                                                                         int                  row,
+                                                                         GtkBaselinePosition  pos);
+GDK_AVAILABLE_IN_ALL
+GtkBaselinePosition     gtk_grid_layout_get_row_baseline_position       (GtkGridLayout       *grid_layout,
+                                                                         int                  row);
+GDK_AVAILABLE_IN_ALL
+void                    gtk_grid_layout_set_baseline_row                (GtkGridLayout       *grid_layout,
+                                                                         int                  row);
+GDK_AVAILABLE_IN_ALL
+int                     gtk_grid_layout_get_baseline_row                (GtkGridLayout       *grid_layout);
+
+#define GTK_TYPE_GRID_LAYOUT_CHILD (gtk_grid_layout_child_get_type())
+
+GDK_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (GtkGridLayoutChild, gtk_grid_layout_child, GTK, GRID_LAYOUT_CHILD, GtkLayoutChild)
+
+GDK_AVAILABLE_IN_ALL
+int                     gtk_grid_layout_child_get_left_attach           (GtkGridLayoutChild  *grid_child);
+GDK_AVAILABLE_IN_ALL
+int                     gtk_grid_layout_child_get_top_attach            (GtkGridLayoutChild  *grid_child);
+GDK_AVAILABLE_IN_ALL
+int                     gtk_grid_layout_child_get_width                 (GtkGridLayoutChild  *grid_child);
+GDK_AVAILABLE_IN_ALL
+int                     gtk_grid_layout_child_get_height                (GtkGridLayoutChild  *grid_child);
+
+G_END_DECLS
diff --git a/gtk/gtkgridlayoutchild.c b/gtk/gtkgridlayoutchild.c
new file mode 100644
index 0000000000..60d365a3f2
--- /dev/null
+++ b/gtk/gtkgridlayoutchild.c
@@ -0,0 +1,175 @@
+/**
+ * SECTION:gtkgridlayoutchild
+ * @Title: GtkGridLayoutChild
+ * @Short_description: Layout properties for children of GtkGridLayout
+ *
+ * GtkGridLayoutChild is a #GtkLayoutChild class used to store layout
+ * properties that apply to children of a #GtkWidget using the #GtkGridLayout
+ * layout manager.
+ *
+ * You can retrieve a GtkGridLayout instance bound to a #GtkWidget by
+ * using gtk_layout_manager_get_layout_child().
+ */
+
+#include "config.h"
+
+#include "gtkgridlayoutprivate.h"
+
+G_DEFINE_TYPE (GtkGridLayoutChild, gtk_grid_layout_child, GTK_TYPE_LAYOUT_CHILD)
+
+enum {
+  PROP_LEFT_ATTACH = 1,
+  PROP_TOP_ATTACH,
+  PROP_COLUMN_SPAN,
+  PROP_ROW_SPAN,
+
+  N_PROPERTIES
+};
+
+static GParamSpec *layout_child_props[N_PROPERTIES];
+
+static void
+gtk_grid_layout_child_get_property (GObject    *gobject,
+                                    guint       property_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+  GtkGridLayoutChild *self = GTK_GRID_LAYOUT_CHILD (gobject);
+
+  switch (property_id)
+    {
+    case PROP_LEFT_ATTACH:
+      g_value_set_int (value, CHILD_LEFT (grid_child));
+      break;
+
+    case PROP_TOP_ATTACH:
+      g_value_set_int (value, CHILD_TOP (grid_child));
+      break;
+
+    case PROP_COLUMN_SPAN:
+      g_value_set_int (value, CHILD_COL_SPAN (grid_child));
+      break;
+
+    case PROP_ROW_SPAN:
+      g_value_set_int (value, CHILD_ROW_SPAN (grid_child));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_grid_layout_child_set_property (GObject      *gobject,
+                                    guint         property_id,
+                                    const GValue *value,
+                                    GParamSpec   *pspec)
+{
+  GtkGridLayoutChild *self = GTK_GRID_LAYOUT_CHILD (gobject);
+
+  switch (property_id)
+    {
+    case PROP_LEFT_ATTACH:
+      CHILD_LEFT (grid_child) = g_value_get_int (value);
+      break;
+
+    case PROP_TOP_ATTACH:
+      CHILD_TOP (grid_child) = g_value_get_int (value);
+      break;
+
+    case PROP_COLUMN_SPAN:
+      CHILD_COL_SPAN (grid_child) = g_value_get_int (value);
+      break;
+
+    case PROP_ROW_SPAN:
+      CHILD_ROW_SPAN (grid_child) = g_value_get_int (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
+      break;
+    }
+
+  gtk_layout_manager_layout_changed (gtk_layout_child_get_layout_manager (GTK_LAYOUT_CHILD (self)));
+}
+
+static void
+gtk_grid_layout_child_class_init (GtkGridLayoutChildClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = gtk_grid_layout_child_set_property;
+  gobject_class->get_property = gtk_grid_layout_child_get_property;
+
+  layout_child_props[PROP_LEFT_ATTACH] =
+    g_param_spec_int ("left-attach",
+                      P_("Left attachment"),
+                      P_("The column number to attach the left side of the child to"),
+                      G_MININT, G_MAXINT, 0,
+                      GTK_PARAM_READWRITE);
+
+  layout_child_props[PROP_TOP_ATTACH] =
+    g_param_spec_int ("top-attach",
+                      P_("Top attachment"),
+                      P_("The row number to attach the top side of a child widget to"),
+                      G_MININT, G_MAXINT, 0,
+                      GTK_PARAM_READWRITE);
+
+  layout_child_props[PROP_COLUMN_SPAN] =
+    g_param_spec_int ("column-span",
+                      P_("Column Span"),
+                      P_("The number of columns that a child spans"),
+                      1, G_MAXINT, 1,
+                      GTK_PARAM_READWRITE);
+
+  layout_child_props[PROP_ROW_SPAN] =
+    g_param_spec_int ("row-span",
+                      P_("Row Span"),
+                      P_("The number of rows that a child spans"),
+                      1, G_MAXINT, 1,
+                      GTK_PARAM_READWRITE);
+
+  g_object_class_install_properties (gobject_class, N_PROPERTIES, layout_child_props);
+}
+
+static void
+gtk_grid_layout_child_init (GtkGridLayoutChild *self)
+{
+  CHILD_LEFT (self) = 0;
+  CHILD_TOP (self) = 0;
+  CHILD_COLUMN_SPAN (self) = 1;
+  CHILD_ROW_SPAN (self) = 1;
+}
+
+int
+gtk_grid_layout_child_get_left_attach (GtkGridLayoutChild *grid_child)
+{
+  g_return_val_if_fail (GTK_IS_GRID_LAYOUT_CHILD (grid_child), 0);
+
+  return CHILD_LEFT (grid_child);
+}
+
+int
+gtk_grid_layout_child_get_top_attach (GtkGridLayoutChild *grid_child)
+{
+  g_return_val_if_fail (GTK_IS_GRID_LAYOUT_CHILD (grid_child), 0);
+
+  return CHILD_TOP (grid_child);
+}
+
+int
+gtk_grid_layout_child_get_width (GtkGridLayoutChild *grid_child)
+{
+  g_return_val_if_fail (GTK_IS_GRID_LAYOUT_CHILD (grid_child), 0);
+
+  return CHILD_WIDTH (grid_child);
+}
+
+int
+gtk_grid_layout_child_get_height (GtkGridLayoutChild *grid_child)
+{
+  g_return_val_if_fail (GTK_IS_GRID_LAYOUT_CHILD (grid_child), 0);
+
+  return CHILD_HEIGHT (grid_child);
+}
diff --git a/gtk/gtkgridlayoutprivate.h b/gtk/gtkgridlayoutprivate.h
new file mode 100644
index 0000000000..31510cd373
--- /dev/null
+++ b/gtk/gtkgridlayoutprivate.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "gtkgridlayout.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GtkGridLayoutChildAttach GtkGridLayoutChildAttach;
+
+struct _GtkGridLayoutChildAttach
+{
+  int pos;
+  int span;
+};
+
+struct _GtkGridLayoutChild
+{
+  GtkLayoutChild parent_instance;
+
+  GtkGridLayoutChildAttach attach[2];
+};
+
+#define CHILD_LEFT(child)       ((child)->attach[GTK_ORIENTATION_HORIZONTAL].pos)
+#define CHILD_COL_SPAN(child)   ((child)->attach[GTK_ORIENTATION_HORIZONTAL].span)
+#define CHILD_TOP(child)        ((child)->attach[GTK_ORIENTATION_VERTICAL].pos)
+#define CHILD_ROW_SPAN(child)   ((child)->attach[GTK_ORIENTATION_VERTICAL].span)
+
+G_END_DECLS


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