summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
authorShawn Amundson <amundson@src.gnome.org>1997-12-17 23:41:42 +0000
committerShawn Amundson <amundson@src.gnome.org>1997-12-17 23:41:42 +0000
commit4de2665e8c3fc46afff354537d0d7b4566e5fcfe (patch)
tree13ae28c4e7170440c037e1a32d43506c66c2e7f3 /gtk
parent865eab2445848f79cab42eb0872efa383937cf35 (diff)
downloadgtk+-4de2665e8c3fc46afff354537d0d7b4566e5fcfe.tar.gz
Tree widget implementation by Bolliet Jerome.
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
Diffstat (limited to 'gtk')
-rw-r--r--gtk/.cvsignore1
-rw-r--r--gtk/Makefile.am17
-rw-r--r--gtk/Makefile.in32
-rw-r--r--gtk/gtktree.c956
-rw-r--r--gtk/gtktree.h64
-rw-r--r--gtk/gtktreeitem.c792
-rw-r--r--gtk/gtktreeitem.h7
-rw-r--r--gtk/testtree.c231
-rw-r--r--gtk/tree_minus.xbm5
-rw-r--r--gtk/tree_minus.xpm18
-rw-r--r--gtk/tree_plus.xbm5
-rw-r--r--gtk/tree_plus.xpm18
12 files changed, 2125 insertions, 21 deletions
diff --git a/gtk/.cvsignore b/gtk/.cvsignore
index 1c5ab9a779..236d5e0899 100644
--- a/gtk/.cvsignore
+++ b/gtk/.cvsignore
@@ -8,3 +8,4 @@ testgtk
testinput
testselection
simple
+testtree
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 41b6625620..b69b69c65d 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -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
diff --git a/gtk/Makefile.in b/gtk/Makefile.in
index 0b637de158..274871b58c 100644
--- a/gtk/Makefile.in
+++ b/gtk/Makefile.in
@@ -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)
diff --git a/gtk/gtktree.c b/gtk/gtktree.c
index f3981ea0a0..a6589acf42 100644
--- a/gtk/gtktree.c
+++ b/gtk/gtktree.c
@@ -16,11 +16,63 @@
* 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;
}
diff --git a/gtk/gtktree.h b/gtk/gtktree.h
index 1486a82ab8..2dc5ece1b3 100644
--- a/gtk/gtktree.h
+++ b/gtk/gtktree.h
@@ -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 */
diff --git a/gtk/gtktreeitem.c b/gtk/gtktreeitem.c
index 8f0d9f078d..ecff341f89 100644
--- a/gtk/gtktreeitem.c
+++ b/gtk/gtktreeitem.c
@@ -16,12 +16,74 @@
* 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);
}
diff --git a/gtk/gtktreeitem.h b/gtk/gtktreeitem.h
index 921f681bc3..6affddd3dc 100644
--- a/gtk/gtktreeitem.h
+++ b/gtk/gtktreeitem.h
@@ -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
index 0000000000..547de5d076
--- /dev/null
+++ b/gtk/testtree.c
@@ -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
index 0000000000..0290a34b6e
--- /dev/null
+++ b/gtk/tree_minus.xbm
@@ -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
index 0000000000..cce0679102
--- /dev/null
+++ b/gtk/tree_minus.xpm
@@ -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
index 0000000000..e512116d82
--- /dev/null
+++ b/gtk/tree_plus.xbm
@@ -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
index 0000000000..d0ba80ca25
--- /dev/null
+++ b/gtk/tree_plus.xpm
@@ -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 */
+".........",
+".#######.",
+".###.###.",
+".###.###.",
+".#.....#.",
+".###.###.",
+".###.###.",
+".#######.",
+"........."
+};