[glade] Fix for drag/resize in GtkGrid.



commit 0391bd594480315da265fe0b72a1cc7070f3e340
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Wed Apr 3 16:12:35 2013 +0900

    Fix for drag/resize in GtkGrid.
    
    This patch ensures that width/height child properties of grid
    are properly updated while expanding left & right, it also
    moves all the GladeFixed code to a single section at the bottom
    of the file.

 plugins/gtk+/glade-gtk-grid.c | 1367 +++++++++++++++++++++--------------------
 1 files changed, 691 insertions(+), 676 deletions(-)
---
diff --git a/plugins/gtk+/glade-gtk-grid.c b/plugins/gtk+/glade-gtk-grid.c
index 63b250d..d5a5900 100644
--- a/plugins/gtk+/glade-gtk-grid.c
+++ b/plugins/gtk+/glade-gtk-grid.c
@@ -31,32 +31,22 @@
 
 typedef struct
 {
-  /* comparable part: */
-  GladeWidget *widget;
-  gint left_attach;
-  gint top_attach;
-  gint width;
-  gint height;
-} GladeGridChild;
-
-typedef struct
-{
   gint left_attach;
   gint top_attach;
   gint width;
   gint height;
 } GladeGridAttachments;
 
-typedef enum
-{
-  DIR_UP,
-  DIR_DOWN,
-  DIR_LEFT,
-  DIR_RIGHT
-} GladeGridDir;
-
-static GladeGridChild grid_edit = { 0, };
-static GladeGridChild grid_cur_attach = { 0, };
+static gboolean glade_gtk_grid_configure_begin (GladeFixed  *fixed,
+                                               GladeWidget *child,
+                                               GtkWidget   *grid);
+static gboolean glade_gtk_grid_configure_end   (GladeFixed  *fixed,
+                                               GladeWidget *child,
+                                               GtkWidget   *grid);
+static gboolean glade_gtk_grid_configure_child (GladeFixed   *fixed,
+                                               GladeWidget  *child,
+                                               GdkRectangle *rect,
+                                               GtkWidget    *grid);
 
 static void
 glade_gtk_grid_get_child_attachments (GtkWidget            *grid,
@@ -141,838 +131,863 @@ glade_gtk_grid_refresh_placeholders (GtkGrid *grid,
   g_list_free (children);
 }
 
-/* Takes a point (x or y depending on 'row') relative to
-* grid, and returns the row or column in which the point
-* was found.
-*/
-static gint
-glade_gtk_grid_get_row_col_from_point (GtkGrid *grid, gboolean row, gint point)
+static void
+glade_gtk_grid_parse_finished (GladeProject *project, GObject *container)
 {
+  GladeWidget *gwidget = glade_widget_get_from_gobject (container);
   GladeGridAttachments attach;
-  GtkAllocation allocation;
   GList *list, *children;
-  gint span, trans_point, size, base, end;
+  gint row = 0, column = 0, n_row = 0, n_column = 0;
 
-  children = gtk_container_get_children (GTK_CONTAINER (grid));
+  children = gtk_container_get_children (GTK_CONTAINER (container));
 
   for (list = children; list; list = list->next)
     {
       GtkWidget *widget = list->data;
 
-      glade_gtk_grid_get_child_attachments (GTK_WIDGET (grid), widget, &attach);
-
-      if (row)
-        gtk_widget_translate_coordinates (GTK_WIDGET (grid), widget, 0, point, NULL, &trans_point);
-      else
-        gtk_widget_translate_coordinates (GTK_WIDGET (grid), widget, point, 0, &trans_point, NULL);
-
-      gtk_widget_get_allocation (widget, &allocation);
+      if (GLADE_IS_PLACEHOLDER (widget)) continue;
 
-      /* Find any widget in our row/column
-       */
-      end = row ? allocation.height : allocation.width;
+      glade_gtk_grid_get_child_attachments (GTK_WIDGET (container), widget, &attach);
 
-      if (trans_point >= 0 &&
-          /* should be trans_point < end ... test FIXME ! */
-          trans_point < end)
-        {
-          base = row ? attach.top_attach : attach.left_attach;
-          size = row ? allocation.height : allocation.width;
-          span = row ? attach.height     : attach.width;
+      n_row = attach.top_attach + attach.height;
+      n_column = attach.left_attach + attach.width;
 
-          return base + (trans_point * span / size);
-        }
+      if (row < n_row) row = n_row;
+      if (column < n_column) column = n_column;
     }
 
+  if (column) glade_widget_property_set (gwidget, "n-columns", column);
+  if (row) glade_widget_property_set (gwidget, "n-rows", row);
+
   g_list_free (children);
 
-  return -1;
+  /* Refresh placeholders only once after the project is finished parsing */
+  glade_gtk_grid_refresh_placeholders (GTK_GRID (container), TRUE);
 }
 
+void
+glade_gtk_grid_post_create (GladeWidgetAdaptor *adaptor,
+                            GObject            *container,
+                            GladeCreateReason   reason)
+{
+  GladeWidget *gwidget = glade_widget_get_from_gobject (container);
+
+  g_signal_connect (G_OBJECT (gwidget), "configure-child",
+                    G_CALLBACK (glade_gtk_grid_configure_child), container);
+
+  g_signal_connect (G_OBJECT (gwidget), "configure-begin",
+                    G_CALLBACK (glade_gtk_grid_configure_begin), container);
+
+  g_signal_connect (G_OBJECT (gwidget), "configure-end",
+                    G_CALLBACK (glade_gtk_grid_configure_end), container);
+
+  if (reason == GLADE_CREATE_LOAD)
+    g_signal_connect (glade_widget_get_project (gwidget), "parse-finished",
+                      G_CALLBACK (glade_gtk_grid_parse_finished),
+                      container);
+}
 
 static gboolean
-glade_gtk_grid_point_crosses_threshold (GtkGrid     *grid,
-                                        gboolean     row,
-                                        gint         num,
-                                        GladeGridDir dir, 
-                                        gint         point)
+glade_gtk_grid_widget_exceeds_bounds (GtkGrid *grid, gint n_rows, gint n_cols)
 {
-  GladeGridAttachments attach;
-  GtkAllocation allocation;
   GList *list, *children;
-  gint span, trans_point, size, rowcol_size, base;
+  gboolean ret = FALSE;
 
   children = gtk_container_get_children (GTK_CONTAINER (grid));
 
-  for (list = children; list; list = list->next)
+  for (list = children; list && list->data; list = g_list_next (list))
     {
+      GladeGridAttachments attach;
       GtkWidget *widget = list->data;
 
+      if (GLADE_IS_PLACEHOLDER (widget)) continue;
+
       glade_gtk_grid_get_child_attachments (GTK_WIDGET (grid), widget, &attach);
 
-      /* Find any widget in our row/column
-       */
-      if ((row  && num >= attach.top_attach  && num < attach.top_attach  + attach.height) ||
-          (!row && num >= attach.left_attach && num < attach.left_attach + attach.width))
+      if (attach.left_attach + attach.width  > n_cols || 
+          attach.top_attach  + attach.height > n_rows)
         {
-
-          if (row)
-            gtk_widget_translate_coordinates (GTK_WIDGET (grid), widget, 0, point, NULL, &trans_point);
-          else
-            gtk_widget_translate_coordinates (GTK_WIDGET (grid), widget, point, 0, &trans_point, NULL);
-
-          span = row ? attach.height : attach.width;
-          gtk_widget_get_allocation (widget, &allocation);
-          size = row ? allocation.height : allocation.width;
-
-          base = row ? attach.top_attach : attach.left_attach;
-          rowcol_size = size / span;
-          trans_point -= (num - base) * rowcol_size;
-
-#if 0
-          g_print ("dir: %s, widget size: %d, rowcol size: %d, "
-                   "requested rowcol: %d, widget base rowcol: %d, trim: %d, "
-                   "widget point: %d, thresh: %d\n",
-                   dir == DIR_UP ? "up" : dir == DIR_DOWN ? "down" :
-                     dir == DIR_LEFT ? "left" : "right",
-                     size, rowcol_size, num, base, (num - base) * rowcol_size,
-                     trans_point,
-                     dir == DIR_UP || dir == DIR_LEFT ?
-                     (rowcol_size / 2) : (rowcol_size / 2));
-#endif
-          switch (dir)
-            {
-              case DIR_UP:
-              case DIR_LEFT:
-                return trans_point <= (rowcol_size / 2);
-              case DIR_DOWN:
-              case DIR_RIGHT:
-                return trans_point >= (rowcol_size / 2);
-              default:
-                break;
-            }
+          ret = TRUE;
+          break;
         }
-
     }
 
   g_list_free (children);
 
-  return FALSE;
+  return ret;
 }
 
-static gboolean
-glade_gtk_grid_get_attachments (GladeFixed        *fixed,
-                                GtkGrid           *grid,
-                                GdkRectangle      *rect,
-                                GladeGridChild    *configure)
+static void
+gtk_grid_children_callback (GtkWidget *widget, gpointer client_data)
 {
-  GladeWidget *widget = GLADE_WIDGET (fixed);
-  gint center_x, center_y, row, column;
-  guint n_columns, n_rows;
-
-  center_x = rect->x + (rect->width / 2);
-  center_y = rect->y + (rect->height / 2);
-
-  column = glade_gtk_grid_get_row_col_from_point (grid, FALSE, center_x);
-  row    = glade_gtk_grid_get_row_col_from_point (grid, TRUE, center_y);
+  GList **children;
 
-  /* its a start, now try to grow when the rect extents
-   * reach at least half way into the next row/column 
-   */
-  configure->left_attach   = column;
-  configure->width         = 1;
-  configure->top_attach    = row;
-  configure->height        = 1;
+  children = (GList **) client_data;
+  *children = g_list_prepend (*children, widget);
+}
 
-  glade_widget_property_get (widget, "n-columns", &n_columns);
-  glade_widget_property_get (widget, "n-rows", &n_rows);
+GList *
+glade_gtk_grid_get_children (GladeWidgetAdaptor *adaptor, 
+                             GtkContainer       *container)
+{
+  GList *children = NULL;
 
-  if (column >= 0 && row >= 0)
-    {
-      /* Check and expand left
-       */
-      while (configure->left_attach > 0)
-        {
-          if (rect->x < fixed->child_x_origin &&
-              fixed->operation != GLADE_CURSOR_DRAG &&
-              GLADE_FIXED_CURSOR_LEFT (fixed->operation) == FALSE)
-            break;
+  g_return_val_if_fail (GTK_IS_GRID (container), NULL);
 
-          if (glade_gtk_grid_point_crosses_threshold
-              (grid, FALSE, configure->left_attach - 1,
-               DIR_LEFT, rect->x) == FALSE)
-            break;
+  gtk_container_forall (container, gtk_grid_children_callback, &children);
 
-          configure->left_attach--;
-        }
+  /* GtkGrid has the children list already reversed */
+  return children;
+}
 
-      /* Check and expand right
-       */
-      while (configure->left_attach + configure->width < n_columns)
-        {
-          if (rect->x + rect->width >
-              fixed->child_x_origin + fixed->child_width_origin &&
-              fixed->operation != GLADE_CURSOR_DRAG &&
-              GLADE_FIXED_CURSOR_RIGHT (fixed->operation) == FALSE)
-            break;
+void
+glade_gtk_grid_add_child (GladeWidgetAdaptor *adaptor,
+                          GObject            *object,
+                          GObject            *child)
+{
+  g_return_if_fail (GTK_IS_GRID (object));
+  g_return_if_fail (GTK_IS_WIDGET (child));
 
-          if (glade_gtk_grid_point_crosses_threshold
-              (grid, FALSE, configure->left_attach + configure->width,
-               DIR_RIGHT, rect->x + rect->width) == FALSE)
-            break;
+  gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (child));
 
-          configure->width++;
-        }
+  glade_gtk_grid_refresh_placeholders (GTK_GRID (object), FALSE);
+}
 
-      /* Check and expand top
-       */
-      while (configure->top_attach > 0)
-        {
-          if (rect->y < fixed->child_y_origin &&
-              fixed->operation != GLADE_CURSOR_DRAG &&
-              GLADE_FIXED_CURSOR_TOP (fixed->operation) == FALSE)
-            break;
+void
+glade_gtk_grid_remove_child (GladeWidgetAdaptor *adaptor,
+                             GObject            *object,
+                             GObject            *child)
+{
+  g_return_if_fail (GTK_IS_GRID (object));
+  g_return_if_fail (GTK_IS_WIDGET (child));
 
-          if (glade_gtk_grid_point_crosses_threshold
-              (grid, TRUE, configure->top_attach - 1,
-               DIR_UP, rect->y) == FALSE)
-            break;
+  gtk_container_remove (GTK_CONTAINER (object), GTK_WIDGET (child));
 
-          configure->top_attach--;
-        }
+  glade_gtk_grid_refresh_placeholders (GTK_GRID (object), FALSE);
+}
 
-      /* Check and expand bottom
-       */
-      while (configure->top_attach + configure->height < n_rows)
-        {
-          if (rect->y + rect->height >
-              fixed->child_y_origin + fixed->child_height_origin &&
-              fixed->operation != GLADE_CURSOR_DRAG &&
-              GLADE_FIXED_CURSOR_BOTTOM (fixed->operation) == FALSE)
-            break;
-
-          if (glade_gtk_grid_point_crosses_threshold
-              (grid, TRUE, configure->top_attach + configure->height,
-               DIR_DOWN, rect->y + rect->height) == FALSE)
-            break;
+void
+glade_gtk_grid_replace_child (GladeWidgetAdaptor *adaptor,
+                              GObject            *container,
+                              GObject            *current,
+                              GObject            *new_widget)
+{
+  g_return_if_fail (GTK_IS_GRID (container));
+  g_return_if_fail (GTK_IS_WIDGET (current));
+  g_return_if_fail (GTK_IS_WIDGET (new_widget));
 
-          configure->height++;
-        }
-    }
+  /* Chain Up */
+  GWA_GET_CLASS (GTK_TYPE_CONTAINER)->replace_child (adaptor,
+                                                     container,
+                                                     current,
+                                                     new_widget);
 
-  return column >= 0 && row >= 0;
+  /* If we are replacing a GladeWidget, we must refresh placeholders
+   * because the widget may have spanned multiple rows/columns, we must
+   * not do so in the case we are pasting multiple widgets into a grid,
+   * where destroying placeholders results in default packing properties
+   * (since the remaining placeholder templates no longer exist, only the
+   * first pasted widget would have proper packing properties).
+   */
+  if (!GLADE_IS_PLACEHOLDER (new_widget))
+    glade_gtk_grid_refresh_placeholders (GTK_GRID (container), FALSE);
 }
 
-static gboolean
-glade_gtk_grid_configure_child (GladeFixed   *fixed,
-                                GladeWidget  *child,
-                                GdkRectangle *rect,
-                                GtkWidget    *grid)
+static void
+glade_gtk_grid_set_n_common (GObject      *object,
+                             const GValue *value,
+                             gboolean      for_rows)
 {
-  GladeGridChild configure = { child, };
+  GladeWidget *widget;
+  GtkGrid *grid;
+  guint new_size, n_columns, n_rows;
 
-  /* Sometimes we are unable to find a widget in the appropriate column,
-   * usually because a placeholder hasnt had its size allocation yet.
-   */
-  if (glade_gtk_grid_get_attachments (fixed, GTK_GRID (grid), rect, &configure))
-    {
-      if (memcmp (&configure, &grid_cur_attach, sizeof (GladeGridChild)) != 0)
-        {
+  grid = GTK_GRID (object);
+  widget = glade_widget_get_from_gobject (GTK_WIDGET (grid));
 
-          glade_property_push_superuser ();
-          glade_widget_pack_property_set (child, "left-attach",
-                                          configure.left_attach);
-          glade_widget_pack_property_set (child, "width",
-                                          configure.width);
-          glade_widget_pack_property_set (child, "top-attach",
-                                          configure.top_attach);
-          glade_widget_pack_property_set (child, "height",
-                                          configure.height);
-          glade_property_pop_superuser ();
+  glade_widget_property_get (widget, "n-columns", &n_columns);
+  glade_widget_property_get (widget, "n-rows", &n_rows);
 
-          memcpy (&grid_cur_attach, &configure, sizeof (GladeGridChild));
-        }
-    }
-  return TRUE;
-}
+  new_size = g_value_get_uint (value);
 
-static gboolean
-glade_gtk_grid_configure_begin (GladeFixed  *fixed,
-                                GladeWidget *child,
-                                GtkWidget   *grid)
-{
-  grid_edit.widget = child;
+  if (new_size < 1)
+    return;
 
-  glade_widget_pack_property_get (child, "left-attach", &grid_edit.left_attach);
-  glade_widget_pack_property_get (child, "width",       &grid_edit.width);
-  glade_widget_pack_property_get (child, "top-attach",  &grid_edit.top_attach);
-  glade_widget_pack_property_get (child, "height",      &grid_edit.height);
+  if (glade_gtk_grid_widget_exceeds_bounds
+      (grid, for_rows ? new_size : n_rows, for_rows ? n_columns : new_size))
+    /* Refuse to shrink if it means orphaning widgets */
+    return;
 
-  memcpy (&grid_cur_attach, &grid_edit, sizeof (GladeGridChild));
+  /* Fill grid with placeholders */
+  glade_gtk_grid_refresh_placeholders (grid, FALSE);
+}
 
-  return TRUE;
+void
+glade_gtk_grid_set_property (GladeWidgetAdaptor *adaptor,
+                             GObject            *object,
+                             const gchar        *id,
+                             const GValue       *value)
+{
+  if (!strcmp (id, "n-rows"))
+    glade_gtk_grid_set_n_common (object, value, TRUE);
+  else if (!strcmp (id, "n-columns"))
+    glade_gtk_grid_set_n_common (object, value, FALSE);
+  else
+    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor, object,
+                                                      id, value);
 }
 
 static gboolean
-glade_gtk_grid_configure_end (GladeFixed  *fixed,
-                              GladeWidget *child,
-                              GtkWidget   *grid)
+glade_gtk_grid_verify_n_common (GObject      *object,
+                                const GValue *value,
+                                gboolean      for_rows)
 {
-  GladeGridChild new_child = { child, };
-
-  glade_widget_pack_property_get (child, "left-attach", &new_child.left_attach);
-  glade_widget_pack_property_get (child, "width",       &new_child.width);
-  glade_widget_pack_property_get (child, "top-attach",  &new_child.top_attach);
-  glade_widget_pack_property_get (child, "height",      &new_child.height);
-
-  /* Compare the meaningfull part of the current edit. */
-  if (memcmp (&new_child, &grid_edit, sizeof (GladeGridChild)) != 0)
-    {
-      GValue left_attach_value = { 0, };
-      GValue width_attach_value = { 0, };
-      GValue top_attach_value = { 0, };
-      GValue height_attach_value = { 0, };
-
-      GValue new_left_attach_value = { 0, };
-      GValue new_width_attach_value = { 0, };
-      GValue new_top_attach_value = { 0, };
-      GValue new_height_attach_value = { 0, };
-
-      GladeProperty *left_attach_prop, *width_attach_prop,
-      *top_attach_prop, *height_attach_prop;
-
-      left_attach_prop   = glade_widget_get_pack_property (child, "left-attach");
-      width_attach_prop  = glade_widget_get_pack_property (child, "width");
-      top_attach_prop    = glade_widget_get_pack_property (child, "top-attach");
-      height_attach_prop = glade_widget_get_pack_property (child, "height");
-
-      g_return_val_if_fail (GLADE_IS_PROPERTY (left_attach_prop), FALSE);
-      g_return_val_if_fail (GLADE_IS_PROPERTY (width_attach_prop), FALSE);
-      g_return_val_if_fail (GLADE_IS_PROPERTY (top_attach_prop), FALSE);
-      g_return_val_if_fail (GLADE_IS_PROPERTY (height_attach_prop), FALSE);
-
-      glade_property_get_value (left_attach_prop, &new_left_attach_value);
-      glade_property_get_value (width_attach_prop, &new_width_attach_value);
-      glade_property_get_value (top_attach_prop, &new_top_attach_value);
-      glade_property_get_value (height_attach_prop, &new_height_attach_value);
+  GtkGrid *grid = GTK_GRID (object);
+  GladeWidget *widget;
+  guint n_columns, n_rows, new_size = g_value_get_uint (value);
 
-      g_value_init (&left_attach_value, G_TYPE_INT);
-      g_value_init (&width_attach_value, G_TYPE_INT);
-      g_value_init (&top_attach_value, G_TYPE_INT);
-      g_value_init (&height_attach_value, G_TYPE_INT);
+  widget = glade_widget_get_from_gobject (GTK_WIDGET (grid));
+  glade_widget_property_get (widget, "n-columns", &n_columns);
+  glade_widget_property_get (widget, "n-rows", &n_rows);
 
-      g_value_set_int (&left_attach_value, grid_edit.left_attach);
-      g_value_set_int (&width_attach_value, grid_edit.width);
-      g_value_set_int (&top_attach_value, grid_edit.top_attach);
-      g_value_set_int (&height_attach_value, grid_edit.height);
+  if (glade_gtk_grid_widget_exceeds_bounds
+      (grid, for_rows ? new_size : n_rows, for_rows ? n_columns : new_size))
+    /* Refuse to shrink if it means orphaning widgets */
+    return FALSE;
 
-      glade_command_push_group (_("Placing %s inside %s"),
-                                glade_widget_get_name (child), 
-                                glade_widget_get_name (GLADE_WIDGET (fixed)));
-      glade_command_set_properties
-        (left_attach_prop,   &left_attach_value,   &new_left_attach_value,
-         width_attach_prop,  &width_attach_value,  &new_width_attach_value,
-         top_attach_prop,    &top_attach_value,    &new_top_attach_value,
-         height_attach_prop, &height_attach_value, &new_height_attach_value,
-         NULL);
-      glade_command_pop_group ();
+  return TRUE;
+}
 
-      g_value_unset (&left_attach_value);
-      g_value_unset (&width_attach_value);
-      g_value_unset (&top_attach_value);
-      g_value_unset (&height_attach_value);
-      g_value_unset (&new_left_attach_value);
-      g_value_unset (&new_width_attach_value);
-      g_value_unset (&new_top_attach_value);
-      g_value_unset (&new_height_attach_value);
-    }
+gboolean
+glade_gtk_grid_verify_property (GladeWidgetAdaptor  *adaptor,
+                                GObject             *object,
+                                const gchar         *id,
+                                const GValue        *value)
+{
+  if (!strcmp (id, "n-rows"))
+    return glade_gtk_grid_verify_n_common (object, value, TRUE);
+  else if (!strcmp (id, "n-columns"))
+    return glade_gtk_grid_verify_n_common (object, value, FALSE);
+  else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property)
+    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property (adaptor, object,
+                                                         id, value);
 
   return TRUE;
 }
 
-static void
-glade_gtk_grid_parse_finished (GladeProject *project, GObject *container)
+void
+glade_gtk_grid_set_child_property (GladeWidgetAdaptor *adaptor,
+                                   GObject            *container,
+                                   GObject            *child,
+                                   const gchar        *property_name,
+                                   GValue             *value)
 {
-  GladeWidget *gwidget = glade_widget_get_from_gobject (container);
-  GladeGridAttachments attach;
-  GList *list, *children;
-  gint row = 0, column = 0, n_row = 0, n_column = 0;
+  g_return_if_fail (GTK_IS_GRID (container));
+  g_return_if_fail (GTK_IS_WIDGET (child));
+  g_return_if_fail (property_name != NULL && value != NULL);
 
-  children = gtk_container_get_children (GTK_CONTAINER (container));
+  GWA_GET_CLASS
+    (GTK_TYPE_CONTAINER)->child_set_property (adaptor,
+                                              container, child,
+                                              property_name, value);
 
-  for (list = children; list; list = list->next)
+  if (strcmp (property_name, "left-attach") == 0 ||
+      strcmp (property_name, "top-attach")  == 0 ||
+      strcmp (property_name, "width")       == 0 ||
+      strcmp (property_name, "height")      == 0)
     {
-      GtkWidget *widget = list->data;
+      /* Refresh placeholders */
+      glade_gtk_grid_refresh_placeholders (GTK_GRID (container), FALSE);
+    }
+}
 
-      if (GLADE_IS_PLACEHOLDER (widget)) continue;
+static gboolean
+glade_gtk_grid_verify_attach_common (GObject     *object,
+                                     GValue      *value,
+                                     const gchar *prop,
+                                     const gchar *parent_prop)
+{
+  GladeWidget *widget, *parent;
+  guint parent_val;
+  gint val, prop_val;
 
-      glade_gtk_grid_get_child_attachments (GTK_WIDGET (container), widget, &attach);
+  widget = glade_widget_get_from_gobject (object);
+  g_return_val_if_fail (GLADE_IS_WIDGET (widget), TRUE);
+  parent = glade_widget_get_parent (widget);
+  g_return_val_if_fail (GLADE_IS_WIDGET (parent), TRUE);
 
-      n_row = attach.top_attach + attach.height;
-      n_column = attach.left_attach + attach.width;
+  val = g_value_get_int (value);
+  glade_widget_property_get (widget, prop, &prop_val);
+  glade_widget_property_get (parent, parent_prop, &parent_val);
 
-      if (row < n_row) row = n_row;
-      if (column < n_column) column = n_column;
-    }
+  if (val < 0 || (val+prop_val) > parent_val)
+    return FALSE;
 
-  if (column) glade_widget_property_set (gwidget, "n-columns", column);
-  if (row) glade_widget_property_set (gwidget, "n-rows", row);
+  return TRUE;
+}
 
-  g_list_free (children);
+gboolean
+glade_gtk_grid_child_verify_property (GladeWidgetAdaptor *adaptor,
+                                      GObject            *container,
+                                      GObject            *child,
+                                      const gchar        *id,
+                                      GValue             *value)
+{
+  if (!strcmp (id, "left-attach"))
+    return glade_gtk_grid_verify_attach_common (child, value, "width", "n-columns");
+  else if (!strcmp (id, "width"))
+    return glade_gtk_grid_verify_attach_common (child, value, "left-attach", "n-columns");
+  else if (!strcmp (id, "top-attach"))
+    return glade_gtk_grid_verify_attach_common (child, value, "height", "n-rows");
+  else if (!strcmp (id, "height"))
+    return glade_gtk_grid_verify_attach_common (child, value, "top-attach", "n-rows");
+  else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_verify_property)
+    GWA_GET_CLASS
+    (GTK_TYPE_CONTAINER)->child_verify_property (adaptor,
+                                                 container, child,
+                                                 id, value);
 
-  /* Refresh placeholders only once after the project is finished parsing */
-  glade_gtk_grid_refresh_placeholders (GTK_GRID (container), TRUE);
+  return TRUE;
 }
 
-void
-glade_gtk_grid_post_create (GladeWidgetAdaptor *adaptor,
-                            GObject            *container,
-                            GladeCreateReason   reason)
+static void
+glade_gtk_grid_child_insert_remove_action (GladeWidgetAdaptor *adaptor, 
+                                           GObject            *container, 
+                                           GObject            *object, 
+                                           const gchar        *group_format, 
+                                           const gchar        *n_row_col, 
+                                           const gchar        *attach1,    /* should be smaller (top/left) 
attachment */
+                                           const gchar        *attach2,      /* should be larger (bot/right) 
attachment */
+                                           gboolean            remove, 
+                                           gboolean            after)
 {
-  GladeWidget *gwidget = glade_widget_get_from_gobject (container);
+  GladeWidget *parent;
+  GList *children, *l;
+  gint child_pos, size, offset;
 
-  g_signal_connect (G_OBJECT (gwidget), "configure-child",
-                    G_CALLBACK (glade_gtk_grid_configure_child), container);
+  gtk_container_child_get (GTK_CONTAINER (container),
+                           GTK_WIDGET (object),
+                           attach1, &child_pos, NULL);
 
-  g_signal_connect (G_OBJECT (gwidget), "configure-begin",
-                    G_CALLBACK (glade_gtk_grid_configure_begin), container);
+  parent = glade_widget_get_from_gobject (container);
+  glade_command_push_group (group_format, glade_widget_get_name (parent));
 
-  g_signal_connect (G_OBJECT (gwidget), "configure-end",
-                    G_CALLBACK (glade_gtk_grid_configure_end), container);
+  children = glade_widget_adaptor_get_children (adaptor, container);
+  /* Make sure widgets does not get destroyed */
+  g_list_foreach (children, (GFunc) g_object_ref, NULL);
 
-  if (reason == GLADE_CREATE_LOAD)
-    g_signal_connect (glade_widget_get_project (gwidget), "parse-finished",
-                      G_CALLBACK (glade_gtk_grid_parse_finished),
-                      container);
-}
+  glade_widget_property_get (parent, n_row_col, &size);
 
-static gboolean
-glade_gtk_grid_widget_exceeds_bounds (GtkGrid *grid, gint n_rows, gint n_cols)
-{
-  GList *list, *children;
-  gboolean ret = FALSE;
+  if (remove)
+    {
+      GList *del = NULL;
+      /* Remove children first */
+      for (l = children; l; l = g_list_next (l))
+        {
+          GladeWidget *gchild = glade_widget_get_from_gobject (l->data);
+          gint pos1, pos2;
 
-  children = gtk_container_get_children (GTK_CONTAINER (grid));
+          /* Skip placeholders */
+          if (gchild == NULL)
+            continue;
 
-  for (list = children; list && list->data; list = g_list_next (list))
+          glade_widget_pack_property_get (gchild, attach1, &pos1);
+          glade_widget_pack_property_get (gchild, attach2, &pos2);
+          pos2 += pos1;
+          if ((pos1 + 1 == pos2) && ((after ? pos2 : pos1) == child_pos))
+            {
+              del = g_list_prepend (del, gchild);
+            }
+        }
+      if (del)
+        {
+          glade_command_delete (del);
+          g_list_free (del);
+        }
+      offset = -1;
+    }
+  else
     {
-      GladeGridAttachments attach;
-      GtkWidget *widget = list->data;
+      /* Expand the grid */
+      glade_command_set_property (glade_widget_get_property (parent, n_row_col),
+                                  size + 1);
+      offset = 1;
+    }
 
-      if (GLADE_IS_PLACEHOLDER (widget)) continue;
+  /* Reorder children */
+  for (l = children; l; l = g_list_next (l))
+    {
+      GladeWidget *gchild = glade_widget_get_from_gobject (l->data);
+      gint pos;
 
-      glade_gtk_grid_get_child_attachments (GTK_WIDGET (grid), widget, &attach);
+      /* Skip placeholders */
+      if (gchild == NULL)
+        continue;
 
-      if (attach.left_attach + attach.width  > n_cols || 
-          attach.top_attach  + attach.height > n_rows)
+      /* if removing, do top/left before bot/right */
+      if (remove)
         {
-          ret = TRUE;
-          break;
+          /* adjust top-left attachment */
+          glade_widget_pack_property_get (gchild, attach1, &pos);
+          if (pos > child_pos || (after && pos == child_pos))
+            {
+              glade_command_set_property (glade_widget_get_pack_property
+                                          (gchild, attach1), pos + offset);
+            }
+        }
+      /* if inserting, do bot/right before top/left */
+      else
+        {
+          /* adjust top-left attachment */
+          glade_widget_pack_property_get (gchild, attach1, &pos);
+
+          if ((after && pos > child_pos) || (!after && pos >= child_pos))
+            {
+              glade_command_set_property (glade_widget_get_pack_property
+                                          (gchild, attach1), pos + offset);
+            }
         }
     }
 
+  if (remove)
+    {
+      /* Shrink the grid */
+      glade_command_set_property (glade_widget_get_property (parent, n_row_col),
+                                  size - 1);
+    }
+
+  g_list_foreach (children, (GFunc) g_object_unref, NULL);
   g_list_free (children);
 
-  return ret;
+  glade_command_pop_group ();
 }
 
-static void
-gtk_grid_children_callback (GtkWidget *widget, gpointer client_data)
+void
+glade_gtk_grid_child_action_activate (GladeWidgetAdaptor *adaptor,
+                                      GObject            *container,
+                                      GObject            *object,
+                                      const gchar        *action_path)
 {
-  GList **children;
-
-  children = (GList **) client_data;
-  *children = g_list_prepend (*children, widget);
+  if (strcmp (action_path, "insert_row/after") == 0)
+    {
+      glade_gtk_grid_child_insert_remove_action (adaptor, container, object,
+                                                 _("Insert Row on %s"),
+                                                 "n-rows", "top-attach",
+                                                 "height", FALSE, TRUE);
+    }
+  else if (strcmp (action_path, "insert_row/before") == 0)
+    {
+      glade_gtk_grid_child_insert_remove_action (adaptor, container, object,
+                                                 _("Insert Row on %s"),
+                                                 "n-rows", "top-attach",
+                                                 "height",
+                                                 FALSE, FALSE);
+    }
+  else if (strcmp (action_path, "insert_column/after") == 0)
+    {
+      glade_gtk_grid_child_insert_remove_action (adaptor, container, object,
+                                                 _("Insert Column on %s"),
+                                                 "n-columns", "left-attach",
+                                                 "width", FALSE, TRUE);
+    }
+  else if (strcmp (action_path, "insert_column/before") == 0)
+    {
+      glade_gtk_grid_child_insert_remove_action (adaptor, container, object,
+                                                 _("Insert Column on %s"),
+                                                 "n-columns", "left-attach",
+                                                 "width", FALSE, FALSE);
+    }
+  else if (strcmp (action_path, "remove_column") == 0)
+    {
+      glade_gtk_grid_child_insert_remove_action (adaptor, container, object,
+                                                 _("Remove Column on %s"),
+                                                 "n-columns", "left-attach",
+                                                 "width", TRUE, FALSE);
+    }
+  else if (strcmp (action_path, "remove_row") == 0)
+    {
+      glade_gtk_grid_child_insert_remove_action (adaptor, container, object,
+                                                 _("Remove Row on %s"),
+                                                 "n-rows", "top-attach",
+                                                 "height", TRUE, FALSE);
+    }
+  else
+    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_action_activate (adaptor,
+                                                               container,
+                                                               object,
+                                                               action_path);
 }
 
-GList *
-glade_gtk_grid_get_children (GladeWidgetAdaptor *adaptor, 
-                             GtkContainer       *container)
+/***************************************************************
+ *                   GladeFixed drag/resize                    *
+ ***************************************************************/
+typedef struct
 {
-  GList *children = NULL;
-
-  g_return_val_if_fail (GTK_IS_GRID (container), NULL);
-
-  gtk_container_forall (container, gtk_grid_children_callback, &children);
-
-  /* GtkGrid has the children list already reversed */
-  return children;
-}
+  GladeWidget *widget;
+  gint left_attach;
+  gint top_attach;
+  gint width;
+  gint height;
+} GladeGridChild;
 
-void
-glade_gtk_grid_add_child (GladeWidgetAdaptor *adaptor,
-                          GObject            *object,
-                          GObject            *child)
+typedef enum
 {
-  g_return_if_fail (GTK_IS_GRID (object));
-  g_return_if_fail (GTK_IS_WIDGET (child));
-
-  gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (child));
+  DIR_UP,
+  DIR_DOWN,
+  DIR_LEFT,
+  DIR_RIGHT
+} GladeGridDir;
 
-  glade_gtk_grid_refresh_placeholders (GTK_GRID (object), FALSE);
-}
+static GladeGridChild grid_edit = { 0, };
+static GladeGridChild grid_cur_attach = { 0, };
 
-void
-glade_gtk_grid_remove_child (GladeWidgetAdaptor *adaptor,
-                             GObject            *object,
-                             GObject            *child)
+/* Takes a point (x or y depending on 'row') relative to
+* grid, and returns the row or column in which the point
+* was found.
+*/
+static gint
+glade_gtk_grid_get_row_col_from_point (GtkGrid *grid, gboolean row, gint point)
 {
-  g_return_if_fail (GTK_IS_GRID (object));
-  g_return_if_fail (GTK_IS_WIDGET (child));
-
-  gtk_container_remove (GTK_CONTAINER (object), GTK_WIDGET (child));
-
-  glade_gtk_grid_refresh_placeholders (GTK_GRID (object), FALSE);
-}
+  GladeGridAttachments attach;
+  GtkAllocation allocation;
+  GList *list, *children;
+  gint span, trans_point, size, base, end;
 
-void
-glade_gtk_grid_replace_child (GladeWidgetAdaptor *adaptor,
-                              GObject            *container,
-                              GObject            *current,
-                              GObject            *new_widget)
-{
-  g_return_if_fail (GTK_IS_GRID (container));
-  g_return_if_fail (GTK_IS_WIDGET (current));
-  g_return_if_fail (GTK_IS_WIDGET (new_widget));
+  children = gtk_container_get_children (GTK_CONTAINER (grid));
 
-  /* Chain Up */
-  GWA_GET_CLASS (GTK_TYPE_CONTAINER)->replace_child (adaptor,
-                                                     container,
-                                                     current,
-                                                     new_widget);
+  for (list = children; list; list = list->next)
+    {
+      GtkWidget *widget = list->data;
 
-  /* If we are replacing a GladeWidget, we must refresh placeholders
-   * because the widget may have spanned multiple rows/columns, we must
-   * not do so in the case we are pasting multiple widgets into a grid,
-   * where destroying placeholders results in default packing properties
-   * (since the remaining placeholder templates no longer exist, only the
-   * first pasted widget would have proper packing properties).
-   */
-  if (!GLADE_IS_PLACEHOLDER (new_widget))
-    glade_gtk_grid_refresh_placeholders (GTK_GRID (container), FALSE);
-}
+      glade_gtk_grid_get_child_attachments (GTK_WIDGET (grid), widget, &attach);
 
-static void
-glade_gtk_grid_set_n_common (GObject      *object,
-                             const GValue *value,
-                             gboolean      for_rows)
-{
-  GladeWidget *widget;
-  GtkGrid *grid;
-  guint new_size, n_columns, n_rows;
+      if (row)
+        gtk_widget_translate_coordinates (GTK_WIDGET (grid), widget, 0, point, NULL, &trans_point);
+      else
+        gtk_widget_translate_coordinates (GTK_WIDGET (grid), widget, point, 0, &trans_point, NULL);
 
-  grid = GTK_GRID (object);
-  widget = glade_widget_get_from_gobject (GTK_WIDGET (grid));
+      gtk_widget_get_allocation (widget, &allocation);
 
-  glade_widget_property_get (widget, "n-columns", &n_columns);
-  glade_widget_property_get (widget, "n-rows", &n_rows);
+      /* Find any widget in our row/column
+       */
+      end = row ? allocation.height : allocation.width;
 
-  new_size = g_value_get_uint (value);
+      if (trans_point >= 0 &&
+          /* should be trans_point < end ... test FIXME ! */
+          trans_point < end)
+        {
+          base = row ? attach.top_attach : attach.left_attach;
+          size = row ? allocation.height : allocation.width;
+          span = row ? attach.height     : attach.width;
 
-  if (new_size < 1)
-    return;
+          return base + (trans_point * span / size);
+        }
+    }
 
-  if (glade_gtk_grid_widget_exceeds_bounds
-      (grid, for_rows ? new_size : n_rows, for_rows ? n_columns : new_size))
-    /* Refuse to shrink if it means orphaning widgets */
-    return;
+  g_list_free (children);
 
-  /* Fill grid with placeholders */
-  glade_gtk_grid_refresh_placeholders (grid, FALSE);
+  return -1;
 }
 
-void
-glade_gtk_grid_set_property (GladeWidgetAdaptor *adaptor,
-                             GObject            *object,
-                             const gchar        *id,
-                             const GValue       *value)
-{
-  if (!strcmp (id, "n-rows"))
-    glade_gtk_grid_set_n_common (object, value, TRUE);
-  else if (!strcmp (id, "n-columns"))
-    glade_gtk_grid_set_n_common (object, value, FALSE);
-  else
-    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor, object,
-                                                      id, value);
-}
 
 static gboolean
-glade_gtk_grid_verify_n_common (GObject      *object,
-                                const GValue *value,
-                                gboolean      for_rows)
+glade_gtk_grid_point_crosses_threshold (GtkGrid     *grid,
+                                        gboolean     row,
+                                        gint         num,
+                                        GladeGridDir dir, 
+                                        gint         point)
 {
-  GtkGrid *grid = GTK_GRID (object);
-  GladeWidget *widget;
-  guint n_columns, n_rows, new_size = g_value_get_uint (value);
+  GladeGridAttachments attach;
+  GtkAllocation allocation;
+  GList *list, *children;
+  gint span, trans_point, size, rowcol_size, base;
 
-  widget = glade_widget_get_from_gobject (GTK_WIDGET (grid));
-  glade_widget_property_get (widget, "n-columns", &n_columns);
-  glade_widget_property_get (widget, "n-rows", &n_rows);
+  children = gtk_container_get_children (GTK_CONTAINER (grid));
 
-  if (glade_gtk_grid_widget_exceeds_bounds
-      (grid, for_rows ? new_size : n_rows, for_rows ? n_columns : new_size))
-    /* Refuse to shrink if it means orphaning widgets */
-    return FALSE;
+  for (list = children; list; list = list->next)
+    {
+      GtkWidget *widget = list->data;
 
-  return TRUE;
-}
+      glade_gtk_grid_get_child_attachments (GTK_WIDGET (grid), widget, &attach);
 
-gboolean
-glade_gtk_grid_verify_property (GladeWidgetAdaptor  *adaptor,
-                                GObject             *object,
-                                const gchar         *id,
-                                const GValue        *value)
-{
-  if (!strcmp (id, "n-rows"))
-    return glade_gtk_grid_verify_n_common (object, value, TRUE);
-  else if (!strcmp (id, "n-columns"))
-    return glade_gtk_grid_verify_n_common (object, value, FALSE);
-  else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property)
-    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property (adaptor, object,
-                                                         id, value);
+      /* Find any widget in our row/column
+       */
+      if ((row  && num >= attach.top_attach  && num < attach.top_attach  + attach.height) ||
+          (!row && num >= attach.left_attach && num < attach.left_attach + attach.width))
+        {
 
-  return TRUE;
-}
+          if (row)
+            gtk_widget_translate_coordinates (GTK_WIDGET (grid), widget, 0, point, NULL, &trans_point);
+          else
+            gtk_widget_translate_coordinates (GTK_WIDGET (grid), widget, point, 0, &trans_point, NULL);
 
-void
-glade_gtk_grid_set_child_property (GladeWidgetAdaptor *adaptor,
-                                   GObject            *container,
-                                   GObject            *child,
-                                   const gchar        *property_name,
-                                   GValue             *value)
-{
-  g_return_if_fail (GTK_IS_GRID (container));
-  g_return_if_fail (GTK_IS_WIDGET (child));
-  g_return_if_fail (property_name != NULL && value != NULL);
+          span = row ? attach.height : attach.width;
+          gtk_widget_get_allocation (widget, &allocation);
+          size = row ? allocation.height : allocation.width;
 
-  GWA_GET_CLASS
-    (GTK_TYPE_CONTAINER)->child_set_property (adaptor,
-                                              container, child,
-                                              property_name, value);
+          base = row ? attach.top_attach : attach.left_attach;
+          rowcol_size = size / span;
+          trans_point -= (num - base) * rowcol_size;
+
+#if 0
+          g_print ("dir: %s, widget size: %d, rowcol size: %d, "
+                   "requested rowcol: %d, widget base rowcol: %d, trim: %d, "
+                   "widget point: %d, thresh: %d\n",
+                   dir == DIR_UP ? "up" : dir == DIR_DOWN ? "down" :
+                     dir == DIR_LEFT ? "left" : "right",
+                     size, rowcol_size, num, base, (num - base) * rowcol_size,
+                     trans_point,
+                     dir == DIR_UP || dir == DIR_LEFT ?
+                     (rowcol_size / 2) : (rowcol_size / 2));
+#endif
+          switch (dir)
+            {
+              case DIR_UP:
+              case DIR_LEFT:
+                return trans_point <= (rowcol_size / 2);
+              case DIR_DOWN:
+              case DIR_RIGHT:
+                return trans_point >= (rowcol_size / 2);
+              default:
+                break;
+            }
+        }
 
-  if (strcmp (property_name, "left-attach") == 0 ||
-      strcmp (property_name, "top-attach")  == 0 ||
-      strcmp (property_name, "width")       == 0 ||
-      strcmp (property_name, "height")      == 0)
-    {
-      /* Refresh placeholders */
-      glade_gtk_grid_refresh_placeholders (GTK_GRID (container), FALSE);
     }
+
+  g_list_free (children);
+
+  return FALSE;
 }
 
 static gboolean
-glade_gtk_grid_verify_attach_common (GObject     *object,
-                                     GValue      *value,
-                                     const gchar *prop,
-                                     const gchar *parent_prop)
+glade_gtk_grid_get_attachments (GladeFixed        *fixed,
+                                GtkGrid           *grid,
+                                GdkRectangle      *rect,
+                                GladeGridChild    *configure)
 {
-  GladeWidget *widget, *parent;
-  guint parent_val;
-  gint val, prop_val;
+  GladeWidget *widget = GLADE_WIDGET (fixed);
+  gint center_x, center_y, row, column;
+  guint n_columns, n_rows;
 
-  widget = glade_widget_get_from_gobject (object);
-  g_return_val_if_fail (GLADE_IS_WIDGET (widget), TRUE);
-  parent = glade_widget_get_parent (widget);
-  g_return_val_if_fail (GLADE_IS_WIDGET (parent), TRUE);
+  center_x = rect->x + (rect->width / 2);
+  center_y = rect->y + (rect->height / 2);
 
-  val = g_value_get_int (value);
-  glade_widget_property_get (widget, prop, &prop_val);
-  glade_widget_property_get (parent, parent_prop, &parent_val);
+  column = glade_gtk_grid_get_row_col_from_point (grid, FALSE, center_x);
+  row    = glade_gtk_grid_get_row_col_from_point (grid, TRUE, center_y);
 
-  if (val < 0 || (val+prop_val) > parent_val)
-    return FALSE;
+  /* its a start, now try to grow when the rect extents
+   * reach at least half way into the next row/column 
+   */
+  configure->left_attach   = column;
+  configure->width         = 1;
+  configure->top_attach    = row;
+  configure->height        = 1;
 
-  return TRUE;
-}
+  glade_widget_property_get (widget, "n-columns", &n_columns);
+  glade_widget_property_get (widget, "n-rows", &n_rows);
 
-gboolean
-glade_gtk_grid_child_verify_property (GladeWidgetAdaptor *adaptor,
-                                      GObject            *container,
-                                      GObject            *child,
-                                      const gchar        *id,
-                                      GValue             *value)
-{
-  if (!strcmp (id, "left-attach"))
-    return glade_gtk_grid_verify_attach_common (child, value, "width", "n-columns");
-  else if (!strcmp (id, "width"))
-    return glade_gtk_grid_verify_attach_common (child, value, "left-attach", "n-columns");
-  else if (!strcmp (id, "top-attach"))
-    return glade_gtk_grid_verify_attach_common (child, value, "height", "n-rows");
-  else if (!strcmp (id, "height"))
-    return glade_gtk_grid_verify_attach_common (child, value, "top-attach", "n-rows");
-  else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_verify_property)
-    GWA_GET_CLASS
-    (GTK_TYPE_CONTAINER)->child_verify_property (adaptor,
-                                                 container, child,
-                                                 id, value);
-
-  return TRUE;
-}
+  if (column >= 0 && row >= 0)
+    {
+      /* Check and expand left
+       */
+      while (configure->left_attach > 0)
+        {
+          if (rect->x < fixed->child_x_origin &&
+              fixed->operation != GLADE_CURSOR_DRAG &&
+              GLADE_FIXED_CURSOR_LEFT (fixed->operation) == FALSE)
+            break;
 
-static void
-glade_gtk_grid_child_insert_remove_action (GladeWidgetAdaptor *adaptor, 
-                                           GObject            *container, 
-                                           GObject            *object, 
-                                           const gchar        *group_format, 
-                                           const gchar        *n_row_col, 
-                                           const gchar        *attach1,    /* should be smaller (top/left) 
attachment */
-                                           const gchar        *attach2,      /* should be larger (bot/right) 
attachment */
-                                           gboolean            remove, 
-                                           gboolean            after)
-{
-  GladeWidget *parent;
-  GList *children, *l;
-  gint child_pos, size, offset;
+          if (glade_gtk_grid_point_crosses_threshold
+              (grid, FALSE, configure->left_attach - 1,
+               DIR_LEFT, rect->x) == FALSE)
+            break;
 
-  gtk_container_child_get (GTK_CONTAINER (container),
-                           GTK_WIDGET (object),
-                           attach1, &child_pos, NULL);
+          configure->left_attach--;
+          configure->width++;
+        }
 
-  parent = glade_widget_get_from_gobject (container);
-  glade_command_push_group (group_format, glade_widget_get_name (parent));
+      /* Check and expand right
+       */
+      while (configure->left_attach + configure->width < n_columns)
+        {
+          if (rect->x + rect->width >
+              fixed->child_x_origin + fixed->child_width_origin &&
+              fixed->operation != GLADE_CURSOR_DRAG &&
+              GLADE_FIXED_CURSOR_RIGHT (fixed->operation) == FALSE)
+            break;
 
-  children = glade_widget_adaptor_get_children (adaptor, container);
-  /* Make sure widgets does not get destroyed */
-  g_list_foreach (children, (GFunc) g_object_ref, NULL);
+          if (glade_gtk_grid_point_crosses_threshold
+              (grid, FALSE, configure->left_attach + configure->width,
+               DIR_RIGHT, rect->x + rect->width) == FALSE)
+            break;
 
-  glade_widget_property_get (parent, n_row_col, &size);
+          configure->width++;
+        }
 
-  if (remove)
-    {
-      GList *del = NULL;
-      /* Remove children first */
-      for (l = children; l; l = g_list_next (l))
+      /* Check and expand top
+       */
+      while (configure->top_attach > 0)
         {
-          GladeWidget *gchild = glade_widget_get_from_gobject (l->data);
-          gint pos1, pos2;
+          if (rect->y < fixed->child_y_origin &&
+              fixed->operation != GLADE_CURSOR_DRAG &&
+              GLADE_FIXED_CURSOR_TOP (fixed->operation) == FALSE)
+            break;
 
-          /* Skip placeholders */
-          if (gchild == NULL)
-            continue;
+          if (glade_gtk_grid_point_crosses_threshold
+              (grid, TRUE, configure->top_attach - 1,
+               DIR_UP, rect->y) == FALSE)
+            break;
 
-          glade_widget_pack_property_get (gchild, attach1, &pos1);
-          glade_widget_pack_property_get (gchild, attach2, &pos2);
-          pos2 += pos1;
-          if ((pos1 + 1 == pos2) && ((after ? pos2 : pos1) == child_pos))
-            {
-              del = g_list_prepend (del, gchild);
-            }
+          configure->top_attach--;
+          configure->height++;
         }
-      if (del)
+
+      /* Check and expand bottom
+       */
+      while (configure->top_attach + configure->height < n_rows)
         {
-          glade_command_delete (del);
-          g_list_free (del);
+          if (rect->y + rect->height >
+              fixed->child_y_origin + fixed->child_height_origin &&
+              fixed->operation != GLADE_CURSOR_DRAG &&
+              GLADE_FIXED_CURSOR_BOTTOM (fixed->operation) == FALSE)
+            break;
+
+          if (glade_gtk_grid_point_crosses_threshold
+              (grid, TRUE, configure->top_attach + configure->height,
+               DIR_DOWN, rect->y + rect->height) == FALSE)
+            break;
+
+          configure->height++;
         }
-      offset = -1;
-    }
-  else
-    {
-      /* Expand the grid */
-      glade_command_set_property (glade_widget_get_property (parent, n_row_col),
-                                  size + 1);
-      offset = 1;
     }
 
-  /* Reorder children */
-  for (l = children; l; l = g_list_next (l))
-    {
-      GladeWidget *gchild = glade_widget_get_from_gobject (l->data);
-      gint pos;
+  return column >= 0 && row >= 0;
+}
 
-      /* Skip placeholders */
-      if (gchild == NULL)
-        continue;
+static gboolean
+glade_gtk_grid_configure_child (GladeFixed   *fixed,
+                                GladeWidget  *child,
+                                GdkRectangle *rect,
+                                GtkWidget    *grid)
+{
+  GladeGridChild configure = { child, };
 
-      /* if removing, do top/left before bot/right */
-      if (remove)
-        {
-          /* adjust top-left attachment */
-          glade_widget_pack_property_get (gchild, attach1, &pos);
-          if (pos > child_pos || (after && pos == child_pos))
-            {
-              glade_command_set_property (glade_widget_get_pack_property
-                                          (gchild, attach1), pos + offset);
-            }
-        }
-      /* if inserting, do bot/right before top/left */
-      else
+  /* Sometimes we are unable to find a widget in the appropriate column,
+   * usually because a placeholder hasnt had its size allocation yet.
+   */
+  if (glade_gtk_grid_get_attachments (fixed, GTK_GRID (grid), rect, &configure))
+    {
+      if (memcmp (&configure, &grid_cur_attach, sizeof (GladeGridChild)) != 0)
         {
-          /* adjust top-left attachment */
-          glade_widget_pack_property_get (gchild, attach1, &pos);
 
-          if ((after && pos > child_pos) || (!after && pos >= child_pos))
-            {
-              glade_command_set_property (glade_widget_get_pack_property
-                                          (gchild, attach1), pos + offset);
-            }
+          glade_property_push_superuser ();
+          glade_widget_pack_property_set (child, "left-attach",
+                                          configure.left_attach);
+          glade_widget_pack_property_set (child, "width",
+                                          configure.width);
+          glade_widget_pack_property_set (child, "top-attach",
+                                          configure.top_attach);
+          glade_widget_pack_property_set (child, "height",
+                                          configure.height);
+          glade_property_pop_superuser ();
+
+          memcpy (&grid_cur_attach, &configure, sizeof (GladeGridChild));
         }
     }
+  return TRUE;
+}
 
-  if (remove)
-    {
-      /* Shrink the grid */
-      glade_command_set_property (glade_widget_get_property (parent, n_row_col),
-                                  size - 1);
-    }
+static gboolean
+glade_gtk_grid_configure_begin (GladeFixed  *fixed,
+                                GladeWidget *child,
+                                GtkWidget   *grid)
+{
+  grid_edit.widget = child;
 
-  g_list_foreach (children, (GFunc) g_object_unref, NULL);
-  g_list_free (children);
+  glade_widget_pack_property_get (child, "left-attach", &grid_edit.left_attach);
+  glade_widget_pack_property_get (child, "width",       &grid_edit.width);
+  glade_widget_pack_property_get (child, "top-attach",  &grid_edit.top_attach);
+  glade_widget_pack_property_get (child, "height",      &grid_edit.height);
 
-  glade_command_pop_group ();
+  memcpy (&grid_cur_attach, &grid_edit, sizeof (GladeGridChild));
+
+  return TRUE;
 }
 
-void
-glade_gtk_grid_child_action_activate (GladeWidgetAdaptor *adaptor,
-                                      GObject            *container,
-                                      GObject            *object,
-                                      const gchar        *action_path)
+static gboolean
+glade_gtk_grid_configure_end (GladeFixed  *fixed,
+                              GladeWidget *child,
+                              GtkWidget   *grid)
 {
-  if (strcmp (action_path, "insert_row/after") == 0)
-    {
-      glade_gtk_grid_child_insert_remove_action (adaptor, container, object,
-                                                 _("Insert Row on %s"),
-                                                 "n-rows", "top-attach",
-                                                 "height", FALSE, TRUE);
-    }
-  else if (strcmp (action_path, "insert_row/before") == 0)
-    {
-      glade_gtk_grid_child_insert_remove_action (adaptor, container, object,
-                                                 _("Insert Row on %s"),
-                                                 "n-rows", "top-attach",
-                                                 "height",
-                                                 FALSE, FALSE);
-    }
-  else if (strcmp (action_path, "insert_column/after") == 0)
-    {
-      glade_gtk_grid_child_insert_remove_action (adaptor, container, object,
-                                                 _("Insert Column on %s"),
-                                                 "n-columns", "left-attach",
-                                                 "width", FALSE, TRUE);
-    }
-  else if (strcmp (action_path, "insert_column/before") == 0)
-    {
-      glade_gtk_grid_child_insert_remove_action (adaptor, container, object,
-                                                 _("Insert Column on %s"),
-                                                 "n-columns", "left-attach",
-                                                 "width", FALSE, FALSE);
-    }
-  else if (strcmp (action_path, "remove_column") == 0)
-    {
-      glade_gtk_grid_child_insert_remove_action (adaptor, container, object,
-                                                 _("Remove Column on %s"),
-                                                 "n-columns", "left-attach",
-                                                 "width", TRUE, FALSE);
-    }
-  else if (strcmp (action_path, "remove_row") == 0)
+  GladeGridChild new_child = { child, };
+
+  glade_widget_pack_property_get (child, "left-attach", &new_child.left_attach);
+  glade_widget_pack_property_get (child, "width",       &new_child.width);
+  glade_widget_pack_property_get (child, "top-attach",  &new_child.top_attach);
+  glade_widget_pack_property_get (child, "height",      &new_child.height);
+
+  /* Compare the meaningfull part of the current edit. */
+  if (memcmp (&new_child, &grid_edit, sizeof (GladeGridChild)) != 0)
     {
-      glade_gtk_grid_child_insert_remove_action (adaptor, container, object,
-                                                 _("Remove Row on %s"),
-                                                 "n-rows", "top-attach",
-                                                 "height", TRUE, FALSE);
+      GValue left_attach_value = { 0, };
+      GValue width_attach_value = { 0, };
+      GValue top_attach_value = { 0, };
+      GValue height_attach_value = { 0, };
+
+      GValue new_left_attach_value = { 0, };
+      GValue new_width_attach_value = { 0, };
+      GValue new_top_attach_value = { 0, };
+      GValue new_height_attach_value = { 0, };
+
+      GladeProperty *left_attach_prop, *width_attach_prop,
+      *top_attach_prop, *height_attach_prop;
+
+      left_attach_prop   = glade_widget_get_pack_property (child, "left-attach");
+      width_attach_prop  = glade_widget_get_pack_property (child, "width");
+      top_attach_prop    = glade_widget_get_pack_property (child, "top-attach");
+      height_attach_prop = glade_widget_get_pack_property (child, "height");
+
+      g_return_val_if_fail (GLADE_IS_PROPERTY (left_attach_prop), FALSE);
+      g_return_val_if_fail (GLADE_IS_PROPERTY (width_attach_prop), FALSE);
+      g_return_val_if_fail (GLADE_IS_PROPERTY (top_attach_prop), FALSE);
+      g_return_val_if_fail (GLADE_IS_PROPERTY (height_attach_prop), FALSE);
+
+      glade_property_get_value (left_attach_prop, &new_left_attach_value);
+      glade_property_get_value (width_attach_prop, &new_width_attach_value);
+      glade_property_get_value (top_attach_prop, &new_top_attach_value);
+      glade_property_get_value (height_attach_prop, &new_height_attach_value);
+
+      g_value_init (&left_attach_value, G_TYPE_INT);
+      g_value_init (&width_attach_value, G_TYPE_INT);
+      g_value_init (&top_attach_value, G_TYPE_INT);
+      g_value_init (&height_attach_value, G_TYPE_INT);
+
+      g_value_set_int (&left_attach_value, grid_edit.left_attach);
+      g_value_set_int (&width_attach_value, grid_edit.width);
+      g_value_set_int (&top_attach_value, grid_edit.top_attach);
+      g_value_set_int (&height_attach_value, grid_edit.height);
+
+      glade_command_push_group (_("Placing %s inside %s"),
+                                glade_widget_get_name (child), 
+                                glade_widget_get_name (GLADE_WIDGET (fixed)));
+      glade_command_set_properties
+        (left_attach_prop,   &left_attach_value,   &new_left_attach_value,
+         width_attach_prop,  &width_attach_value,  &new_width_attach_value,
+         top_attach_prop,    &top_attach_value,    &new_top_attach_value,
+         height_attach_prop, &height_attach_value, &new_height_attach_value,
+         NULL);
+      glade_command_pop_group ();
+
+      g_value_unset (&left_attach_value);
+      g_value_unset (&width_attach_value);
+      g_value_unset (&top_attach_value);
+      g_value_unset (&height_attach_value);
+      g_value_unset (&new_left_attach_value);
+      g_value_unset (&new_width_attach_value);
+      g_value_unset (&new_top_attach_value);
+      g_value_unset (&new_height_attach_value);
     }
-  else
-    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_action_activate (adaptor,
-                                                               container,
-                                                               object,
-                                                               action_path);
+
+  return TRUE;
 }


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