Blame plugins/gtk+/glade-gtk-table.c

Packit 1e8aac
/*
Packit 1e8aac
 * glade-gtk-table.c - GladeWidgetAdaptor for GtkTable widget
Packit 1e8aac
 *
Packit 1e8aac
 * Copyright (C) 2008 Tristan Van Berkom
Packit 1e8aac
 *
Packit 1e8aac
 * Author(s):
Packit 1e8aac
 *      Tristan Van Berkom <tvb@gnome.org>
Packit 1e8aac
 *
Packit 1e8aac
 * This library is free software; you can redistribute it and/or modify it
Packit 1e8aac
 * under the terms of the GNU Lesser General Public License as
Packit 1e8aac
 * published by the Free Software Foundation; either version 2.1 of
Packit 1e8aac
 * the License, or (at your option) any later version.
Packit 1e8aac
 *
Packit 1e8aac
 * This library is distributed in the hope that it will be useful, but
Packit 1e8aac
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 1e8aac
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 1e8aac
 * Lesser General Public License for more details.
Packit 1e8aac
 *
Packit 1e8aac
 * You should have received a copy of the GNU Lesser General Public 
Packit 1e8aac
 * License along with this program; if not, write to the Free Software
Packit 1e8aac
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 1e8aac
 */
Packit 1e8aac
Packit 1e8aac
#include <config.h>
Packit 1e8aac
Packit 1e8aac
#include <gtk/gtk.h>
Packit 1e8aac
#include <glib/gi18n-lib.h>
Packit 1e8aac
#include <string.h>
Packit 1e8aac
Packit 1e8aac
#include "glade-fixed.h"
Packit 1e8aac
Packit 1e8aac
typedef struct
Packit 1e8aac
{
Packit 1e8aac
  /* comparable part: */
Packit 1e8aac
  GladeWidget *widget;
Packit 1e8aac
  gint left_attach;
Packit 1e8aac
  gint right_attach;
Packit 1e8aac
  gint top_attach;
Packit 1e8aac
  gint bottom_attach;
Packit 1e8aac
} GladeGtkTableChild;
Packit 1e8aac
Packit 1e8aac
typedef enum
Packit 1e8aac
{
Packit 1e8aac
  DIR_UP,
Packit 1e8aac
  DIR_DOWN,
Packit 1e8aac
  DIR_LEFT,
Packit 1e8aac
  DIR_RIGHT
Packit 1e8aac
} GladeTableDir;
Packit 1e8aac
Packit 1e8aac
typedef enum
Packit 1e8aac
{
Packit 1e8aac
  GROUP_ACTION_INSERT_ROW,
Packit 1e8aac
  GROUP_ACTION_INSERT_COLUMN,
Packit 1e8aac
  GROUP_ACTION_REMOVE_COLUMN,
Packit 1e8aac
  GROUP_ACTION_REMOVE_ROW
Packit 1e8aac
} GroupAction;
Packit 1e8aac
Packit 1e8aac
/* Redefine GTK_TABLE() macro, as GtkTable is deprecated */
Packit 1e8aac
#undef GTK_TABLE
Packit 1e8aac
#define GTK_TABLE(obj) ((GtkTable *)obj)
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
glade_gtk_table_get_child_attachments (GtkWidget * table,
Packit 1e8aac
                                       GtkWidget * child,
Packit 1e8aac
                                       GtkTableChild * tchild)
Packit 1e8aac
{
Packit 1e8aac
  guint left, right, top, bottom;
Packit 1e8aac
Packit 1e8aac
  gtk_container_child_get (GTK_CONTAINER (table), child,
Packit 1e8aac
                           "left-attach", (guint *) & left,
Packit 1e8aac
                           "right-attach", (guint *) & right,
Packit 1e8aac
                           "bottom-attach", (guint *) & bottom,
Packit 1e8aac
                           "top-attach", (guint *) & top, NULL);
Packit 1e8aac
Packit 1e8aac
  tchild->widget = child;
Packit 1e8aac
  tchild->left_attach = left;
Packit 1e8aac
  tchild->right_attach = right;
Packit 1e8aac
  tchild->top_attach = top;
Packit 1e8aac
  tchild->bottom_attach = bottom;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static gboolean
Packit 1e8aac
glade_gtk_table_widget_exceeds_bounds (GtkTable * table, gint n_rows,
Packit 1e8aac
                                       gint n_cols)
Packit 1e8aac
{
Packit 1e8aac
  GList *list, *children;
Packit 1e8aac
  gboolean ret = FALSE;
Packit 1e8aac
Packit 1e8aac
  children = gtk_container_get_children (GTK_CONTAINER (table));
Packit 1e8aac
Packit 1e8aac
  for (list = children; list && list->data; list = list->next)
Packit 1e8aac
    {
Packit 1e8aac
      GtkTableChild child;
Packit 1e8aac
Packit 1e8aac
      glade_gtk_table_get_child_attachments (GTK_WIDGET (table),
Packit 1e8aac
                                             GTK_WIDGET (list->data), &child);
Packit 1e8aac
Packit 1e8aac
      if (GLADE_IS_PLACEHOLDER (child.widget) == FALSE &&
Packit 1e8aac
          (child.right_attach > n_cols || child.bottom_attach > n_rows))
Packit 1e8aac
        {
Packit 1e8aac
          ret = TRUE;
Packit 1e8aac
          break;
Packit 1e8aac
        }
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  g_list_free (children);
Packit 1e8aac
Packit 1e8aac
  return ret;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
#define TABLE_OCCUPIED(occmap, n_columns, col, row) \
Packit 1e8aac
    (occmap)[row * n_columns + col]
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
glade_gtk_table_build_occupation_maps(GtkTable *table, guint n_columns, guint n_rows,
Packit 1e8aac
				      gchar **child_map, gpointer **placeholder_map)
Packit 1e8aac
{
Packit 1e8aac
    guint i, j;
Packit 1e8aac
    GList *list, *children = gtk_container_get_children (GTK_CONTAINER (table));
Packit 1e8aac
Packit 1e8aac
    *child_map = g_malloc0(n_columns * n_rows * sizeof(gchar));  /* gchar is smaller than gboolean */
Packit 1e8aac
    *placeholder_map = g_malloc0(n_columns * n_rows * sizeof(gpointer));
Packit 1e8aac
Packit 1e8aac
    for (list = children; list && list->data; list = list->next)
Packit 1e8aac
    {
Packit 1e8aac
	GtkTableChild child;
Packit 1e8aac
Packit 1e8aac
	glade_gtk_table_get_child_attachments (GTK_WIDGET (table),
Packit 1e8aac
					       GTK_WIDGET (list->data), &child);
Packit 1e8aac
Packit 1e8aac
	if (GLADE_IS_PLACEHOLDER(list->data))
Packit 1e8aac
	{
Packit 1e8aac
	    /* assumption: placeholders are always attached to exactly 1 cell */
Packit 1e8aac
	    TABLE_OCCUPIED(*placeholder_map, n_columns, child.left_attach, child.top_attach) = list->data;
Packit 1e8aac
	}
Packit 1e8aac
	else
Packit 1e8aac
	{
Packit 1e8aac
	    for (i = child.left_attach; i < child.right_attach && i < n_columns; i++)
Packit 1e8aac
	    {
Packit 1e8aac
		for (j = child.top_attach; j < child.bottom_attach && j < n_rows; j++)
Packit 1e8aac
		{
Packit 1e8aac
		    TABLE_OCCUPIED(*child_map, n_columns, i, j) = 1;
Packit 1e8aac
		}
Packit 1e8aac
	    }
Packit 1e8aac
	}
Packit 1e8aac
    }
Packit 1e8aac
    g_list_free (children);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
glade_gtk_table_refresh_placeholders (GtkTable * table)
Packit 1e8aac
{
Packit 1e8aac
  guint n_columns, n_rows, i, j;
Packit 1e8aac
  gchar *child_map;
Packit 1e8aac
  gpointer *placeholder_map;
Packit 1e8aac
Packit 1e8aac
  g_object_get (table, "n-columns", &n_columns, "n-rows", &n_rows, NULL);
Packit 1e8aac
  glade_gtk_table_build_occupation_maps (table, n_columns, n_rows,
Packit 1e8aac
					 &child_map, &placeholder_map);
Packit 1e8aac
Packit 1e8aac
  for (i = 0; i < n_columns; i++)
Packit 1e8aac
    {
Packit 1e8aac
      for (j = 0; j < n_rows; j++)
Packit 1e8aac
	{
Packit 1e8aac
	  gpointer placeholder = TABLE_OCCUPIED(placeholder_map, n_columns, i, j);
Packit 1e8aac
Packit 1e8aac
	  if (TABLE_OCCUPIED(child_map, n_columns, i, j))
Packit 1e8aac
	    {
Packit 1e8aac
	      if (placeholder)
Packit 1e8aac
		{
Packit 1e8aac
		  gtk_container_remove (GTK_CONTAINER (table), 
Packit 1e8aac
					GTK_WIDGET (placeholder));
Packit 1e8aac
		}
Packit 1e8aac
	    }
Packit 1e8aac
	  else
Packit 1e8aac
	    {
Packit 1e8aac
	      if (!placeholder)
Packit 1e8aac
		{
Packit 1e8aac
		  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
Packit 1e8aac
		  gtk_table_attach_defaults (table, 
Packit 1e8aac
					     glade_placeholder_new (), 
Packit 1e8aac
					     i, i + 1, j, j + 1);
Packit 1e8aac
		  G_GNUC_END_IGNORE_DEPRECATIONS;
Packit 1e8aac
		}
Packit 1e8aac
	    }
Packit 1e8aac
	}
Packit 1e8aac
    }
Packit 1e8aac
  g_free(child_map);
Packit 1e8aac
  g_free(placeholder_map);
Packit 1e8aac
Packit 1e8aac
  if (gtk_widget_get_realized (GTK_WIDGET (table)))
Packit 1e8aac
    gtk_container_check_resize (GTK_CONTAINER (table));
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
gtk_table_children_callback (GtkWidget * widget, gpointer client_data)
Packit 1e8aac
{
Packit 1e8aac
  GList **children;
Packit 1e8aac
Packit 1e8aac
  children = (GList **) client_data;
Packit 1e8aac
  *children = g_list_prepend (*children, widget);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
GList *
Packit 1e8aac
glade_gtk_table_get_children (GladeWidgetAdaptor * adaptor,
Packit 1e8aac
                              GtkContainer * container)
Packit 1e8aac
{
Packit 1e8aac
  GList *children = NULL;
Packit 1e8aac
Packit 1e8aac
  gtk_container_forall (container, gtk_table_children_callback, &children);
Packit 1e8aac
Packit 1e8aac
  /* GtkTable has the children list already reversed */
Packit 1e8aac
  return children;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
void
Packit 1e8aac
glade_gtk_table_add_child (GladeWidgetAdaptor * adaptor,
Packit 1e8aac
                           GObject * object, GObject * child)
Packit 1e8aac
{
Packit 1e8aac
  gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (child));
Packit 1e8aac
Packit 1e8aac
  glade_gtk_table_refresh_placeholders (GTK_TABLE (object));
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
void
Packit 1e8aac
glade_gtk_table_remove_child (GladeWidgetAdaptor * adaptor,
Packit 1e8aac
                              GObject * object, GObject * child)
Packit 1e8aac
{
Packit 1e8aac
  gtk_container_remove (GTK_CONTAINER (object), GTK_WIDGET (child));
Packit 1e8aac
Packit 1e8aac
  glade_gtk_table_refresh_placeholders (GTK_TABLE (object));
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
void
Packit 1e8aac
glade_gtk_table_replace_child (GladeWidgetAdaptor * adaptor,
Packit 1e8aac
                               GtkWidget * container,
Packit 1e8aac
                               GtkWidget * current, GtkWidget * new_widget)
Packit 1e8aac
{
Packit 1e8aac
  /* Chain Up */
Packit 1e8aac
  GWA_GET_CLASS
Packit 1e8aac
      (GTK_TYPE_CONTAINER)->replace_child (adaptor,
Packit 1e8aac
                                           G_OBJECT (container),
Packit 1e8aac
                                           G_OBJECT (current),
Packit 1e8aac
                                           G_OBJECT (new_widget));
Packit 1e8aac
Packit 1e8aac
  /* If we are replacing a GladeWidget, we must refresh placeholders
Packit 1e8aac
   * because the widget may have spanned multiple rows/columns, we must
Packit 1e8aac
   * not do so in the case we are pasting multiple widgets into a table,
Packit 1e8aac
   * where destroying placeholders results in default packing properties
Packit 1e8aac
   * (since the remaining placeholder templates no longer exist, only the
Packit 1e8aac
   * first pasted widget would have proper packing properties).
Packit 1e8aac
   */
Packit 1e8aac
  if (!GLADE_IS_PLACEHOLDER (new_widget))
Packit 1e8aac
    glade_gtk_table_refresh_placeholders (GTK_TABLE (container));
Packit 1e8aac
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
glade_gtk_table_set_n_common (GObject * object, const GValue * value,
Packit 1e8aac
                              gboolean for_rows)
Packit 1e8aac
{
Packit 1e8aac
  GladeWidget *widget;
Packit 1e8aac
  GtkTable *table;
Packit 1e8aac
  guint new_size, old_size, n_columns, n_rows;
Packit 1e8aac
Packit 1e8aac
  table = GTK_TABLE (object);
Packit 1e8aac
Packit 1e8aac
  g_object_get (table, "n-columns", &n_columns, "n-rows", &n_rows, NULL);
Packit 1e8aac
Packit 1e8aac
  new_size = g_value_get_uint (value);
Packit 1e8aac
  old_size = for_rows ? n_rows : n_columns;
Packit 1e8aac
Packit 1e8aac
  if (new_size < 1)
Packit 1e8aac
    return;
Packit 1e8aac
Packit 1e8aac
  if (glade_gtk_table_widget_exceeds_bounds
Packit 1e8aac
      (table, for_rows ? new_size : n_rows, for_rows ? n_columns : new_size))
Packit 1e8aac
    /* Refuse to shrink if it means orphaning widgets */
Packit 1e8aac
    return;
Packit 1e8aac
Packit 1e8aac
  widget = glade_widget_get_from_gobject (GTK_WIDGET (table));
Packit 1e8aac
  g_return_if_fail (widget != NULL);
Packit 1e8aac
Packit 1e8aac
  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
Packit 1e8aac
  if (for_rows)
Packit 1e8aac
    gtk_table_resize (table, new_size, n_columns);
Packit 1e8aac
  else
Packit 1e8aac
    gtk_table_resize (table, n_rows, new_size);
Packit 1e8aac
  G_GNUC_END_IGNORE_DEPRECATIONS;
Packit 1e8aac
Packit 1e8aac
  /* Fill table with placeholders */
Packit 1e8aac
  glade_gtk_table_refresh_placeholders (table);
Packit 1e8aac
Packit 1e8aac
  if (new_size < old_size)
Packit 1e8aac
    {
Packit 1e8aac
      /* Remove from the bottom up */
Packit 1e8aac
      GList *list, *children;
Packit 1e8aac
      GList *list_to_free = NULL;
Packit 1e8aac
Packit 1e8aac
      children = gtk_container_get_children (GTK_CONTAINER (table));
Packit 1e8aac
Packit 1e8aac
      for (list = children; list && list->data; list = list->next)
Packit 1e8aac
        {
Packit 1e8aac
          GtkTableChild child;
Packit 1e8aac
          guint start, end;
Packit 1e8aac
Packit 1e8aac
          glade_gtk_table_get_child_attachments (GTK_WIDGET (table),
Packit 1e8aac
                                                 GTK_WIDGET (list->data),
Packit 1e8aac
                                                 &child);
Packit 1e8aac
Packit 1e8aac
          start = for_rows ? child.top_attach : child.left_attach;
Packit 1e8aac
          end = for_rows ? child.bottom_attach : child.right_attach;
Packit 1e8aac
Packit 1e8aac
          /* We need to completely remove it */
Packit 1e8aac
          if (start >= new_size)
Packit 1e8aac
            {
Packit 1e8aac
              list_to_free = g_list_prepend (list_to_free, child.widget);
Packit 1e8aac
              continue;
Packit 1e8aac
            }
Packit 1e8aac
Packit 1e8aac
          /* If the widget spans beyond the new border,
Packit 1e8aac
           * we should resize it to fit on the new table */
Packit 1e8aac
          if (end > new_size)
Packit 1e8aac
            gtk_container_child_set
Packit 1e8aac
                (GTK_CONTAINER (table), GTK_WIDGET (child.widget),
Packit 1e8aac
                 for_rows ? "bottom_attach" : "right_attach", new_size, NULL);
Packit 1e8aac
        }
Packit 1e8aac
Packit 1e8aac
      g_list_free (children);
Packit 1e8aac
Packit 1e8aac
      if (list_to_free)
Packit 1e8aac
        {
Packit 1e8aac
          for (list = g_list_first (list_to_free);
Packit 1e8aac
               list && list->data; list = list->next)
Packit 1e8aac
            {
Packit 1e8aac
              g_object_ref (G_OBJECT (list->data));
Packit 1e8aac
              gtk_container_remove (GTK_CONTAINER (table),
Packit 1e8aac
                                    GTK_WIDGET (list->data));
Packit 1e8aac
              /* This placeholder is no longer valid, force destroy */
Packit 1e8aac
              gtk_widget_destroy (GTK_WIDGET (list->data));
Packit 1e8aac
            }
Packit 1e8aac
          g_list_free (list_to_free);
Packit 1e8aac
        }
Packit 1e8aac
Packit 1e8aac
      G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
Packit 1e8aac
      gtk_table_resize (table,
Packit 1e8aac
                        for_rows ? new_size : n_rows,
Packit 1e8aac
                        for_rows ? n_columns : new_size);
Packit 1e8aac
      G_GNUC_END_IGNORE_DEPRECATIONS;
Packit 1e8aac
    }
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
void
Packit 1e8aac
glade_gtk_table_set_property (GladeWidgetAdaptor * adaptor,
Packit 1e8aac
                              GObject * object,
Packit 1e8aac
                              const gchar * id, const GValue * value)
Packit 1e8aac
{
Packit 1e8aac
  if (!strcmp (id, "n-rows"))
Packit 1e8aac
    glade_gtk_table_set_n_common (object, value, TRUE);
Packit 1e8aac
  else if (!strcmp (id, "n-columns"))
Packit 1e8aac
    glade_gtk_table_set_n_common (object, value, FALSE);
Packit 1e8aac
  else
Packit 1e8aac
    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor, object,
Packit 1e8aac
                                                      id, value);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static gboolean
Packit 1e8aac
glade_gtk_table_verify_n_common (GObject * object, const GValue * value,
Packit 1e8aac
                                 gboolean for_rows)
Packit 1e8aac
{
Packit 1e8aac
  GtkTable *table = GTK_TABLE (object);
Packit 1e8aac
  guint n_columns, n_rows, new_size = g_value_get_uint (value);
Packit 1e8aac
Packit 1e8aac
  g_object_get (table, "n-columns", &n_columns, "n-rows", &n_rows, NULL);
Packit 1e8aac
Packit 1e8aac
  if (glade_gtk_table_widget_exceeds_bounds
Packit 1e8aac
      (table, for_rows ? new_size : n_rows, for_rows ? n_columns : new_size))
Packit 1e8aac
    /* Refuse to shrink if it means orphaning widgets */
Packit 1e8aac
    return FALSE;
Packit 1e8aac
Packit 1e8aac
  return TRUE;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
gboolean
Packit 1e8aac
glade_gtk_table_verify_property (GladeWidgetAdaptor * adaptor,
Packit 1e8aac
                                 GObject * object,
Packit 1e8aac
                                 const gchar * id, const GValue * value)
Packit 1e8aac
{
Packit 1e8aac
  if (!strcmp (id, "n-rows"))
Packit 1e8aac
    return glade_gtk_table_verify_n_common (object, value, TRUE);
Packit 1e8aac
  else if (!strcmp (id, "n-columns"))
Packit 1e8aac
    return glade_gtk_table_verify_n_common (object, value, FALSE);
Packit 1e8aac
  else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property)
Packit 1e8aac
    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property (adaptor, object,
Packit 1e8aac
                                                         id, value);
Packit 1e8aac
Packit 1e8aac
  return TRUE;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
void
Packit 1e8aac
glade_gtk_table_set_child_property (GladeWidgetAdaptor * adaptor,
Packit 1e8aac
                                    GObject * container,
Packit 1e8aac
                                    GObject * child,
Packit 1e8aac
                                    const gchar * property_name, GValue * value)
Packit 1e8aac
{
Packit 1e8aac
  GWA_GET_CLASS
Packit 1e8aac
      (GTK_TYPE_CONTAINER)->child_set_property (adaptor,
Packit 1e8aac
                                                container, child,
Packit 1e8aac
                                                property_name, value);
Packit 1e8aac
Packit 1e8aac
  if (strcmp (property_name, "bottom-attach") == 0 ||
Packit 1e8aac
      strcmp (property_name, "left-attach") == 0 ||
Packit 1e8aac
      strcmp (property_name, "right-attach") == 0 ||
Packit 1e8aac
      strcmp (property_name, "top-attach") == 0)
Packit 1e8aac
    {
Packit 1e8aac
      /* Refresh placeholders */
Packit 1e8aac
      glade_gtk_table_refresh_placeholders (GTK_TABLE (container));
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static gboolean
Packit 1e8aac
glade_gtk_table_verify_attach_common (GObject * object,
Packit 1e8aac
                                      GValue * value,
Packit 1e8aac
                                      guint * val,
Packit 1e8aac
                                      const gchar * prop,
Packit 1e8aac
                                      guint * prop_val,
Packit 1e8aac
                                      const gchar * parent_prop,
Packit 1e8aac
                                      guint * parent_val)
Packit 1e8aac
{
Packit 1e8aac
  GladeWidget *widget, *parent;
Packit 1e8aac
Packit 1e8aac
  widget = glade_widget_get_from_gobject (object);
Packit 1e8aac
  g_return_val_if_fail (GLADE_IS_WIDGET (widget), TRUE);
Packit 1e8aac
  parent = glade_widget_get_parent (widget);
Packit 1e8aac
  g_return_val_if_fail (GLADE_IS_WIDGET (parent), TRUE);
Packit 1e8aac
Packit 1e8aac
  *val = g_value_get_uint (value);
Packit 1e8aac
  glade_widget_property_get (widget, prop, prop_val);
Packit 1e8aac
  glade_widget_property_get (parent, parent_prop, parent_val);
Packit 1e8aac
Packit 1e8aac
  return FALSE;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static gboolean
Packit 1e8aac
glade_gtk_table_verify_left_top_attach (GObject * object,
Packit 1e8aac
                                        GValue * value,
Packit 1e8aac
                                        const gchar * prop,
Packit 1e8aac
                                        const gchar * parent_prop)
Packit 1e8aac
{
Packit 1e8aac
  guint val, prop_val, parent_val;
Packit 1e8aac
Packit 1e8aac
  if (glade_gtk_table_verify_attach_common (object, value, &val,
Packit 1e8aac
                                            prop, &prop_val,
Packit 1e8aac
                                            parent_prop, &parent_val))
Packit 1e8aac
    return FALSE;
Packit 1e8aac
Packit 1e8aac
  if (val >= parent_val || val >= prop_val)
Packit 1e8aac
    return FALSE;
Packit 1e8aac
Packit 1e8aac
  return TRUE;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static gboolean
Packit 1e8aac
glade_gtk_table_verify_right_bottom_attach (GObject * object,
Packit 1e8aac
                                            GValue * value,
Packit 1e8aac
                                            const gchar * prop,
Packit 1e8aac
                                            const gchar * parent_prop)
Packit 1e8aac
{
Packit 1e8aac
  guint val, prop_val, parent_val;
Packit 1e8aac
Packit 1e8aac
  if (glade_gtk_table_verify_attach_common (object, value, &val,
Packit 1e8aac
                                            prop, &prop_val,
Packit 1e8aac
                                            parent_prop, &parent_val))
Packit 1e8aac
    return FALSE;
Packit 1e8aac
Packit 1e8aac
  if (val <= prop_val || val > parent_val)
Packit 1e8aac
    return FALSE;
Packit 1e8aac
Packit 1e8aac
  return TRUE;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
gboolean
Packit 1e8aac
glade_gtk_table_child_verify_property (GladeWidgetAdaptor * adaptor,
Packit 1e8aac
                                       GObject * container,
Packit 1e8aac
                                       GObject * child,
Packit 1e8aac
                                       const gchar * id, GValue * value)
Packit 1e8aac
{
Packit 1e8aac
  if (!strcmp (id, "left-attach"))
Packit 1e8aac
    return glade_gtk_table_verify_left_top_attach (child,
Packit 1e8aac
                                                   value,
Packit 1e8aac
                                                   "right-attach", "n-columns");
Packit 1e8aac
  else if (!strcmp (id, "right-attach"))
Packit 1e8aac
    return glade_gtk_table_verify_right_bottom_attach (child,
Packit 1e8aac
                                                       value,
Packit 1e8aac
                                                       "left-attach",
Packit 1e8aac
                                                       "n-columns");
Packit 1e8aac
  else if (!strcmp (id, "top-attach"))
Packit 1e8aac
    return glade_gtk_table_verify_left_top_attach (child,
Packit 1e8aac
                                                   value,
Packit 1e8aac
                                                   "bottom-attach", "n-rows");
Packit 1e8aac
  else if (!strcmp (id, "bottom-attach"))
Packit 1e8aac
    return glade_gtk_table_verify_right_bottom_attach (child,
Packit 1e8aac
                                                       value,
Packit 1e8aac
                                                       "top-attach", "n-rows");
Packit 1e8aac
  else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_verify_property)
Packit 1e8aac
    GWA_GET_CLASS
Packit 1e8aac
        (GTK_TYPE_CONTAINER)->child_verify_property (adaptor,
Packit 1e8aac
                                                     container, child,
Packit 1e8aac
                                                     id, value);
Packit 1e8aac
Packit 1e8aac
  return TRUE;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
glade_gtk_table_child_insert_remove_action (GladeWidgetAdaptor *adaptor, 
Packit 1e8aac
					    GObject            *container, 
Packit 1e8aac
					    GObject            *object, 
Packit 1e8aac
					    GroupAction         group_action,
Packit 1e8aac
					    const gchar        *n_row_col, 
Packit 1e8aac
					    const gchar        *attach1,    /* should be smaller (top/left) attachment */
Packit 1e8aac
                                            const gchar        *attach2,      /* should be larger (bot/right) attachment */
Packit 1e8aac
                                            gboolean            remove, 
Packit 1e8aac
					    gboolean            after)
Packit 1e8aac
{
Packit 1e8aac
  GladeWidget *parent;
Packit 1e8aac
  GList *children, *l;
Packit 1e8aac
  gint child_pos, size, offset;
Packit 1e8aac
Packit 1e8aac
  gtk_container_child_get (GTK_CONTAINER (container),
Packit 1e8aac
                           GTK_WIDGET (object),
Packit 1e8aac
                           after ? attach2 : attach1, &child_pos, NULL);
Packit 1e8aac
Packit 1e8aac
  parent = glade_widget_get_from_gobject (container);
Packit 1e8aac
  switch (group_action)
Packit 1e8aac
    {
Packit 1e8aac
      case GROUP_ACTION_INSERT_ROW:
Packit 1e8aac
        glade_command_push_group (_("Insert Row on %s"), glade_widget_get_name (parent));
Packit 1e8aac
        break;
Packit 1e8aac
      case GROUP_ACTION_INSERT_COLUMN:
Packit 1e8aac
        glade_command_push_group (_("Insert Column on %s"), glade_widget_get_name (parent));
Packit 1e8aac
        break;
Packit 1e8aac
      case GROUP_ACTION_REMOVE_COLUMN:
Packit 1e8aac
        glade_command_push_group (_("Remove Column on %s"), glade_widget_get_name (parent));
Packit 1e8aac
        break;
Packit 1e8aac
      case GROUP_ACTION_REMOVE_ROW:
Packit 1e8aac
        glade_command_push_group (_("Remove Row on %s"), glade_widget_get_name (parent));
Packit 1e8aac
        break;
Packit 1e8aac
      default:
Packit 1e8aac
        g_assert_not_reached ();
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  children = glade_widget_adaptor_get_children (adaptor, container);
Packit 1e8aac
  /* Make sure widgets does not get destroyed */
Packit 1e8aac
  g_list_foreach (children, (GFunc) g_object_ref, NULL);
Packit 1e8aac
Packit 1e8aac
  glade_widget_property_get (parent, n_row_col, &size);
Packit 1e8aac
Packit 1e8aac
  if (remove)
Packit 1e8aac
    {
Packit 1e8aac
      GList *del = NULL;
Packit 1e8aac
      /* Remove children first */
Packit 1e8aac
      for (l = children; l; l = g_list_next (l))
Packit 1e8aac
        {
Packit 1e8aac
          GladeWidget *gchild = glade_widget_get_from_gobject (l->data);
Packit 1e8aac
          gint pos1, pos2;
Packit 1e8aac
Packit 1e8aac
          /* Skip placeholders */
Packit 1e8aac
          if (gchild == NULL)
Packit 1e8aac
            continue;
Packit 1e8aac
Packit 1e8aac
          glade_widget_pack_property_get (gchild, attach1, &pos1);
Packit 1e8aac
          glade_widget_pack_property_get (gchild, attach2, &pos2);
Packit 1e8aac
          if ((pos1 + 1 == pos2) && ((after ? pos2 : pos1) == child_pos))
Packit 1e8aac
            {
Packit 1e8aac
              del = g_list_prepend (del, gchild);
Packit 1e8aac
            }
Packit 1e8aac
        }
Packit 1e8aac
      if (del)
Packit 1e8aac
        {
Packit 1e8aac
          glade_command_delete (del);
Packit 1e8aac
          g_list_free (del);
Packit 1e8aac
        }
Packit 1e8aac
      offset = -1;
Packit 1e8aac
    }
Packit 1e8aac
  else
Packit 1e8aac
    {
Packit 1e8aac
      /* Expand the table */
Packit 1e8aac
      glade_command_set_property (glade_widget_get_property (parent, n_row_col),
Packit 1e8aac
                                  size + 1);
Packit 1e8aac
      offset = 1;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  /* Reorder children */
Packit 1e8aac
  for (l = children; l; l = g_list_next (l))
Packit 1e8aac
    {
Packit 1e8aac
      GladeWidget *gchild = glade_widget_get_from_gobject (l->data);
Packit 1e8aac
      gint pos;
Packit 1e8aac
Packit 1e8aac
      /* Skip placeholders */
Packit 1e8aac
      if (gchild == NULL)
Packit 1e8aac
        continue;
Packit 1e8aac
Packit 1e8aac
      /* if removing, do top/left before bot/right */
Packit 1e8aac
      if (remove)
Packit 1e8aac
        {
Packit 1e8aac
          /* adjust top-left attachment */
Packit 1e8aac
          glade_widget_pack_property_get (gchild, attach1, &pos;;
Packit 1e8aac
          if (pos > child_pos || (after && pos == child_pos))
Packit 1e8aac
            {
Packit 1e8aac
              glade_command_set_property (glade_widget_get_pack_property
Packit 1e8aac
                                          (gchild, attach1), pos + offset);
Packit 1e8aac
            }
Packit 1e8aac
Packit 1e8aac
          /* adjust bottom-right attachment */
Packit 1e8aac
          glade_widget_pack_property_get (gchild, attach2, &pos;;
Packit 1e8aac
          if (pos > child_pos || (after && pos == child_pos))
Packit 1e8aac
            {
Packit 1e8aac
              glade_command_set_property (glade_widget_get_pack_property
Packit 1e8aac
                                          (gchild, attach2), pos + offset);
Packit 1e8aac
            }
Packit 1e8aac
Packit 1e8aac
        }
Packit 1e8aac
      /* if inserting, do bot/right before top/left */
Packit 1e8aac
      else
Packit 1e8aac
        {
Packit 1e8aac
          /* adjust bottom-right attachment */
Packit 1e8aac
          glade_widget_pack_property_get (gchild, attach2, &pos;;
Packit 1e8aac
          if (pos > child_pos)
Packit 1e8aac
            {
Packit 1e8aac
              glade_command_set_property (glade_widget_get_pack_property
Packit 1e8aac
                                          (gchild, attach2), pos + offset);
Packit 1e8aac
            }
Packit 1e8aac
Packit 1e8aac
          /* adjust top-left attachment */
Packit 1e8aac
          glade_widget_pack_property_get (gchild, attach1, &pos;;
Packit 1e8aac
          if (pos >= child_pos)
Packit 1e8aac
            {
Packit 1e8aac
              glade_command_set_property (glade_widget_get_pack_property
Packit 1e8aac
                                          (gchild, attach1), pos + offset);
Packit 1e8aac
            }
Packit 1e8aac
        }
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  if (remove)
Packit 1e8aac
    {
Packit 1e8aac
      /* Shrink the table */
Packit 1e8aac
      glade_command_set_property (glade_widget_get_property (parent, n_row_col),
Packit 1e8aac
                                  size - 1);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  g_list_foreach (children, (GFunc) g_object_unref, NULL);
Packit 1e8aac
  g_list_free (children);
Packit 1e8aac
Packit 1e8aac
  glade_command_pop_group ();
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
void
Packit 1e8aac
glade_gtk_table_child_action_activate (GladeWidgetAdaptor * adaptor,
Packit 1e8aac
                                       GObject * container,
Packit 1e8aac
                                       GObject * object,
Packit 1e8aac
                                       const gchar * action_path)
Packit 1e8aac
{
Packit 1e8aac
  if (strcmp (action_path, "insert_row/after") == 0)
Packit 1e8aac
    {
Packit 1e8aac
      glade_gtk_table_child_insert_remove_action (adaptor, container, object,
Packit 1e8aac
                                                  GROUP_ACTION_INSERT_ROW,
Packit 1e8aac
                                                  "n-rows", "top-attach",
Packit 1e8aac
                                                  "bottom-attach", FALSE, TRUE);
Packit 1e8aac
    }
Packit 1e8aac
  else if (strcmp (action_path, "insert_row/before") == 0)
Packit 1e8aac
    {
Packit 1e8aac
      glade_gtk_table_child_insert_remove_action (adaptor, container, object,
Packit 1e8aac
                                                  GROUP_ACTION_INSERT_ROW,
Packit 1e8aac
                                                  "n-rows", "top-attach",
Packit 1e8aac
                                                  "bottom-attach",
Packit 1e8aac
                                                  FALSE, FALSE);
Packit 1e8aac
    }
Packit 1e8aac
  else if (strcmp (action_path, "insert_column/after") == 0)
Packit 1e8aac
    {
Packit 1e8aac
      glade_gtk_table_child_insert_remove_action (adaptor, container, object,
Packit 1e8aac
                                                  GROUP_ACTION_INSERT_COLUMN,
Packit 1e8aac
                                                  "n-columns", "left-attach",
Packit 1e8aac
                                                  "right-attach", FALSE, TRUE);
Packit 1e8aac
    }
Packit 1e8aac
  else if (strcmp (action_path, "insert_column/before") == 0)
Packit 1e8aac
    {
Packit 1e8aac
      glade_gtk_table_child_insert_remove_action (adaptor, container, object,
Packit 1e8aac
                                                  GROUP_ACTION_INSERT_COLUMN,
Packit 1e8aac
                                                  "n-columns", "left-attach",
Packit 1e8aac
                                                  "right-attach", FALSE, FALSE);
Packit 1e8aac
    }
Packit 1e8aac
  else if (strcmp (action_path, "remove_column") == 0)
Packit 1e8aac
    {
Packit 1e8aac
      glade_gtk_table_child_insert_remove_action (adaptor, container, object,
Packit 1e8aac
                                                  GROUP_ACTION_REMOVE_COLUMN,
Packit 1e8aac
                                                  "n-columns", "left-attach",
Packit 1e8aac
                                                  "right-attach", TRUE, FALSE);
Packit 1e8aac
    }
Packit 1e8aac
  else if (strcmp (action_path, "remove_row") == 0)
Packit 1e8aac
    {
Packit 1e8aac
      glade_gtk_table_child_insert_remove_action (adaptor, container, object,
Packit 1e8aac
                                                  GROUP_ACTION_REMOVE_ROW,
Packit 1e8aac
                                                  "n-rows", "top-attach",
Packit 1e8aac
                                                  "bottom-attach", TRUE, FALSE);
Packit 1e8aac
    }
Packit 1e8aac
  else
Packit 1e8aac
    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_action_activate (adaptor,
Packit 1e8aac
                                                               container,
Packit 1e8aac
                                                               object,
Packit 1e8aac
                                                               action_path);
Packit 1e8aac
}