]> Pileus Git - ~andy/gtk/commitdiff
Tree widget implementation by Bolliet Jerome.
authorShawn Amundson <amundson@src.gnome.org>
Wed, 17 Dec 1997 23:41:42 +0000 (23:41 +0000)
committerShawn Amundson <amundson@src.gnome.org>
Wed, 17 Dec 1997 23:41:42 +0000 (23:41 +0000)
There is also another tree widget implementation by
AOSASA Shigeru <aozasa@sakuranet.or.jp>:

ftp://ftp.gimp.org/pub/gtk/contrib/gtk-shige-971216-0.tar.gz

-Shawn

12 files changed:
gtk/.cvsignore
gtk/Makefile.am
gtk/Makefile.in
gtk/gtktree.c
gtk/gtktree.h
gtk/gtktreeitem.c
gtk/gtktreeitem.h
gtk/testtree.c [new file with mode: 0644]
gtk/tree_minus.xbm [new file with mode: 0644]
gtk/tree_minus.xpm [new file with mode: 0644]
gtk/tree_plus.xbm [new file with mode: 0644]
gtk/tree_plus.xpm [new file with mode: 0644]

index 1c5ab9a779c6a7ae6d7a5ecb5bdc36f728c75f01..236d5e089926a30819ace56e3e097fc7b324a1b2 100644 (file)
@@ -8,3 +8,4 @@ testgtk
 testinput
 testselection
 simple
+testtree
index 41b6625620f68d6b89ae97dade561aaf7046fc57..b69b69c65de888e421c9a959f091e20c79cb1472 100644 (file)
@@ -193,11 +193,15 @@ EXTRA_DIST = \
        marble.xpm              \
        3DRings.xpm             \
        FilesQueue.xpm          \
-       Modeller.xpm
+       Modeller.xpm            \
+       tree_plus.xpm           \
+       tree_minus.xpm          \
+       tree_plus.xbm           \
+       tree_minus.xbm
 
 INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/glib @x_cflags@ 
 
-noinst_PROGRAMS = testgtk testinput testselection simple
+noinst_PROGRAMS = testgtk testinput testselection simple testtree
 testgtk_LDADD = \
        libgtk.la                               \
        $(top_builddir)/gdk/libgdk.la           \
@@ -230,6 +234,14 @@ simple_LDADD = \
        $(top_builddir)/glib/libglib.la         \
        -lm
 
+testtree_LDADD = \
+       libgtk.la                               \
+       $(top_builddir)/gdk/libgdk.la           \
+       @x_ldflags@                             \
+       @x_libs@                                \
+       $(top_builddir)/glib/libglib.la         \
+       -lm
+
 DEPS = \
        $(top_builddir)/gtk/libgtk.la           \
        $(top_builddir)/gdk/libgdk.la           \
@@ -239,6 +251,7 @@ testgtk_DEPENDENCIES = $(DEPS)
 testinput_DEPENDENCIES = $(DEPS)
 testselection_DEPENDENCIES = $(DEPS)
 simple_DEPENDENCIES = $(DEPS)
+testtree_DEPENDENCIES = $(DEPS)
 
 .PHONY: files
 
index 0b637de158e63dc442be5c11ca21e0bad9d784a1..274871b58cde7ac36456ad6a55fea515f8c1eb09 100644 (file)
@@ -259,11 +259,15 @@ EXTRA_DIST = \
        marble.xpm              \
        3DRings.xpm             \
        FilesQueue.xpm          \
-       Modeller.xpm
+       Modeller.xpm            \
+       tree_plus.xpm           \
+       tree_minus.xpm          \
+       tree_plus.xbm           \
+       tree_minus.xbm
 
 INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/glib @x_cflags@ 
 
-noinst_PROGRAMS = testgtk testinput testselection simple
+noinst_PROGRAMS = testgtk testinput testselection simple testtree
 testgtk_LDADD = \
        libgtk.la                               \
        $(top_builddir)/gdk/libgdk.la           \
@@ -296,6 +300,14 @@ simple_LDADD = \
        $(top_builddir)/glib/libglib.la         \
        -lm
 
+testtree_LDADD = \
+       libgtk.la                               \
+       $(top_builddir)/gdk/libgdk.la           \
+       @x_ldflags@                             \
+       @x_libs@                                \
+       $(top_builddir)/glib/libglib.la         \
+       -lm
+
 DEPS = \
        $(top_builddir)/gtk/libgtk.la           \
        $(top_builddir)/gdk/libgdk.la           \
@@ -305,6 +317,7 @@ testgtk_DEPENDENCIES = $(DEPS)
 testinput_DEPENDENCIES = $(DEPS)
 testselection_DEPENDENCIES = $(DEPS)
 simple_DEPENDENCIES = $(DEPS)
+testtree_DEPENDENCIES = $(DEPS)
 mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
 CONFIG_HEADER = ../config.h
 CONFIG_CLEAN_FILES = 
@@ -352,6 +365,9 @@ testselection_LDFLAGS =
 simple_SOURCES = simple.c
 simple_OBJECTS =  simple.o
 simple_LDFLAGS = 
+testtree_SOURCES = testtree.c
+testtree_OBJECTS =  testtree.o
+testtree_LDFLAGS = 
 CFLAGS = @CFLAGS@
 COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
 LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
@@ -363,7 +379,7 @@ DIST_COMMON =  Makefile.am Makefile.in
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = gtar
+TAR = tar
 GZIP = --best
 DEP_FILES =  .deps/fnmatch.P .deps/gtkaccelerator.P \
 .deps/gtkadjustment.P .deps/gtkalignment.P .deps/gtkarrow.P \
@@ -391,9 +407,9 @@ DEP_FILES =  .deps/fnmatch.P .deps/gtkaccelerator.P \
 .deps/gtkviewport.P .deps/gtkvpaned.P .deps/gtkvruler.P \
 .deps/gtkvscale.P .deps/gtkvscrollbar.P .deps/gtkvseparator.P \
 .deps/gtkwidget.P .deps/gtkwindow.P .deps/simple.P .deps/testgtk.P \
-.deps/testinput.P .deps/testselection.P
-SOURCES = $(libgtk_la_SOURCES) testgtk.c testinput.c testselection.c simple.c
-OBJECTS = $(libgtk_la_OBJECTS) testgtk.o testinput.o testselection.o simple.o
+.deps/testinput.P .deps/testselection.P .deps/testtree.P
+SOURCES = $(libgtk_la_SOURCES) testgtk.c testinput.c testselection.c simple.c testtree.c
+OBJECTS = $(libgtk_la_OBJECTS) testgtk.o testinput.o testselection.o simple.o testtree.o
 
 default: all
 
@@ -498,6 +514,10 @@ simple: $(simple_OBJECTS) $(simple_DEPENDENCIES)
        @rm -f simple
        $(LINK) $(simple_LDFLAGS) $(simple_OBJECTS) $(simple_LDADD) $(LIBS)
 
+testtree: $(testtree_OBJECTS) $(testtree_DEPENDENCIES)
+       @rm -f testtree
+       $(LINK) $(testtree_LDFLAGS) $(testtree_OBJECTS) $(testtree_LDADD) $(LIBS)
+
 install-gtkincludeHEADERS: $(gtkinclude_HEADERS)
        @$(NORMAL_INSTALL)
        $(mkinstalldirs) $(gtkincludedir)
index f3981ea0a00ee6ae8ce42526c74813088785dde2..a6589acf427154a1975fbd82d4dcf8fe9ac033cd 100644 (file)
  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 #include "gtktree.h"
+#include "gtktreeitem.h"
+#include "gtkmain.h"
+#include "gtksignal.h"
+#include "gtklist.h"
+
+enum {
+  SELECTION_CHANGED,
+  SELECT_CHILD,
+  UNSELECT_CHILD,
+  LAST_SIGNAL
+};
+
+typedef void (*GtkTreeSignal) (GtkObject *object,
+                              gpointer   arg1,
+                              gpointer   data);
 
 
 static void gtk_tree_class_init (GtkTreeClass *klass);
 static void gtk_tree_init       (GtkTree      *tree);
+static void gtk_tree_destroy         (GtkObject      *object);
+static void gtk_tree_map             (GtkWidget      *widget);
+static void gtk_tree_unmap           (GtkWidget      *widget);
+static void gtk_tree_realize         (GtkWidget      *widget);
+static void gtk_tree_draw            (GtkWidget      *widget,
+                                     GdkRectangle   *area);
+static gint gtk_tree_expose          (GtkWidget      *widget,
+                                     GdkEventExpose *event);
+static gint gtk_tree_motion_notify   (GtkWidget      *widget,
+                                     GdkEventMotion *event);
+static gint gtk_tree_button_press    (GtkWidget      *widget,
+                                     GdkEventButton *event);
+static gint gtk_tree_button_release  (GtkWidget      *widget,
+                                     GdkEventButton *event);
+static void gtk_tree_size_request    (GtkWidget      *widget,
+                                     GtkRequisition *requisition);
+static void gtk_tree_size_allocate   (GtkWidget      *widget,
+                                     GtkAllocation  *allocation);
+static void gtk_tree_add             (GtkContainer   *container,
+                                     GtkWidget      *widget);
+static void gtk_tree_remove          (GtkContainer   *container,
+                                     GtkWidget      *widget);
+static void gtk_tree_foreach         (GtkContainer   *container,
+                                     GtkCallback     callback,
+                                     gpointer        callback_data);
+
+static void gtk_real_tree_select_child   (GtkTree       *tree,
+                                         GtkWidget     *child);
+static void gtk_real_tree_unselect_child (GtkTree       *tree,
+                                         GtkWidget     *child);
 
+static void gtk_tree_marshal_signal (GtkObject      *object,
+                                    GtkSignalFunc   func,
+                                    gpointer        func_data,
+                                    GtkArg         *args);
+
+static GtkContainerClass *parent_class = NULL;
+static gint tree_signals[LAST_SIGNAL] = { 0 };
 
 guint
 gtk_tree_get_type ()
@@ -48,11 +100,75 @@ gtk_tree_get_type ()
 static void
 gtk_tree_class_init (GtkTreeClass *class)
 {
+  GtkObjectClass *object_class;
+  GtkWidgetClass *widget_class;
+  GtkContainerClass *container_class;
+
+  object_class = (GtkObjectClass*) class;
+  widget_class = (GtkWidgetClass*) class;
+  container_class = (GtkContainerClass*) class;
+
+  parent_class = gtk_type_class (gtk_container_get_type ());
+
+  tree_signals[SELECTION_CHANGED] =
+    gtk_signal_new ("selection_changed",
+                   GTK_RUN_FIRST,
+                   object_class->type,
+                   GTK_SIGNAL_OFFSET (GtkTreeClass, selection_changed),
+                   gtk_signal_default_marshaller,
+                   GTK_TYPE_NONE, 0);
+  tree_signals[SELECT_CHILD] =
+    gtk_signal_new ("select_child",
+                   GTK_RUN_FIRST,
+                   object_class->type,
+                   GTK_SIGNAL_OFFSET (GtkTreeClass, select_child),
+                   gtk_tree_marshal_signal,
+                   GTK_TYPE_NONE, 1,
+                   GTK_TYPE_WIDGET);
+  tree_signals[UNSELECT_CHILD] =
+    gtk_signal_new ("unselect_child",
+                   GTK_RUN_FIRST,
+                   object_class->type,
+                   GTK_SIGNAL_OFFSET (GtkTreeClass, unselect_child),
+                   gtk_tree_marshal_signal,
+                   GTK_TYPE_NONE, 1,
+                   GTK_TYPE_WIDGET);
+
+  gtk_object_class_add_signals (object_class, tree_signals, LAST_SIGNAL);
+
+  object_class->destroy = gtk_tree_destroy;
+
+  widget_class->map = gtk_tree_map;
+  widget_class->unmap = gtk_tree_unmap;
+  widget_class->realize = gtk_tree_realize;
+  widget_class->draw = gtk_tree_draw;
+  widget_class->expose_event = gtk_tree_expose;
+  widget_class->motion_notify_event = gtk_tree_motion_notify;
+  widget_class->button_press_event = gtk_tree_button_press;
+  widget_class->button_release_event = gtk_tree_button_release;
+  widget_class->size_request = gtk_tree_size_request;
+  widget_class->size_allocate = gtk_tree_size_allocate;
+
+  container_class->add = gtk_tree_add;
+  container_class->remove = gtk_tree_remove;
+  container_class->foreach = gtk_tree_foreach;
+
+  class->selection_changed = NULL;
+  class->select_child = gtk_real_tree_select_child;
+  class->unselect_child = gtk_real_tree_unselect_child;
 }
 
 static void
 gtk_tree_init (GtkTree *tree)
 {
+  tree->children = NULL;
+  tree->root_tree = NULL;
+  tree->selection = NULL;
+  tree->tree_owner = NULL;
+  tree->selection_mode = GTK_SELECTION_SINGLE;
+  tree->indent_value = 10;
+  tree->current_indent = 0;
+  tree->view_mode = GTK_TREE_VIEW_LINE;
 }
 
 GtkWidget*
@@ -65,12 +181,22 @@ void
 gtk_tree_append (GtkTree   *tree,
                 GtkWidget *child)
 {
+
+  g_return_if_fail (tree != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (child));
+
+  gtk_tree_insert(tree, child, -1);
 }
 
 void
 gtk_tree_prepend (GtkTree   *tree,
                  GtkWidget *child)
 {
+  g_return_if_fail (tree != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (child));
+
+  gtk_tree_insert(tree, child, 0);
+
 }
 
 void
@@ -78,4 +204,834 @@ gtk_tree_insert (GtkTree   *tree,
                 GtkWidget *child,
                 gint       position)
 {
+  gint nchildren;
+    
+  g_return_if_fail (tree != NULL || child != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM(child));
+
+  /* set parent widget to item */
+  gtk_widget_set_parent (child, GTK_WIDGET (tree));
+    
+  if (GTK_WIDGET_VISIBLE (child->parent))
+    {
+      if (GTK_WIDGET_REALIZED (child->parent) &&
+         !GTK_WIDGET_REALIZED (child))
+       gtk_widget_realize (child);
+
+      if (GTK_WIDGET_MAPPED (child->parent) &&
+         !GTK_WIDGET_MAPPED (child))
+       gtk_widget_map (child);
+    }
+
+  nchildren = g_list_length (tree->children);
+    
+  if ((position < 0) || (position > nchildren))
+    position = nchildren;
+
+  if (position == nchildren)
+    {
+      tree->children = g_list_append(tree->children, child);
+    }
+  else
+    {
+      g_list_insert(tree->children, child, position);
+    }
+    
+  if (GTK_WIDGET_VISIBLE (tree))
+    gtk_widget_queue_resize (GTK_WIDGET (tree));
+
+}
+
+static void
+gtk_tree_add (GtkContainer *container,
+             GtkWidget    *widget)
+{
+  GtkTree *tree;
+
+  g_return_if_fail (container != NULL);
+  g_return_if_fail (GTK_IS_TREE (container));
+  g_return_if_fail (widget != NULL);
+
+  tree = GTK_TREE (container);
+
+  gtk_widget_set_parent (widget, GTK_WIDGET (container));
+  if (GTK_WIDGET_VISIBLE (widget->parent))
+    {
+      if (GTK_WIDGET_REALIZED (widget->parent) &&
+         !GTK_WIDGET_REALIZED (widget))
+       gtk_widget_realize (widget);
+
+      if (GTK_WIDGET_MAPPED (widget->parent) &&
+         !GTK_WIDGET_MAPPED (widget))
+       gtk_widget_map (widget);
+    }
+
+  tree->children = g_list_append (tree->children, widget);
+
+#ifdef 0
+  if (!tree->selection && (tree->selection_mode == GTK_SELECTION_BROWSE))
+    {
+      gtk_tree_select_child (tree, widget);
+    }
+#endif
+
+  if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container))
+    gtk_widget_queue_resize (widget);
+
+}
+
+static gint
+gtk_tree_button_press (GtkWidget      *widget,
+                      GdkEventButton *event)
+{
+  GtkTree *tree;
+  GtkWidget *item;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TREE (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  tree = GTK_TREE (widget);
+  item = gtk_get_event_widget ((GdkEvent*) event);
+
+  while (!gtk_type_is_a (GTK_WIDGET_TYPE (item), gtk_tree_item_get_type ()))
+    item = item->parent;
+
+  switch(event->button) 
+    {
+    case 1:
+      gtk_tree_select_child (tree, item);
+      break;
+    case 2:
+      if(GTK_TREE_ITEM(item)->subtree) gtk_tree_item_expand(GTK_TREE_ITEM(item));
+      break;
+    case 3:
+      if(GTK_TREE_ITEM(item)->subtree) gtk_tree_item_collapse(GTK_TREE_ITEM(item));
+      break;
+    }
+
+  return TRUE;
+}
+
+static gint
+gtk_tree_button_release (GtkWidget      *widget,
+                        GdkEventButton *event)
+{
+  GtkTree *tree;
+  GtkWidget *item;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TREE (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  tree = GTK_TREE (widget);
+  item = gtk_get_event_widget ((GdkEvent*) event);
+
+  return TRUE;
+}
+
+gint
+gtk_tree_child_position (GtkTree   *tree,
+                        GtkWidget *child)
+{
+  GList *children;
+  gint pos;
+
+
+  g_return_val_if_fail (tree != NULL, -1);
+  g_return_val_if_fail (GTK_IS_TREE (tree), -1);
+  g_return_val_if_fail (child != NULL, -1);
+
+  pos = 0;
+  children = tree->children;
+
+  while (children)
+    {
+      if (child == GTK_WIDGET (children->data)) 
+       return pos;
+
+      pos += 1;
+      children = children->next;
+    }
+
+
+  return -1;
+}
+
+void
+gtk_tree_clear_items (GtkTree *tree,
+                     gint     start,
+                     gint     end)
+{
+  g_return_if_fail (tree != NULL);
+  g_return_if_fail (GTK_IS_TREE (tree));
+
+}
+
+static void
+gtk_tree_destroy (GtkObject *object)
+{
+  GtkTree *tree;
+  GtkWidget *child;
+  GList *children;
+
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GTK_IS_TREE (object));
+
+  tree = GTK_TREE (object);
+
+  children = tree->children;
+  while (children)
+    {
+      child = children->data;
+      children = children->next;
+
+      child->parent = NULL;
+      gtk_object_unref (GTK_OBJECT (child));
+      gtk_widget_destroy (child);
+    }
+
+  g_list_free (tree->children);
+
+  if(tree->root_tree == NULL)
+    g_list_free (tree->selection);
+
+  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+static void
+gtk_tree_draw (GtkWidget    *widget,
+              GdkRectangle *area)
+{
+  GtkTree *tree;
+  GtkWidget *subtree;
+  GtkWidget *child;
+  GdkRectangle child_area;
+  GList *children;
+
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TREE (widget));
+  g_return_if_fail (area != NULL);
+
+  if (GTK_WIDGET_DRAWABLE (widget))
+    {
+      tree = GTK_TREE (widget);
+
+      children = tree->children;
+      while (children)
+       {
+         child = children->data;
+         children = children->next;
+
+         if (gtk_widget_intersect (child, area, &child_area))
+           gtk_widget_draw (child, &child_area);
+
+         if((subtree = GTK_TREE_ITEM(child)->subtree) &&
+            GTK_WIDGET_VISIBLE(subtree) &&
+            gtk_widget_intersect (subtree, area, &child_area))
+           gtk_widget_draw (subtree, &child_area);
+       }
+    }
+
+}
+
+static gint
+gtk_tree_expose (GtkWidget      *widget,
+                GdkEventExpose *event)
+{
+  GtkTree *tree;
+  GtkWidget *child;
+  GdkEventExpose child_event;
+  GList *children;
+
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TREE (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  if (GTK_WIDGET_DRAWABLE (widget))
+    {
+      tree = GTK_TREE (widget);
+
+      child_event = *event;
+
+      children = tree->children;
+      while (children)
+       {
+         child = children->data;
+         children = children->next;
+
+         if (GTK_WIDGET_NO_WINDOW (child) &&
+             gtk_widget_intersect (child, &event->area, &child_event.area))
+           gtk_widget_event (child, (GdkEvent*) &child_event);
+       }
+    }
+
+
+  return FALSE;
+}
+
+static void
+gtk_tree_foreach (GtkContainer *container,
+                 GtkCallback   callback,
+                 gpointer      callback_data)
+{
+  GtkTree *tree;
+  GtkWidget *child;
+  GList *children;
+
+
+  g_return_if_fail (container != NULL);
+  g_return_if_fail (GTK_IS_TREE (container));
+  g_return_if_fail (callback != NULL);
+
+  tree = GTK_TREE (container);
+  children = tree->children;
+
+  while (children)
+    {
+      child = children->data;
+      children = children->next;
+
+      (* callback) (child, callback_data);
+
+      if(GTK_TREE_ITEM(child)->subtree)
+       (* callback)(GTK_TREE_ITEM(child)->subtree, callback_data);
+    }
+}
+
+static void
+gtk_tree_map (GtkWidget *widget)
+{
+  GtkTree *tree;
+  GtkWidget *child;
+  GList *children;
+
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TREE (widget));
+
+  GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
+  tree = GTK_TREE (widget);
+
+  gdk_window_show (widget->window);
+
+  if(GTK_IS_TREE(widget->parent)) 
+    {
+      /* set root tree for this tree */
+      tree->root_tree = GTK_TREE(widget->parent)->root_tree;
+
+      tree->indent_value = GTK_TREE(GTK_WIDGET(tree)->parent)->indent_value;
+      tree->current_indent = GTK_TREE(GTK_WIDGET(tree)->parent)->current_indent + 
+       tree->indent_value;
+      tree->view_mode = GTK_TREE(GTK_WIDGET(tree)->parent)->view_mode;
+    } else
+      tree->root_tree = tree;
+
+  children = tree->children;
+  while (children)
+    {
+      child = children->data;
+      children = children->next;
+
+      if (GTK_WIDGET_VISIBLE (child) &&
+         !GTK_WIDGET_MAPPED (child))
+       gtk_widget_map (child);
+
+      if ((child = GTK_WIDGET(GTK_TREE_ITEM(child)->subtree)) &&
+         GTK_WIDGET_VISIBLE (child) &&
+         !GTK_WIDGET_MAPPED (child))
+       gtk_widget_map (child);
+    }
+}
+
+static void
+gtk_tree_marshal_signal (GtkObject      *object,
+                        GtkSignalFunc   func,
+                        gpointer        func_data,
+                        GtkArg         *args)
+{
+  GtkTreeSignal rfunc;
+
+  rfunc = (GtkTreeSignal) func;
+
+  (* rfunc) (object, GTK_VALUE_OBJECT (args[0]), func_data);
+}
+
+static gint
+gtk_tree_motion_notify (GtkWidget      *widget,
+                       GdkEventMotion *event)
+{
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TREE (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  g_print("gtk_tree_motion_notify\n");
+
+  return FALSE;
+}
+
+static void
+gtk_tree_realize (GtkWidget *widget)
+{
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TREE (widget));
+
+  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.x = widget->allocation.x;
+  attributes.y = widget->allocation.y;
+  attributes.width = widget->allocation.width;
+  attributes.height = widget->allocation.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+  attributes.event_mask = GDK_EXPOSURE_MASK;
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+  widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
+  gdk_window_set_user_data (widget->window, widget);
+
+  widget->style = gtk_style_attach (widget->style, widget->window);
+  gdk_window_set_background (widget->window, &widget->style->white);
+
+}
+
+static void
+gtk_tree_remove (GtkContainer *container,
+                GtkWidget    *widget)
+{
+  GList *item_list;
+
+  g_return_if_fail (container != NULL);
+  g_return_if_fail (GTK_IS_TREE (container));
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (container == GTK_CONTAINER (widget->parent));
+
+  item_list = g_list_alloc ();
+  item_list->data = widget;
+  
+  gtk_tree_remove_items (GTK_TREE (container), item_list);
+  
+  g_list_free (item_list);
+}
+
+void
+gtk_tree_remove_items (GtkTree *tree,
+                      GList   *items)
+{
+  GtkWidget *widget;
+  GList *selected_widgets;
+  GList *tmp_list;
+  GtkTree *real_tree, *root_tree;
+
+  g_return_if_fail (tree != NULL);
+  g_return_if_fail (GTK_IS_TREE (tree));
+
+  root_tree = GTK_TREE(GTK_TREE_ROOT_TREE(tree));
+  tmp_list = items;
+  selected_widgets = NULL;
+  widget = NULL;
+
+  while (tmp_list)
+    {
+      widget = tmp_list->data;
+      tmp_list = tmp_list->next;
+
+      /* get real owner of this widget */
+      real_tree = GTK_TREE(widget->parent);
+      
+      if (widget->state == GTK_STATE_SELECTED)
+       selected_widgets = g_list_prepend (selected_widgets, widget);
+
+      /* remove this item of his real parent */
+      real_tree->children = g_list_remove (real_tree->children, widget);
+
+      /* delete subtree if there is no children in it */
+      if(real_tree->children == NULL && 
+        real_tree != root_tree)
+       {
+         gtk_tree_item_remove_subtree(GTK_TREE_ITEM(real_tree->tree_owner));
+       }
+
+      /* remove subtree associate at this item if it exist */      
+      if(GTK_TREE_ITEM(widget)->subtree) 
+       {
+         if (GTK_WIDGET_MAPPED (GTK_TREE_ITEM(widget)->subtree))
+           gtk_widget_unmap (GTK_TREE_ITEM(widget)->subtree);
+
+         gtk_widget_unparent (GTK_TREE_ITEM(widget)->subtree);
+       }
+
+      /* remove really widget for this item */
+      if (GTK_WIDGET_MAPPED (widget))
+       gtk_widget_unmap (widget);
+
+      gtk_widget_unparent (widget);
+    }
+
+  if (selected_widgets)
+    {
+      tmp_list = selected_widgets;
+      while (tmp_list)
+       {
+         widget = tmp_list->data;
+         tmp_list = tmp_list->next;
+
+         gtk_tree_unselect_child (tree, widget);
+       }
+    }
+
+  g_list_free (selected_widgets);
+
+  if (root_tree->children && !root_tree->selection &&
+      (root_tree->selection_mode == GTK_SELECTION_BROWSE))
+    {
+      widget = root_tree->children->data;
+      gtk_tree_select_child (root_tree, widget);
+    }
+
+  if (GTK_WIDGET_VISIBLE (root_tree))
+    gtk_widget_queue_resize (GTK_WIDGET (root_tree));
+}
+void
+gtk_tree_select_child (GtkTree   *tree,
+                      GtkWidget *child)
+{
+
+  gtk_signal_emit (GTK_OBJECT (tree), tree_signals[SELECT_CHILD], child);
+
+}
+
+void
+gtk_tree_select_item (GtkTree   *tree,
+                     gint     item)
+{
+  GList *tmp_list;
+
+
+  g_return_if_fail (tree != NULL);
+  g_return_if_fail (GTK_IS_TREE (tree));
+
+  tmp_list = g_list_nth (tree->children, item);
+  if (tmp_list)
+    gtk_tree_select_child (tree, GTK_WIDGET (tmp_list->data));
+
+}
+
+static void
+gtk_tree_size_allocate (GtkWidget     *widget,
+                       GtkAllocation *allocation)
+{
+  GtkTree *tree;
+  GtkWidget *child, *subtree;
+  GtkAllocation child_allocation;
+  GList *children;
+
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TREE (widget));
+  g_return_if_fail (allocation != NULL);
+
+  tree = GTK_TREE (widget);
+
+  widget->allocation = *allocation;
+  if (GTK_WIDGET_REALIZED (widget))
+    gdk_window_move_resize (widget->window,
+                           allocation->x, allocation->y,
+                           allocation->width, allocation->height);
+  
+  if (tree->children)
+    {
+      child_allocation.x = GTK_CONTAINER (tree)->border_width;
+      child_allocation.y = GTK_CONTAINER (tree)->border_width;
+      child_allocation.width = allocation->width - child_allocation.x * 2;
+
+      children = tree->children;
+
+      while (children)
+       {
+         child = children->data;
+         children = children->next;
+
+         if (GTK_WIDGET_VISIBLE (child))
+           {
+             child_allocation.height = child->requisition.height;
+
+             gtk_widget_size_allocate (child, &child_allocation);
+
+             child_allocation.y += child_allocation.height;
+
+             if((subtree = GTK_TREE_ITEM(child)->subtree))
+               if(GTK_WIDGET_VISIBLE (subtree))
+                 {
+                   child_allocation.height = subtree->requisition.height;
+                   gtk_widget_size_allocate (subtree, &child_allocation);
+                   child_allocation.y += child_allocation.height;
+                 }
+           }
+       }
+    }
+
+}
+
+static void
+gtk_tree_size_request (GtkWidget      *widget,
+                      GtkRequisition *requisition)
+{
+  GtkTree *tree;
+  GtkWidget *child, *subtree;
+  GList *children;
+
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TREE (widget));
+  g_return_if_fail (requisition != NULL);
+
+  tree = GTK_TREE (widget);
+  requisition->width = 0;
+  requisition->height = 0;
+
+  children = tree->children;
+  while (children)
+    {
+      child = children->data;
+      children = children->next;
+
+      if (GTK_WIDGET_VISIBLE (child))
+       {
+         gtk_widget_size_request (child, &child->requisition);
+
+         requisition->width = MAX (requisition->width, child->requisition.width);
+         requisition->height += child->requisition.height;
+
+         if((subtree = GTK_TREE_ITEM(child)->subtree) &&
+            GTK_WIDGET_VISIBLE (subtree))
+           {
+             gtk_widget_size_request (subtree, &subtree->requisition);
+
+             requisition->width = MAX (requisition->width, 
+                                       subtree->requisition.width);
+
+             requisition->height += subtree->requisition.height;
+           }
+       }
+    }
+
+  requisition->width += GTK_CONTAINER (tree)->border_width * 2;
+  requisition->height += GTK_CONTAINER (tree)->border_width * 2;
+
+  requisition->width = MAX (requisition->width, 1);
+  requisition->height = MAX (requisition->height, 1);
+
+}
+
+static void
+gtk_tree_unmap (GtkWidget *widget)
+{
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TREE (widget));
+
+  GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
+  gdk_window_hide (widget->window);
+
+}
+
+void
+gtk_tree_unselect_child (GtkTree   *tree,
+                        GtkWidget *child)
+{
+  gtk_signal_emit (GTK_OBJECT (tree), tree_signals[UNSELECT_CHILD], child);
+}
+
+void
+gtk_tree_unselect_item (GtkTree *tree,
+                       gint     item)
+{
+  GList *tmp_list;
+
+
+  g_return_if_fail (tree != NULL);
+  g_return_if_fail (GTK_IS_TREE (tree));
+
+  tmp_list = g_list_nth (tree->children, item);
+  if (tmp_list)
+    gtk_tree_unselect_child (tree, GTK_WIDGET (tmp_list->data));
+
+}
+
+static void
+gtk_real_tree_select_child (GtkTree   *tree,
+                           GtkWidget *child)
+{
+  GList *selection, *root_selection;
+  GList *tmp_list;
+  GtkWidget *tmp_item;
+
+
+  g_return_if_fail (tree != NULL);
+  g_return_if_fail (GTK_IS_TREE (tree));
+  g_return_if_fail (child != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (child));
+
+  root_selection = tree->root_tree->selection;
+
+  switch (tree->root_tree->selection_mode)
+    {
+    case GTK_SELECTION_SINGLE:
+
+      selection = root_selection;
+
+      /* remove old selection list */
+      while (selection)
+       {
+         tmp_item = selection->data;
+
+         if (tmp_item != child)
+           {
+             gtk_tree_item_deselect (GTK_TREE_ITEM (tmp_item));
+
+             tmp_list = selection;
+             selection = selection->next;
+
+             root_selection = g_list_remove_link (root_selection, tmp_list);
+
+             g_list_free (tmp_list);
+           }
+         else
+           selection = selection->next;
+       }
+
+      if (child->state == GTK_STATE_NORMAL)
+       {
+         gtk_tree_item_select (GTK_TREE_ITEM (child));
+         root_selection = g_list_prepend (root_selection, child);
+       }
+      else if (child->state == GTK_STATE_SELECTED)
+       {
+         gtk_tree_item_deselect (GTK_TREE_ITEM (child));
+         root_selection = g_list_remove (root_selection, child);
+       }
+
+      tree->root_tree->selection= root_selection;
+
+      gtk_signal_emit (GTK_OBJECT (tree->root_tree), 
+                      tree_signals[SELECTION_CHANGED]);
+
+    case GTK_SELECTION_BROWSE:
+      selection = root_selection;
+
+      while (selection)
+       {
+         tmp_item = selection->data;
+
+         if (tmp_item != child)
+           {
+             gtk_tree_item_deselect (GTK_TREE_ITEM (tmp_item));
+
+             tmp_list = selection;
+             selection = selection->next;
+
+             root_selection = g_list_remove_link (root_selection, tmp_list);
+
+             g_list_free (tmp_list);
+           }
+         else
+           selection = selection->next;
+       }
+
+      tree->root_tree->selection= root_selection;
+
+      if (child->state == GTK_STATE_NORMAL)
+       {
+         gtk_tree_item_select (GTK_TREE_ITEM (child));
+         root_selection = g_list_prepend (root_selection, child);
+         tree->root_tree->selection= root_selection;
+         gtk_signal_emit (GTK_OBJECT (tree->root_tree), 
+                          tree_signals[SELECTION_CHANGED]);
+       }
+      break;
+
+    case GTK_SELECTION_MULTIPLE:
+      if (child->state == GTK_STATE_NORMAL)
+       {
+         gtk_tree_item_select (GTK_TREE_ITEM (child));
+         root_selection = g_list_prepend (root_selection, child);
+         tree->root_tree->selection= root_selection;
+         gtk_signal_emit (GTK_OBJECT (tree->root_tree), 
+                          tree_signals[SELECTION_CHANGED]);
+       }
+      else if (child->state == GTK_STATE_SELECTED)
+       {
+         gtk_tree_item_deselect (GTK_TREE_ITEM (child));
+         root_selection = g_list_remove (root_selection, child);
+         tree->root_tree->selection= root_selection;
+         gtk_signal_emit (GTK_OBJECT (tree->root_tree), 
+                          tree_signals[SELECTION_CHANGED]);
+       }
+      break;
+
+    case GTK_SELECTION_EXTENDED:
+      break;
+    }
+}
+
+static void
+gtk_real_tree_unselect_child (GtkTree   *tree,
+                             GtkWidget *child)
+{
+
+  g_return_if_fail (tree != NULL);
+  g_return_if_fail (GTK_IS_TREE (tree));
+  g_return_if_fail (child != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (child));
+
+  switch (tree->selection_mode)
+    {
+    case GTK_SELECTION_SINGLE:
+    case GTK_SELECTION_MULTIPLE:
+    case GTK_SELECTION_BROWSE:
+      if (child->state == GTK_STATE_SELECTED)
+       {
+         GtkTree* root_tree = GTK_TREE_ROOT_TREE(tree);
+         gtk_tree_item_deselect (GTK_TREE_ITEM (child));
+         root_tree->selection = g_list_remove (root_tree->selection, child);
+         gtk_signal_emit (GTK_OBJECT (tree->root_tree), 
+                          tree_signals[SELECTION_CHANGED]);
+       }
+      break;
+
+    case GTK_SELECTION_EXTENDED:
+      break;
+    }
+}
+
+void
+gtk_tree_set_selection_mode (GtkTree       *tree,
+                            GtkSelectionMode mode) 
+{
+  g_return_if_fail (tree != NULL);
+  g_return_if_fail (GTK_IS_TREE (tree));
+
+  tree->selection_mode = mode;
+}
+
+void
+gtk_tree_set_view_mode (GtkTree       *tree,
+                       GtkTreeViewMode mode) 
+{
+  g_return_if_fail (tree != NULL);
+  g_return_if_fail (GTK_IS_TREE (tree));
+
+  tree->view_mode = mode;
 }
index 1486a82ab872186f28d04e4f18d8d2cc963202dc..2dc5ece1b34011027cb67463f7f2677732f321ff 100644 (file)
@@ -32,6 +32,15 @@ extern "C" {
 #define GTK_TREE_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_tree_get_type (), GtkTreeClass)
 #define GTK_IS_TREE(obj)       GTK_CHECK_TYPE (obj, gtk_tree_get_type ())
 
+#define GTK_IS_ROOT_TREE(obj)   (GTK_TREE(obj)->root_tree == NULL)
+#define GTK_TREE_ROOT_TREE(obj) (GTK_TREE(obj)->root_tree ? GTK_TREE(obj)->root_tree : GTK_TREE(obj))
+#define GTK_TREE_SELECTION(obj) (GTK_TREE_ROOT_TREE(obj)->selection)
+
+typedef enum 
+{
+  GTK_TREE_VIEW_LINE,  /* default view mode */
+  GTK_TREE_VIEW_ITEM
+} GtkTreeViewMode;
 
 typedef struct _GtkTree       GtkTree;
 typedef struct _GtkTreeClass  GtkTreeClass;
@@ -41,25 +50,58 @@ struct _GtkTree
   GtkContainer container;
 
   GList *children;
+  
+  GtkTree* root_tree; /* owner of selection list */
+  GtkWidget* tree_owner;
+  GList *selection;
+  guint indent_value;
+  guint current_indent;
+  guint selection_mode : 2;
+  guint view_mode : 1;
 };
 
 struct _GtkTreeClass
 {
   GtkContainerClass parent_class;
-};
 
-
-guint      gtk_tree_get_type   (void);
-GtkWidget* gtk_tree_new        (void);
-void       gtk_tree_append     (GtkTree   *tree,
-                               GtkWidget *child);
-void       gtk_tree_prepend    (GtkTree   *tree,
-                               GtkWidget *child);
-void       gtk_tree_insert     (GtkTree   *tree,
-                               GtkWidget *child,
-                               gint       position);
+  void (* selection_changed) (GtkTree   *tree);
+  void (* select_child)      (GtkTree   *tree,
+                             GtkWidget *child);
+  void (* unselect_child)    (GtkTree   *tree,
+                             GtkWidget *child);
+};
 
 
+guint      gtk_tree_get_type           (void);
+GtkWidget* gtk_tree_new                (void);
+void       gtk_tree_append             (GtkTree          *tree,
+                                       GtkWidget        *child);
+void       gtk_tree_prepend            (GtkTree          *tree,
+                                       GtkWidget        *child);
+void       gtk_tree_insert             (GtkTree          *tree,
+                                       GtkWidget        *child,
+                                       gint              position);
+void       gtk_tree_remove_item        (GtkTree          *tree,
+                                       GtkWidget        *child);
+void       gtk_tree_remove_items       (GtkTree          *tree,
+                                       GList            *items);
+void       gtk_tree_clear_items        (GtkTree          *tree,
+                                       gint              start,
+                                       gint              end);
+void       gtk_tree_select_item        (GtkTree          *tree,
+                                       gint              item);
+void       gtk_tree_unselect_item      (GtkTree          *tree,
+                                       gint              item);
+void       gtk_tree_select_child       (GtkTree          *tree,
+                                       GtkWidget        *child);
+void       gtk_tree_unselect_child     (GtkTree          *tree,
+                                       GtkWidget        *child);
+gint       gtk_tree_child_position     (GtkTree          *tree,
+                                       GtkWidget        *child);
+void       gtk_tree_set_selection_mode (GtkTree          *tree,
+                                       GtkSelectionMode  mode);
+void       gtk_tree_set_view_mode      (GtkTree          *tree,
+                                       GtkTreeViewMode   mode); 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
index 8f0d9f078d1290ab3371399109bb6ed5723e9700..ecff341f89eaf20379f942ac6c72a5e28d2eee63 100644 (file)
  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 #include "gtklabel.h"
+#include "gtktree.h"
 #include "gtktreeitem.h"
+#include "gtkeventbox.h"
+#include "gtkpixmap.h"
+#include "gtkmain.h"
+#include "gtksignal.h"
 
+/* remove comment if you want replace loading pixmap by static bitmap 
+   for icons 
+   experimental code and it is buggy */
+/* #define WITH_BITMAP */
+
+#define DEFAULT_DELTA 9
+
+#ifdef WITH_BITMAP
+#include "tree_plus.xbm"
+#include "tree_minus.xbm"
+#endif
+
+enum {
+  COLLAPSE_TREE,
+  EXPAND_TREE,
+  LAST_SIGNAL
+};
+
+typedef void (*GtkTreeItemSignal) (GtkObject *object,
+                                  gpointer   arg1,
+                                  gpointer   data);
 
 static void gtk_tree_item_class_init (GtkTreeItemClass *klass);
 static void gtk_tree_item_init       (GtkTreeItem      *tree_item);
+static void gtk_tree_item_realize       (GtkWidget        *widget);
+static void gtk_tree_item_size_request  (GtkWidget        *widget,
+                                        GtkRequisition   *requisition);
+static void gtk_tree_item_size_allocate (GtkWidget        *widget,
+                                        GtkAllocation    *allocation);
+static void gtk_tree_item_draw          (GtkWidget        *widget,
+                                        GdkRectangle     *area);
+static void gtk_tree_item_draw_focus    (GtkWidget        *widget);
+static gint gtk_tree_item_button_press  (GtkWidget        *widget,
+                                        GdkEventButton   *event);
+static gint gtk_tree_item_expose        (GtkWidget        *widget,
+                                        GdkEventExpose   *event);
+static gint gtk_tree_item_focus_in      (GtkWidget        *widget,
+                                        GdkEventFocus    *event);
+static gint gtk_tree_item_focus_out     (GtkWidget        *widget,
+                                        GdkEventFocus    *event);
+static void gtk_real_tree_item_select   (GtkItem          *item);
+static void gtk_real_tree_item_deselect (GtkItem          *item);
+static void gtk_real_tree_item_toggle   (GtkItem          *item);
+static void gtk_real_tree_item_expand   (GtkTreeItem      *item);
+static void gtk_real_tree_item_collapse (GtkTreeItem      *item);
+static void gtk_real_tree_item_expand   (GtkTreeItem      *item);
+static void gtk_real_tree_item_collapse (GtkTreeItem      *item);
+static void gtk_tree_item_marshal_signal (GtkObject      *object,
+                                         GtkSignalFunc   func,
+                                         gpointer        func_data,
+                                         GtkArg         *args);
+static void gtk_tree_item_destroy        (GtkObject *object);
+static void gtk_tree_item_subtree_button_click (GtkWidget *widget);
+static void gtk_tree_item_subtree_button_changed_state (GtkWidget *widget);
 
+static void gtk_tree_item_map(GtkWidget*);
+static void gtk_tree_item_unmap(GtkWidget*);
+
+static GtkItemClass *parent_class = NULL;
+static GtkContainerClass *container_class = NULL;
+static gint tree_item_signals[LAST_SIGNAL] = { 0 };
 
 guint
 gtk_tree_item_get_type ()
@@ -49,18 +111,191 @@ gtk_tree_item_get_type ()
 static void
 gtk_tree_item_class_init (GtkTreeItemClass *class)
 {
+  GtkObjectClass *object_class;
+  GtkWidgetClass *widget_class;
+  GtkItemClass *item_class;
+
+  object_class = (GtkObjectClass*) class;
+  widget_class = (GtkWidgetClass*) class;
+  item_class = (GtkItemClass*) class;
+  container_class = (GtkContainerClass*) class;
+
+  parent_class = gtk_type_class (gtk_item_get_type ());
+  
+  tree_item_signals[EXPAND_TREE] =
+    gtk_signal_new ("expand",
+                   GTK_RUN_FIRST,
+                   object_class->type,
+                   GTK_SIGNAL_OFFSET (GtkTreeItemClass, expand),
+                   gtk_tree_item_marshal_signal,
+                   GTK_TYPE_NONE, 0);
+  tree_item_signals[COLLAPSE_TREE] =
+    gtk_signal_new ("collapse",
+                   GTK_RUN_FIRST,
+                   object_class->type,
+                   GTK_SIGNAL_OFFSET (GtkTreeItemClass, collapse),
+                   gtk_tree_item_marshal_signal,
+                   GTK_TYPE_NONE, 0);
+
+  gtk_object_class_add_signals (object_class, tree_item_signals, LAST_SIGNAL);
+
+  object_class->destroy = gtk_tree_item_destroy;
+
+  widget_class->realize = gtk_tree_item_realize;
+  widget_class->size_request = gtk_tree_item_size_request;
+  widget_class->size_allocate = gtk_tree_item_size_allocate;
+  widget_class->draw = gtk_tree_item_draw;
+  widget_class->draw_focus = gtk_tree_item_draw_focus;
+  widget_class->button_press_event = gtk_tree_item_button_press;
+  widget_class->expose_event = gtk_tree_item_expose;
+  widget_class->focus_in_event = gtk_tree_item_focus_in;
+  widget_class->focus_out_event = gtk_tree_item_focus_out;
+  widget_class->map = gtk_tree_item_map;
+  widget_class->unmap = gtk_tree_item_unmap;
+
+  item_class->select = gtk_real_tree_item_select;
+  item_class->deselect = gtk_real_tree_item_deselect;
+  item_class->toggle = gtk_real_tree_item_toggle;
+
+  class->expand = gtk_real_tree_item_expand;
+  class->collapse = gtk_real_tree_item_collapse;
+
+  container_class = (GtkContainerClass*) parent_class;
+}
+
+/* callback for event box mouse event */
+static void 
+gtk_tree_item_subtree_button_click (GtkWidget *widget)
+{
+  GtkTreeItem* item;
+
+  item = (GtkTreeItem*) gtk_object_get_user_data(GTK_OBJECT(widget));
+
+  if(item->expanded)
+    gtk_tree_item_collapse(item);
+  else
+    gtk_tree_item_expand(item);
+}
+
+/* callback for event box state changed */
+static void
+gtk_tree_item_subtree_button_changed_state(GtkWidget *w)
+{
+  if(GTK_WIDGET_VISIBLE (w)) {
+
+    if (w->state == GTK_STATE_NORMAL)
+      gdk_window_set_background (w->window, &w->style->white);
+    else
+      gdk_window_set_background (w->window, &w->style->bg[w->state]);
+
+    if (GTK_WIDGET_DRAWABLE(w))
+      gdk_window_clear_area (w->window, 0, 0, 
+                            w->allocation.width, w->allocation.height);
+  }
 }
 
 static void
 gtk_tree_item_init (GtkTreeItem *tree_item)
 {
+  GtkWidget *eventbox, *pixmapwid;
+  static GdkPixmap *pixmap_plus = NULL;
+  static GdkPixmap *pixmap_minus = NULL;
+#ifndef WITH_BITMAP
+  static GdkBitmap *mask = NULL; 
+#endif
+  static GtkStyle *style = NULL;
+
+  tree_item->expanded = FALSE;
+  tree_item->subtree = NULL;
+  GTK_WIDGET_SET_FLAGS (tree_item, GTK_CAN_FOCUS);
+
+  if(style == NULL) 
+    {
+
+      style=gtk_widget_get_style(GTK_WIDGET(tree_item));
+
+#ifndef WITH_BITMAP
+      /* create pixmaps for one time, based on xpm file */
+      pixmap_plus = gdk_pixmap_create_from_xpm (GTK_WIDGET(tree_item)->window, &mask, 
+                                               &style->bg[GTK_STATE_NORMAL],
+                                               "tree_plus.xpm");
+      if(!pixmap_plus)
+       g_warning("gtk_tree_item_init: can't find tree_plus.xpm file !\n");
+
+      pixmap_minus = gdk_pixmap_create_from_xpm (GTK_WIDGET(tree_item)->window, &mask, 
+                                                &style->bg[GTK_STATE_NORMAL],
+                                                "tree_minus.xpm");      
+      if(!pixmap_minus)
+       g_warning("gtk_tree_item_init: can't find tree_minus.xpm file !\n");
+#else
+
+      pixmap_plus = gdk_pixmap_create_from_data(GTK_WIDGET(tree_item)->window,
+                                               (gchar*) tree_plus_bits,
+                                               tree_plus_width, tree_plus_height, -1,
+                                               &style->black,
+                                               &style->white);
+
+      pixmap_minus = gdk_pixmap_create_from_data(GTK_WIDGET(tree_item)->window,
+                                                (gchar*) tree_minus_bits,
+                                                tree_minus_width, tree_minus_height, -1,
+                                                &style->black,
+                                                &style->white);
+#endif /* WITH_BITMAP */
+    }
+  
+  if(pixmap_plus && pixmap_minus) 
+    {
+      /* create an event box containing one pixmaps */
+      eventbox = gtk_event_box_new();
+      gtk_widget_set_events (eventbox, GDK_BUTTON_PRESS_MASK);
+      gtk_signal_connect(GTK_OBJECT(eventbox), "state_changed",
+                        (GtkSignalFunc)gtk_tree_item_subtree_button_changed_state, 
+                        (gpointer)NULL);
+      gtk_signal_connect(GTK_OBJECT(eventbox), "realize",
+                        (GtkSignalFunc)gtk_tree_item_subtree_button_changed_state, 
+                        (gpointer)NULL);
+      gtk_signal_connect(GTK_OBJECT(eventbox), "button_press_event",
+                        (GtkSignalFunc)gtk_tree_item_subtree_button_click,
+                        (gpointer)NULL);
+      gtk_object_set_user_data(GTK_OBJECT(eventbox), tree_item);
+      tree_item->pixmaps_box = eventbox;
+
+      /* create pixmap for button '+' */
+#ifndef WITH_BITMAP
+      pixmapwid = gtk_pixmap_new (pixmap_plus, mask);
+#else
+      pixmapwid = gtk_pixmap_new (pixmap_plus, NULL);
+#endif
+      if(!tree_item->expanded) 
+       gtk_container_add(GTK_CONTAINER(eventbox), pixmapwid);
+      gtk_widget_show(pixmapwid);
+      tree_item->plus_pix_widget = pixmapwid;
+
+      /* create pixmap for button '-' */
+#ifndef WITH_BITMAP
+      pixmapwid = gtk_pixmap_new (pixmap_minus, mask);
+#else
+      pixmapwid = gtk_pixmap_new (pixmap_minus, NULL);
+#endif
+      if(tree_item->expanded) 
+       gtk_container_add(GTK_CONTAINER(eventbox), pixmapwid);
+      gtk_widget_show(pixmapwid);
+      tree_item->minus_pix_widget = pixmapwid;
+
+      gtk_widget_set_parent(eventbox, GTK_WIDGET(tree_item));
+    } else
+      tree_item->pixmaps_box = NULL;
 }
 
 
 GtkWidget*
 gtk_tree_item_new ()
 {
-  return GTK_WIDGET (gtk_type_new (gtk_tree_item_get_type ()));
+  GtkWidget *tree_item;
+
+  tree_item = GTK_WIDGET (gtk_type_new (gtk_tree_item_get_type ()));
+
+  return tree_item;
 }
 
 GtkWidget*
@@ -69,6 +304,7 @@ gtk_tree_item_new_with_label (gchar *label)
   GtkWidget *tree_item;
   GtkWidget *label_widget;
 
+
   tree_item = gtk_tree_item_new ();
   label_widget = gtk_label_new (label);
   gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
@@ -76,6 +312,7 @@ gtk_tree_item_new_with_label (gchar *label)
   gtk_container_add (GTK_CONTAINER (tree_item), label_widget);
   gtk_widget_show (label_widget);
 
+
   return tree_item;
 }
 
@@ -85,24 +322,577 @@ gtk_tree_item_set_subtree (GtkTreeItem *tree_item,
 {
   g_return_if_fail (tree_item != NULL);
   g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
+
+  if(tree_item->subtree) {
+    g_warning("there is already a subtree for this tree item\n");
+    return;
+  }
+
+  tree_item->subtree = subtree; 
+  GTK_TREE(subtree)->tree_owner = GTK_WIDGET(tree_item);
+
+  /* set root tree for selection list */
+  GTK_TREE(subtree)->root_tree = GTK_TREE(GTK_WIDGET(tree_item)->parent)->root_tree;
+
+  /* show subtree button */
+  if(tree_item->pixmaps_box)
+    gtk_widget_show(tree_item->pixmaps_box);
+
+  /* set parent widget */
+  gtk_widget_set_parent(subtree, GTK_WIDGET(tree_item)->parent);
+
+  if(GTK_WIDGET_VISIBLE(GTK_WIDGET(tree_item))) 
+    {
+      if(GTK_WIDGET_REALIZED (GTK_WIDGET(tree_item)) &&
+        !GTK_WIDGET_REALIZED (GTK_WIDGET(subtree)))
+       gtk_widget_realize (GTK_WIDGET(subtree));
+
+      if(GTK_WIDGET_MAPPED (GTK_WIDGET(tree_item)) &&
+        !GTK_WIDGET_MAPPED (GTK_WIDGET(subtree)))
+       gtk_widget_map (GTK_WIDGET(subtree));
+    }
+
+  if(tree_item->expanded)
+    gtk_widget_show(subtree);
+  else
+    gtk_widget_hide(subtree);
+  
+  if (GTK_WIDGET_VISIBLE (tree_item) && GTK_WIDGET_VISIBLE (tree_item))
+    gtk_widget_queue_resize (GTK_WIDGET(tree_item));
+
 }
 
 void
 gtk_tree_item_select (GtkTreeItem *tree_item)
 {
+
+  gtk_item_select (GTK_ITEM (tree_item));
+
 }
 
 void
 gtk_tree_item_deselect (GtkTreeItem *tree_item)
 {
+
+  gtk_item_deselect (GTK_ITEM (tree_item));
+
 }
 
 void
 gtk_tree_item_expand (GtkTreeItem *tree_item)
 {
+
+  gtk_signal_emit (GTK_OBJECT (tree_item), tree_item_signals[EXPAND_TREE], NULL);
+
 }
 
 void
 gtk_tree_item_collapse (GtkTreeItem *tree_item)
 {
+
+  gtk_signal_emit (GTK_OBJECT (tree_item), tree_item_signals[COLLAPSE_TREE], NULL);
+
+}
+
+static void
+gtk_tree_item_realize (GtkWidget *widget)
+{    
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (widget));
+
+  if (GTK_WIDGET_CLASS (parent_class)->realize)
+    (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
+  
+  gdk_window_set_background (widget->window, &widget->style->white);
+}
+
+static void
+gtk_tree_item_size_request (GtkWidget      *widget,
+                           GtkRequisition *requisition)
+{
+  GtkBin *bin;
+  GtkTreeItem* item;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (widget));
+  g_return_if_fail (requisition != NULL);
+
+  bin = GTK_BIN (widget);
+  item = GTK_TREE_ITEM(widget);
+
+  requisition->width = (GTK_CONTAINER (widget)->border_width +
+                       widget->style->klass->xthickness) * 2;
+  requisition->height = GTK_CONTAINER (widget)->border_width * 2;
+
+  if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
+    {
+      gtk_widget_size_request (bin->child, &bin->child->requisition);
+
+      requisition->width += bin->child->requisition.width;
+
+      gtk_widget_size_request (item->pixmaps_box, 
+                              &item->pixmaps_box->requisition);
+      requisition->width += item->pixmaps_box->requisition.width + DEFAULT_DELTA + 
+       GTK_TREE(widget->parent)->current_indent;
+
+      requisition->height += MAX(bin->child->requisition.height,
+                                item->pixmaps_box->requisition.height);
+    }
+}
+
+static void
+gtk_tree_item_size_allocate (GtkWidget     *widget,
+                            GtkAllocation *allocation)
+{
+  GtkBin *bin;
+  GtkTreeItem* item;
+  GtkAllocation child_allocation;
+  guint border_width;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (widget));
+  g_return_if_fail (allocation != NULL);
+
+  widget->allocation = *allocation;
+  if (GTK_WIDGET_REALIZED (widget))
+    gdk_window_move_resize (widget->window,
+                           allocation->x, allocation->y,
+                           allocation->width, allocation->height);
+
+  bin = GTK_BIN (widget);
+  item = GTK_TREE_ITEM(widget);
+
+  if (bin->child)
+    {
+      border_width = (GTK_CONTAINER (widget)->border_width +
+                     widget->style->klass->xthickness);
+
+      child_allocation.x = border_width + GTK_TREE(widget->parent)->current_indent;
+      child_allocation.y = GTK_CONTAINER (widget)->border_width;
+
+      child_allocation.height = allocation->height - child_allocation.y * 2;
+      child_allocation.width = item->pixmaps_box->requisition.width;
+
+      child_allocation.y += 1;
+      child_allocation.height -= 2;
+      gtk_widget_size_allocate (item->pixmaps_box, &child_allocation);
+
+      child_allocation.height += 2;
+      child_allocation.x += item->pixmaps_box->requisition.width+DEFAULT_DELTA;
+
+      child_allocation.width = 
+       allocation->width - (child_allocation.x + border_width);
+
+      gtk_widget_size_allocate (bin->child, &child_allocation);
+    }
+
+}
+
+static void
+gtk_tree_item_draw (GtkWidget    *widget,
+                   GdkRectangle *area)
+{
+  GtkBin *bin;
+  GdkRectangle child_area, item_area;
+  GtkTreeItem* tree_item;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (widget));
+  g_return_if_fail (area != NULL);
+
+  if (GTK_WIDGET_DRAWABLE (widget))
+    {
+      bin = GTK_BIN (widget);
+      tree_item = GTK_TREE_ITEM(widget);
+
+      /* draw left size of tree item */
+      item_area.x = 0; item_area.y = 0;
+      item_area.width = tree_item->pixmaps_box->allocation.width+DEFAULT_DELTA +
+       (GTK_TREE(widget->parent)->current_indent + 2);
+      item_area.height = widget->allocation.height;
+
+      if(gdk_rectangle_intersect(&item_area, area, &child_area)) {
+       
+       if (!GTK_WIDGET_IS_SENSITIVE (widget)) 
+         gtk_style_set_background (widget->style, widget->window, 
+                                   GTK_STATE_INSENSITIVE);
+       else if(GTK_TREE(widget->parent)->view_mode == GTK_TREE_VIEW_LINE &&
+               widget->state == GTK_STATE_SELECTED)
+         gtk_style_set_background (widget->style, widget->window, widget->state);
+       else
+         gdk_window_set_background (widget->window, &widget->style->white);
+
+       gdk_window_clear_area (widget->window, 
+                              child_area.x, child_area.y,
+                              child_area.width, child_area.height);
+
+       if (tree_item->pixmaps_box && 
+           GTK_WIDGET_VISIBLE(tree_item->pixmaps_box) &&
+           gtk_widget_intersect (tree_item->pixmaps_box, area, &child_area))
+         gtk_widget_draw (tree_item->pixmaps_box, &child_area);
+      }
+
+      /* draw right side */
+      if(gtk_widget_intersect (bin->child, area, &child_area)) {
+
+       if (!GTK_WIDGET_IS_SENSITIVE (widget)) 
+         gtk_style_set_background (widget->style, widget->window, 
+                                   GTK_STATE_INSENSITIVE);
+       else if (widget->state == GTK_STATE_NORMAL)
+         gdk_window_set_background(widget->window, &widget->style->white);
+       else
+         gtk_style_set_background (widget->style, widget->window, widget->state);
+
+       gdk_window_clear_area (widget->window, child_area.x, child_area.y,
+                              child_area.width+1, child_area.height);
+
+       if (bin->child && 
+           GTK_WIDGET_VISIBLE(bin->child) &&
+           gtk_widget_intersect (bin->child, area, &child_area))
+         gtk_widget_draw (bin->child, &child_area);
+      }
+
+      gtk_widget_draw_focus (widget);
+    }
+}
+
+static void
+gtk_tree_item_draw_focus (GtkWidget *widget)
+{
+  GdkGC *gc;
+  int dx;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (widget));
+
+  if (GTK_WIDGET_DRAWABLE (widget))
+    {
+      if (GTK_WIDGET_HAS_FOCUS (widget))
+       gc = widget->style->black_gc;
+      else if (!GTK_WIDGET_IS_SENSITIVE (widget))
+       gc = widget->style->bg_gc[GTK_STATE_INSENSITIVE];
+      else if (widget->state == GTK_STATE_NORMAL)
+       gc = widget->style->white_gc;
+      else
+       gc = widget->style->bg_gc[widget->state];
+
+      dx = 0;
+
+      if(GTK_TREE(widget->parent)->view_mode == GTK_TREE_VIEW_ITEM) 
+       dx = GTK_TREE_ITEM(widget)->pixmaps_box->allocation.width + DEFAULT_DELTA +
+         GTK_TREE(widget->parent)->current_indent+1;
+
+      gdk_draw_rectangle (widget->window, gc, FALSE, dx, 0,
+                         widget->allocation.width - 1 - dx,
+                         widget->allocation.height - 1);
+    }
+}
+
+static gint
+gtk_tree_item_button_press (GtkWidget      *widget,
+                           GdkEventButton *event)
+{
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TREE_ITEM (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  if (event->type == GDK_BUTTON_PRESS)
+    if (!GTK_WIDGET_HAS_FOCUS (widget))
+      gtk_widget_grab_focus (widget);
+
+  return FALSE;
+}
+
+static gint
+gtk_tree_item_expose (GtkWidget      *widget,
+                     GdkEventExpose *event)
+{
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TREE_ITEM (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  if (GTK_WIDGET_DRAWABLE (widget))
+    gtk_tree_item_draw(widget, &event->area);
+
+  return FALSE;
+}
+
+static gint
+gtk_tree_item_focus_in (GtkWidget     *widget,
+                       GdkEventFocus *event)
+{
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TREE_ITEM (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
+  gtk_widget_draw_focus (widget);
+
+
+  return FALSE;
+}
+
+static gint
+gtk_tree_item_focus_out (GtkWidget     *widget,
+                        GdkEventFocus *event)
+{
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TREE_ITEM (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
+  gtk_widget_draw_focus (widget);
+
+
+  return FALSE;
+}
+
+static void
+gtk_real_tree_item_select (GtkItem *item)
+{
+    
+  g_return_if_fail (item != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (item));
+
+  if (GTK_WIDGET (item)->state == GTK_STATE_SELECTED)
+    return;
+
+  gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);
+
+  if(GTK_TREE(GTK_WIDGET(item)->parent)->view_mode == GTK_TREE_VIEW_LINE)
+    gtk_widget_set_state (GTK_TREE_ITEM (item)->pixmaps_box, GTK_STATE_SELECTED);
+  
+  gtk_widget_queue_draw (GTK_WIDGET (item));
+}
+
+static void
+gtk_real_tree_item_deselect (GtkItem *item)
+{
+
+  g_return_if_fail (item != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (item));
+
+  if (GTK_WIDGET (item)->state == GTK_STATE_NORMAL)
+    return;
+
+  gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_NORMAL);
+
+  if(GTK_TREE(GTK_WIDGET(item)->parent)->view_mode == GTK_TREE_VIEW_LINE)
+    gtk_widget_set_state (GTK_TREE_ITEM (item)->pixmaps_box, GTK_STATE_NORMAL);
+
+  gtk_widget_queue_draw (GTK_WIDGET (item));
+}
+
+static void
+gtk_real_tree_item_toggle (GtkItem *item)
+{
+
+  g_return_if_fail (item != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (item));
+
+  if (GTK_WIDGET (item)->parent && GTK_IS_TREE (GTK_WIDGET (item)->parent))
+    gtk_tree_select_child (GTK_TREE (GTK_WIDGET (item)->parent),
+                          GTK_WIDGET (item));
+  else
+    {
+      /* Should we really bother with this bit? A listitem not in a list?
+       * -Johannes Keukelaar
+       * yes, always be on the save side!
+       * -timj
+       */
+      if (GTK_WIDGET (item)->state == GTK_STATE_SELECTED)
+       gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_NORMAL);
+      else
+       gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED);
+      gtk_widget_queue_draw (GTK_WIDGET (item));
+    }
+}
+
+static void
+gtk_tree_item_marshal_signal (GtkObject      *object,
+                             GtkSignalFunc   func,
+                             gpointer        func_data,
+                             GtkArg         *args)
+{
+  GtkTreeItemSignal rfunc;
+
+  rfunc = (GtkTreeItemSignal) func;
+
+  (* rfunc) (object, GTK_VALUE_OBJECT (args[0]), func_data);
+}
+
+static void
+gtk_real_tree_item_expand (GtkTreeItem *tree_item)
+{
+  GtkTree* tree;
+  
+  g_return_if_fail (tree_item != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
+  g_return_if_fail (tree_item->subtree != NULL);
+
+
+  if(!tree_item->expanded) 
+    {
+      tree = GTK_TREE(GTK_WIDGET(tree_item)->parent); 
+
+      /* hide subtree widget */
+      gtk_widget_show(tree_item->subtree);
+
+      /* hide button '+' and show button '-' */
+      if(tree_item->pixmaps_box) {
+       gtk_container_remove(GTK_CONTAINER(tree_item->pixmaps_box), 
+                            tree_item->plus_pix_widget);
+       gtk_container_add(GTK_CONTAINER(tree_item->pixmaps_box), 
+                         tree_item->minus_pix_widget);
+      }
+      if(tree->root_tree) gtk_widget_queue_resize(GTK_WIDGET(tree->root_tree));
+      tree_item->expanded = TRUE;
+    }
+}
+
+static void
+gtk_real_tree_item_collapse (GtkTreeItem *tree_item)
+{
+  GtkTree* tree;
+
+  g_return_if_fail (tree_item != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (tree_item));
+  g_return_if_fail (tree_item->subtree != NULL);
+
+  if(tree_item->expanded) 
+    {
+      tree = GTK_TREE(GTK_WIDGET(tree_item)->parent);
+
+      /* hide subtree widget */
+      gtk_widget_hide(tree_item->subtree);
+
+      /* hide button '-' and show button '+' */
+      if(tree_item->pixmaps_box) {
+       gtk_container_remove(GTK_CONTAINER(tree_item->pixmaps_box), 
+                            tree_item->minus_pix_widget);
+       gtk_container_add(GTK_CONTAINER(tree_item->pixmaps_box), 
+                         tree_item->plus_pix_widget);
+      }
+      if(tree->root_tree) gtk_widget_queue_resize(GTK_WIDGET(tree->root_tree));
+      tree_item->expanded = FALSE;
+    }
+
+}
+
+static void
+gtk_tree_item_destroy (GtkObject *object)
+{
+  GtkTreeItem* item;
+  GtkWidget* child;
+
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (object));
+
+  item = GTK_TREE_ITEM(object);
+
+  /* free sub tree if it exist */
+  if((child = item->subtree)) 
+    {
+      child->parent = NULL; 
+      gtk_object_unref (GTK_OBJECT (child));
+      gtk_widget_destroy (child);
+    }
+
+  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+
+}
+
+void
+gtk_tree_item_remove_subtree (GtkTreeItem* item) 
+{
+  g_return_if_fail(item != NULL);
+  g_return_if_fail(GTK_IS_TREE_ITEM(item));
+  g_return_if_fail(item->subtree);
+
+  if(GTK_TREE(item->subtree)->children)
+    gtk_tree_remove_items(GTK_TREE(item->subtree), 
+                         GTK_TREE(item->subtree)->children);
+
+  if (GTK_WIDGET_MAPPED (item->subtree))
+    gtk_widget_unmap (item->subtree);
+
+  gtk_widget_unparent (item->subtree);
+
+  if(item->pixmaps_box)
+    gtk_widget_hide(item->pixmaps_box);
+
+  item->subtree = NULL;
+  item->expanded = FALSE;
+  if(item->pixmaps_box) {
+    gtk_container_remove(GTK_CONTAINER(item->pixmaps_box), 
+                        item->minus_pix_widget);
+    gtk_container_add(GTK_CONTAINER(item->pixmaps_box), 
+                     item->plus_pix_widget);
+  }
+}
+
+static void
+gtk_tree_item_map (GtkWidget *widget)
+{
+  GtkBin *bin;
+  GtkTreeItem* item;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (widget));
+
+  GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
+  bin = GTK_BIN (widget);
+  item = GTK_TREE_ITEM(widget);
+
+  if (!GTK_WIDGET_NO_WINDOW (widget))
+    gdk_window_show (widget->window);
+  else
+    gtk_widget_queue_draw (widget);
+
+  if(item->pixmaps_box &&
+     GTK_WIDGET_VISIBLE (item->pixmaps_box) &&
+     !GTK_WIDGET_MAPPED (item->pixmaps_box))
+    gtk_widget_map (item->pixmaps_box);
+
+  if (bin->child &&
+      GTK_WIDGET_VISIBLE (bin->child) &&
+      !GTK_WIDGET_MAPPED (bin->child))
+    gtk_widget_map (bin->child);
+}
+
+static void
+gtk_tree_item_unmap (GtkWidget *widget)
+{
+  GtkBin *bin;
+  GtkTreeItem* item;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_TREE_ITEM (widget));
+
+  GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
+  bin = GTK_BIN (widget);
+  item = GTK_TREE_ITEM(widget);
+
+  if (GTK_WIDGET_NO_WINDOW (widget))
+    gdk_window_clear_area (widget->window,
+                          widget->allocation.x,
+                          widget->allocation.y,
+                          widget->allocation.width,
+                          widget->allocation.height);
+  else
+    gdk_window_hide (widget->window);
+
+  if(item->pixmaps_box &&
+     GTK_WIDGET_VISIBLE (item->pixmaps_box) &&
+     GTK_WIDGET_MAPPED (item->pixmaps_box))
+    gtk_widget_unmap (bin->child);
+
+  if (bin->child &&
+      GTK_WIDGET_VISIBLE (bin->child) &&
+      GTK_WIDGET_MAPPED (bin->child))
+    gtk_widget_unmap (bin->child);
 }
index 921f681bc3bb7ce5130292f65b317205b561e5ba..6affddd3dc74b025a891a12fc8af8a0a7c1c35d5 100644 (file)
@@ -32,6 +32,7 @@ extern "C" {
 #define GTK_TREE_ITEM_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_tree_item_get_type (), GtkTreeItemClass)
 #define GTK_IS_TREE_ITEM(obj)       GTK_CHECK_TYPE (obj, gtk_tree_item_get_type ())
 
+#define GTK_TREE_ITEM_SUBTREE(obj)  GTK_TREE_ITEM(obj)->subtree;
 
 typedef struct _GtkTreeItem       GtkTreeItem;
 typedef struct _GtkTreeItemClass  GtkTreeItemClass;
@@ -40,8 +41,11 @@ struct _GtkTreeItem
 {
   GtkItem item;
 
-  GtkWidget *child;
   GtkWidget *subtree;
+  GtkWidget *pixmaps_box;
+  GtkWidget *plus_pix_widget, *minus_pix_widget;
+
+  guint expanded : 1;
 };
 
 struct _GtkTreeItemClass
@@ -58,6 +62,7 @@ GtkWidget* gtk_tree_item_new            (void);
 GtkWidget* gtk_tree_item_new_with_label (gchar       *label);
 void       gtk_tree_item_set_subtree    (GtkTreeItem *tree_item,
                                         GtkWidget   *subtree);
+void       gtk_tree_item_remove_subtree (GtkTreeItem *tree_item);
 void       gtk_tree_item_select         (GtkTreeItem *tree_item);
 void       gtk_tree_item_deselect       (GtkTreeItem *tree_item);
 void       gtk_tree_item_expand         (GtkTreeItem *tree_item);
diff --git a/gtk/testtree.c b/gtk/testtree.c
new file mode 100644 (file)
index 0000000..547de5d
--- /dev/null
@@ -0,0 +1,231 @@
+#include "gtk.h"
+
+typedef struct sTreeButtons {
+    GtkWidget *button_add, *button_remove;
+} sTreeButton;
+
+static gint cb_delete_event() {
+    return TRUE;
+}
+static void cb_destroy_event() {
+    gtk_main_quit();
+}
+static void cb_tree_changed(GtkTree* tree) {
+    sTreeButton* tree_buttons;
+    GList* selected;
+    gint nb_selected;
+
+    tree_buttons = gtk_object_get_user_data(GTK_OBJECT(tree));
+
+    selected = tree->selection;
+    nb_selected = g_list_length(selected);
+
+    if(nb_selected == 0) {
+       if(tree->children == NULL)
+           gtk_widget_set_sensitive(tree_buttons->button_add, TRUE);
+       else
+           gtk_widget_set_sensitive(tree_buttons->button_add, FALSE);
+       gtk_widget_set_sensitive(tree_buttons->button_remove, FALSE);
+    } else {
+       gtk_widget_set_sensitive(tree_buttons->button_remove, TRUE);
+       gtk_widget_set_sensitive(tree_buttons->button_add, (nb_selected == 1));
+    }
+}
+
+static void add_tree_item(GtkWidget* w, GtkTree* tree) {
+    static gint nb_item_add = 0;
+    GList* selected;
+    gint nb_selected;
+    GtkTreeItem *selected_item;
+    GtkWidget* new_item;
+    GtkWidget* subtree;
+    gchar buffer[255];
+
+    selected = GTK_TREE_SELECTION(tree);
+    nb_selected = g_list_length(selected);
+
+    if(nb_selected > 1) return;
+
+    if(nb_selected == 0 && tree->children != NULL) return;
+
+    if(tree->children == NULL) {
+       subtree = GTK_WIDGET(tree);
+    } else {
+       selected_item = GTK_TREE_ITEM(selected->data);
+       subtree = GTK_TREE_ITEM_SUBTREE(selected_item);
+    }
+    if(!subtree) { /* create a new subtree if not exist */
+       subtree = gtk_tree_new();
+       gtk_signal_connect(GTK_OBJECT(subtree), "selection_changed",
+                          (GtkSignalFunc)cb_tree_changed,
+                          (gpointer)NULL);
+       gtk_tree_item_set_subtree(GTK_TREE_ITEM(selected_item), subtree);
+    }
+
+    /* create a new item */
+    sprintf(buffer, "new item %d", nb_item_add++);
+    new_item = gtk_tree_item_new_with_label(buffer);
+    gtk_tree_append(GTK_TREE(subtree), new_item);
+    gtk_widget_show(new_item);
+}
+
+static void remove_tree_item(GtkWidget* w, GtkTree* tree) {
+    GList* selected, *clear_list;
+    GtkTree* root_tree;
+
+    root_tree = GTK_TREE_ROOT_TREE(tree);
+    selected = GTK_TREE_SELECTION(tree);
+
+    clear_list = NULL;
+    
+    while (selected) {
+       clear_list = g_list_prepend (clear_list, selected->data);
+       selected = selected->next;
+    }
+
+    if(clear_list) {
+       clear_list = g_list_reverse (clear_list);
+       gtk_tree_remove_items(root_tree, clear_list);
+
+       selected = clear_list;
+       
+       while (selected) {
+           gtk_widget_destroy (GTK_WIDGET (selected->data));
+           selected = selected->next;
+       }
+
+       g_list_free (clear_list);
+    }
+}
+
+void create_tree_item(GtkWidget* parent, int level, int nb_item, int level_max) {
+    int i;
+    char buffer[255];
+    GtkWidget *item, *tree;
+    
+    for(i = 0; i<nb_item; i++) { 
+
+       sprintf(buffer, "item %d-%d", level, i);
+       item = gtk_tree_item_new_with_label(buffer);
+       gtk_tree_append(GTK_TREE(parent), item);
+       gtk_widget_show(item);
+
+/*     g_print("item '%s' : 0x%x\n", buffer, (int)item); */
+
+       if(level < level_max) {
+           tree = gtk_tree_new();
+
+/*         g_print("subtree '%s' : 0x%x\n", buffer, (int)tree); */
+           gtk_signal_connect(GTK_OBJECT(tree), "selection_changed",
+                              (GtkSignalFunc)cb_tree_changed,
+                              (gpointer)NULL);
+           create_tree_item(tree, level+1, nb_item, level_max);
+           gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), tree);
+/*         gtk_tree_item_expand(GTK_TREE_ITEM(item)); */
+
+       }
+    }
+
+}
+
+void create_tree_page(GtkWidget* parent, GtkSelectionMode mode, 
+                     char* page_name) {
+    GtkWidget *root, *scrolled_win;
+    GtkWidget *box, *label;
+    GtkWidget *button;
+    sTreeButton* tree_buttons;
+
+    /* create notebook page */
+    box = gtk_vbox_new(FALSE, 5);
+    gtk_container_border_width (GTK_CONTAINER (box), 5);
+    gtk_widget_show (box);
+
+    label = gtk_label_new(page_name);
+    gtk_notebook_append_page(GTK_NOTEBOOK(parent), box, label);
+
+    scrolled_win = gtk_scrolled_window_new (NULL, NULL);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
+                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+    gtk_box_pack_start (GTK_BOX (box), scrolled_win, TRUE, TRUE, 0);
+    gtk_widget_set_usize (scrolled_win, 200, 200);
+    gtk_widget_show (scrolled_win);
+
+    root = gtk_tree_new();
+/*     g_print("root: 0x%x\n", (int)root); */
+    gtk_container_add(GTK_CONTAINER(scrolled_win), root);
+    gtk_tree_set_selection_mode(GTK_TREE(root), mode);
+/*     gtk_tree_set_view_mode(GTK_TREE(root), GTK_TREE_VIEW_ITEM); */
+    gtk_signal_connect(GTK_OBJECT(root), "selection_changed",
+                      (GtkSignalFunc)cb_tree_changed,
+                      (gpointer)NULL);
+    gtk_widget_show(root);
+    
+    create_tree_item(root, 1, 3, 3);
+
+    tree_buttons = g_malloc(sizeof(sTreeButton));
+
+    button = gtk_button_new_with_label("Add");
+    gtk_box_pack_start(GTK_BOX (box), button, TRUE, TRUE, 0);
+    gtk_signal_connect(GTK_OBJECT(button), "clicked",
+                      (GtkSignalFunc)add_tree_item, 
+                      (gpointer)root);
+    gtk_widget_set_sensitive(button, FALSE);
+    gtk_widget_show(button);
+    tree_buttons->button_add = button;
+
+    button = gtk_button_new_with_label("Remove");
+    gtk_box_pack_start(GTK_BOX (box), button, TRUE, TRUE, 0);
+    gtk_signal_connect(GTK_OBJECT(button), "clicked",
+                      (GtkSignalFunc)remove_tree_item, 
+                      (gpointer)root);
+    gtk_widget_set_sensitive(button, FALSE);
+    gtk_widget_show(button);
+    tree_buttons->button_remove = button;
+
+    gtk_object_set_user_data(GTK_OBJECT(root), (gpointer)tree_buttons);
+}
+
+void main(int argc, char** argv) {
+    GtkWidget* window, *notebook;
+    GtkWidget* box1;
+    GtkWidget* separator;
+    GtkWidget* button;
+
+    gtk_init (&argc, &argv);
+
+    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_title(GTK_WINDOW(window), "Test Tree");
+    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+                        (GtkSignalFunc) cb_delete_event, NULL);
+    gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                        (GtkSignalFunc) cb_destroy_event, NULL);
+    box1 = gtk_vbox_new(FALSE, 0);
+    gtk_container_add(GTK_CONTAINER(window), box1);
+    gtk_widget_show(box1);
+
+    /* create notebook */
+    notebook = gtk_notebook_new ();
+    gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
+    gtk_box_pack_start (GTK_BOX (box1), notebook, TRUE, TRUE, 0);
+    gtk_widget_show (notebook);
+
+    /* create unique selection page */
+    create_tree_page(notebook, GTK_SELECTION_SINGLE, "Single");
+    create_tree_page(notebook, GTK_SELECTION_BROWSE, "Browse");
+    create_tree_page(notebook, GTK_SELECTION_MULTIPLE, "Multiple");
+
+    separator = gtk_hseparator_new();
+    gtk_box_pack_start(GTK_BOX (box1), separator, TRUE, TRUE, 0);
+    gtk_widget_show (separator);
+
+    button = gtk_button_new_with_label("Close");
+    gtk_box_pack_start(GTK_BOX (box1), button, TRUE, TRUE, 0);
+    gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
+                             (GtkSignalFunc)gtk_widget_destroy, 
+                             GTK_OBJECT(window));
+    gtk_widget_show(button);
+
+    gtk_widget_show(window);
+
+    gtk_main();
+}
diff --git a/gtk/tree_minus.xbm b/gtk/tree_minus.xbm
new file mode 100644 (file)
index 0000000..0290a34
--- /dev/null
@@ -0,0 +1,5 @@
+#define tree_minus_width 9
+#define tree_minus_height 9
+static char tree_minus_bits[] = {
+ 0xff,0xff,0x01,0xff,0x01,0xff,0x01,0xff,0x7d,0xff,0x01,0xff,0x01,0xff,0x01,
+ 0xff,0xff,0xff};
diff --git a/gtk/tree_minus.xpm b/gtk/tree_minus.xpm
new file mode 100644 (file)
index 0000000..cce0679
--- /dev/null
@@ -0,0 +1,18 @@
+/* XPM */
+static char *tree_minus[] = {
+/* width height num_colors chars_per_pixel */
+"     9     9        2            1",
+/* colors */
+". c #000000",
+"# c #f8fcf8",
+/* pixels */
+".........",
+".#######.",
+".#######.",
+".#######.",
+".#.....#.",
+".#######.",
+".#######.",
+".#######.",
+"........."
+};
diff --git a/gtk/tree_plus.xbm b/gtk/tree_plus.xbm
new file mode 100644 (file)
index 0000000..e512116
--- /dev/null
@@ -0,0 +1,5 @@
+#define tree_plus_width 9
+#define tree_plus_height 9
+static char tree_plus_bits[] = {
+ 0xff,0xff,0x01,0xff,0x11,0xff,0x11,0xff,0x7d,0xff,0x11,0xff,0x11,0xff,0x01,
+ 0xff,0xff,0xff};
diff --git a/gtk/tree_plus.xpm b/gtk/tree_plus.xpm
new file mode 100644 (file)
index 0000000..d0ba80c
--- /dev/null
@@ -0,0 +1,18 @@
+/* XPM */
+static char *tree_plus[] = {
+/* width height num_colors chars_per_pixel */
+"     9     9        2            1",
+/* colors */
+". c #000000",
+"# c #f8fcf8",
+/* pixels */
+".........",
+".#######.",
+".###.###.",
+".###.###.",
+".#.....#.",
+".###.###.",
+".###.###.",
+".#######.",
+"........."
+};