diff options
author | Shawn Amundson <amundson@src.gnome.org> | 1997-12-17 23:41:42 +0000 |
---|---|---|
committer | Shawn Amundson <amundson@src.gnome.org> | 1997-12-17 23:41:42 +0000 |
commit | 4de2665e8c3fc46afff354537d0d7b4566e5fcfe (patch) | |
tree | 13ae28c4e7170440c037e1a32d43506c66c2e7f3 /gtk | |
parent | 865eab2445848f79cab42eb0872efa383937cf35 (diff) | |
download | gtk+-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/.cvsignore | 1 | ||||
-rw-r--r-- | gtk/Makefile.am | 17 | ||||
-rw-r--r-- | gtk/Makefile.in | 32 | ||||
-rw-r--r-- | gtk/gtktree.c | 956 | ||||
-rw-r--r-- | gtk/gtktree.h | 64 | ||||
-rw-r--r-- | gtk/gtktreeitem.c | 792 | ||||
-rw-r--r-- | gtk/gtktreeitem.h | 7 | ||||
-rw-r--r-- | gtk/testtree.c | 231 | ||||
-rw-r--r-- | gtk/tree_minus.xbm | 5 | ||||
-rw-r--r-- | gtk/tree_minus.xpm | 18 | ||||
-rw-r--r-- | gtk/tree_plus.xbm | 5 | ||||
-rw-r--r-- | gtk/tree_plus.xpm | 18 |
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 */ +".........", +".#######.", +".###.###.", +".###.###.", +".#.....#.", +".###.###.", +".###.###.", +".#######.", +"........." +}; |