[dia] layer-editor: bring minimal gtklist in-tree



commit 25fc84df597036cbe47c33ac11f105cc1d14089a
Author: Zander Brown <zbrown gnome org>
Date:   Sun Apr 5 01:07:13 2020 +0100

    layer-editor: bring minimal gtklist in-tree
    
    DiaList is GtkList stripped of alternative selection modes, horizontal
    scrolling and drag-n-drop
    
    DiaListItem is a combination of GtkListItem and GtkItem supporting only
    the basic selection case
    
    This allows us to stop using GtkList, the latest gtk2 deprecation
    warning

 app/dia-change.c                    |    2 +-
 app/dia-list-item.c                 |  301 ++++++++++
 app/dia-list-item.h                 |   50 ++
 app/dia-list.c                      | 1097 +++++++++++++++++++++++++++++++++++
 app/dia-list.h                      |   75 +++
 app/layer-editor/dia-layer-widget.c |  107 ++--
 app/layer-editor/dia-layer-widget.h |    9 +-
 app/meson.build                     |    6 +
 meson.build                         |    1 +
 9 files changed, 1589 insertions(+), 59 deletions(-)
---
diff --git a/app/dia-change.c b/app/dia-change.c
index b48689f1..3b523204 100644
--- a/app/dia-change.c
+++ b/app/dia-change.c
@@ -38,7 +38,7 @@ static void
 dia_change_real_revert (DiaChange *self,
                         Diagram   *diagram)
 {
- g_critical ("%s doesn't implement revert", DIA_CHANGE_TYPE_NAME (self));
+  g_critical ("%s doesn't implement revert", DIA_CHANGE_TYPE_NAME (self));
 }
 
 
diff --git a/app/dia-list-item.c b/app/dia-list-item.c
new file mode 100644
index 00000000..8719708d
--- /dev/null
+++ b/app/dia-list-item.c
@@ -0,0 +1,301 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "dia-list-item.h"
+
+
+G_DEFINE_TYPE (DiaListItem, dia_list_item, GTK_TYPE_BIN)
+
+
+enum {
+  SCROLL_VERTICAL,
+  SCROLL_HORIZONTAL,
+  LAST_SIGNAL
+};
+static guint list_item_signals[LAST_SIGNAL] = {0};
+
+
+static void
+dia_list_item_realize (GtkWidget *widget)
+{
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+  GtkAllocation alloc;
+  GdkWindow *window;
+  GtkStyle *style;
+
+  /*GTK_WIDGET_CLASS (parent_class)->realize (widget);*/
+
+  g_return_if_fail (DIA_IS_LIST_ITEM (widget));
+
+  gtk_widget_set_realized (widget, TRUE);
+
+  gtk_widget_get_allocation (widget, &alloc);
+
+  attributes.x = alloc.x;
+  attributes.y = alloc.y;
+  attributes.width = alloc.width;
+  attributes.height = alloc.height;
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+  attributes.event_mask = (gtk_widget_get_events (widget) |
+                           GDK_EXPOSURE_MASK |
+                           GDK_BUTTON_PRESS_MASK |
+                           GDK_BUTTON_RELEASE_MASK |
+                           GDK_KEY_PRESS_MASK |
+                           GDK_KEY_RELEASE_MASK);
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+  window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
+  gtk_widget_set_window (widget, window);
+  gdk_window_set_user_data (window, widget);
+
+  gtk_widget_style_attach (widget);
+
+  style = gtk_widget_get_style (widget);
+  gdk_window_set_background (window, &style->base[GTK_STATE_NORMAL]);
+}
+
+
+static void
+dia_list_item_size_request (GtkWidget      *widget,
+                                GtkRequisition *requisition)
+{
+  GtkBin *bin;
+  GtkWidget *child;
+  GtkRequisition child_requisition;
+  GtkStyle *style;
+  gint focus_width;
+  gint focus_pad;
+  int border_width;
+
+  g_return_if_fail (DIA_IS_LIST_ITEM (widget));
+  g_return_if_fail (requisition != NULL);
+
+  bin = GTK_BIN (widget);
+  gtk_widget_style_get (widget,
+                        "focus-line-width", &focus_width,
+                        "focus-padding", &focus_pad,
+                        NULL);
+
+  style = gtk_widget_get_style (widget);
+  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
+
+  requisition->width = 2 * (border_width + style->xthickness + focus_width + focus_pad - 1);
+  requisition->height = 2 * (border_width + focus_width + focus_pad - 1);
+
+  child = gtk_bin_get_child (bin);
+
+  if (child && gtk_widget_get_visible (child)) {
+    gtk_widget_size_request (child, &child_requisition);
+
+    requisition->width += child_requisition.width;
+    requisition->height += child_requisition.height;
+  }
+}
+
+
+static void
+dia_list_item_size_allocate (GtkWidget     *widget,
+                                 GtkAllocation *allocation)
+{
+  GtkBin *bin;
+  GtkStyle *style;
+  int border_width;
+  GtkAllocation child_allocation;
+
+  g_return_if_fail (DIA_IS_LIST_ITEM (widget));
+  g_return_if_fail (allocation != NULL);
+
+
+  gtk_widget_set_allocation (widget, allocation);
+
+  style = gtk_widget_get_style (widget);
+  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
+
+  if (gtk_widget_get_realized (widget)) {
+    gdk_window_move_resize (gtk_widget_get_window (widget),
+                            allocation->x, allocation->y,
+                            allocation->width, allocation->height);
+  }
+
+  bin = GTK_BIN (widget);
+
+  if (gtk_bin_get_child (bin)) {
+    child_allocation.x = (border_width + style->xthickness);
+    child_allocation.y = border_width;
+    child_allocation.width = allocation->width - child_allocation.x * 2;
+    child_allocation.height = allocation->height - child_allocation.y * 2;
+
+    gtk_widget_size_allocate (gtk_bin_get_child (bin), &child_allocation);
+  }
+}
+
+
+static void
+dia_list_item_style_set (GtkWidget      *widget,
+                             GtkStyle       *previous_style)
+{
+  GtkStyle *style;
+
+  g_return_if_fail (widget != NULL);
+
+  if (previous_style && gtk_widget_get_realized (widget)) {
+    style = gtk_widget_get_style (widget);
+    gdk_window_set_background (gtk_widget_get_window (widget),
+                               &style->base[gtk_widget_get_state (widget)]);
+  }
+}
+
+
+static gint
+dia_list_item_expose (GtkWidget      *widget,
+                          GdkEventExpose *event)
+{
+  GtkAllocation alloc;
+  GdkWindow *window;
+  GtkStyle *style;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+
+  if (gtk_widget_is_drawable (widget)) {
+    window = gtk_widget_get_window (widget);
+    style = gtk_widget_get_style (widget);
+
+    if (gtk_widget_get_state (GTK_WIDGET (widget)) == GTK_STATE_NORMAL) {
+      gdk_window_set_back_pixmap (window, NULL, TRUE);
+      gdk_window_clear_area (window, event->area.x, event->area.y,
+                             event->area.width, event->area.height);
+    } else {
+      gtk_paint_flat_box (style, window,
+                          gtk_widget_get_state (GTK_WIDGET (widget)), GTK_SHADOW_ETCHED_OUT,
+                          &event->area, widget, "listitem",
+                          0, 0, -1, -1);
+    }
+
+    GTK_WIDGET_CLASS (dia_list_item_parent_class)->expose_event (widget, event);
+
+    gtk_widget_get_allocation (widget, &alloc);
+
+    if (gtk_widget_has_focus (widget)) {
+      gtk_paint_focus (style, window, gtk_widget_get_state (widget),
+                       NULL, widget, NULL,
+                       0, 0, alloc.width, alloc.height);
+    }
+  }
+
+  return FALSE;
+}
+
+
+static void
+dia_list_item_class_init (DiaListItemClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GtkBindingSet *binding_set;
+
+  widget_class->realize = dia_list_item_realize;
+  widget_class->size_request = dia_list_item_size_request;
+  widget_class->size_allocate = dia_list_item_size_allocate;
+  widget_class->style_set = dia_list_item_style_set;
+  widget_class->expose_event = dia_list_item_expose;
+
+  klass->scroll_vertical = NULL;
+
+  list_item_signals[SCROLL_VERTICAL] =
+    g_signal_new ("scroll-vertical",
+                  G_OBJECT_CLASS_TYPE (object_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (DiaListItemClass, scroll_vertical),
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_DOUBLE);
+
+  binding_set = gtk_binding_set_by_class (klass);
+  gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
+                                "scroll-vertical", 2,
+                                G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
+                                G_TYPE_DOUBLE, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0,
+                                "scroll-vertical", 2,
+                                G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
+                                G_TYPE_DOUBLE, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
+                                "scroll-vertical", 2,
+                                G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
+                                G_TYPE_DOUBLE, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0,
+                                "scroll-vertical", 2,
+                                G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
+                                G_TYPE_DOUBLE, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
+                                "scroll-vertical", 2,
+                                G_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
+                                G_TYPE_DOUBLE, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0,
+                                "scroll-vertical", 2,
+                                G_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD,
+                                G_TYPE_DOUBLE, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
+                                "scroll-vertical", 2,
+                                G_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
+                                G_TYPE_DOUBLE, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0,
+                                "scroll-vertical", 2,
+                                G_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD,
+                                G_TYPE_DOUBLE, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK,
+                                "scroll-vertical", 2,
+                                G_TYPE_ENUM, GTK_SCROLL_JUMP,
+                                G_TYPE_DOUBLE, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
+                                "scroll-vertical", 2,
+                                G_TYPE_ENUM, GTK_SCROLL_JUMP,
+                                G_TYPE_DOUBLE, 0.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK,
+                                "scroll-vertical", 2,
+                                G_TYPE_ENUM, GTK_SCROLL_JUMP,
+                                G_TYPE_DOUBLE, 1.0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
+                                "scroll-vertical", 2,
+                                G_TYPE_ENUM, GTK_SCROLL_JUMP,
+                                G_TYPE_DOUBLE, 1.0);
+}
+
+
+static void
+dia_list_item_init (DiaListItem *list_item)
+{
+  gtk_widget_set_has_window (GTK_WIDGET (list_item), TRUE);
+  gtk_widget_set_can_focus (GTK_WIDGET (list_item), TRUE);
+}
diff --git a/app/dia-list-item.h b/app/dia-list-item.h
new file mode 100644
index 00000000..b41cc1ec
--- /dev/null
+++ b/app/dia-list-item.h
@@ -0,0 +1,50 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define DIA_TYPE_LIST_ITEM dia_list_item_get_type ()
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GtkBin, g_object_unref)
+
+G_DECLARE_DERIVABLE_TYPE (DiaListItem, dia_list_item, DIA, LIST_ITEM, GtkBin)
+
+
+struct _DiaListItemClass {
+  GtkBinClass parent_class;
+
+  void (*select)          (DiaListItem   *list_item);
+  void (*deselect)        (DiaListItem   *list_item);
+  void (*scroll_vertical) (DiaListItem   *list_item,
+                           GtkScrollType  scroll_type,
+                           gfloat         position);
+};
+
+G_END_DECLS
diff --git a/app/dia-list.c b/app/dia-list.c
new file mode 100644
index 00000000..80c45b96
--- /dev/null
+++ b/app/dia-list.c
@@ -0,0 +1,1097 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+
+#include "dia-list.h"
+#include "dia-list-item.h"
+
+
+typedef struct _DiaListPrivate DiaListPrivate;
+struct _DiaListPrivate
+{
+  GtkContainer container;
+
+  GList *children;
+  DiaListItem *selected;
+
+  GtkWidget *last_focus_child;
+  GtkWidget *undo_focus_child;
+
+  guint htimer;
+  guint vtimer;
+};
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (DiaList, dia_list, GTK_TYPE_CONTAINER)
+
+
+enum {
+  SELECT_CHILD,
+  UNSELECT_CHILD,
+  LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
+
+static void
+dia_list_dispose (GObject *object)
+{
+  dia_list_clear_items (DIA_LIST (object), 0, -1);
+
+  G_OBJECT_CLASS (dia_list_parent_class)->dispose (object);
+}
+
+
+static void
+dia_list_size_request (GtkWidget      *widget,
+                       GtkRequisition *requisition)
+{
+  DiaList *list = DIA_LIST (widget);
+  DiaListPrivate *priv = dia_list_get_instance_private (list);
+  GtkWidget *child;
+  GList *children;
+  int border_width;
+
+  requisition->width = 0;
+  requisition->height = 0;
+
+  children = priv->children;
+  while (children) {
+    child = children->data;
+    children = children->next;
+
+    if (gtk_widget_get_visible (child)) {
+      GtkRequisition child_requisition;
+
+      gtk_widget_size_request (child, &child_requisition);
+
+      requisition->width = MAX (requisition->width,
+              child_requisition.width);
+      requisition->height += child_requisition.height;
+    }
+  }
+
+  border_width = gtk_container_get_border_width (GTK_CONTAINER (list));
+
+  requisition->width += border_width * 2;
+  requisition->height += border_width * 2;
+
+  requisition->width = MAX (requisition->width, 1);
+  requisition->height = MAX (requisition->height, 1);
+}
+
+
+static void
+dia_list_size_allocate (GtkWidget     *widget,
+                        GtkAllocation *allocation)
+{
+  DiaList *list = DIA_LIST (widget);
+  DiaListPrivate *priv = dia_list_get_instance_private (list);
+  GtkWidget *child;
+  GtkAllocation child_allocation;
+  GList *children;
+  GdkWindow *window;
+
+  gtk_widget_set_allocation (widget, allocation);
+
+  window = gtk_widget_get_window (widget);
+
+  if (gtk_widget_get_realized (widget)) {
+    gdk_window_move_resize (window,
+                            allocation->x, allocation->y,
+                            allocation->width, allocation->height);
+  }
+
+  if (priv->children) {
+    int border_width = gtk_container_get_border_width (GTK_CONTAINER (list));
+    child_allocation.x = border_width;
+    child_allocation.y = border_width;
+    child_allocation.width = MAX (1,
+                                  allocation->width - child_allocation.x * 2);
+
+    children = priv->children;
+
+    while (children) {
+      child = children->data;
+      children = children->next;
+
+      if (gtk_widget_get_visible (child)) {
+          GtkRequisition child_requisition;
+
+          gtk_widget_get_child_requisition (child, &child_requisition);
+
+          child_allocation.height = child_requisition.height;
+
+          gtk_widget_size_allocate (child, &child_allocation);
+
+          child_allocation.y += child_allocation.height;
+        }
+    }
+  }
+}
+
+
+static void
+dia_list_realize (GtkWidget *widget)
+{
+  GtkAllocation alloc;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+  GdkWindow *window;
+  GtkStyle *style;
+  gtk_widget_set_realized (widget, TRUE);
+
+  gtk_widget_get_allocation (widget, &alloc);
+
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.x = alloc.x;
+  attributes.y = alloc.y;
+  attributes.width = alloc.width;
+  attributes.height = alloc.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+  attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+
+  window = gdk_window_new (gtk_widget_get_parent_window (widget),
+                           &attributes, attributes_mask);
+  gtk_widget_set_window (widget, window);
+  gdk_window_set_user_data (window, widget);
+
+  gtk_widget_style_attach (widget);
+
+  style = gtk_widget_get_style (widget);
+
+  gdk_window_set_background (window,
+                             &style->base[GTK_STATE_NORMAL]);
+}
+
+
+static void
+dia_list_unmap (GtkWidget *widget)
+{
+  GdkWindow *window;
+
+  if (!gtk_widget_get_mapped (widget)) {
+    return;
+  }
+
+  gtk_widget_set_mapped (widget, FALSE);
+
+  window = gtk_widget_get_window (widget);
+
+  gdk_window_hide (window);
+}
+
+
+static gboolean
+dia_list_button_press (GtkWidget      *widget,
+                       GdkEventButton *event)
+{
+  GtkWidget *item;
+
+  if (event->button != 1) {
+    return FALSE;
+  }
+
+  item = gtk_get_event_widget ((GdkEvent*) event);
+
+  while (item && !DIA_IS_LIST_ITEM (item)) {
+    item = gtk_widget_get_parent (item);
+  }
+
+  if (item && (gtk_widget_get_parent (item) == widget)) {
+    if (!gtk_widget_has_focus (item)) {
+      gtk_widget_grab_focus (item);
+    }
+
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+
+static void
+dia_list_style_set (GtkWidget *widget,
+                    GtkStyle  *previous_style)
+{
+  GtkStyle *style;
+
+  if (previous_style && gtk_widget_get_realized (widget)) {
+    style = gtk_widget_get_style (widget);
+    gdk_window_set_background (gtk_widget_get_window (widget),
+                               &style->base[gtk_widget_get_state (widget)]);
+  }
+}
+
+
+static void
+dia_list_add (GtkContainer *container,
+              GtkWidget    *widget)
+{
+  GList *item_list;
+
+  g_return_if_fail (DIA_IS_LIST_ITEM (widget));
+
+  item_list = g_list_alloc ();
+  item_list->data = widget;
+
+  dia_list_append_items (DIA_LIST (container), item_list);
+}
+
+
+static void
+dia_list_remove (GtkContainer *container,
+                 GtkWidget    *widget)
+{
+  GList *item_list;
+
+  g_return_if_fail (container == GTK_CONTAINER (gtk_widget_get_parent (widget)));
+
+  item_list = g_list_alloc ();
+  item_list->data = widget;
+
+  dia_list_remove_items (DIA_LIST (container), item_list);
+
+  g_list_free (item_list);
+}
+
+
+static void
+dia_list_forall (GtkContainer  *container,
+                 gboolean       include_internals,
+                 GtkCallback    callback,
+                 gpointer       callback_data)
+{
+  DiaList *list = DIA_LIST (container);
+  DiaListPrivate *priv = dia_list_get_instance_private (list);
+  GtkWidget *child;
+  GList *children;
+
+  children = priv->children;
+
+  while (children) {
+    child = children->data;
+    children = children->next;
+
+    (* callback) (child, callback_data);
+  }
+}
+
+
+static GType
+dia_list_child_type (GtkContainer *container)
+{
+  return DIA_TYPE_LIST_ITEM;
+}
+
+
+static void
+dia_list_set_focus_child (GtkContainer *container,
+                          GtkWidget    *child)
+{
+  DiaList *list;
+  GtkWidget *focus_child;
+  DiaListPrivate *priv;
+
+  g_return_if_fail (DIA_IS_LIST (container));
+
+  if (child) {
+    g_return_if_fail (GTK_IS_WIDGET (child));
+  }
+
+  list = DIA_LIST (container);
+  priv = dia_list_get_instance_private (list);
+
+  focus_child = gtk_container_get_focus_child (container);
+
+  if (child != focus_child) {
+    if (focus_child) {
+      priv->last_focus_child = focus_child;
+      g_clear_object (&focus_child);
+    }
+    GTK_CONTAINER_CLASS (dia_list_parent_class)->set_focus_child (container, child);
+    if (child) {
+      g_object_ref (child);
+    }
+  }
+
+  /* check for v adjustment */
+  if (child) {
+    GtkAdjustment *adjustment;
+
+    adjustment = gtk_container_get_focus_vadjustment (container);
+    if (adjustment) {
+      GtkAllocation alloc;
+
+      gtk_widget_get_allocation (child, &alloc);
+
+      gtk_adjustment_clamp_page (adjustment,
+                                 alloc.y,
+                                 (alloc.y +
+                                 alloc.height));
+    }
+
+    dia_list_select_child (list, DIA_LIST_ITEM (child));
+  }
+}
+
+
+static gboolean
+dia_list_focus (GtkWidget        *widget,
+                GtkDirectionType  direction)
+{
+  gint return_val = FALSE;
+  GtkContainer *container;
+  GtkWidget *focus_child;
+  DiaListPrivate *priv;
+
+  g_return_val_if_fail (DIA_IS_LIST (widget), FALSE);
+
+  priv = dia_list_get_instance_private (DIA_LIST (widget));
+
+  container = GTK_CONTAINER (widget);
+  focus_child = gtk_container_get_focus_child (container);
+
+  if (focus_child == NULL || !gtk_widget_has_focus (focus_child)) {
+    if (priv->last_focus_child) {
+      gtk_container_set_focus_child (container, priv->last_focus_child);
+    }
+
+    if (GTK_WIDGET_CLASS (dia_list_parent_class)->focus) {
+      return_val = GTK_WIDGET_CLASS (dia_list_parent_class)->focus (widget,
+                                                                        direction);
+    }
+  }
+
+  if (!return_val) {
+    focus_child = gtk_container_get_focus_child (GTK_CONTAINER (container));
+
+    if (focus_child) {
+      priv->last_focus_child = focus_child;
+    }
+  }
+
+  return return_val;
+}
+
+
+static void
+dia_list_real_select_child (DiaList     *self,
+                            DiaListItem *item)
+{
+  DiaListPrivate *priv;
+  DiaListItem *old = NULL;
+
+  g_return_if_fail (DIA_IS_LIST (self));
+  g_return_if_fail (DIA_IS_LIST_ITEM (item));
+
+  priv = dia_list_get_instance_private (self);
+
+  if (priv->selected) {
+    old = g_object_ref (priv->selected);
+  }
+
+  if (g_set_object (&priv->selected, item)) {
+    if (old) {
+      gtk_widget_set_state (GTK_WIDGET (old), GTK_STATE_NORMAL);
+    }
+
+    gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);
+  }
+
+  g_clear_object (&old);
+}
+
+
+static void
+dia_list_real_unselect_child (DiaList     *self,
+                              DiaListItem *item)
+{
+  DiaListPrivate *priv;
+
+  g_return_if_fail (DIA_IS_LIST (self));
+  g_return_if_fail (DIA_IS_LIST_ITEM (item));
+
+  priv = dia_list_get_instance_private (self);
+
+  g_return_if_fail (priv->selected == item);
+
+  gtk_widget_set_state (GTK_WIDGET (priv->selected), GTK_STATE_NORMAL);
+
+  g_clear_object (&priv->selected);
+}
+
+
+static void
+dia_list_class_init (DiaListClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+  object_class->dispose = dia_list_dispose;
+
+  widget_class->unmap = dia_list_unmap;
+  widget_class->style_set = dia_list_style_set;
+  widget_class->realize = dia_list_realize;
+  widget_class->button_press_event = dia_list_button_press;
+  widget_class->size_request = dia_list_size_request;
+  widget_class->size_allocate = dia_list_size_allocate;
+  widget_class->focus = dia_list_focus;
+
+  container_class->add = dia_list_add;
+  container_class->remove = dia_list_remove;
+  container_class->forall = dia_list_forall;
+  container_class->child_type = dia_list_child_type;
+  container_class->set_focus_child = dia_list_set_focus_child;
+
+  klass->select_child = dia_list_real_select_child;
+  klass->unselect_child = dia_list_real_unselect_child;
+
+  signals[SELECT_CHILD] =
+    g_signal_new ("select-child",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (DiaListClass, select_child),
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 1,
+                  DIA_TYPE_LIST_ITEM);
+  signals[UNSELECT_CHILD] =
+    g_signal_new ("unselect-child",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (DiaListClass, unselect_child),
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 1,
+                  DIA_TYPE_LIST_ITEM);
+}
+
+
+static void
+dia_list_init (DiaList *list)
+{
+  DiaListPrivate *priv = dia_list_get_instance_private (list);
+
+  priv->children = NULL;
+  priv->selected = NULL;
+
+  priv->last_focus_child = NULL;
+  priv->undo_focus_child = NULL;
+
+  priv->htimer = 0;
+  priv->vtimer = 0;
+}
+
+
+GtkWidget*
+dia_list_new (void)
+{
+  return g_object_new (DIA_TYPE_LIST, NULL);
+}
+
+
+static void
+scroll_vertical (DiaListItem   *list_item,
+                 GtkScrollType  scroll_type,
+                 double         position,
+                 DiaList       *list)
+{
+  GtkContainer *container;
+  DiaListPrivate *priv;
+  GList *work;
+  GtkWidget *item;
+  GtkAdjustment *adj;
+  GtkWidget *focus_child;
+  GtkAllocation alloc;
+  gint new_value;
+
+  g_return_if_fail (DIA_IS_LIST (list));
+
+  priv = dia_list_get_instance_private (list);
+
+  container = GTK_CONTAINER (list);
+  focus_child = gtk_container_get_focus_child (container);
+
+  if (focus_child) {
+    work = g_list_find (priv->children, focus_child);
+  } else {
+    work = priv->children;
+  }
+
+  if (!work) {
+    return;
+  }
+
+  switch (scroll_type) {
+    case GTK_SCROLL_STEP_BACKWARD:
+      work = work->prev;
+      if (work) {
+        gtk_widget_grab_focus (GTK_WIDGET (work->data));
+      }
+      break;
+    case GTK_SCROLL_STEP_FORWARD:
+      work = work->next;
+      if (work) {
+        gtk_widget_grab_focus (GTK_WIDGET (work->data));
+      }
+      break;
+    case GTK_SCROLL_PAGE_BACKWARD:
+      if (!work->prev) {
+        return;
+      }
+      item = work->data;
+      adj = gtk_container_get_focus_vadjustment (GTK_CONTAINER (list));
+
+      if (adj) {
+        gboolean correct = FALSE;
+        double value = gtk_adjustment_get_value (adj);
+        double page_size = gtk_adjustment_get_page_size (adj);
+        double lower = gtk_adjustment_get_lower (adj);
+
+        gtk_widget_get_allocation (item, &alloc);
+
+        new_value = value;
+
+        if (alloc.y <= value) {
+          new_value = MAX (alloc.y + alloc.height - page_size, lower);
+          correct = TRUE;
+        }
+
+        if (alloc.y > new_value) {
+          for (; work; work = work->prev) {
+            item = GTK_WIDGET (work->data);
+
+            gtk_widget_get_allocation (item, &alloc);
+
+            if (alloc.y <= new_value &&
+                alloc.y + alloc.height > new_value) {
+              break;
+            }
+          }
+        } else {
+          for (; work; work = work->next) {
+            item = GTK_WIDGET (work->data);
+
+            gtk_widget_get_allocation (item, &alloc);
+
+            if (alloc.y <= new_value &&
+                alloc.y + alloc.height > new_value) {
+              break;
+            }
+          }
+        }
+
+        gtk_widget_get_allocation (item, &alloc);
+
+        if (correct && work && work->next && alloc.y < new_value) {
+          item = work->next->data;
+        }
+      } else {
+        item = priv->children->data;
+      }
+
+      gtk_widget_grab_focus (item);
+      break;
+    case GTK_SCROLL_PAGE_FORWARD:
+      if (!work->next) {
+        return;
+      }
+
+      item = work->data;
+      adj = gtk_container_get_focus_vadjustment (GTK_CONTAINER (list));
+
+      if (adj) {
+        gboolean correct = FALSE;
+        double value = gtk_adjustment_get_value (adj);
+        double upper = gtk_adjustment_get_upper (adj);
+        double page_size = gtk_adjustment_get_page_size (adj);
+
+        new_value = value;
+
+        gtk_widget_get_allocation (item, &alloc);
+
+        if (alloc.y + alloc.height >=
+            value + page_size) {
+          new_value = alloc.y;
+          correct = TRUE;
+        }
+
+        new_value = MIN (new_value + page_size, upper);
+
+        if (alloc.y > new_value) {
+          for (; work; work = work->prev) {
+            item = GTK_WIDGET (work->data);
+
+            gtk_widget_get_allocation (item, &alloc);
+
+            if (alloc.y <= new_value &&
+                alloc.y + alloc.height > new_value) {
+              break;
+            }
+          }
+        } else {
+          for (; work; work = work->next) {
+            item = GTK_WIDGET (work->data);
+
+            gtk_widget_get_allocation (item, &alloc);
+
+            if (alloc.y <= new_value &&
+                alloc.y + alloc.height > new_value) {
+              break;
+            }
+          }
+        }
+
+        gtk_widget_get_allocation (item, &alloc);
+
+        if (correct && work && work->prev &&
+            alloc.y + alloc.height - 1 > new_value) {
+          item = work->prev->data;
+        }
+      } else {
+        item = g_list_last (work)->data;
+      }
+
+      gtk_widget_grab_focus (item);
+      break;
+    case GTK_SCROLL_JUMP:
+      gtk_widget_get_allocation (GTK_WIDGET (list), &alloc);
+
+      new_value = alloc.height * CLAMP (position, 0, 1);
+
+      for (item = NULL, work = priv->children; work; work = work->next) {
+        item = GTK_WIDGET (work->data);
+
+        gtk_widget_get_allocation (item, &alloc);
+
+        if (alloc.y <= new_value &&
+            alloc.y + alloc.height > new_value) {
+          break;
+        }
+      }
+
+      gtk_widget_grab_focus (item);
+      break;
+    case GTK_SCROLL_STEP_UP:
+    case GTK_SCROLL_STEP_DOWN:
+    case GTK_SCROLL_STEP_LEFT:
+    case GTK_SCROLL_STEP_RIGHT:
+    case GTK_SCROLL_PAGE_UP:
+    case GTK_SCROLL_PAGE_DOWN:
+    case GTK_SCROLL_PAGE_LEFT:
+    case GTK_SCROLL_PAGE_RIGHT:
+    case GTK_SCROLL_START:
+    case GTK_SCROLL_END:
+    case GTK_SCROLL_NONE:
+    default:
+      break;
+  }
+}
+
+
+void
+dia_list_insert_items (DiaList *list,
+                       GList   *items,
+                       int      position)
+{
+  GtkWidget *widget;
+  DiaListPrivate *priv;
+  GList *tmp_list;
+  GList *last;
+  int nchildren;
+
+  g_return_if_fail (DIA_IS_LIST (list));
+
+  if (!items) {
+    return;
+  }
+
+  tmp_list = items;
+  while (tmp_list) {
+    widget = tmp_list->data;
+    tmp_list = tmp_list->next;
+
+    gtk_widget_set_parent (widget, GTK_WIDGET (list));
+
+    g_signal_connect (widget,
+                      "scroll-vertical",
+                      G_CALLBACK (scroll_vertical),
+                      list);
+  }
+
+  priv = dia_list_get_instance_private (list);
+
+  nchildren = g_list_length (priv->children);
+  if ((position < 0) || (position > nchildren))
+    position = nchildren;
+
+  if (position == nchildren) {
+    if (priv->children) {
+      tmp_list = g_list_last (priv->children);
+      tmp_list->next = items;
+      items->prev = tmp_list;
+    } else {
+      priv->children = items;
+    }
+  } else {
+    tmp_list = g_list_nth (priv->children, position);
+    last = g_list_last (items);
+
+    if (tmp_list->prev) {
+      tmp_list->prev->next = items;
+    }
+    last->next = tmp_list;
+    items->prev = tmp_list->prev;
+    tmp_list->prev = last;
+
+    if (tmp_list == priv->children) {
+      priv->children = items;
+    }
+  }
+
+  if (priv->children && !priv->selected) {
+    widget = priv->children->data;
+    dia_list_select_child (list, DIA_LIST_ITEM (widget));
+  }
+}
+
+
+void
+dia_list_append_items (DiaList *list,
+                           GList   *items)
+{
+  g_return_if_fail (DIA_IS_LIST (list));
+
+  dia_list_insert_items (list, items, -1);
+}
+
+
+void
+dia_list_prepend_items (DiaList *list,
+                            GList      *items)
+{
+  g_return_if_fail (DIA_IS_LIST (list));
+
+  dia_list_insert_items (list, items, 0);
+}
+
+
+void
+dia_list_remove_items (DiaList *list,
+                       GList   *items)
+{
+  GtkWidget *widget;
+  DiaListPrivate *priv;
+  GtkWidget *new_focus_child;
+  GtkWidget *old_focus_child;
+  GtkWidget *focus_child;
+  GtkContainer *container;
+  GList *tmp_list;
+  GList *work;
+  gboolean grab_focus = FALSE;
+
+  g_return_if_fail (DIA_IS_LIST (list));
+
+  priv = dia_list_get_instance_private (list);
+
+  if (!items) {
+    return;
+  }
+
+  container = GTK_CONTAINER (list);
+  focus_child = gtk_container_get_focus_child (container);
+
+  tmp_list = items;
+  while (tmp_list) {
+    widget = tmp_list->data;
+    tmp_list = tmp_list->next;
+
+    if (gtk_widget_get_state (widget) == GTK_STATE_SELECTED) {
+      dia_list_unselect_child (list, DIA_LIST_ITEM (widget));
+    }
+  }
+
+  if (focus_child) {
+    old_focus_child = new_focus_child = focus_child;
+    if (gtk_widget_has_focus (focus_child)) {
+      grab_focus = TRUE;
+    }
+  } else {
+    old_focus_child = new_focus_child = priv->last_focus_child;
+  }
+
+  tmp_list = items;
+  while (tmp_list) {
+    widget = tmp_list->data;
+    tmp_list = tmp_list->next;
+
+    g_object_ref (widget);
+
+    if (widget == new_focus_child) {
+      work = g_list_find (priv->children, widget);
+
+      if (work) {
+        if (work->next) {
+          new_focus_child = work->next->data;
+        } else if (priv->children != work && work->prev) {
+          new_focus_child = work->prev->data;
+        } else {
+          new_focus_child = NULL;
+        }
+      }
+    }
+
+    g_signal_handlers_disconnect_by_data (widget, list);
+    priv->children = g_list_remove (priv->children, widget);
+    gtk_widget_unparent (widget);
+
+    if (widget == priv->undo_focus_child) {
+      priv->undo_focus_child = NULL;
+    }
+
+    if (widget == priv->last_focus_child) {
+      priv->last_focus_child = NULL;
+    }
+
+    g_clear_object (&widget);
+  }
+
+  focus_child = gtk_container_get_focus_child (container);
+
+  if (new_focus_child && new_focus_child != old_focus_child) {
+    if (grab_focus) {
+      gtk_widget_grab_focus (new_focus_child);
+    } else if (focus_child) {
+      gtk_container_set_focus_child (container, new_focus_child);
+    }
+
+    if (!priv->selected) {
+      priv->last_focus_child = new_focus_child;
+      dia_list_select_child (list, DIA_LIST_ITEM (new_focus_child));
+    }
+  }
+
+  if (gtk_widget_get_visible (GTK_WIDGET (list))) {
+    gtk_widget_queue_resize (GTK_WIDGET (list));
+  }
+}
+
+
+void
+dia_list_clear_items (DiaList *list,
+                          int         start,
+                          int         end)
+{
+  GtkContainer *container;
+  GtkWidget *widget;
+  DiaListPrivate *priv;
+  GtkWidget *new_focus_child = NULL;
+  GtkWidget *focus_child;
+  GList *start_list;
+  GList *end_list;
+  GList *tmp_list;
+  guint nchildren;
+  gboolean grab_focus = FALSE;
+
+  g_return_if_fail (DIA_IS_LIST (list));
+
+  priv = dia_list_get_instance_private (list);
+
+  nchildren = g_list_length (priv->children);
+
+  if (nchildren == 0) {
+    return;
+  }
+
+  if ((end < 0) || (end > nchildren)) {
+    end = nchildren;
+  }
+
+  if (start >= end) {
+    return;
+  }
+
+  container = GTK_CONTAINER (list);
+
+  start_list = g_list_nth (priv->children, start);
+  end_list = g_list_nth (priv->children, end);
+
+  if (start_list->prev) {
+    start_list->prev->next = end_list;
+  }
+  if (end_list && end_list->prev) {
+    end_list->prev->next = NULL;
+  }
+  if (end_list) {
+    end_list->prev = start_list->prev;
+  }
+  if (start_list == priv->children) {
+    priv->children = end_list;
+  }
+
+  focus_child = gtk_container_get_focus_child (container);
+
+  if (focus_child) {
+    if (g_list_find (start_list, focus_child)) {
+      if (start_list->prev) {
+        new_focus_child = start_list->prev->data;
+      } else if (priv->children) {
+        new_focus_child = priv->children->data;
+      }
+
+      if (gtk_widget_has_focus (focus_child)) {
+        grab_focus = TRUE;
+      }
+    }
+  }
+
+  tmp_list = start_list;
+  while (tmp_list) {
+    widget = tmp_list->data;
+    tmp_list = tmp_list->next;
+
+    g_object_ref (widget);
+
+    if (gtk_widget_get_state (widget) == GTK_STATE_SELECTED) {
+      dia_list_unselect_child (list, DIA_LIST_ITEM (widget));
+    }
+
+    g_signal_handlers_disconnect_by_data (widget, list);
+    gtk_widget_unparent (widget);
+
+    if (widget == priv->undo_focus_child) {
+      priv->undo_focus_child = NULL;
+    }
+    if (widget == priv->last_focus_child) {
+      priv->last_focus_child = NULL;
+    }
+
+    g_clear_object (&widget);
+  }
+
+  g_list_free (start_list);
+
+  if (new_focus_child) {
+    if (grab_focus) {
+      gtk_widget_grab_focus (new_focus_child);
+    } else if (focus_child) {
+      gtk_container_set_focus_child (container, new_focus_child);
+    }
+
+    if (!priv->selected) {
+      priv->last_focus_child = new_focus_child;
+      dia_list_select_child (list, DIA_LIST_ITEM (new_focus_child));
+    }
+  }
+
+  if (gtk_widget_get_visible (GTK_WIDGET (list))) {
+    gtk_widget_queue_resize (GTK_WIDGET (list));
+  }
+}
+
+
+void
+dia_list_select_item (DiaList *list,
+                      int      item)
+{
+  GList *tmp_list;
+  DiaListPrivate *priv;
+
+  g_return_if_fail (DIA_IS_LIST (list));
+
+  priv = dia_list_get_instance_private (list);
+
+  tmp_list = g_list_nth (priv->children, item);
+  if (tmp_list) {
+    dia_list_select_child (list, tmp_list->data);
+  }
+}
+
+
+void
+dia_list_select_child (DiaList     *self,
+                       DiaListItem *item)
+{
+  g_signal_emit (self, signals[SELECT_CHILD], 0, item);
+}
+
+
+void
+dia_list_unselect_child (DiaList     *self,
+                         DiaListItem *item)
+{
+  g_signal_emit (self, signals[UNSELECT_CHILD], 0, item);
+}
+
+
+int
+dia_list_child_position (DiaList     *self,
+                         DiaListItem *item)
+{
+  DiaListPrivate *priv;
+  GList *children;
+  int pos;
+
+  g_return_val_if_fail (DIA_IS_LIST (self), -1);
+  g_return_val_if_fail (DIA_IS_LIST_ITEM (item), -1);
+
+  priv = dia_list_get_instance_private (self);
+
+  pos = 0;
+  children = priv->children;
+
+  while (children) {
+    if (item == children->data) {
+      return pos;
+    }
+
+    pos += 1;
+    children = children->next;
+  }
+
+  return -1;
+}
+
+
+DiaListItem *
+dia_list_get_selected (DiaList *self)
+{
+  DiaListPrivate *priv;
+
+  g_return_val_if_fail (DIA_IS_LIST (self), NULL);
+
+  priv = dia_list_get_instance_private (self);
+
+  return priv->selected;
+}
diff --git a/app/dia-list.h b/app/dia-list.h
new file mode 100644
index 00000000..edd24c24
--- /dev/null
+++ b/app/dia-list.h
@@ -0,0 +1,75 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include "dia-list-item.h"
+
+G_BEGIN_DECLS
+
+#define DIA_TYPE_LIST dia_list_get_type ()
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GtkContainer, g_object_unref)
+
+G_DECLARE_DERIVABLE_TYPE (DiaList, dia_list, DIA, LIST, GtkContainer)
+
+
+struct _DiaListClass {
+  GtkContainerClass parent_class;
+
+  void (* select_child)   (DiaList     *list,
+                           DiaListItem *item);
+  void (* unselect_child) (DiaList     *list,
+                           DiaListItem *item);
+};
+
+
+GtkWidget   *dia_list_new            (void);
+void         dia_list_insert_items   (DiaList     *self,
+                                      GList       *items,
+                                      int          position);
+void         dia_list_append_items   (DiaList     *self,
+                                      GList       *items);
+void         dia_list_prepend_items  (DiaList     *self,
+                                      GList       *items);
+void         dia_list_remove_items   (DiaList     *self,
+                                      GList       *items);
+void         dia_list_clear_items    (DiaList     *self,
+                                      int          start,
+                                      int          end);
+void         dia_list_select_item    (DiaList     *self,
+                                      int          item);
+void         dia_list_select_child   (DiaList     *self,
+                                      DiaListItem *item);
+void         dia_list_unselect_child (DiaList     *self,
+                                      DiaListItem *item);
+gint         dia_list_child_position (DiaList     *self,
+                                      DiaListItem *item);
+DiaListItem *dia_list_get_selected   (DiaList     *self);
+
+G_END_DECLS
diff --git a/app/layer-editor/dia-layer-widget.c b/app/layer-editor/dia-layer-widget.c
index d66dde95..959fb9da 100644
--- a/app/layer-editor/dia-layer-widget.c
+++ b/app/layer-editor/dia-layer-widget.c
@@ -65,7 +65,7 @@ struct _DiaLayerWidgetPrivate
   gboolean shifted;
 };
 
-G_DEFINE_TYPE_WITH_PRIVATE (DiaLayerWidget, dia_layer_widget, GTK_TYPE_LIST_ITEM)
+G_DEFINE_TYPE_WITH_PRIVATE (DiaLayerWidget, dia_layer_widget, DIA_TYPE_LIST_ITEM)
 
 enum {
   EXCLUSIVE,
@@ -230,6 +230,7 @@ button_event (GtkWidget      *widget,
   return FALSE;
 }
 
+
 static void
 connectable_toggled (GtkToggleButton *widget,
                      gpointer         userdata)
@@ -294,48 +295,6 @@ visible_clicked (GtkToggleButton *widget,
   }
 }
 
-static void
-select_callback (GtkWidget *widget, gpointer data)
-{
-  DiaLayerWidget *self = DIA_LAYER_WIDGET (widget);
-  DiaLayerWidgetPrivate *priv = dia_layer_widget_get_instance_private (self);
-  DiagramData *diagram;
-
-  g_return_if_fail (priv->layer != NULL);
-
-  diagram = dia_layer_get_parent_diagram (priv->layer);
-
-  /* Don't deselect if we're selected the active layer.  This can happen
-   * if the window has been defocused. */
-  if (diagram->active_layer != priv->layer) {
-    diagram_remove_all_selected (DIA_DIAGRAM (diagram), TRUE);
-  }
-  diagram_update_extents (DIA_DIAGRAM (diagram));
-  data_set_active_layer (diagram, priv->layer);
-  diagram_add_update_all (DIA_DIAGRAM (diagram));
-  diagram_flush (DIA_DIAGRAM (diagram));
-
-  priv->internal_call = TRUE;
-  if (priv->connect_off) { /* If the user wants this off, it becomes so */
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->connectable), FALSE);
-  } else {
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->connectable), TRUE);
-  }
-  priv->internal_call = FALSE;
-}
-
-static void
-deselect_callback (GtkWidget *widget, gpointer data)
-{
-  DiaLayerWidget *self = DIA_LAYER_WIDGET (widget);
-  DiaLayerWidgetPrivate *priv = dia_layer_widget_get_instance_private (self);
-
-  priv->internal_call = TRUE;
-  /** Set to on if the user has requested so. */
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->connectable),
-                                priv->connect_on);
-  priv->internal_call = FALSE;
-}
 
 static void
 dia_layer_widget_init (DiaLayerWidget *self)
@@ -373,8 +332,6 @@ dia_layer_widget_init (DiaLayerWidget *self)
   gtk_box_pack_start (GTK_BOX (hbox), priv->visible, FALSE, TRUE, 2);
   gtk_widget_show (priv->visible);
 
-  /*gtk_image_new_from_stock(GTK_STOCK_CONNECT,
-                           GTK_ICON_SIZE_BUTTON), */
   priv->connectable =
     dia_toggle_button_new_with_icon_names ("dia-connectable",
                                            "dia-connectable-empty");
@@ -403,15 +360,6 @@ dia_layer_widget_init (DiaLayerWidget *self)
   gtk_widget_show (hbox);
 
   gtk_container_add (GTK_CONTAINER (self), hbox);
-
-  g_signal_connect (G_OBJECT (self),
-                    "select",
-                    G_CALLBACK (select_callback),
-                    NULL);
-  g_signal_connect (G_OBJECT (self),
-                    "deselect",
-                    G_CALLBACK (deselect_callback),
-                    NULL);
 }
 
 
@@ -550,3 +498,54 @@ dia_layer_widget_new (DiaLayer *layer, DiaLayerEditor *editor)
                        "editor", editor,
                        NULL);
 }
+
+
+void
+dia_layer_widget_select (DiaLayerWidget *self)
+{
+  DiaLayerWidgetPrivate *priv;
+  DiagramData *diagram;
+
+  g_return_if_fail (DIA_IS_LAYER_WIDGET (self));
+
+  priv = dia_layer_widget_get_instance_private (self);
+
+  g_return_if_fail (priv->layer != NULL);
+
+  diagram = dia_layer_get_parent_diagram (priv->layer);
+
+  /* Don't deselect if we're selected the active layer.  This can happen
+   * if the window has been defocused. */
+  if (dia_diagram_data_get_active_layer (diagram) != priv->layer) {
+    diagram_remove_all_selected (DIA_DIAGRAM (diagram), TRUE);
+  }
+  diagram_update_extents (DIA_DIAGRAM (diagram));
+  data_set_active_layer (diagram, priv->layer);
+  diagram_add_update_all (DIA_DIAGRAM (diagram));
+  diagram_flush (DIA_DIAGRAM (diagram));
+
+  priv->internal_call = TRUE;
+  if (priv->connect_off) { /* If the user wants this off, it becomes so */
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->connectable), FALSE);
+  } else {
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->connectable), TRUE);
+  }
+  priv->internal_call = FALSE;
+}
+
+
+void
+dia_layer_widget_deselect (DiaLayerWidget *self)
+{
+  DiaLayerWidgetPrivate *priv;
+
+  g_return_if_fail (DIA_IS_LAYER_WIDGET (self));
+
+  priv = dia_layer_widget_get_instance_private (self);
+
+  priv->internal_call = TRUE;
+  /** Set to on if the user has requested so. */
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->connectable),
+                                priv->connect_on);
+  priv->internal_call = FALSE;
+}
diff --git a/app/layer-editor/dia-layer-widget.h b/app/layer-editor/dia-layer-widget.h
index f6f4dff4..9e0d8989 100644
--- a/app/layer-editor/dia-layer-widget.h
+++ b/app/layer-editor/dia-layer-widget.h
@@ -22,17 +22,16 @@
 
 #include "dia-layer.h"
 #include "dia-layer-editor.h"
+#include "dia-list-item.h"
 
 G_BEGIN_DECLS
 
 #define DIA_TYPE_LAYER_WIDGET dia_layer_widget_get_type ()
 
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (GtkListItem, g_object_unref)
-
-G_DECLARE_DERIVABLE_TYPE (DiaLayerWidget, dia_layer_widget, DIA, LAYER_WIDGET, GtkListItem)
+G_DECLARE_DERIVABLE_TYPE (DiaLayerWidget, dia_layer_widget, DIA, LAYER_WIDGET, DiaListItem)
 
 struct _DiaLayerWidgetClass {
-  GtkListItemClass parent;
+  DiaListItemClass parent;
 };
 
 GtkWidget      *dia_layer_widget_new             (DiaLayer       *layer,
@@ -46,5 +45,7 @@ DiaLayerEditor *dia_layer_widget_get_editor      (DiaLayerWidget *self);
 void            dia_layer_widget_set_connectable (DiaLayerWidget *self,
                                                   gboolean        on);
 gboolean        dia_layer_widget_get_connectable (DiaLayerWidget *self);
+void            dia_layer_widget_select          (DiaLayerWidget *self);
+void            dia_layer_widget_deselect        (DiaLayerWidget *self);
 
 G_END_DECLS
diff --git a/app/meson.build b/app/meson.build
index c113bfaa..2a2a92a6 100644
--- a/app/meson.build
+++ b/app/meson.build
@@ -55,6 +55,12 @@ dia_sources = [
     'dia-props.c',
     'gtkwrapbox.c',
     'gtkhwrapbox.c',
+
+    'dia-list.c',
+    'dia-list.h',
+    'dia-list-item.c',
+    'dia-list-item.h',
+
     'cursor.c',
     'splash.c',
     'recent_files.c',
diff --git a/meson.build b/meson.build
index 20860529..a2019f30 100644
--- a/meson.build
+++ b/meson.build
@@ -79,6 +79,7 @@ add_project_arguments([
   '-DGLIB_VERSION_MIN_REQUIRED=@0@'.format(glib_ver),
   '-DGLIB_VERSION_MAX_ALLOWED=@0@'.format(glib_ver),
   '-DGSEAL_ENABLE',
+  '-DGTK_DISABLE_DEPRECATED',
 ], language: 'c')
 
 


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