talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

commit 68fd42c359a98575690b67dc3f4a7189aa92eb94
parent 486232b510920329e379d0c8bbffac1175524b88
Author: Colin Leroy <colin@colino.net>
Date:   Tue,  5 Aug 2008 06:37:13 +0000

2008-08-05 [colin]	3.5.0cvs49

	* src/prefs_account.c
	* src/prefs_filtering_action.c
	* src/prefs_matcher.c
	* src/gtk/Makefile.am
	* src/gtk/claws-marshal.list
	* src/gtk/colorlabel.c
	* src/gtk/colorsel.c
	* src/gtk/foldersort.c
	* src/gtk/gtkaspell.c
	* src/gtk/gtkcmclist.c
	* src/gtk/gtkcmclist.h
	* src/gtk/gtkcmctree.c
	* src/gtk/gtkcmctree.h
	* src/gtk/gtkcmoptionmenu.c
	* src/gtk/gtkcmoptionmenu.h
	* src/gtk/gtksctree.c
	* src/gtk/gtksctree.h
	* src/gtk/gtkutils.c
	* src/gtk/gtkutils.h
	* src/gtk/gtkvscrollbutton.c
	* src/gtk/menu.c
	* src/gtk/menu.h
	* src/gtk/quicksearch.c
	* src/plugins/dillo_viewer/dillo_viewer.c
	* src/plugins/pgpcore/select-keys.c
		Try to finish yesterday's commit

Diffstat:
MChangeLog | 29+++++++++++++++++++++++++++++
MPATCHSETS | 1+
Mconfigure.ac | 10+++++++++-
Msrc/gtk/Makefile.am | 8++++++--
Msrc/gtk/claws-marshal.list | 11+++++++++++
Msrc/gtk/colorlabel.c | 2+-
Msrc/gtk/colorsel.c | 1+
Msrc/gtk/foldersort.c | 26+++++++++++++-------------
Msrc/gtk/gtkaspell.c | 10+++-------
Asrc/gtk/gtkcmclist.c | 7842+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/gtk/gtkcmclist.h | 789+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/gtk/gtkcmctree.c | 6198+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/gtk/gtkcmctree.h | 450+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/gtk/gtkcmoptionmenu.c | 1025+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/gtk/gtkcmoptionmenu.h | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/gtk/gtksctree.c | 1134++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/gtk/gtksctree.h | 45+++++++++++++++++++++++----------------------
Msrc/gtk/gtkutils.c | 105++++++++++++++++++++++++++++++++++++++-----------------------------------------
Msrc/gtk/gtkutils.h | 59+++++++++++++++++++++++++----------------------------------
Msrc/gtk/gtkvscrollbutton.c | 32++++++++++++++++++--------------
Msrc/gtk/menu.c | 7+++++--
Msrc/gtk/menu.h | 7++++---
Msrc/gtk/quicksearch.c | 11++++++-----
Msrc/plugins/dillo_viewer/dillo_viewer.c | 4++--
Msrc/plugins/pgpcore/select-keys.c | 62+++++++++++++++++++++++++++++++-------------------------------
Msrc/prefs_account.c | 14+++++++-------
Msrc/prefs_filtering_action.c | 15++++++++-------
Msrc/prefs_matcher.c | 17+++++++++--------
28 files changed, 17219 insertions(+), 781 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,32 @@ +2008-08-05 [colin] 3.5.0cvs49 + + * src/prefs_account.c + * src/prefs_filtering_action.c + * src/prefs_matcher.c + * src/gtk/Makefile.am + * src/gtk/claws-marshal.list + * src/gtk/colorlabel.c + * src/gtk/colorsel.c + * src/gtk/foldersort.c + * src/gtk/gtkaspell.c + * src/gtk/gtkcmclist.c + * src/gtk/gtkcmclist.h + * src/gtk/gtkcmctree.c + * src/gtk/gtkcmctree.h + * src/gtk/gtkcmoptionmenu.c + * src/gtk/gtkcmoptionmenu.h + * src/gtk/gtksctree.c + * src/gtk/gtksctree.h + * src/gtk/gtkutils.c + * src/gtk/gtkutils.h + * src/gtk/gtkvscrollbutton.c + * src/gtk/menu.c + * src/gtk/menu.h + * src/gtk/quicksearch.c + * src/plugins/dillo_viewer/dillo_viewer.c + * src/plugins/pgpcore/select-keys.c + Try to finish yesterday's commit + 2008-08-04 [colin] 3.5.0cvs48 * src/addressadd.c diff --git a/PATCHSETS b/PATCHSETS @@ -3460,3 +3460,4 @@ ( cvs diff -u -r 1.274.2.261 -r 1.274.2.262 src/mainwindow.c; ) > 3.5.0cvs46.patchset ( cvs diff -u -r 1.382.2.462 -r 1.382.2.463 src/compose.c; cvs diff -u -r 1.50.2.48 -r 1.50.2.49 src/compose.h; cvs diff -u -r 1.19.2.27 -r 1.19.2.28 src/toolbar.h; cvs diff -u -r 1.96.2.203 -r 1.96.2.204 src/textview.c; cvs diff -u -r 1.25.2.58 -r 1.25.2.59 src/stock_pixmap.c; cvs diff -u -r 1.5.2.21 -r 1.5.2.22 src/statusbar.c; cvs diff -u -r 1.3.8.8 -r 1.3.8.9 src/noticeview.h; cvs diff -u -r 1.20.2.25 -r 1.20.2.26 src/mimeview.h; cvs diff -u -r 1.274.2.262 -r 1.274.2.263 src/mainwindow.c; cvs diff -u -r 1.1.2.22 -r 1.1.2.23 src/image_viewer.c; cvs diff -u -r 1.9.2.57 -r 1.9.2.58 src/gtk/gtkaspell.c; cvs diff -u -r 1.5.2.13 -r 1.5.2.14 src/gtk/gtkvscrollbutton.c; cvs diff -u -r 1.12.2.26 -r 1.12.2.27 src/plugins/dillo_viewer/dillo_viewer.c; ) > 3.5.0cvs47.patchset ( cvs diff -u -r 1.9.2.23 -r 1.9.2.24 src/addressadd.c; cvs diff -u -r 1.60.2.122 -r 1.60.2.123 src/addressbook.c; cvs diff -u -r 1.1.2.11 -r 1.1.2.12 src/addressbook_foldersel.c; cvs diff -u -r 1.5.2.10 -r 1.5.2.11 src/addressitem.h; cvs diff -u -r 1.5.10.24 -r 1.5.10.25 src/addrgather.c; cvs diff -u -r 1.2.4.20 -r 1.2.4.21 src/browseldap.c; cvs diff -u -r 1.382.2.462 -r 1.382.2.463 src/compose.c; cvs diff -u -r 1.50.2.48 -r 1.50.2.49 src/compose.h; cvs diff -u -r 1.14.2.51 -r 1.14.2.52 src/editaddress.c; cvs diff -u -r 1.1.2.6 -r 1.1.2.7 src/editaddress_other_attributes_ldap.c; cvs diff -u -r 1.11.2.19 -r 1.11.2.20 src/editgroup.c; cvs diff -u -r 1.10.2.13 -r 1.10.2.14 src/editldap_basedn.c; cvs diff -u -r 1.207.2.204 -r 1.207.2.205 src/folderview.c; cvs diff -u -r 1.20.2.23 -r 1.20.2.24 src/folderview.h; cvs diff -u -r 1.14.2.20 -r 1.14.2.21 src/grouplistdialog.c; cvs diff -u -r 1.1.2.22 -r 1.1.2.23 src/image_viewer.c; cvs diff -u -r 1.1.2.60 -r 1.1.2.61 src/imap_gtk.c; cvs diff -u -r 1.14.2.18 -r 1.14.2.19 src/importldif.c; cvs diff -u -r 1.115.2.200 -r 1.115.2.201 src/main.c; cvs diff -u -r 1.274.2.262 -r 1.274.2.263 src/mainwindow.c; cvs diff -u -r 1.3.12.30 -r 1.3.12.31 src/message_search.c; cvs diff -u -r 1.2.2.33 -r 1.2.2.34 src/mh_gtk.c; cvs diff -u -r 1.83.2.138 -r 1.83.2.139 src/mimeview.c; cvs diff -u -r 1.20.2.25 -r 1.20.2.26 src/mimeview.h; cvs diff -u -r 1.2.2.28 -r 1.2.2.29 src/news_gtk.c; cvs diff -u -r 1.3.8.8 -r 1.3.8.9 src/noticeview.h; cvs diff -u -r 1.105.2.139 -r 1.105.2.140 src/prefs_account.c; cvs diff -u -r 1.1.4.53 -r 1.1.4.54 src/prefs_filtering_action.c; cvs diff -u -r 1.43.2.73 -r 1.43.2.74 src/prefs_matcher.c; cvs diff -u -r 1.1.2.37 -r 1.1.2.38 src/prefs_msg_colors.c; cvs diff -u -r 1.1.2.56 -r 1.1.2.57 src/prefs_summaries.c; cvs diff -u -r 1.5.2.21 -r 1.5.2.22 src/statusbar.c; cvs diff -u -r 1.25.2.58 -r 1.25.2.59 src/stock_pixmap.c; cvs diff -u -r 1.15.2.54 -r 1.15.2.55 src/summary_search.c; cvs diff -u -r 1.395.2.379 -r 1.395.2.380 src/summaryview.c; cvs diff -u -r 1.68.2.48 -r 1.68.2.49 src/summaryview.h; cvs diff -u -r 1.96.2.203 -r 1.96.2.204 src/textview.c; cvs diff -u -r 1.19.2.27 -r 1.19.2.28 src/toolbar.h; cvs diff -u -r 1.20.2.16 -r 1.20.2.17 src/gtk/Makefile.am; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/gtk/claws-marshal.list; cvs diff -u -r 1.1.4.11 -r 1.1.4.12 src/gtk/colorsel.c; cvs diff -u -r 1.1.2.16 -r 1.1.2.17 src/gtk/foldersort.c; cvs diff -u -r 1.9.2.57 -r 1.9.2.58 src/gtk/gtkaspell.c; diff -u /dev/null src/gtk/gtkcmclist.c; diff -u /dev/null src/gtk/gtkcmclist.h; diff -u /dev/null src/gtk/gtkcmctree.c; diff -u /dev/null src/gtk/gtkcmctree.h; cvs diff -u -r 1.1.4.46 -r 1.1.4.47 src/gtk/gtksctree.c; cvs diff -u -r 1.1.4.13 -r 1.1.4.14 src/gtk/gtksctree.h; cvs diff -u -r 1.5.2.78 -r 1.5.2.79 src/gtk/gtkutils.c; cvs diff -u -r 1.4.2.42 -r 1.4.2.43 src/gtk/gtkutils.h; cvs diff -u -r 1.5.2.13 -r 1.5.2.14 src/gtk/gtkvscrollbutton.c; cvs diff -u -r 1.5.2.34 -r 1.5.2.35 src/gtk/menu.c; cvs diff -u -r 1.4.2.19 -r 1.4.2.20 src/gtk/menu.h; cvs diff -u -r 1.1.2.83 -r 1.1.2.84 src/gtk/quicksearch.c; cvs diff -u -r 1.12.2.26 -r 1.12.2.27 src/plugins/dillo_viewer/dillo_viewer.c; cvs diff -u -r 1.1.2.20 -r 1.1.2.21 src/plugins/pgpcore/select-keys.c; ) > 3.5.0cvs48.patchset +( cvs diff -u -r 1.105.2.140 -r 1.105.2.141 src/prefs_account.c; cvs diff -u -r 1.1.4.54 -r 1.1.4.55 src/prefs_filtering_action.c; cvs diff -u -r 1.43.2.74 -r 1.43.2.75 src/prefs_matcher.c; cvs diff -u -r 1.20.2.16 -r 1.20.2.17 src/gtk/Makefile.am; cvs diff -u -r 1.1.2.1 -r 1.1.2.2 src/gtk/claws-marshal.list; cvs diff -u -r 1.2.2.21 -r 1.2.2.22 src/gtk/colorlabel.c; cvs diff -u -r 1.1.4.11 -r 1.1.4.12 src/gtk/colorsel.c; cvs diff -u -r 1.1.2.16 -r 1.1.2.17 src/gtk/foldersort.c; cvs diff -u -r 1.9.2.57 -r 1.9.2.58 src/gtk/gtkaspell.c; diff -u /dev/null src/gtk/gtkcmclist.c; diff -u /dev/null src/gtk/gtkcmclist.h; diff -u /dev/null src/gtk/gtkcmctree.c; diff -u /dev/null src/gtk/gtkcmctree.h; diff -u /dev/null src/gtk/gtkcmoptionmenu.c; diff -u /dev/null src/gtk/gtkcmoptionmenu.h; cvs diff -u -r 1.1.4.46 -r 1.1.4.47 src/gtk/gtksctree.c; cvs diff -u -r 1.1.4.13 -r 1.1.4.14 src/gtk/gtksctree.h; cvs diff -u -r 1.5.2.78 -r 1.5.2.79 src/gtk/gtkutils.c; cvs diff -u -r 1.4.2.42 -r 1.4.2.43 src/gtk/gtkutils.h; cvs diff -u -r 1.5.2.13 -r 1.5.2.14 src/gtk/gtkvscrollbutton.c; cvs diff -u -r 1.5.2.34 -r 1.5.2.35 src/gtk/menu.c; cvs diff -u -r 1.4.2.19 -r 1.4.2.20 src/gtk/menu.h; cvs diff -u -r 1.1.2.83 -r 1.1.2.84 src/gtk/quicksearch.c; cvs diff -u -r 1.12.2.26 -r 1.12.2.27 src/plugins/dillo_viewer/dillo_viewer.c; cvs diff -u -r 1.1.2.20 -r 1.1.2.21 src/plugins/pgpcore/select-keys.c; ) > 3.5.0cvs49.patchset diff --git a/configure.ac b/configure.ac @@ -11,7 +11,7 @@ MINOR_VERSION=5 MICRO_VERSION=0 INTERFACE_AGE=0 BINARY_AGE=0 -EXTRA_VERSION=48 +EXTRA_VERSION=49 EXTRA_RELEASE= EXTRA_GTK2_VERSION= @@ -142,11 +142,19 @@ then fi CFLAGS="$CFLAGS -Wall" +<<<<<<< configure.ac + +if test $USE_MAINTAINER_MODE = yes; then + CFLAGS="$CFLAGS -DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED" +fi + +======= if test $USE_MAINTAINER_MODE = yes; then CFLAGS="$CFLAGS -DGTK_DISABLE_DEPRECATED" fi +>>>>>>> 1.654.2.3521 pthread_name= case "$target" in *-darwin*) diff --git a/src/gtk/Makefile.am b/src/gtk/Makefile.am @@ -15,7 +15,9 @@ libclawsgtk_la_SOURCES = \ filesel.c \ foldersort.c \ gtkaspell.c \ - gtksctree.c \ + gtkcmctree.c \ + gtkcmclist.c \ + gtkcmoptionmenu.c \ gtkshruler.c \ gtksctree.c \ gtksourceprintjob.c \ @@ -44,9 +46,11 @@ clawsgtkinclude_HEADERS = \ filesel.h \ foldersort.h \ gtkaspell.h \ + gtkcmctree.h \ + gtkcmclist.h \ + gtkcmoptionmenu.h \ gtksctree.h \ gtkshruler.h \ - gtksctree.h \ gtksourceprintjob.h \ gtkutils.h \ gtkvscrollbutton.h \ diff --git a/src/gtk/claws-marshal.list b/src/gtk/claws-marshal.list @@ -1,2 +1,13 @@ NONE:POINTER NONE:INT,POINTER +NONE:OBJECT,OBJECT +NONE:INT,INT,BOXED +NONE:INT,INT +NONE:INT +NONE:VOID +NONE:VOID,VOID +NONE:ENUM,FLOAT,BOOLEAN +NONE:ENUM,FLOAT +NONE:POINTER,INT +NONE:POINTER,POINTER,POINTER +NONE:ENUM diff --git a/src/gtk/colorlabel.c b/src/gtk/colorlabel.c @@ -218,7 +218,7 @@ static gboolean colorlabel_drawing_area_expose_event_cb TRUE, 1, 1, widget->allocation.width - 2, widget->allocation.height - 2); - gdk_gc_unref(gc); + g_object_unref(gc); return FALSE; } diff --git a/src/gtk/colorsel.c b/src/gtk/colorsel.c @@ -17,6 +17,7 @@ * */ +#undef GTK_DISABLE_DEPRECATED /* FIXME set_color */ #include <gtk/gtk.h> #include <gdk/gdkkeysyms.h> diff --git a/src/gtk/foldersort.c b/src/gtk/foldersort.c @@ -53,7 +53,7 @@ static void ok_clicked(GtkWidget *widget, FolderSortDialog *dialog) int i; for (i = 0; i < dialog->rows; i++) { - folder = gtk_clist_get_row_data(GTK_CLIST(dialog->folderlist), i); + folder = gtk_cmclist_get_row_data(GTK_CMCLIST(dialog->folderlist), i); folder_set_sort(folder, dialog->rows - i); } @@ -83,27 +83,27 @@ static void moveup_clicked(GtkWidget *widget, FolderSortDialog *dialog) { g_return_if_fail(dialog->selected > 0); - gtk_clist_swap_rows(GTK_CLIST(dialog->folderlist), dialog->selected, dialog->selected - 1); + gtk_cmclist_swap_rows(GTK_CMCLIST(dialog->folderlist), dialog->selected, dialog->selected - 1); } static void movedown_clicked(GtkWidget *widget, FolderSortDialog *dialog) { g_return_if_fail(dialog->selected < (dialog->rows - 1)); - gtk_clist_swap_rows(GTK_CLIST(dialog->folderlist), dialog->selected, dialog->selected + 1); + gtk_cmclist_swap_rows(GTK_CMCLIST(dialog->folderlist), dialog->selected, dialog->selected + 1); } -static void row_selected(GtkCList *clist, gint row, gint column, GdkEventButton *event, FolderSortDialog *dialog) +static void row_selected(GtkCMCList *clist, gint row, gint column, GdkEventButton *event, FolderSortDialog *dialog) { set_selected(dialog, row); } -static void row_unselected(GtkCList *clist, gint row, gint column, GdkEventButton *event, FolderSortDialog *dialog) +static void row_unselected(GtkCMCList *clist, gint row, gint column, GdkEventButton *event, FolderSortDialog *dialog) { set_selected(dialog, -1); } -static void row_moved(GtkCList *clist, gint srcpos, gint destpos, FolderSortDialog *dialog) +static void row_moved(GtkCMCList *clist, gint srcpos, gint destpos, FolderSortDialog *dialog) { if (dialog->selected == -1) return; @@ -207,15 +207,15 @@ void foldersort_open() GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - folderlist = gtk_clist_new(1); + folderlist = gtk_cmclist_new(1); gtk_widget_show(folderlist); gtk_container_add(GTK_CONTAINER(scrolledwindow1), folderlist); - gtk_clist_set_column_width(GTK_CLIST(folderlist), 0, 80); - gtk_clist_column_titles_show(GTK_CLIST(folderlist)); + gtk_cmclist_set_column_width(GTK_CMCLIST(folderlist), 0, 80); + gtk_cmclist_column_titles_show(GTK_CMCLIST(folderlist)); label2 = gtk_label_new(_("Folders")); gtk_widget_show(label2); - gtk_clist_set_column_widget(GTK_CLIST(folderlist), 0, label2); + gtk_cmclist_set_column_widget(GTK_CMCLIST(folderlist), 0, label2); gtk_label_set_justify(GTK_LABEL(label2), GTK_JUSTIFY_LEFT); gtk_misc_set_alignment(GTK_MISC(label2), 0, 0.5); @@ -239,7 +239,7 @@ void foldersort_open() gtk_widget_show(window); gtk_widget_set_sensitive(moveup_btn, FALSE); gtk_widget_set_sensitive(movedown_btn, FALSE); - gtk_clist_set_reorderable(GTK_CLIST(folderlist), TRUE); + gtk_cmclist_set_reorderable(GTK_CMCLIST(folderlist), TRUE); g_signal_connect(G_OBJECT(moveup_btn), "clicked", G_CALLBACK(moveup_clicked), dialog); @@ -261,8 +261,8 @@ void foldersort_open() gchar *text[1]; text[0] = folder->name; - row = gtk_clist_append(GTK_CLIST(folderlist), text); - gtk_clist_set_row_data(GTK_CLIST(folderlist), row, folder); + row = gtk_cmclist_append(GTK_CMCLIST(folderlist), text); + gtk_cmclist_set_row_data(GTK_CMCLIST(folderlist), row, folder); dialog->rows++; } diff --git a/src/gtk/gtkaspell.c b/src/gtk/gtkaspell.c @@ -1536,7 +1536,7 @@ static void replace_with_create_dialog_cb(GtkWidget *w, gpointer data) gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); gtk_window_set_title(GTK_WINDOW(dialog),_("Replace unknown word")); gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); - gtk_widget_set_uposition(dialog, xx, yy); + gtk_window_move(GTK_WINDOW(dialog), xx, yy); g_signal_connect_swapped(G_OBJECT(dialog), "destroy", G_CALLBACK(gtk_widget_destroy), @@ -2274,18 +2274,14 @@ static void set_menu_pos(GtkMenu *menu, gint *x, gint *y, wx = r.width; wy = r.height; - *x = rect.x + xx + - gdk_char_width(gtk_style_get_font(GTK_WIDGET(text)->style), ' '); + *x = rect.x + xx + 8; *y = rect.y + rect.height + yy; if (*x + wx > sx) *x = sx - wx; if (*y + wy > sy) - *y = *y - wy - - gdk_string_height(gtk_style_get_font( - GTK_WIDGET(text)->style), - gtkaspell->theword); + *y = *y - wy - 10; } /* change the current dictionary of gtkaspell diff --git a/src/gtk/gtkcmclist.c b/src/gtk/gtkcmclist.c @@ -0,0 +1,7842 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald, + * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include <config.h> + +#include <stdlib.h> +#include <string.h> + +#include <gtk/gtk.h> +#include "claws-marshal.h" +#include "gtkcmclist.h" +#include <gdk/gdkkeysyms.h> + +/* length of button_actions array */ +#define MAX_BUTTON 5 + +/* the width of the column resize windows */ +#define DRAG_WIDTH 6 + +/* minimum allowed width of a column */ +#define COLUMN_MIN_WIDTH 5 + +/* this defigns the base grid spacing */ +#define CELL_SPACING 1 + +/* added the horizontal space at the beginning and end of a row*/ +#define COLUMN_INSET 3 + +/* used for auto-scrolling */ +#define SCROLL_TIME 100 + +/* gives the top pixel of the given row in context of + * the clist's voffset */ +#define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \ + (((row) + 1) * CELL_SPACING) + \ + (clist)->voffset) + +/* returns the row index from a y pixel location in the + * context of the clist's voffset */ +#define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \ + ((clist)->row_height + CELL_SPACING)) + +/* gives the left pixel of the given column in context of + * the clist's hoffset */ +#define COLUMN_LEFT_XPIXEL(clist, colnum) ((clist)->column[(colnum)].area.x + \ + (clist)->hoffset) + +/* returns the column index from a x pixel location in the + * context of the clist's hoffset */ +static inline gint +COLUMN_FROM_XPIXEL (GtkCMCList * clist, + gint x) +{ + gint i, cx; + + for (i = 0; i < clist->columns; i++) + if (clist->column[i].visible) + { + cx = clist->column[i].area.x + clist->hoffset; + + if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) && + x <= (cx + clist->column[i].area.width + COLUMN_INSET)) + return i; + } + + /* no match */ + return -1; +} + +/* returns the top pixel of the given row in the context of + * the list height */ +#define ROW_TOP(clist, row) (((clist)->row_height + CELL_SPACING) * (row)) + +/* returns the left pixel of the given column in the context of + * the list width */ +#define COLUMN_LEFT(clist, colnum) ((clist)->column[(colnum)].area.x) + +/* returns the total height of the list */ +#define LIST_HEIGHT(clist) (((clist)->row_height * ((clist)->rows)) + \ + (CELL_SPACING * ((clist)->rows + 1))) + + +/* returns the total width of the list */ +static inline gint +LIST_WIDTH (GtkCMCList * clist) +{ + gint last_column; + + for (last_column = clist->columns - 1; + last_column >= 0 && !clist->column[last_column].visible; last_column--); + + if (last_column >= 0) + return (clist->column[last_column].area.x + + clist->column[last_column].area.width + + COLUMN_INSET + CELL_SPACING); + return 0; +} + +/* returns the GList item for the nth row */ +#define ROW_ELEMENT(clist, row) (((row) == (clist)->rows - 1) ? \ + (clist)->row_list_end : \ + g_list_nth ((clist)->row_list, (row))) + + +/* redraw the list if it's not frozen */ +#define CLIST_UNFROZEN(clist) (((GtkCMCList*) (clist))->freeze_count == 0) +#define CLIST_REFRESH(clist) G_STMT_START { \ + if (CLIST_UNFROZEN (clist)) \ + GTK_CMCLIST_GET_CLASS (clist)->refresh ((GtkCMCList*) (clist)); \ +} G_STMT_END + + +/* Signals */ +enum { + SELECT_ROW, + UNSELECT_ROW, + ROW_MOVE, + CLICK_COLUMN, + RESIZE_COLUMN, + TOGGLE_FOCUS_ROW, + SELECT_ALL, + UNSELECT_ALL, + UNDO_SELECTION, + START_SELECTION, + END_SELECTION, + TOGGLE_ADD_MODE, + EXTEND_SELECTION, + SCROLL_VERTICAL, + SCROLL_HORIZONTAL, + ABORT_COLUMN_RESIZE, + LAST_SIGNAL +}; + +enum { + SYNC_REMOVE, + SYNC_INSERT +}; + +enum { + ARG_0, + ARG_N_COLUMNS, + ARG_SHADOW_TYPE, + ARG_SELECTION_MODE, + ARG_ROW_HEIGHT, + ARG_TITLES_ACTIVE, + ARG_REORDERABLE, + ARG_USE_DRAG_ICONS, + ARG_SORT_TYPE +}; + +/* GtkCMCList Methods */ +static void gtk_cmclist_class_init (GtkCMCListClass *klass); +static void gtk_cmclist_init (GtkCMCList *clist); +static GObject* gtk_cmclist_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_params); + +/* GtkObject Methods */ +static void gtk_cmclist_destroy (GtkObject *object); +static void gtk_cmclist_finalize (GObject *object); +static void gtk_cmclist_set_arg (GObject *object, + guint arg_id, + const GValue *value, + GParamSpec *spec); +static void gtk_cmclist_get_arg (GObject *object, + guint arg_id, + GValue *value, + GParamSpec *spec); + +/* GtkWidget Methods */ +static void gtk_cmclist_set_scroll_adjustments (GtkCMCList *clist, + GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment); +static void gtk_cmclist_realize (GtkWidget *widget); +static void gtk_cmclist_unrealize (GtkWidget *widget); +static void gtk_cmclist_map (GtkWidget *widget); +static void gtk_cmclist_unmap (GtkWidget *widget); +static gint gtk_cmclist_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_cmclist_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_cmclist_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_cmclist_motion (GtkWidget *widget, + GdkEventMotion *event); +static void gtk_cmclist_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_cmclist_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_cmclist_draw_focus (GtkWidget *widget); +static gint gtk_cmclist_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_cmclist_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_cmclist_focus (GtkWidget *widget, + GtkDirectionType direction); +static void gtk_cmclist_set_focus_child (GtkContainer *container, + GtkWidget *child); +static void gtk_cmclist_style_set (GtkWidget *widget, + GtkStyle *previous_style); +static void gtk_cmclist_drag_begin (GtkWidget *widget, + GdkDragContext *context); +static gint gtk_cmclist_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time); +static void gtk_cmclist_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time); +static void gtk_cmclist_drag_end (GtkWidget *widget, + GdkDragContext *context); +static gboolean gtk_cmclist_drag_drop (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time); +static void gtk_cmclist_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time); +static void gtk_cmclist_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time); + +/* GtkContainer Methods */ +static void gtk_cmclist_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); + +/* Selection */ +static void toggle_row (GtkCMCList *clist, + gint row, + gint column, + GdkEvent *event); +static void real_select_row (GtkCMCList *clist, + gint row, + gint column, + GdkEvent *event); +static void real_unselect_row (GtkCMCList *clist, + gint row, + gint column, + GdkEvent *event); +static void update_extended_selection (GtkCMCList *clist, + gint row); +static GList *selection_find (GtkCMCList *clist, + gint row_number, + GList *row_list_element); +static void real_select_all (GtkCMCList *clist); +static void real_unselect_all (GtkCMCList *clist); +static void move_vertical (GtkCMCList *clist, + gint row, + gfloat align); +static void move_horizontal (GtkCMCList *clist, + gint diff); +static void real_undo_selection (GtkCMCList *clist); +static void fake_unselect_all (GtkCMCList *clist, + gint row); +static void fake_toggle_row (GtkCMCList *clist, + gint row); +static void resync_selection (GtkCMCList *clist, + GdkEvent *event); +static void sync_selection (GtkCMCList *clist, + gint row, + gint mode); +static void set_anchor (GtkCMCList *clist, + gboolean add_mode, + gint anchor, + gint undo_anchor); +static void start_selection (GtkCMCList *clist); +static void end_selection (GtkCMCList *clist); +static void toggle_add_mode (GtkCMCList *clist); +static void toggle_focus_row (GtkCMCList *clist); +static void extend_selection (GtkCMCList *clist, + GtkScrollType scroll_type, + gfloat position, + gboolean auto_start_selection); +static gint get_selection_info (GtkCMCList *clist, + gint x, + gint y, + gint *row, + gint *column); + +/* Scrolling */ +static void move_focus_row (GtkCMCList *clist, + GtkScrollType scroll_type, + gfloat position); +static void scroll_horizontal (GtkCMCList *clist, + GtkScrollType scroll_type, + gfloat position); +static void scroll_vertical (GtkCMCList *clist, + GtkScrollType scroll_type, + gfloat position); +static void move_horizontal (GtkCMCList *clist, + gint diff); +static void move_vertical (GtkCMCList *clist, + gint row, + gfloat align); +static gint horizontal_timeout (GtkCMCList *clist); +static gint vertical_timeout (GtkCMCList *clist); +static void remove_grab (GtkCMCList *clist); + + +/* Resize Columns */ +static void draw_xor_line (GtkCMCList *clist); +static gint new_column_width (GtkCMCList *clist, + gint column, + gint *x); +static void column_auto_resize (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint column, + gint old_width); +static void real_resize_column (GtkCMCList *clist, + gint column, + gint width); +static void abort_column_resize (GtkCMCList *clist); +static void cell_size_request (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint column, + GtkRequisition *requisition); + +/* Buttons */ +static void column_button_create (GtkCMCList *clist, + gint column); +static void column_button_clicked (GtkWidget *widget, + gpointer data); + +/* Adjustments */ +static void adjust_adjustments (GtkCMCList *clist, + gboolean block_resize); +static void vadjustment_changed (GtkAdjustment *adjustment, + gpointer data); +static void vadjustment_value_changed (GtkAdjustment *adjustment, + gpointer data); +static void hadjustment_changed (GtkAdjustment *adjustment, + gpointer data); +static void hadjustment_value_changed (GtkAdjustment *adjustment, + gpointer data); + +/* Drawing */ +static void get_cell_style (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint state, + gint column, + GtkStyle **style, + GdkGC **fg_gc, + GdkGC **bg_gc); +static gint draw_cell_pixmap (GdkWindow *window, + GdkRectangle *clip_rectangle, + GdkGC *fg_gc, + GdkPixmap *pixmap, + GdkBitmap *mask, + gint x, + gint y, + gint width, + gint height); +static void draw_row (GtkCMCList *clist, + GdkRectangle *area, + gint row, + GtkCMCListRow *clist_row); +static void draw_rows (GtkCMCList *clist, + GdkRectangle *area); +static void clist_refresh (GtkCMCList *clist); +static void draw_drag_highlight (GtkCMCList *clist, + GtkCMCListRow *dest_row, + gint dest_row_number, + GtkCMCListDragPos drag_pos); + +/* Size Allocation / Requisition */ +static void size_allocate_title_buttons (GtkCMCList *clist); +static void size_allocate_columns (GtkCMCList *clist, + gboolean block_resize); +static gint list_requisition_width (GtkCMCList *clist); + +/* Memory Allocation/Distruction Routines */ +static GtkCMCListColumn *columns_new (GtkCMCList *clist); +static void column_title_new (GtkCMCList *clist, + gint column, + const gchar *title); +static void columns_delete (GtkCMCList *clist); +static GtkCMCListRow *row_new (GtkCMCList *clist); +static void row_delete (GtkCMCList *clist, + GtkCMCListRow *clist_row); +static void set_cell_contents (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint column, + GtkCMCellType type, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap, + GdkBitmap *mask); +static gint real_insert_row (GtkCMCList *clist, + gint row, + gchar *text[]); +static void real_remove_row (GtkCMCList *clist, + gint row); +static void real_clear (GtkCMCList *clist); + +/* Sorting */ +static gint default_compare (GtkCMCList *clist, + gconstpointer row1, + gconstpointer row2); +static void real_sort_list (GtkCMCList *clist); +static GList *gtk_cmclist_merge (GtkCMCList *clist, + GList *a, + GList *b); +static GList *gtk_cmclist_mergesort (GtkCMCList *clist, + GList *list, + gint num); +/* Misc */ +static gboolean title_focus_in (GtkCMCList *clist, + gint dir); +static gboolean title_focus_move (GtkCMCList *clist, + gint dir); + +static void real_row_move (GtkCMCList *clist, + gint source_row, + gint dest_row); +static gint column_title_passive_func (GtkWidget *widget, + GdkEvent *event, + gpointer data); +static void drag_dest_cell (GtkCMCList *clist, + gint x, + gint y, + GtkCMCListDestInfo *dest_info); + + + +static GtkContainerClass *parent_class = NULL; +static guint clist_signals[LAST_SIGNAL] = {0}; + +static const GtkTargetEntry clist_target_table = { "gtk-clist-drag-reorder", 0, 0}; + +GType +gtk_cmclist_get_type (void) +{ + static GType clist_type = 0; + + if (!clist_type) + { + static const GTypeInfo clist_info = + { + sizeof (GtkCMCListClass), + + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + + (GClassInitFunc) gtk_cmclist_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + + sizeof (GtkCMCList), + 0, /* n_preallocs */ + (GInstanceInitFunc) gtk_cmclist_init, + }; + clist_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkCMCList", &clist_info, (GTypeFlags)0); + } + + return clist_type; +} + +static void +gtk_cmclist_class_init (GtkCMCListClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkObjectClass *gtk_object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + GtkBindingSet *binding_set; + + object_class->constructor = gtk_cmclist_constructor; + + gtk_object_class = (GtkObjectClass *) klass; + widget_class = (GtkWidgetClass *) klass; + container_class = (GtkContainerClass *) klass; + + parent_class = gtk_type_class (GTK_TYPE_CONTAINER); + + object_class->finalize = gtk_cmclist_finalize; + gtk_object_class->destroy = gtk_cmclist_destroy; + object_class->set_property = gtk_cmclist_set_arg; + object_class->get_property = gtk_cmclist_get_arg; + + + widget_class->realize = gtk_cmclist_realize; + widget_class->unrealize = gtk_cmclist_unrealize; + widget_class->map = gtk_cmclist_map; + widget_class->unmap = gtk_cmclist_unmap; + widget_class->button_press_event = gtk_cmclist_button_press; + widget_class->button_release_event = gtk_cmclist_button_release; + widget_class->motion_notify_event = gtk_cmclist_motion; + widget_class->expose_event = gtk_cmclist_expose; + widget_class->size_request = gtk_cmclist_size_request; + widget_class->size_allocate = gtk_cmclist_size_allocate; + widget_class->focus_in_event = gtk_cmclist_focus_in; + widget_class->focus_out_event = gtk_cmclist_focus_out; + widget_class->style_set = gtk_cmclist_style_set; + widget_class->drag_begin = gtk_cmclist_drag_begin; + widget_class->drag_end = gtk_cmclist_drag_end; + widget_class->drag_motion = gtk_cmclist_drag_motion; + widget_class->drag_leave = gtk_cmclist_drag_leave; + widget_class->drag_drop = gtk_cmclist_drag_drop; + widget_class->drag_data_get = gtk_cmclist_drag_data_get; + widget_class->drag_data_received = gtk_cmclist_drag_data_received; + widget_class->focus = gtk_cmclist_focus; + + /* container_class->add = NULL; use the default GtkContainerClass warning */ + /* container_class->remove=NULL; use the default GtkContainerClass warning */ + + container_class->forall = gtk_cmclist_forall; + container_class->set_focus_child = gtk_cmclist_set_focus_child; + + klass->set_scroll_adjustments = gtk_cmclist_set_scroll_adjustments; + klass->refresh = clist_refresh; + klass->select_row = real_select_row; + klass->unselect_row = real_unselect_row; + klass->row_move = real_row_move; + klass->undo_selection = real_undo_selection; + klass->resync_selection = resync_selection; + klass->selection_find = selection_find; + klass->click_column = NULL; + klass->resize_column = real_resize_column; + klass->draw_row = draw_row; + klass->draw_drag_highlight = draw_drag_highlight; + klass->insert_row = real_insert_row; + klass->remove_row = real_remove_row; + klass->clear = real_clear; + klass->sort_list = real_sort_list; + klass->select_all = real_select_all; + klass->unselect_all = real_unselect_all; + klass->fake_unselect_all = fake_unselect_all; + klass->scroll_horizontal = scroll_horizontal; + klass->scroll_vertical = scroll_vertical; + klass->extend_selection = extend_selection; + klass->toggle_focus_row = toggle_focus_row; + klass->toggle_add_mode = toggle_add_mode; + klass->start_selection = start_selection; + klass->end_selection = end_selection; + klass->abort_column_resize = abort_column_resize; + klass->set_cell_contents = set_cell_contents; + klass->cell_size_request = cell_size_request; + + g_object_class_install_property (object_class, + ARG_N_COLUMNS, + g_param_spec_uint ("n-columns", + "N-Columns", + "N-Columns", + 1, + G_MAXINT, + 1, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + ARG_SHADOW_TYPE, + g_param_spec_enum ("shadow-type", + "shadow-type", + "shadow-type", + GTK_TYPE_SHADOW_TYPE, 0, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + ARG_SELECTION_MODE, + g_param_spec_enum ("selection-mode", + "selection-mode", + "selection-mode", + GTK_TYPE_SELECTION_MODE, 0, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + ARG_ROW_HEIGHT, + g_param_spec_uint ("row-height", + "row-height", + "row-height", + 0, + G_MAXINT, + 0, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + ARG_REORDERABLE, + g_param_spec_boolean ("reorderable", + "reorderable", + "reorderable", + TRUE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + ARG_TITLES_ACTIVE, + g_param_spec_boolean ("titles-active", + "titles-active", + "titles-active", + TRUE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + ARG_USE_DRAG_ICONS, + g_param_spec_boolean ("use-drag-icons", + "use-drag-icons", + "use-drag-icons", + TRUE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + ARG_SORT_TYPE, + g_param_spec_enum ("sort-type", + "sort-type", + "sort-type", + GTK_TYPE_SORT_TYPE, 0, + G_PARAM_READWRITE)); + widget_class->set_scroll_adjustments_signal = + g_signal_new ("set_scroll_adjustments", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkCMCListClass, set_scroll_adjustments), + NULL, NULL, + claws_marshal_VOID__OBJECT_OBJECT, + G_TYPE_NONE, 2, + GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT); + + clist_signals[SELECT_ROW] = + g_signal_new ("select_row", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkCMCListClass, select_row), + NULL, NULL, + claws_marshal_VOID__INT_INT_BOXED, + G_TYPE_NONE, 3, + G_TYPE_INT, + G_TYPE_INT, + GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); + clist_signals[UNSELECT_ROW] = + g_signal_new ("unselect_row", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkCMCListClass, unselect_row), + NULL, NULL, + claws_marshal_VOID__INT_INT_BOXED, + G_TYPE_NONE, 3, + G_TYPE_INT, + G_TYPE_INT, + GDK_TYPE_EVENT); + clist_signals[ROW_MOVE] = + g_signal_new ("row_move", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkCMCListClass, row_move), + NULL, NULL, + claws_marshal_VOID__INT_INT, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); + clist_signals[CLICK_COLUMN] = + g_signal_new ("click_column", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkCMCListClass, click_column), + NULL, NULL, + claws_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + clist_signals[RESIZE_COLUMN] = + g_signal_new ("resize_column", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkCMCListClass, resize_column), + NULL, NULL, + claws_marshal_VOID__INT_INT, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); + + clist_signals[TOGGLE_FOCUS_ROW] = + g_signal_new ("toggle_focus_row", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkCMCListClass, toggle_focus_row), + NULL, NULL, + claws_marshal_VOID__VOID, + G_TYPE_NONE, 0); + clist_signals[SELECT_ALL] = + g_signal_new ("select_all", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkCMCListClass, select_all), + NULL, NULL, + claws_marshal_VOID__VOID, + G_TYPE_NONE, 0); + clist_signals[UNSELECT_ALL] = + g_signal_new ("unselect_all", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkCMCListClass, unselect_all), + NULL, NULL, + claws_marshal_VOID__VOID, + G_TYPE_NONE, 0); + clist_signals[UNDO_SELECTION] = + g_signal_new ("undo_selection", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkCMCListClass, undo_selection), + NULL, NULL, + claws_marshal_VOID__VOID, + G_TYPE_NONE, 0); + clist_signals[START_SELECTION] = + g_signal_new ("start_selection", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkCMCListClass, start_selection), + NULL, NULL, + claws_marshal_VOID__VOID, + G_TYPE_NONE, 0); + clist_signals[END_SELECTION] = + g_signal_new ("end_selection", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkCMCListClass, end_selection), + NULL, NULL, + claws_marshal_VOID__VOID, + G_TYPE_NONE, 0); + clist_signals[TOGGLE_ADD_MODE] = + g_signal_new ("toggle_add_mode", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkCMCListClass, toggle_add_mode), + NULL, NULL, + claws_marshal_VOID__VOID, + G_TYPE_NONE, 0); + clist_signals[EXTEND_SELECTION] = + g_signal_new ("extend_selection", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkCMCListClass, extend_selection), + NULL, NULL, + claws_marshal_VOID__ENUM_FLOAT_BOOLEAN, + G_TYPE_NONE, 3, GTK_TYPE_SCROLL_TYPE, G_TYPE_FLOAT, G_TYPE_BOOLEAN); + clist_signals[SCROLL_VERTICAL] = + g_signal_new ("scroll_vertical", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkCMCListClass, scroll_vertical), + NULL, NULL, + claws_marshal_VOID__ENUM_FLOAT, + G_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_FLOAT); + clist_signals[SCROLL_HORIZONTAL] = + g_signal_new ("scroll_horizontal", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkCMCListClass, scroll_horizontal), + NULL, NULL, + claws_marshal_VOID__ENUM_FLOAT, + G_TYPE_NONE, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_FLOAT); + clist_signals[ABORT_COLUMN_RESIZE] = + g_signal_new ("abort_column_resize", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkCMCListClass, abort_column_resize), + NULL, NULL, + claws_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + binding_set = gtk_binding_set_by_class (klass); + gtk_binding_entry_add_signal (binding_set, GDK_Up, 0, + "scroll_vertical", 2, + G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD, + G_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0, + "scroll_vertical", 2, + G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD, + G_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_Down, 0, + "scroll_vertical", 2, + G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD, + G_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0, + "scroll_vertical", 2, + G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD, + G_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0, + "scroll_vertical", 2, + G_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD, + G_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0, + "scroll_vertical", 2, + G_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD, + G_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0, + "scroll_vertical", 2, + G_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD, + G_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0, + "scroll_vertical", 2, + G_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD, + G_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_Home, GDK_CONTROL_MASK, + "scroll_vertical", 2, + G_TYPE_ENUM, GTK_SCROLL_JUMP, + G_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, GDK_CONTROL_MASK, + "scroll_vertical", 2, + G_TYPE_ENUM, GTK_SCROLL_JUMP, + G_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_End, GDK_CONTROL_MASK, + "scroll_vertical", 2, + G_TYPE_ENUM, GTK_SCROLL_JUMP, + G_TYPE_FLOAT, 1.0); + gtk_binding_entry_add_signal (binding_set, GDK_KP_End, GDK_CONTROL_MASK, + "scroll_vertical", 2, + G_TYPE_ENUM, GTK_SCROLL_JUMP, + G_TYPE_FLOAT, 1.0); + + gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_SHIFT_MASK, + "extend_selection", 3, + G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD, + G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, GDK_SHIFT_MASK, + "extend_selection", 3, + G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD, + G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_SHIFT_MASK, + "extend_selection", 3, + G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD, + G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, GDK_SHIFT_MASK, + "extend_selection", 3, + G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD, + G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, GDK_SHIFT_MASK, + "extend_selection", 3, + G_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD, + G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, GDK_SHIFT_MASK, + "extend_selection", 3, + G_TYPE_ENUM, GTK_SCROLL_PAGE_BACKWARD, + G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, GDK_SHIFT_MASK, + "extend_selection", 3, + G_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD, + G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, GDK_SHIFT_MASK, + "extend_selection", 3, + G_TYPE_ENUM, GTK_SCROLL_PAGE_FORWARD, + G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_Home, + GDK_SHIFT_MASK | GDK_CONTROL_MASK, + "extend_selection", 3, + G_TYPE_ENUM, GTK_SCROLL_JUMP, + G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, + GDK_SHIFT_MASK | GDK_CONTROL_MASK, + "extend_selection", 3, + G_TYPE_ENUM, GTK_SCROLL_JUMP, + G_TYPE_FLOAT, 0.0, G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_End, + GDK_SHIFT_MASK | GDK_CONTROL_MASK, + "extend_selection", 3, + G_TYPE_ENUM, GTK_SCROLL_JUMP, + G_TYPE_FLOAT, 1.0, G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set, GDK_KP_End, + GDK_SHIFT_MASK | GDK_CONTROL_MASK, + "extend_selection", 3, + G_TYPE_ENUM, GTK_SCROLL_JUMP, + G_TYPE_FLOAT, 1.0, G_TYPE_BOOLEAN, TRUE); + + + gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, + "scroll_horizontal", 2, + G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD, + G_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, + "scroll_horizontal", 2, + G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD, + G_TYPE_FLOAT, 0.0); + + gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, + "scroll_horizontal", 2, + G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD, + G_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, + "scroll_horizontal", 2, + G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD, + G_TYPE_FLOAT, 0.0); + + gtk_binding_entry_add_signal (binding_set, GDK_Home, 0, + "scroll_horizontal", 2, + G_TYPE_ENUM, GTK_SCROLL_JUMP, + G_TYPE_FLOAT, 0.0); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0, + "scroll_horizontal", 2, + G_TYPE_ENUM, GTK_SCROLL_JUMP, + G_TYPE_FLOAT, 0.0); + + gtk_binding_entry_add_signal (binding_set, GDK_End, 0, + "scroll_horizontal", 2, + G_TYPE_ENUM, GTK_SCROLL_JUMP, + G_TYPE_FLOAT, 1.0); + + gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0, + "scroll_horizontal", 2, + G_TYPE_ENUM, GTK_SCROLL_JUMP, + G_TYPE_FLOAT, 1.0); + + gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, + "undo_selection", 0); + gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, + "abort_column_resize", 0); + gtk_binding_entry_add_signal (binding_set, GDK_space, 0, + "toggle_focus_row", 0); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0, + "toggle_focus_row", 0); + gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, + "toggle_add_mode", 0); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_CONTROL_MASK, + "toggle_add_mode", 0); + gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, + "select_all", 0); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, GDK_CONTROL_MASK, + "select_all", 0); + gtk_binding_entry_add_signal (binding_set, '\\', GDK_CONTROL_MASK, + "unselect_all", 0); + gtk_binding_entry_add_signal (binding_set, GDK_Shift_L, + GDK_RELEASE_MASK | GDK_SHIFT_MASK, + "end_selection", 0); + gtk_binding_entry_add_signal (binding_set, GDK_Shift_R, + GDK_RELEASE_MASK | GDK_SHIFT_MASK, + "end_selection", 0); + gtk_binding_entry_add_signal (binding_set, GDK_Shift_L, + GDK_RELEASE_MASK | GDK_SHIFT_MASK | + GDK_CONTROL_MASK, + "end_selection", 0); + gtk_binding_entry_add_signal (binding_set, GDK_Shift_R, + GDK_RELEASE_MASK | GDK_SHIFT_MASK | + GDK_CONTROL_MASK, + "end_selection", 0); +} + +static void +gtk_cmclist_set_arg (GObject *object, + guint arg_id, + const GValue *value, + GParamSpec *spec) +{ + GtkCMCList *clist; + + clist = GTK_CMCLIST (object); + + switch (arg_id) + { + case ARG_N_COLUMNS: /* only set at construction time */ + clist->columns = MAX (1, g_value_get_uint (value)); + break; + case ARG_SHADOW_TYPE: + gtk_cmclist_set_shadow_type (clist, g_value_get_enum (value)); + break; + case ARG_SELECTION_MODE: + gtk_cmclist_set_selection_mode (clist, g_value_get_enum (value)); + break; + case ARG_ROW_HEIGHT: + gtk_cmclist_set_row_height (clist, g_value_get_uint (value)); + break; + case ARG_REORDERABLE: + gtk_cmclist_set_reorderable (clist, g_value_get_boolean (value)); + break; + case ARG_TITLES_ACTIVE: + if (g_value_get_boolean (value)) + gtk_cmclist_column_titles_active (clist); + else + gtk_cmclist_column_titles_passive (clist); + break; + case ARG_USE_DRAG_ICONS: + gtk_cmclist_set_use_drag_icons (clist, g_value_get_boolean (value)); + break; + case ARG_SORT_TYPE: + gtk_cmclist_set_sort_type (clist, g_value_get_enum (value)); + break; + } +} + +static void +gtk_cmclist_get_arg (GObject *object, + guint arg_id, + GValue *value, + GParamSpec *spec) +{ + GtkCMCList *clist; + + clist = GTK_CMCLIST (object); + + switch (arg_id) + { + guint i; + + case ARG_N_COLUMNS: + g_value_set_uint(value, clist->columns); + break; + case ARG_SHADOW_TYPE: + g_value_set_enum(value, clist->shadow_type); + break; + case ARG_SELECTION_MODE: + g_value_set_enum(value, clist->selection_mode); + break; + case ARG_ROW_HEIGHT: + g_value_set_uint(value, GTK_CMCLIST_ROW_HEIGHT_SET(clist) ? clist->row_height : 0); + break; + case ARG_REORDERABLE: + g_value_set_boolean(value, GTK_CMCLIST_REORDERABLE (clist)); + break; + case ARG_TITLES_ACTIVE: + g_value_set_boolean(value, TRUE); + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button && + !GTK_WIDGET_SENSITIVE (clist->column[i].button)) + { + g_value_set_boolean(value, FALSE); + break; + } + break; + case ARG_USE_DRAG_ICONS: + g_value_set_boolean(value, GTK_CMCLIST_USE_DRAG_ICONS (clist)); + break; + case ARG_SORT_TYPE: + g_value_set_enum(value, clist->sort_type); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, spec); + break; + } +} + +static void +gtk_cmclist_init (GtkCMCList *clist) +{ + clist->flags = 0; + + GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW); + GTK_WIDGET_SET_FLAGS (clist, GTK_CAN_FOCUS); + GTK_CMCLIST_SET_FLAG (clist, CMCLIST_DRAW_DRAG_LINE); + GTK_CMCLIST_SET_FLAG (clist, CMCLIST_USE_DRAG_ICONS); + + clist->freeze_count = 0; + + clist->rows = 0; + clist->row_height = 0; + clist->row_list = NULL; + clist->row_list_end = NULL; + + clist->columns = 0; + + clist->title_window = NULL; + clist->column_title_area.x = 0; + clist->column_title_area.y = 0; + clist->column_title_area.width = 1; + clist->column_title_area.height = 1; + + clist->clist_window = NULL; + clist->clist_window_width = 1; + clist->clist_window_height = 1; + + clist->hoffset = 0; + clist->voffset = 0; + + clist->shadow_type = GTK_SHADOW_IN; + clist->vadjustment = NULL; + clist->hadjustment = NULL; + + clist->button_actions[0] = GTK_CMBUTTON_SELECTS | GTK_CMBUTTON_DRAGS; + clist->button_actions[1] = GTK_CMBUTTON_IGNORED; + clist->button_actions[2] = GTK_CMBUTTON_IGNORED; + clist->button_actions[3] = GTK_CMBUTTON_IGNORED; + clist->button_actions[4] = GTK_CMBUTTON_IGNORED; + + clist->cursor_drag = NULL; + clist->xor_gc = NULL; + clist->fg_gc = NULL; + clist->bg_gc = NULL; + clist->x_drag = 0; + + clist->selection_mode = GTK_SELECTION_SINGLE; + clist->selection = NULL; + clist->selection_end = NULL; + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + + clist->focus_row = -1; + clist->focus_header_column = -1; + clist->undo_anchor = -1; + + clist->anchor = -1; + clist->anchor_state = GTK_STATE_SELECTED; + clist->drag_pos = -1; + clist->htimer = 0; + clist->vtimer = 0; + + clist->click_cell.row = -1; + clist->click_cell.column = -1; + + clist->compare = default_compare; + clist->sort_type = GTK_SORT_ASCENDING; + clist->sort_column = 0; + + clist->drag_highlight_row = -1; +} + +/* Constructor */ +static GObject* +gtk_cmclist_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *object = G_OBJECT_CLASS (parent_class)->constructor (type, + n_construct_properties, + construct_properties); + GtkCMCList *clist = GTK_CMCLIST (object); + + /* allocate memory for columns */ + clist->column = columns_new (clist); + + /* there needs to be at least one column button + * because there is alot of code that will break if it + * isn't there + */ + column_button_create (clist, 0); + + return object; +} + +/* GTKCLIST PUBLIC INTERFACE + * gtk_cmclist_new + * gtk_cmclist_new_with_titles + * gtk_cmclist_set_hadjustment + * gtk_cmclist_set_vadjustment + * gtk_cmclist_get_hadjustment + * gtk_cmclist_get_vadjustment + * gtk_cmclist_set_shadow_type + * gtk_cmclist_set_selection_mode + * gtk_cmclist_freeze + * gtk_cmclist_thaw + */ +GtkWidget* +gtk_cmclist_new (gint columns) +{ + return gtk_cmclist_new_with_titles (columns, NULL); +} + +GtkWidget* +gtk_cmclist_new_with_titles (gint columns, + gchar *titles[]) +{ + GtkCMCList *clist; + + clist = g_object_new (GTK_TYPE_CMCLIST, + "n_columns", columns, + NULL); + if (titles) + { + guint i; + + for (i = 0; i < clist->columns; i++) + gtk_cmclist_set_column_title (clist, i, titles[i]); + gtk_cmclist_column_titles_show (clist); + } + else + gtk_cmclist_column_titles_hide (clist); + + return GTK_WIDGET (clist); +} + +void +gtk_cmclist_set_hadjustment (GtkCMCList *clist, + GtkAdjustment *adjustment) +{ + GtkAdjustment *old_adjustment; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + if (adjustment) + g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); + + if (clist->hadjustment == adjustment) + return; + + old_adjustment = clist->hadjustment; + + if (clist->hadjustment) + { + g_signal_handlers_disconnect_matched(GTK_OBJECT (clist->hadjustment), G_SIGNAL_MATCH_DATA, + 0, 0, 0, 0, clist); + + g_object_unref (GTK_OBJECT (clist->hadjustment)); + } + + clist->hadjustment = adjustment; + + if (clist->hadjustment) + { + g_object_ref_sink (clist->hadjustment); + + g_signal_connect (G_OBJECT (clist->hadjustment), "changed", + G_CALLBACK( hadjustment_changed), + (gpointer) clist); + g_signal_connect (G_OBJECT (clist->hadjustment), "value_changed", + G_CALLBACK( hadjustment_value_changed), + (gpointer) clist); + } + + if (!clist->hadjustment || !old_adjustment) + gtk_widget_queue_resize (GTK_WIDGET (clist)); +} + +GtkAdjustment * +gtk_cmclist_get_hadjustment (GtkCMCList *clist) +{ + g_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL); + + return clist->hadjustment; +} + +void +gtk_cmclist_set_vadjustment (GtkCMCList *clist, + GtkAdjustment *adjustment) +{ + GtkAdjustment *old_adjustment; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + if (adjustment) + g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); + + if (clist->vadjustment == adjustment) + return; + + old_adjustment = clist->vadjustment; + + if (clist->vadjustment) + { + g_signal_handlers_disconnect_matched(GTK_OBJECT (clist->vadjustment), G_SIGNAL_MATCH_DATA, + 0, 0, 0, 0, clist); + g_object_unref (GTK_OBJECT (clist->vadjustment)); + } + + clist->vadjustment = adjustment; + + if (clist->vadjustment) + { + g_object_ref_sink (clist->vadjustment); + + g_signal_connect (GTK_OBJECT (clist->vadjustment), "changed", + G_CALLBACK(vadjustment_changed), + (gpointer) clist); + g_signal_connect (GTK_OBJECT (clist->vadjustment), "value_changed", + G_CALLBACK(vadjustment_value_changed), + (gpointer) clist); + } + + if (!clist->vadjustment || !old_adjustment) + gtk_widget_queue_resize (GTK_WIDGET (clist)); +} + +GtkAdjustment * +gtk_cmclist_get_vadjustment (GtkCMCList *clist) +{ + g_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL); + + return clist->vadjustment; +} + +static void +gtk_cmclist_set_scroll_adjustments (GtkCMCList *clist, + GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment) +{ + if (clist->hadjustment != hadjustment) + gtk_cmclist_set_hadjustment (clist, hadjustment); + if (clist->vadjustment != vadjustment) + gtk_cmclist_set_vadjustment (clist, vadjustment); +} + +void +gtk_cmclist_set_shadow_type (GtkCMCList *clist, + GtkShadowType type) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + clist->shadow_type = type; + + if (GTK_WIDGET_VISIBLE (clist)) + gtk_widget_queue_resize (GTK_WIDGET (clist)); +} + +void +gtk_cmclist_set_selection_mode (GtkCMCList *clist, + GtkSelectionMode mode) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + g_return_if_fail (mode != GTK_SELECTION_NONE); + + if (mode == clist->selection_mode) + return; + + clist->selection_mode = mode; + clist->anchor = -1; + clist->anchor_state = GTK_STATE_SELECTED; + clist->drag_pos = -1; + clist->undo_anchor = clist->focus_row; + + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + + switch (mode) + { + case GTK_SELECTION_MULTIPLE: + return; + case GTK_SELECTION_BROWSE: + case GTK_SELECTION_SINGLE: + gtk_cmclist_unselect_all (clist); + break; + default: + /* Someone set it by hand */ + g_assert_not_reached (); + } +} + +void +gtk_cmclist_freeze (GtkCMCList *clist) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + clist->freeze_count++; +} + +void +gtk_cmclist_thaw (GtkCMCList *clist) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (clist->freeze_count) + { + clist->freeze_count--; + CLIST_REFRESH (clist); + } +} + +/* PUBLIC COLUMN FUNCTIONS + * gtk_cmclist_column_titles_show + * gtk_cmclist_column_titles_hide + * gtk_cmclist_column_title_active + * gtk_cmclist_column_title_passive + * gtk_cmclist_column_titles_active + * gtk_cmclist_column_titles_passive + * gtk_cmclist_set_column_title + * gtk_cmclist_get_column_title + * gtk_cmclist_set_column_widget + * gtk_cmclist_set_column_justification + * gtk_cmclist_set_column_visibility + * gtk_cmclist_set_column_resizeable + * gtk_cmclist_set_column_auto_resize + * gtk_cmclist_optimal_column_width + * gtk_cmclist_set_column_width + * gtk_cmclist_set_column_min_width + * gtk_cmclist_set_column_max_width + */ +void +gtk_cmclist_column_titles_show (GtkCMCList *clist) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (!GTK_CMCLIST_SHOW_TITLES(clist)) + { + GTK_CMCLIST_SET_FLAG (clist, CMCLIST_SHOW_TITLES); + if (clist->title_window) + gdk_window_show (clist->title_window); + gtk_widget_queue_resize (GTK_WIDGET (clist)); + } +} + +void +gtk_cmclist_column_titles_hide (GtkCMCList *clist) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (GTK_CMCLIST_SHOW_TITLES(clist)) + { + GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_SHOW_TITLES); + if (clist->title_window) + gdk_window_hide (clist->title_window); + gtk_widget_queue_resize (GTK_WIDGET (clist)); + } +} + +void +gtk_cmclist_column_title_active (GtkCMCList *clist, + gint column) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (column < 0 || column >= clist->columns) + return; + if (!clist->column[column].button || !clist->column[column].button_passive) + return; + + clist->column[column].button_passive = FALSE; + + g_signal_handlers_disconnect_matched(GTK_OBJECT (clist->column[column].button), G_SIGNAL_MATCH_FUNC, + 0, 0, 0, column_title_passive_func, 0); + + GTK_WIDGET_SET_FLAGS (clist->column[column].button, GTK_CAN_FOCUS); + if (GTK_WIDGET_VISIBLE (clist)) + gtk_widget_queue_draw (clist->column[column].button); +} + +void +gtk_cmclist_column_title_passive (GtkCMCList *clist, + gint column) +{ + GtkButton *button; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (column < 0 || column >= clist->columns) + return; + if (!clist->column[column].button || clist->column[column].button_passive) + return; + + button = GTK_BUTTON (clist->column[column].button); + + clist->column[column].button_passive = TRUE; + + if (button->button_down) + gtk_button_released (button); + if (button->in_button) + gtk_button_leave (button); + + g_signal_connect (G_OBJECT (clist->column[column].button), "event", + G_CALLBACK(column_title_passive_func), NULL); + + GTK_WIDGET_UNSET_FLAGS (clist->column[column].button, GTK_CAN_FOCUS); + if (GTK_WIDGET_VISIBLE (clist)) + gtk_widget_queue_draw (clist->column[column].button); +} + +void +gtk_cmclist_column_titles_active (GtkCMCList *clist) +{ + gint i; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + for (i = 0; i < clist->columns; i++) + gtk_cmclist_column_title_active (clist, i); +} + +void +gtk_cmclist_column_titles_passive (GtkCMCList *clist) +{ + gint i; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + for (i = 0; i < clist->columns; i++) + gtk_cmclist_column_title_passive (clist, i); +} + +void +gtk_cmclist_set_column_title (GtkCMCList *clist, + gint column, + const gchar *title) +{ + gint new_button = 0; + GtkWidget *old_widget; + GtkWidget *alignment = NULL; + GtkWidget *label; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (column < 0 || column >= clist->columns) + return; + + /* if the column button doesn't currently exist, + * it has to be created first */ + if (!clist->column[column].button) + { + column_button_create (clist, column); + new_button = 1; + } + + column_title_new (clist, column, title); + + /* remove and destroy the old widget */ + old_widget = GTK_BIN (clist->column[column].button)->child; + if (old_widget) + gtk_container_remove (GTK_CONTAINER (clist->column[column].button), old_widget); + + /* create new alignment based no column justification */ + switch (clist->column[column].justification) + { + case GTK_JUSTIFY_LEFT: + alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0); + break; + + case GTK_JUSTIFY_RIGHT: + alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0); + break; + + case GTK_JUSTIFY_CENTER: + alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); + break; + + case GTK_JUSTIFY_FILL: + alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); + break; + } + + gtk_widget_push_composite_child (); + label = gtk_label_new (clist->column[column].title); + gtk_widget_pop_composite_child (); + gtk_container_add (GTK_CONTAINER (alignment), label); + gtk_container_add (GTK_CONTAINER (clist->column[column].button), alignment); + gtk_widget_show (label); + gtk_widget_show (alignment); + + /* if this button didn't previously exist, then the + * column button positions have to be re-computed */ + if (GTK_WIDGET_VISIBLE (clist) && new_button) + size_allocate_title_buttons (clist); +} + +gchar * +gtk_cmclist_get_column_title (GtkCMCList *clist, + gint column) +{ + g_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL); + + if (column < 0 || column >= clist->columns) + return NULL; + + return clist->column[column].title; +} + +void +gtk_cmclist_set_column_widget (GtkCMCList *clist, + gint column, + GtkWidget *widget) +{ + gint new_button = 0; + GtkWidget *old_widget; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (column < 0 || column >= clist->columns) + return; + + /* if the column button doesn't currently exist, + * it has to be created first */ + if (!clist->column[column].button) + { + column_button_create (clist, column); + new_button = 1; + } + + column_title_new (clist, column, NULL); + + /* remove and destroy the old widget */ + old_widget = GTK_BIN (clist->column[column].button)->child; + if (old_widget) + gtk_container_remove (GTK_CONTAINER (clist->column[column].button), + old_widget); + + /* add and show the widget */ + if (widget) + { + gtk_container_add (GTK_CONTAINER (clist->column[column].button), widget); + gtk_widget_show (widget); + } + + /* if this button didn't previously exist, then the + * column button positions have to be re-computed */ + if (GTK_WIDGET_VISIBLE (clist) && new_button) + size_allocate_title_buttons (clist); +} + +GtkWidget * +gtk_cmclist_get_column_widget (GtkCMCList *clist, + gint column) +{ + g_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL); + + if (column < 0 || column >= clist->columns) + return NULL; + + if (clist->column[column].button) + return GTK_BIN (clist->column[column].button)->child; + + return NULL; +} + +void +gtk_cmclist_set_column_justification (GtkCMCList *clist, + gint column, + GtkJustification justification) +{ + GtkWidget *alignment; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (column < 0 || column >= clist->columns) + return; + + clist->column[column].justification = justification; + + /* change the alinment of the button title if it's not a + * custom widget */ + if (clist->column[column].title) + { + alignment = GTK_BIN (clist->column[column].button)->child; + + switch (clist->column[column].justification) + { + case GTK_JUSTIFY_LEFT: + gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.0, 0.5, 0.0, 0.0); + break; + + case GTK_JUSTIFY_RIGHT: + gtk_alignment_set (GTK_ALIGNMENT (alignment), 1.0, 0.5, 0.0, 0.0); + break; + + case GTK_JUSTIFY_CENTER: + gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0); + break; + + case GTK_JUSTIFY_FILL: + gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 0.0, 0.0); + break; + + default: + break; + } + } + + if (CLIST_UNFROZEN (clist)) + draw_rows (clist, NULL); +} + +void +gtk_cmclist_set_column_visibility (GtkCMCList *clist, + gint column, + gboolean visible) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (column < 0 || column >= clist->columns) + return; + if (clist->column[column].visible == visible) + return; + + /* don't hide last visible column */ + if (!visible) + { + gint i; + gint vis_columns = 0; + + for (i = 0, vis_columns = 0; i < clist->columns && vis_columns < 2; i++) + if (clist->column[i].visible) + vis_columns++; + + if (vis_columns < 2) + return; + } + + clist->column[column].visible = visible; + + if (clist->column[column].button) + { + if (visible) + gtk_widget_show (clist->column[column].button); + else + gtk_widget_hide (clist->column[column].button); + } + + gtk_widget_queue_resize (GTK_WIDGET(clist)); +} + +void +gtk_cmclist_set_column_resizeable (GtkCMCList *clist, + gint column, + gboolean resizeable) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (column < 0 || column >= clist->columns) + return; + if (clist->column[column].resizeable == resizeable) + return; + + clist->column[column].resizeable = resizeable; + if (resizeable) + clist->column[column].auto_resize = FALSE; + + if (GTK_WIDGET_VISIBLE (clist)) + size_allocate_title_buttons (clist); +} + +void +gtk_cmclist_set_column_auto_resize (GtkCMCList *clist, + gint column, + gboolean auto_resize) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (column < 0 || column >= clist->columns) + return; + if (clist->column[column].auto_resize == auto_resize) + return; + + clist->column[column].auto_resize = auto_resize; + if (auto_resize) + { + clist->column[column].resizeable = FALSE; + if (!GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + { + gint width; + + width = gtk_cmclist_optimal_column_width (clist, column); + gtk_cmclist_set_column_width (clist, column, width); + } + } + + if (GTK_WIDGET_VISIBLE (clist)) + size_allocate_title_buttons (clist); +} + +gint +gtk_cmclist_columns_autosize (GtkCMCList *clist) +{ + gint i; + gint width; + + g_return_val_if_fail (GTK_IS_CMCLIST (clist), 0); + + gtk_cmclist_freeze (clist); + width = 0; + for (i = 0; i < clist->columns; i++) + { + gtk_cmclist_set_column_width (clist, i, + gtk_cmclist_optimal_column_width (clist, i)); + + width += clist->column[i].width; + } + + gtk_cmclist_thaw (clist); + return width; +} + +gint +gtk_cmclist_optimal_column_width (GtkCMCList *clist, + gint column) +{ + GtkRequisition requisition; + GList *list; + gint width; + + g_return_val_if_fail (GTK_CMCLIST (clist), 0); + + if (column < 0 || column >= clist->columns) + return 0; + + if (GTK_CMCLIST_SHOW_TITLES(clist) && clist->column[column].button) + width = (clist->column[column].button->requisition.width) +#if 0 + (CELL_SPACING + (2 * COLUMN_INSET))) +#endif + ; + else + width = 0; + + for (list = clist->row_list; list; list = list->next) + { + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request + (clist, GTK_CMCLIST_ROW (list), column, &requisition); + width = MAX (width, requisition.width); + } + + return width; +} + +void +gtk_cmclist_set_column_width (GtkCMCList *clist, + gint column, + gint width) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (column < 0 || column >= clist->columns) + return; + + g_signal_emit (GTK_OBJECT (clist), clist_signals[RESIZE_COLUMN], 0, + column, width); +} + +void +gtk_cmclist_set_column_min_width (GtkCMCList *clist, + gint column, + gint min_width) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (column < 0 || column >= clist->columns) + return; + if (clist->column[column].min_width == min_width) + return; + + if (clist->column[column].max_width >= 0 && + clist->column[column].max_width < min_width) + clist->column[column].min_width = clist->column[column].max_width; + else + clist->column[column].min_width = min_width; + + if (clist->column[column].area.width < clist->column[column].min_width) + gtk_cmclist_set_column_width (clist, column,clist->column[column].min_width); +} + +void +gtk_cmclist_set_column_max_width (GtkCMCList *clist, + gint column, + gint max_width) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (column < 0 || column >= clist->columns) + return; + if (clist->column[column].max_width == max_width) + return; + + if (clist->column[column].min_width >= 0 && max_width >= 0 && + clist->column[column].min_width > max_width) + clist->column[column].max_width = clist->column[column].min_width; + else + clist->column[column].max_width = max_width; + + if (clist->column[column].area.width > clist->column[column].max_width) + gtk_cmclist_set_column_width (clist, column,clist->column[column].max_width); +} + +/* PRIVATE COLUMN FUNCTIONS + * column_auto_resize + * real_resize_column + * abort_column_resize + * size_allocate_title_buttons + * size_allocate_columns + * list_requisition_width + * new_column_width + * column_button_create + * column_button_clicked + * column_title_passive_func + */ +static void +column_auto_resize (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint column, + gint old_width) +{ + /* resize column if needed for auto_resize */ + GtkRequisition requisition; + + if (!clist->column[column].auto_resize || + GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + return; + + if (clist_row) + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row, + column, &requisition); + else + requisition.width = 0; + + if (requisition.width > clist->column[column].width) + gtk_cmclist_set_column_width (clist, column, requisition.width); + else if (requisition.width < old_width && + old_width == clist->column[column].width) + { + GList *list; + gint new_width = 0; + + /* run a "gtk_cmclist_optimal_column_width" but break, if + * the column doesn't shrink */ + if (GTK_CMCLIST_SHOW_TITLES(clist) && clist->column[column].button) + new_width = (clist->column[column].button->requisition.width - + (CELL_SPACING + (2 * COLUMN_INSET))); + else + new_width = 0; + + for (list = clist->row_list; list; list = list->next) + { + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request + (clist, GTK_CMCLIST_ROW (list), column, &requisition); + new_width = MAX (new_width, requisition.width); + if (new_width == clist->column[column].width) + break; + } + if (new_width < clist->column[column].width) + gtk_cmclist_set_column_width + (clist, column, MAX (new_width, clist->column[column].min_width)); + } +} + +static void +real_resize_column (GtkCMCList *clist, + gint column, + gint width) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (column < 0 || column >= clist->columns) + return; + + if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width)) + width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width); + if (clist->column[column].max_width >= 0 && + width > clist->column[column].max_width) + width = clist->column[column].max_width; + + clist->column[column].width = width; + clist->column[column].width_set = TRUE; + + /* FIXME: this is quite expensive to do if the widget hasn't + * been size_allocated yet, and pointless. Should + * a flag be kept + */ + size_allocate_columns (clist, TRUE); + size_allocate_title_buttons (clist); + + CLIST_REFRESH (clist); +} + +static void +abort_column_resize (GtkCMCList *clist) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (!GTK_CMCLIST_IN_DRAG(clist)) + return; + + GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_IN_DRAG); + gtk_grab_remove (GTK_WIDGET (clist)); + gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (clist)), + GDK_CURRENT_TIME); + clist->drag_pos = -1; + + if (clist->x_drag >= 0 && clist->x_drag <= clist->clist_window_width - 1) + draw_xor_line (clist); + + if (GTK_CMCLIST_ADD_MODE(clist)) + { + gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_ON_OFF_DASH, 0,0); + gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2); + } +} + +static void +size_allocate_title_buttons (GtkCMCList *clist) +{ + GtkAllocation button_allocation; + gint last_column; + gint last_button = 0; + gint i; + + if (!GTK_WIDGET_REALIZED (clist)) + return; + + button_allocation.x = clist->hoffset; + button_allocation.y = 0; + button_allocation.width = 0; + button_allocation.height = clist->column_title_area.height; + + /* find last visible column */ + for (last_column = clist->columns - 1; last_column >= 0; last_column--) + if (clist->column[last_column].visible) + break; + + for (i = 0; i < last_column; i++) + { + if (!clist->column[i].visible) + { + last_button = i + 1; + gdk_window_hide (clist->column[i].window); + continue; + } + + button_allocation.width += (clist->column[i].area.width + + CELL_SPACING + 2 * COLUMN_INSET); + + if (!clist->column[i + 1].button) + { + gdk_window_hide (clist->column[i].window); + continue; + } + + gtk_widget_size_allocate (clist->column[last_button].button, + &button_allocation); + button_allocation.x += button_allocation.width; + button_allocation.width = 0; + + if (clist->column[last_button].resizeable) + { + gdk_window_show (clist->column[last_button].window); + gdk_window_move_resize (clist->column[last_button].window, + button_allocation.x - (DRAG_WIDTH / 2), + 0, DRAG_WIDTH, + clist->column_title_area.height); + } + else + gdk_window_hide (clist->column[last_button].window); + + last_button = i + 1; + } + + button_allocation.width += (clist->column[last_column].area.width + + 2 * (CELL_SPACING + COLUMN_INSET)); + gtk_widget_size_allocate (clist->column[last_button].button, + &button_allocation); + + if (clist->column[last_button].resizeable) + { + button_allocation.x += button_allocation.width; + + gdk_window_show (clist->column[last_button].window); + gdk_window_move_resize (clist->column[last_button].window, + button_allocation.x - (DRAG_WIDTH / 2), + 0, DRAG_WIDTH, clist->column_title_area.height); + } + else + gdk_window_hide (clist->column[last_button].window); +} + +static void +size_allocate_columns (GtkCMCList *clist, + gboolean block_resize) +{ + gint xoffset = CELL_SPACING + COLUMN_INSET; + gint last_column; + gint i; + + /* find last visible column and calculate correct column width */ + for (last_column = clist->columns - 1; + last_column >= 0 && !clist->column[last_column].visible; last_column--); + + if (last_column < 0) + return; + + for (i = 0; i <= last_column; i++) + { + if (!clist->column[i].visible) + continue; + clist->column[i].area.x = xoffset; + if (clist->column[i].width_set) + { + if (!block_resize && GTK_CMCLIST_SHOW_TITLES(clist) && + clist->column[i].auto_resize && clist->column[i].button) + { + gint width; + + width = (clist->column[i].button->requisition.width - + (CELL_SPACING + (2 * COLUMN_INSET))); + + if (width > clist->column[i].width) + gtk_cmclist_set_column_width (clist, i, width); + } + + clist->column[i].area.width = clist->column[i].width; + xoffset += clist->column[i].width + CELL_SPACING + (2* COLUMN_INSET); + } + else if (GTK_CMCLIST_SHOW_TITLES(clist) && clist->column[i].button) + { + clist->column[i].area.width = + clist->column[i].button->requisition.width - + (CELL_SPACING + (2 * COLUMN_INSET)); + xoffset += clist->column[i].button->requisition.width; + } + } + + clist->column[last_column].area.width = clist->column[last_column].area.width + + MAX (0, clist->clist_window_width + COLUMN_INSET - xoffset); +} + +static gint +list_requisition_width (GtkCMCList *clist) +{ + gint width = CELL_SPACING; + gint i; + + for (i = clist->columns - 1; i >= 0; i--) + { + if (!clist->column[i].visible) + continue; + + if (clist->column[i].width_set) + width += clist->column[i].width + CELL_SPACING + (2 * COLUMN_INSET); + else if (GTK_CMCLIST_SHOW_TITLES(clist) && clist->column[i].button) + width += clist->column[i].button->requisition.width; + } + + return width; +} + +/* this function returns the new width of the column being resized given + * the column and x position of the cursor; the x cursor position is passed + * in as a pointer and automagicly corrected if it's beyond min/max limits */ +static gint +new_column_width (GtkCMCList *clist, + gint column, + gint *x) +{ + gint xthickness = GTK_WIDGET (clist)->style->xthickness; + gint width; + gint cx; + gint dx; + gint last_column; + + /* first translate the x position from widget->window + * to clist->clist_window */ + cx = *x - xthickness; + + for (last_column = clist->columns - 1; + last_column >= 0 && !clist->column[last_column].visible; last_column--); + + /* calculate new column width making sure it doesn't end up + * less than the minimum width */ + dx = (COLUMN_LEFT_XPIXEL (clist, column) + COLUMN_INSET + + (column < last_column) * CELL_SPACING); + width = cx - dx; + + if (width < MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width)) + { + width = MAX (COLUMN_MIN_WIDTH, clist->column[column].min_width); + cx = dx + width; + *x = cx + xthickness; + } + else if (clist->column[column].max_width >= COLUMN_MIN_WIDTH && + width > clist->column[column].max_width) + { + width = clist->column[column].max_width; + cx = dx + clist->column[column].max_width; + *x = cx + xthickness; + } + + if (cx < 0 || cx > clist->clist_window_width) + *x = -1; + + return width; +} + +static void +column_button_create (GtkCMCList *clist, + gint column) +{ + GtkWidget *button; + + gtk_widget_push_composite_child (); + button = clist->column[column].button = gtk_button_new (); + gtk_container_set_border_width(GTK_CONTAINER(button), 0); + gtk_widget_pop_composite_child (); + + if (GTK_WIDGET_REALIZED (clist) && clist->title_window) + gtk_widget_set_parent_window (clist->column[column].button, + clist->title_window); + gtk_widget_set_parent (button, GTK_WIDGET (clist)); + + g_signal_connect (GTK_OBJECT (button), "clicked", + G_CALLBACK(column_button_clicked), + (gpointer) clist); + gtk_widget_show (button); +} + +static void +column_button_clicked (GtkWidget *widget, + gpointer data) +{ + gint i; + GtkCMCList *clist; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CMCLIST (data)); + + clist = GTK_CMCLIST (data); + + /* find the column who's button was pressed */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button == widget) + break; + + g_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], 0, i); +} + +static gint +column_title_passive_func (GtkWidget *widget, + GdkEvent *event, + gpointer data) +{ + g_return_val_if_fail (event != NULL, FALSE); + + switch (event->type) + { + case GDK_MOTION_NOTIFY: + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + return TRUE; + default: + break; + } + return FALSE; +} + + +/* PUBLIC CELL FUNCTIONS + * gtk_cmclist_get_cell_type + * gtk_cmclist_set_text + * gtk_cmclist_get_text + * gtk_cmclist_set_pixmap + * gtk_cmclist_get_pixmap + * gtk_cmclist_set_pixtext + * gtk_cmclist_get_pixtext + * gtk_cmclist_set_shift + */ +GtkCMCellType +gtk_cmclist_get_cell_type (GtkCMCList *clist, + gint row, + gint column) +{ + GtkCMCListRow *clist_row; + + g_return_val_if_fail (GTK_IS_CMCLIST (clist), -1); + + if (row < 0 || row >= clist->rows) + return -1; + if (column < 0 || column >= clist->columns) + return -1; + + clist_row = ROW_ELEMENT (clist, row)->data; + + return clist_row->cell[column].type; +} + +void +gtk_cmclist_set_text (GtkCMCList *clist, + gint row, + gint column, + const gchar *text) +{ + GtkCMCListRow *clist_row; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) + return; + + clist_row = ROW_ELEMENT (clist, row)->data; + + /* if text is null, then the cell is empty */ + GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents + (clist, clist_row, column, GTK_CMCELL_TEXT, text, 0, NULL, NULL); + + /* redraw the list if it's not frozen */ + if (CLIST_UNFROZEN (clist)) + { + if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row); + } +} + +gint +gtk_cmclist_get_text (GtkCMCList *clist, + gint row, + gint column, + gchar **text) +{ + GtkCMCListRow *clist_row; + + g_return_val_if_fail (GTK_IS_CMCLIST (clist), 0); + + if (row < 0 || row >= clist->rows) + return 0; + if (column < 0 || column >= clist->columns) + return 0; + + clist_row = ROW_ELEMENT (clist, row)->data; + + if (clist_row->cell[column].type != GTK_CMCELL_TEXT) + return 0; + + if (text) + *text = GTK_CMCELL_TEXT (clist_row->cell[column])->text; + + return 1; +} + +void +gtk_cmclist_set_pixmap (GtkCMCList *clist, + gint row, + gint column, + GdkPixmap *pixmap, + GdkBitmap *mask) +{ + GtkCMCListRow *clist_row; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) + return; + + clist_row = ROW_ELEMENT (clist, row)->data; + + g_object_ref (pixmap); + + if (mask) g_object_ref (mask); + + GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents + (clist, clist_row, column, GTK_CMCELL_PIXMAP, NULL, 0, pixmap, mask); + + /* redraw the list if it's not frozen */ + if (CLIST_UNFROZEN (clist)) + { + if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row); + } +} + +gint +gtk_cmclist_get_pixmap (GtkCMCList *clist, + gint row, + gint column, + GdkPixmap **pixmap, + GdkBitmap **mask) +{ + GtkCMCListRow *clist_row; + + g_return_val_if_fail (GTK_IS_CMCLIST (clist), 0); + + if (row < 0 || row >= clist->rows) + return 0; + if (column < 0 || column >= clist->columns) + return 0; + + clist_row = ROW_ELEMENT (clist, row)->data; + + if (clist_row->cell[column].type != GTK_CMCELL_PIXMAP) + return 0; + + if (pixmap) + { + *pixmap = GTK_CMCELL_PIXMAP (clist_row->cell[column])->pixmap; + /* mask can be NULL */ + *mask = GTK_CMCELL_PIXMAP (clist_row->cell[column])->mask; + } + + return 1; +} + +void +gtk_cmclist_set_pixtext (GtkCMCList *clist, + gint row, + gint column, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap, + GdkBitmap *mask) +{ + GtkCMCListRow *clist_row; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) + return; + + clist_row = ROW_ELEMENT (clist, row)->data; + + g_object_ref (pixmap); + if (mask) g_object_ref (mask); + GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents + (clist, clist_row, column, GTK_CMCELL_PIXTEXT, text, spacing, pixmap, mask); + + /* redraw the list if it's not frozen */ + if (CLIST_UNFROZEN (clist)) + { + if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row); + } +} + +gint +gtk_cmclist_get_pixtext (GtkCMCList *clist, + gint row, + gint column, + gchar **text, + guint8 *spacing, + GdkPixmap **pixmap, + GdkBitmap **mask) +{ + GtkCMCListRow *clist_row; + + g_return_val_if_fail (GTK_IS_CMCLIST (clist), 0); + + if (row < 0 || row >= clist->rows) + return 0; + if (column < 0 || column >= clist->columns) + return 0; + + clist_row = ROW_ELEMENT (clist, row)->data; + + if (clist_row->cell[column].type != GTK_CMCELL_PIXTEXT) + return 0; + + if (text) + *text = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text; + if (spacing) + *spacing = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing; + if (pixmap) + *pixmap = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixmap; + + /* mask can be NULL */ + if (mask) + *mask = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->mask; + + return 1; +} + +void +gtk_cmclist_set_shift (GtkCMCList *clist, + gint row, + gint column, + gint vertical, + gint horizontal) +{ + GtkRequisition requisition = { 0 }; + GtkCMCListRow *clist_row; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) + return; + + clist_row = ROW_ELEMENT (clist, row)->data; + + if (clist->column[column].auto_resize && + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row, + column, &requisition); + + clist_row->cell[column].vertical = vertical; + clist_row->cell[column].horizontal = horizontal; + + column_auto_resize (clist, clist_row, column, requisition.width); + + if (CLIST_UNFROZEN (clist) && gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row); +} + +/* PRIVATE CELL FUNCTIONS + * set_cell_contents + * cell_size_request + */ +static void +set_cell_contents (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint column, + GtkCMCellType type, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap, + GdkBitmap *mask) +{ + GtkRequisition requisition; + gchar *old_text = NULL; + GdkPixmap *old_pixmap = NULL; + GdkBitmap *old_mask = NULL; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + g_return_if_fail (clist_row != NULL); + + if (clist->column[column].auto_resize && + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row, + column, &requisition); + + switch (clist_row->cell[column].type) + { + case GTK_CMCELL_EMPTY: + break; + case GTK_CMCELL_TEXT: + old_text = GTK_CMCELL_TEXT (clist_row->cell[column])->text; + break; + case GTK_CMCELL_PIXMAP: + old_pixmap = GTK_CMCELL_PIXMAP (clist_row->cell[column])->pixmap; + old_mask = GTK_CMCELL_PIXMAP (clist_row->cell[column])->mask; + break; + case GTK_CMCELL_PIXTEXT: + old_text = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text; + old_pixmap = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixmap; + old_mask = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->mask; + break; + case GTK_CMCELL_WIDGET: + /* unimplemented */ + break; + default: + break; + } + + clist_row->cell[column].type = GTK_CMCELL_EMPTY; + + /* Note that pixmap and mask were already ref'ed by the caller + */ + switch (type) + { + case GTK_CMCELL_TEXT: + if (text) + { + clist_row->cell[column].type = GTK_CMCELL_TEXT; + GTK_CMCELL_TEXT (clist_row->cell[column])->text = g_strdup (text); + } + break; + case GTK_CMCELL_PIXMAP: + if (pixmap) + { + clist_row->cell[column].type = GTK_CMCELL_PIXMAP; + GTK_CMCELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap; + /* We set the mask even if it is NULL */ + GTK_CMCELL_PIXMAP (clist_row->cell[column])->mask = mask; + } + break; + case GTK_CMCELL_PIXTEXT: + if (text && pixmap) + { + clist_row->cell[column].type = GTK_CMCELL_PIXTEXT; + GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text); + GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing; + GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap; + GTK_CMCELL_PIXTEXT (clist_row->cell[column])->mask = mask; + } + break; + default: + break; + } + + if (clist->column[column].auto_resize && + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + column_auto_resize (clist, clist_row, column, requisition.width); + + g_free (old_text); + if (old_pixmap) + g_object_unref (old_pixmap); + if (old_mask) + g_object_unref (old_mask); +} + +PangoLayout * +_gtk_cmclist_create_cell_layout (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint column) +{ + PangoLayout *layout; + GtkStyle *style; + GtkCMCell *cell; + gchar *text; + + get_cell_style (clist, clist_row, GTK_STATE_NORMAL, column, &style, + NULL, NULL); + + + cell = &clist_row->cell[column]; + switch (cell->type) + { + case GTK_CMCELL_TEXT: + case GTK_CMCELL_PIXTEXT: + text = ((cell->type == GTK_CMCELL_PIXTEXT) ? + GTK_CMCELL_PIXTEXT (*cell)->text : + GTK_CMCELL_TEXT (*cell)->text); + + if (!text) + return NULL; + + layout = gtk_widget_create_pango_layout (GTK_WIDGET (clist), + ((cell->type == GTK_CMCELL_PIXTEXT) ? + GTK_CMCELL_PIXTEXT (*cell)->text : + GTK_CMCELL_TEXT (*cell)->text)); + pango_layout_set_font_description (layout, style->font_desc); + + return layout; + + default: + return NULL; + } +} + +static void +cell_size_request (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint column, + GtkRequisition *requisition) +{ + gint width; + gint height; + PangoLayout *layout; + PangoRectangle logical_rect; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + g_return_if_fail (requisition != NULL); + + layout = _gtk_cmclist_create_cell_layout (clist, clist_row, column); + if (layout) + { + pango_layout_get_pixel_extents (layout, NULL, &logical_rect); + + requisition->width = logical_rect.width; + requisition->height = logical_rect.height; + + g_object_unref (G_OBJECT (layout)); + } + else + { + requisition->width = 0; + requisition->height = 0; + } + + if (layout && clist_row->cell[column].type == GTK_CMCELL_PIXTEXT) + requisition->width += GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing; + + switch (clist_row->cell[column].type) + { + case GTK_CMCELL_PIXTEXT: + gdk_drawable_get_size (GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixmap, + &width, &height); + requisition->width += width; + requisition->height = MAX (requisition->height, height); + break; + case GTK_CMCELL_PIXMAP: + gdk_drawable_get_size (GTK_CMCELL_PIXMAP (clist_row->cell[column])->pixmap, + &width, &height); + requisition->width += width; + requisition->height = MAX (requisition->height, height); + break; + + default: + break; + } + + requisition->width += clist_row->cell[column].horizontal; + requisition->height += clist_row->cell[column].vertical; +} + +/* PUBLIC INSERT/REMOVE ROW FUNCTIONS + * gtk_cmclist_prepend + * gtk_cmclist_append + * gtk_cmclist_insert + * gtk_cmclist_remove + * gtk_cmclist_clear + */ +gint +gtk_cmclist_prepend (GtkCMCList *clist, + gchar *text[]) +{ + g_return_val_if_fail (GTK_IS_CMCLIST (clist), -1); + g_return_val_if_fail (text != NULL, -1); + + return GTK_CMCLIST_GET_CLASS (clist)->insert_row (clist, 0, text); +} + +gint +gtk_cmclist_append (GtkCMCList *clist, + gchar *text[]) +{ + g_return_val_if_fail (GTK_IS_CMCLIST (clist), -1); + g_return_val_if_fail (text != NULL, -1); + + return GTK_CMCLIST_GET_CLASS (clist)->insert_row (clist, clist->rows, text); +} + +gint +gtk_cmclist_insert (GtkCMCList *clist, + gint row, + gchar *text[]) +{ + g_return_val_if_fail (GTK_IS_CMCLIST (clist), -1); + g_return_val_if_fail (text != NULL, -1); + + if (row < 0 || row > clist->rows) + row = clist->rows; + + return GTK_CMCLIST_GET_CLASS (clist)->insert_row (clist, row, text); +} + +void +gtk_cmclist_remove (GtkCMCList *clist, + gint row) +{ + GTK_CMCLIST_GET_CLASS (clist)->remove_row (clist, row); +} + +void +gtk_cmclist_clear (GtkCMCList *clist) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + GTK_CMCLIST_GET_CLASS (clist)->clear (clist); +} + +/* PRIVATE INSERT/REMOVE ROW FUNCTIONS + * real_insert_row + * real_remove_row + * real_clear + * real_row_move + */ +static gint +real_insert_row (GtkCMCList *clist, + gint row, + gchar *text[]) +{ + gint i; + GtkCMCListRow *clist_row; + + g_return_val_if_fail (GTK_IS_CMCLIST (clist), -1); + g_return_val_if_fail (text != NULL, -1); + + /* return if out of bounds */ + if (row < 0 || row > clist->rows) + return -1; + + /* create the row */ + clist_row = row_new (clist); + + /* set the text in the row's columns */ + for (i = 0; i < clist->columns; i++) + if (text[i]) + GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents + (clist, clist_row, i, GTK_CMCELL_TEXT, text[i], 0, NULL ,NULL); + + if (!clist->rows) + { + clist->row_list = g_list_append (clist->row_list, clist_row); + clist->row_list_end = clist->row_list; + } + else + { + if (GTK_CMCLIST_AUTO_SORT(clist)) /* override insertion pos */ + { + GList *work; + + row = 0; + work = clist->row_list; + + if (clist->sort_type == GTK_SORT_ASCENDING) + { + while (row < clist->rows && + clist->compare (clist, clist_row, + GTK_CMCLIST_ROW (work)) > 0) + { + row++; + work = work->next; + } + } + else + { + while (row < clist->rows && + clist->compare (clist, clist_row, + GTK_CMCLIST_ROW (work)) < 0) + { + row++; + work = work->next; + } + } + } + + /* reset the row end pointer if we're inserting at the end of the list */ + if (row == clist->rows) + clist->row_list_end = (g_list_append (clist->row_list_end, + clist_row))->next; + else + clist->row_list = g_list_insert (clist->row_list, clist_row, row); + + } + clist->rows++; + + if (row < ROW_FROM_YPIXEL (clist, 0)) + clist->voffset -= (clist->row_height + CELL_SPACING); + + /* syncronize the selection list */ + sync_selection (clist, row, SYNC_INSERT); + + if (clist->rows == 1) + { + clist->focus_row = 0; + if (clist->selection_mode == GTK_SELECTION_BROWSE) + gtk_cmclist_select_row (clist, 0, -1); + } + + /* redraw the list if it isn't frozen */ + if (CLIST_UNFROZEN (clist)) + { + adjust_adjustments (clist, FALSE); + + if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + draw_rows (clist, NULL); + } + + return row; +} + +static void +real_remove_row (GtkCMCList *clist, + gint row) +{ + gint was_visible; + GList *list; + GtkCMCListRow *clist_row; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + /* return if out of bounds */ + if (row < 0 || row > (clist->rows - 1)) + return; + + was_visible = (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE); + + /* get the row we're going to delete */ + list = ROW_ELEMENT (clist, row); + g_assert (list != NULL); + clist_row = list->data; + + /* if we're removing a selected row, we have to make sure + * it's properly unselected, and then sync up the clist->selected + * list to reflect the deincrimented indexies of rows after the + * removal */ + if (clist_row->state == GTK_STATE_SELECTED) + g_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], 0, + row, -1, NULL); + + sync_selection (clist, row, SYNC_REMOVE); + + /* reset the row end pointer if we're removing at the end of the list */ + clist->rows--; + if (clist->row_list == list) + clist->row_list = g_list_next (list); + if (clist->row_list_end == list) + clist->row_list_end = g_list_previous (list); + list = g_list_remove (list, clist_row); + + if (row < ROW_FROM_YPIXEL (clist, 0)) + clist->voffset += clist->row_height + CELL_SPACING; + + if (clist->selection_mode == GTK_SELECTION_BROWSE && !clist->selection && + clist->focus_row >= 0) + g_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], 0, + clist->focus_row, -1, NULL); + + /* toast the row */ + row_delete (clist, clist_row); + + /* redraw the row if it isn't frozen */ + if (CLIST_UNFROZEN (clist)) + { + adjust_adjustments (clist, FALSE); + + if (was_visible) + draw_rows (clist, NULL); + } +} + +static void +real_clear (GtkCMCList *clist) +{ + GList *list; + GList *free_list; + gint i; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + /* free up the selection list */ + g_list_free (clist->selection); + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + + clist->selection = NULL; + clist->selection_end = NULL; + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + clist->voffset = 0; + clist->focus_row = -1; + clist->anchor = -1; + clist->undo_anchor = -1; + clist->anchor_state = GTK_STATE_SELECTED; + clist->drag_pos = -1; + + /* remove all the rows */ + GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED); + free_list = clist->row_list; + clist->row_list = NULL; + clist->row_list_end = NULL; + clist->rows = 0; + for (list = free_list; list; list = list->next) + row_delete (clist, GTK_CMCLIST_ROW (list)); + g_list_free (free_list); + GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED); + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + { + if (GTK_CMCLIST_SHOW_TITLES(clist) && clist->column[i].button) + gtk_cmclist_set_column_width + (clist, i, (clist->column[i].button->requisition.width - + (CELL_SPACING + (2 * COLUMN_INSET)))); + else + gtk_cmclist_set_column_width (clist, i, 0); + } + /* zero-out the scrollbars */ + if (clist->vadjustment) + { + gtk_adjustment_set_value (clist->vadjustment, 0.0); + CLIST_REFRESH (clist); + } + else + gtk_widget_queue_resize (GTK_WIDGET (clist)); +} + +static void +real_row_move (GtkCMCList *clist, + gint source_row, + gint dest_row) +{ + GtkCMCListRow *clist_row; + GList *list; + gint first, last; + gint d; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (GTK_CMCLIST_AUTO_SORT(clist)) + return; + + if (source_row < 0 || source_row >= clist->rows || + dest_row < 0 || dest_row >= clist->rows || + source_row == dest_row) + return; + + gtk_cmclist_freeze (clist); + + /* unlink source row */ + clist_row = ROW_ELEMENT (clist, source_row)->data; + if (source_row == clist->rows - 1) + clist->row_list_end = clist->row_list_end->prev; + clist->row_list = g_list_remove (clist->row_list, clist_row); + clist->rows--; + + /* relink source row */ + clist->row_list = g_list_insert (clist->row_list, clist_row, dest_row); + if (dest_row == clist->rows) + clist->row_list_end = clist->row_list_end->next; + clist->rows++; + + /* sync selection */ + if (source_row > dest_row) + { + first = dest_row; + last = source_row; + d = 1; + } + else + { + first = source_row; + last = dest_row; + d = -1; + } + + for (list = clist->selection; list; list = list->next) + { + if (list->data == GINT_TO_POINTER (source_row)) + list->data = GINT_TO_POINTER (dest_row); + else if (first <= GPOINTER_TO_INT (list->data) && + last >= GPOINTER_TO_INT (list->data)) + list->data = GINT_TO_POINTER (GPOINTER_TO_INT (list->data) + d); + } + + if (clist->focus_row == source_row) + clist->focus_row = dest_row; + else if (clist->focus_row > first) + clist->focus_row += d; + + gtk_cmclist_thaw (clist); +} + +/* PUBLIC ROW FUNCTIONS + * gtk_cmclist_moveto + * gtk_cmclist_set_row_height + * gtk_cmclist_set_row_data + * gtk_cmclist_set_row_data_full + * gtk_cmclist_get_row_data + * gtk_cmclist_find_row_from_data + * gtk_cmclist_swap_rows + * gtk_cmclist_row_move + * gtk_cmclist_row_is_visible + * gtk_cmclist_set_foreground + * gtk_cmclist_set_background + */ +void +gtk_cmclist_moveto (GtkCMCList *clist, + gint row, + gint column, + gfloat row_align, + gfloat col_align) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (row < -1 || row >= clist->rows) + return; + if (column < -1 || column >= clist->columns) + return; + + row_align = CLAMP (row_align, 0, 1); + col_align = CLAMP (col_align, 0, 1); + + /* adjust horizontal scrollbar */ + if (clist->hadjustment && column >= 0) + { + gint x; + + x = (COLUMN_LEFT (clist, column) - CELL_SPACING - COLUMN_INSET - + (col_align * (clist->clist_window_width - 2 * COLUMN_INSET - + CELL_SPACING - clist->column[column].area.width))); + if (x < 0) + gtk_adjustment_set_value (clist->hadjustment, 0.0); + else if (x > LIST_WIDTH (clist) - clist->clist_window_width) + gtk_adjustment_set_value + (clist->hadjustment, LIST_WIDTH (clist) - clist->clist_window_width); + else + gtk_adjustment_set_value (clist->hadjustment, x); + } + + /* adjust vertical scrollbar */ + if (clist->vadjustment && row >= 0) + move_vertical (clist, row, row_align); +} + +void +gtk_cmclist_set_row_height (GtkCMCList *clist, + guint height) +{ + GtkWidget *widget; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + widget = GTK_WIDGET (clist); + + if (height > 0) + { + clist->row_height = height; + GTK_CMCLIST_SET_FLAG (clist, CMCLIST_ROW_HEIGHT_SET); + } + else + { + GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_ROW_HEIGHT_SET); + clist->row_height = 0; + } + + if (widget->style->font_desc) + { + PangoContext *context = gtk_widget_get_pango_context (widget); + PangoFontMetrics *metrics; + + metrics = pango_context_get_metrics (context, + widget->style->font_desc, + pango_context_get_language (context)); + + if (!GTK_CMCLIST_ROW_HEIGHT_SET(clist)) + { + clist->row_height = (pango_font_metrics_get_ascent (metrics) + + pango_font_metrics_get_descent (metrics)); + clist->row_height = PANGO_PIXELS (clist->row_height); + } + + pango_font_metrics_unref (metrics); + } + + CLIST_REFRESH (clist); +} + +void +gtk_cmclist_set_row_data (GtkCMCList *clist, + gint row, + gpointer data) +{ + gtk_cmclist_set_row_data_full (clist, row, data, NULL); +} + +void +gtk_cmclist_set_row_data_full (GtkCMCList *clist, + gint row, + gpointer data, + GtkDestroyNotify destroy) +{ + GtkCMCListRow *clist_row; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (row < 0 || row > (clist->rows - 1)) + return; + + clist_row = ROW_ELEMENT (clist, row)->data; + + if (clist_row->destroy) + clist_row->destroy (clist_row->data); + + clist_row->data = data; + clist_row->destroy = destroy; +} + +gpointer +gtk_cmclist_get_row_data (GtkCMCList *clist, + gint row) +{ + GtkCMCListRow *clist_row; + + g_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL); + + if (row < 0 || row > (clist->rows - 1)) + return NULL; + + clist_row = ROW_ELEMENT (clist, row)->data; + return clist_row->data; +} + +gint +gtk_cmclist_find_row_from_data (GtkCMCList *clist, + gpointer data) +{ + GList *list; + gint n; + + g_return_val_if_fail (GTK_IS_CMCLIST (clist), -1); + + for (n = 0, list = clist->row_list; list; n++, list = list->next) + if (GTK_CMCLIST_ROW (list)->data == data) + return n; + + return -1; +} + +void +gtk_cmclist_swap_rows (GtkCMCList *clist, + gint row1, + gint row2) +{ + gint first, last; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + g_return_if_fail (row1 != row2); + + if (GTK_CMCLIST_AUTO_SORT(clist)) + return; + + gtk_cmclist_freeze (clist); + + first = MIN (row1, row2); + last = MAX (row1, row2); + + gtk_cmclist_row_move (clist, last, first); + gtk_cmclist_row_move (clist, first + 1, last); + + gtk_cmclist_thaw (clist); +} + +void +gtk_cmclist_row_move (GtkCMCList *clist, + gint source_row, + gint dest_row) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (GTK_CMCLIST_AUTO_SORT(clist)) + return; + + if (source_row < 0 || source_row >= clist->rows || + dest_row < 0 || dest_row >= clist->rows || + source_row == dest_row) + return; + + g_signal_emit (GTK_OBJECT (clist), clist_signals[ROW_MOVE], 0, + source_row, dest_row); +} + +GtkVisibility +gtk_cmclist_row_is_visible (GtkCMCList *clist, + gint row) +{ + gint top; + + g_return_val_if_fail (GTK_IS_CMCLIST (clist), 0); + + if (row < 0 || row >= clist->rows) + return GTK_VISIBILITY_NONE; + + if (clist->row_height == 0) + return GTK_VISIBILITY_NONE; + + if (row < ROW_FROM_YPIXEL (clist, 0)) + return GTK_VISIBILITY_NONE; + + if (row > ROW_FROM_YPIXEL (clist, clist->clist_window_height)) + return GTK_VISIBILITY_NONE; + + top = ROW_TOP_YPIXEL (clist, row); + + if ((top < 0) + || ((top + clist->row_height) >= clist->clist_window_height)) + return GTK_VISIBILITY_PARTIAL; + + return GTK_VISIBILITY_FULL; +} + +void +gtk_cmclist_set_foreground (GtkCMCList *clist, + gint row, + const GdkColor *color) +{ + GtkCMCListRow *clist_row; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (row < 0 || row >= clist->rows) + return; + + clist_row = ROW_ELEMENT (clist, row)->data; + + if (color) + { + clist_row->foreground = *color; + clist_row->fg_set = TRUE; + if (GTK_WIDGET_REALIZED (clist)) + gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (clist)), + &clist_row->foreground, TRUE, TRUE); + } + else + clist_row->fg_set = FALSE; + + if (CLIST_UNFROZEN (clist) && gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row); +} + +void +gtk_cmclist_set_background (GtkCMCList *clist, + gint row, + const GdkColor *color) +{ + GtkCMCListRow *clist_row; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (row < 0 || row >= clist->rows) + return; + + clist_row = ROW_ELEMENT (clist, row)->data; + + if (color) + { + clist_row->background = *color; + clist_row->bg_set = TRUE; + if (GTK_WIDGET_REALIZED (clist)) + gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (clist)), + &clist_row->background, TRUE, TRUE); + } + else + clist_row->bg_set = FALSE; + + if (CLIST_UNFROZEN (clist) + && (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) + GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row); +} + +/* PUBLIC ROW/CELL STYLE FUNCTIONS + * gtk_cmclist_set_cell_style + * gtk_cmclist_get_cell_style + * gtk_cmclist_set_row_style + * gtk_cmclist_get_row_style + */ +void +gtk_cmclist_set_cell_style (GtkCMCList *clist, + gint row, + gint column, + GtkStyle *style) +{ + GtkRequisition requisition = { 0 }; + GtkCMCListRow *clist_row; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (row < 0 || row >= clist->rows) + return; + if (column < 0 || column >= clist->columns) + return; + + clist_row = ROW_ELEMENT (clist, row)->data; + + if (clist_row->cell[column].style == style) + return; + + if (clist->column[column].auto_resize && + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row, + column, &requisition); + + if (clist_row->cell[column].style) + { + if (GTK_WIDGET_REALIZED (clist)) + gtk_style_detach (clist_row->cell[column].style); + g_object_unref (clist_row->cell[column].style); + } + + clist_row->cell[column].style = style; + + if (clist_row->cell[column].style) + { + g_object_ref (clist_row->cell[column].style); + + if (GTK_WIDGET_REALIZED (clist)) + clist_row->cell[column].style = + gtk_style_attach (clist_row->cell[column].style, + clist->clist_window); + } + + column_auto_resize (clist, clist_row, column, requisition.width); + + /* redraw the list if it's not frozen */ + if (CLIST_UNFROZEN (clist)) + { + if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row); + } +} + +GtkStyle * +gtk_cmclist_get_cell_style (GtkCMCList *clist, + gint row, + gint column) +{ + GtkCMCListRow *clist_row; + + g_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL); + + if (row < 0 || row >= clist->rows || column < 0 || column >= clist->columns) + return NULL; + + clist_row = ROW_ELEMENT (clist, row)->data; + + return clist_row->cell[column].style; +} + +void +gtk_cmclist_set_row_style (GtkCMCList *clist, + gint row, + GtkStyle *style) +{ + GtkRequisition requisition; + GtkCMCListRow *clist_row; + gint *old_width; + gint i; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (row < 0 || row >= clist->rows) + return; + + clist_row = ROW_ELEMENT (clist, row)->data; + + if (clist_row->style == style) + return; + + old_width = g_new (gint, clist->columns); + + if (!GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + { + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + { + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row, + i, &requisition); + old_width[i] = requisition.width; + } + } + + if (clist_row->style) + { + if (GTK_WIDGET_REALIZED (clist)) + gtk_style_detach (clist_row->style); + g_object_unref (clist_row->style); + } + + clist_row->style = style; + + if (clist_row->style) + { + g_object_ref (clist_row->style); + + if (GTK_WIDGET_REALIZED (clist)) + clist_row->style = gtk_style_attach (clist_row->style, + clist->clist_window); + } + + if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + for (i = 0; i < clist->columns; i++) + column_auto_resize (clist, clist_row, i, old_width[i]); + + g_free (old_width); + + /* redraw the list if it's not frozen */ + if (CLIST_UNFROZEN (clist)) + { + if (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row); + } +} + +GtkStyle * +gtk_cmclist_get_row_style (GtkCMCList *clist, + gint row) +{ + GtkCMCListRow *clist_row; + + g_return_val_if_fail (GTK_IS_CMCLIST (clist), NULL); + + if (row < 0 || row >= clist->rows) + return NULL; + + clist_row = ROW_ELEMENT (clist, row)->data; + + return clist_row->style; +} + +/* PUBLIC SELECTION FUNCTIONS + * gtk_cmclist_set_selectable + * gtk_cmclist_get_selectable + * gtk_cmclist_select_row + * gtk_cmclist_unselect_row + * gtk_cmclist_select_all + * gtk_cmclist_unselect_all + * gtk_cmclist_undo_selection + */ +void +gtk_cmclist_set_selectable (GtkCMCList *clist, + gint row, + gboolean selectable) +{ + GtkCMCListRow *clist_row; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (row < 0 || row >= clist->rows) + return; + + clist_row = ROW_ELEMENT (clist, row)->data; + + if (selectable == clist_row->selectable) + return; + + clist_row->selectable = selectable; + + if (!selectable && clist_row->state == GTK_STATE_SELECTED) + { + if (clist->anchor >= 0 && + clist->selection_mode == GTK_SELECTION_MULTIPLE) + { + clist->drag_button = 0; + remove_grab (clist); + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + } + g_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], 0, + row, -1, NULL); + } +} + +gboolean +gtk_cmclist_get_selectable (GtkCMCList *clist, + gint row) +{ + g_return_val_if_fail (GTK_IS_CMCLIST (clist), FALSE); + + if (row < 0 || row >= clist->rows) + return FALSE; + + return GTK_CMCLIST_ROW (ROW_ELEMENT (clist, row))->selectable; +} + +void +gtk_cmclist_select_row (GtkCMCList *clist, + gint row, + gint column) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (row < 0 || row >= clist->rows) + return; + if (column < -1 || column >= clist->columns) + return; + + g_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], 0, + row, column, NULL); +} + +void +gtk_cmclist_unselect_row (GtkCMCList *clist, + gint row, + gint column) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (row < 0 || row >= clist->rows) + return; + if (column < -1 || column >= clist->columns) + return; + + g_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], 0, + row, column, NULL); +} + +void +gtk_cmclist_select_all (GtkCMCList *clist) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + GTK_CMCLIST_GET_CLASS (clist)->select_all (clist); +} + +void +gtk_cmclist_unselect_all (GtkCMCList *clist) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + GTK_CMCLIST_GET_CLASS (clist)->unselect_all (clist); +} + +void +gtk_cmclist_undo_selection (GtkCMCList *clist) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (clist->selection_mode == GTK_SELECTION_MULTIPLE && + (clist->undo_selection || clist->undo_unselection)) + g_signal_emit (GTK_OBJECT (clist), clist_signals[UNDO_SELECTION], 0); +} + +/* PRIVATE SELECTION FUNCTIONS + * selection_find + * toggle_row + * fake_toggle_row + * toggle_focus_row + * toggle_add_mode + * real_select_row + * real_unselect_row + * real_select_all + * real_unselect_all + * fake_unselect_all + * real_undo_selection + * set_anchor + * resync_selection + * update_extended_selection + * start_selection + * end_selection + * extend_selection + * sync_selection + */ +static GList * +selection_find (GtkCMCList *clist, + gint row_number, + GList *row_list_element) +{ + return g_list_find (clist->selection, GINT_TO_POINTER (row_number)); +} + +static void +toggle_row (GtkCMCList *clist, + gint row, + gint column, + GdkEvent *event) +{ + GtkCMCListRow *clist_row; + + switch (clist->selection_mode) + { + case GTK_SELECTION_MULTIPLE: + case GTK_SELECTION_SINGLE: + clist_row = ROW_ELEMENT (clist, row)->data; + + if (!clist_row) + return; + + if (clist_row->state == GTK_STATE_SELECTED) + { + g_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], 0, + row, column, event); + return; + } + case GTK_SELECTION_BROWSE: + g_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], 0, + row, column, event); + break; + default: + g_assert_not_reached (); + } +} + +static void +fake_toggle_row (GtkCMCList *clist, + gint row) +{ + GList *work; + + work = ROW_ELEMENT (clist, row); + + if (!work || !GTK_CMCLIST_ROW (work)->selectable) + return; + + if (GTK_CMCLIST_ROW (work)->state == GTK_STATE_NORMAL) + clist->anchor_state = GTK_CMCLIST_ROW (work)->state = GTK_STATE_SELECTED; + else + clist->anchor_state = GTK_CMCLIST_ROW (work)->state = GTK_STATE_NORMAL; + + if (CLIST_UNFROZEN (clist) && + gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, + GTK_CMCLIST_ROW (work)); +} + +static gboolean +clist_has_grab (GtkCMCList *clist) +{ + return (GTK_WIDGET_HAS_GRAB (clist) && + gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (clist)))); +} + +static void +toggle_focus_row (GtkCMCList *clist) +{ + g_return_if_fail (clist != 0); + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (clist_has_grab (clist) || + clist->focus_row < 0 || clist->focus_row >= clist->rows) + return; + + switch (clist->selection_mode) + { + case GTK_SELECTION_SINGLE: + toggle_row (clist, clist->focus_row, 0, NULL); + break; + case GTK_SELECTION_MULTIPLE: + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + + clist->anchor = clist->focus_row; + clist->drag_pos = clist->focus_row; + clist->undo_anchor = clist->focus_row; + + if (GTK_CMCLIST_ADD_MODE(clist)) + fake_toggle_row (clist, clist->focus_row); + else + GTK_CMCLIST_GET_CLASS (clist)->fake_unselect_all (clist,clist->focus_row); + + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + break; + default: + break; + } +} + +static void +toggle_add_mode (GtkCMCList *clist) +{ + g_return_if_fail (clist != 0); + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (clist_has_grab (clist) || + clist->selection_mode != GTK_SELECTION_MULTIPLE) + return; + + gtk_cmclist_draw_focus (GTK_WIDGET (clist)); + if (!GTK_CMCLIST_ADD_MODE(clist)) + { + GTK_CMCLIST_SET_FLAG (clist, CMCLIST_ADD_MODE); + gdk_gc_set_line_attributes (clist->xor_gc, 1, + GDK_LINE_ON_OFF_DASH, 0, 0); + gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2); + } + else + { + GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_ADD_MODE); + gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0); + clist->anchor_state = GTK_STATE_SELECTED; + } + gtk_cmclist_draw_focus (GTK_WIDGET (clist)); +} + +static void +real_select_row (GtkCMCList *clist, + gint row, + gint column, + GdkEvent *event) +{ + GtkCMCListRow *clist_row; + GList *list; + gint sel_row; + gboolean row_selected; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (row < 0 || row > (clist->rows - 1)) + return; + + switch (clist->selection_mode) + { + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_BROWSE: + + row_selected = FALSE; + list = clist->selection; + + while (list) + { + sel_row = GPOINTER_TO_INT (list->data); + list = list->next; + + if (row == sel_row) + row_selected = TRUE; + else + g_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], 0, + sel_row, column, event); + } + + if (row_selected) + return; + + default: + break; + } + + clist_row = ROW_ELEMENT (clist, row)->data; + + if (clist_row->state != GTK_STATE_NORMAL || !clist_row->selectable) + return; + + clist_row->state = GTK_STATE_SELECTED; + if (!clist->selection) + { + clist->selection = g_list_append (clist->selection, + GINT_TO_POINTER (row)); + clist->selection_end = clist->selection; + } + else + clist->selection_end = + g_list_append (clist->selection_end, GINT_TO_POINTER (row))->next; + + if (CLIST_UNFROZEN (clist) + && (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) + GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row); +} + +static void +real_unselect_row (GtkCMCList *clist, + gint row, + gint column, + GdkEvent *event) +{ + GtkCMCListRow *clist_row; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (row < 0 || row > (clist->rows - 1)) + return; + + clist_row = ROW_ELEMENT (clist, row)->data; + + if (clist_row->state == GTK_STATE_SELECTED) + { + clist_row->state = GTK_STATE_NORMAL; + + if (clist->selection_end && + clist->selection_end->data == GINT_TO_POINTER (row)) + clist->selection_end = clist->selection_end->prev; + + clist->selection = g_list_remove (clist->selection, + GINT_TO_POINTER (row)); + + if (CLIST_UNFROZEN (clist) + && (gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE)) + GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, clist_row); + } +} + +static void +real_select_all (GtkCMCList *clist) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (clist_has_grab (clist)) + return; + + switch (clist->selection_mode) + { + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_BROWSE: + return; + + case GTK_SELECTION_MULTIPLE: + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + + if (clist->rows && + ((GtkCMCListRow *) (clist->row_list->data))->state != + GTK_STATE_SELECTED) + fake_toggle_row (clist, 0); + + clist->anchor_state = GTK_STATE_SELECTED; + clist->anchor = 0; + clist->drag_pos = 0; + clist->undo_anchor = clist->focus_row; + update_extended_selection (clist, clist->rows); + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + return; + default: + g_assert_not_reached (); + } +} + +static void +real_unselect_all (GtkCMCList *clist) +{ + GList *list; + gint i; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (clist_has_grab (clist)) + return; + + switch (clist->selection_mode) + { + case GTK_SELECTION_BROWSE: + if (clist->focus_row >= 0) + { + g_signal_emit (GTK_OBJECT (clist), + clist_signals[SELECT_ROW], 0, + clist->focus_row, -1, NULL); + return; + } + break; + case GTK_SELECTION_MULTIPLE: + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + + clist->anchor = -1; + clist->drag_pos = -1; + clist->undo_anchor = clist->focus_row; + break; + default: + break; + } + + list = clist->selection; + while (list) + { + i = GPOINTER_TO_INT (list->data); + list = list->next; + g_signal_emit (GTK_OBJECT (clist), + clist_signals[UNSELECT_ROW], 0, i, -1, NULL); + } +} + +static void +fake_unselect_all (GtkCMCList *clist, + gint row) +{ + GList *list; + GList *work; + gint i; + + if (row >= 0 && (work = ROW_ELEMENT (clist, row))) + { + if (GTK_CMCLIST_ROW (work)->state == GTK_STATE_NORMAL && + GTK_CMCLIST_ROW (work)->selectable) + { + GTK_CMCLIST_ROW (work)->state = GTK_STATE_SELECTED; + + if (CLIST_UNFROZEN (clist) && + gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, + GTK_CMCLIST_ROW (work)); + } + } + + clist->undo_selection = clist->selection; + clist->selection = NULL; + clist->selection_end = NULL; + + for (list = clist->undo_selection; list; list = list->next) + { + if ((i = GPOINTER_TO_INT (list->data)) == row || + !(work = g_list_nth (clist->row_list, i))) + continue; + + GTK_CMCLIST_ROW (work)->state = GTK_STATE_NORMAL; + if (CLIST_UNFROZEN (clist) && + gtk_cmclist_row_is_visible (clist, i) != GTK_VISIBILITY_NONE) + GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, i, + GTK_CMCLIST_ROW (work)); + } +} + +static void +real_undo_selection (GtkCMCList *clist) +{ + GList *work; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (clist_has_grab (clist) || + clist->selection_mode != GTK_SELECTION_MULTIPLE) + return; + + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + + if (!(clist->undo_selection || clist->undo_unselection)) + { + gtk_cmclist_unselect_all (clist); + return; + } + + for (work = clist->undo_selection; work; work = work->next) + g_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], 0, + GPOINTER_TO_INT (work->data), -1, NULL); + + for (work = clist->undo_unselection; work; work = work->next) + { + /* g_print ("unselect %d\n",GPOINTER_TO_INT (work->data)); */ + g_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], 0, + GPOINTER_TO_INT (work->data), -1, NULL); + } + + if (GTK_WIDGET_HAS_FOCUS(clist) && clist->focus_row != clist->undo_anchor) + { + gtk_cmclist_draw_focus (GTK_WIDGET (clist)); + clist->focus_row = clist->undo_anchor; + gtk_cmclist_draw_focus (GTK_WIDGET (clist)); + } + else + clist->focus_row = clist->undo_anchor; + + clist->undo_anchor = -1; + + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + + if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > + clist->clist_window_height) + gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0); + else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) + gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0); +} + +static void +set_anchor (GtkCMCList *clist, + gboolean add_mode, + gint anchor, + gint undo_anchor) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (clist->selection_mode != GTK_SELECTION_MULTIPLE || clist->anchor >= 0) + return; + + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + + if (add_mode) + fake_toggle_row (clist, anchor); + else + { + GTK_CMCLIST_GET_CLASS (clist)->fake_unselect_all (clist, anchor); + clist->anchor_state = GTK_STATE_SELECTED; + } + + clist->anchor = anchor; + clist->drag_pos = anchor; + clist->undo_anchor = undo_anchor; +} + +static void +resync_selection (GtkCMCList *clist, + GdkEvent *event) +{ + gint i; + gint e; + gint row; + GList *list; + GtkCMCListRow *clist_row; + + if (clist->selection_mode != GTK_SELECTION_MULTIPLE) + return; + + if (clist->anchor < 0 || clist->drag_pos < 0) + return; + + gtk_cmclist_freeze (clist); + + i = MIN (clist->anchor, clist->drag_pos); + e = MAX (clist->anchor, clist->drag_pos); + + if (clist->undo_selection) + { + list = clist->selection; + clist->selection = clist->undo_selection; + clist->selection_end = g_list_last (clist->selection); + clist->undo_selection = list; + list = clist->selection; + while (list) + { + row = GPOINTER_TO_INT (list->data); + list = list->next; + if (row < i || row > e) + { + clist_row = g_list_nth (clist->row_list, row)->data; + if (clist_row->selectable) + { + clist_row->state = GTK_STATE_SELECTED; + g_signal_emit (GTK_OBJECT (clist), + clist_signals[UNSELECT_ROW], 0, + row, -1, event); + clist->undo_selection = g_list_prepend + (clist->undo_selection, GINT_TO_POINTER (row)); + } + } + } + } + + if (clist->anchor < clist->drag_pos) + { + for (list = g_list_nth (clist->row_list, i); i <= e; + i++, list = list->next) + if (GTK_CMCLIST_ROW (list)->selectable) + { + if (g_list_find (clist->selection, GINT_TO_POINTER(i))) + { + if (GTK_CMCLIST_ROW (list)->state == GTK_STATE_NORMAL) + { + GTK_CMCLIST_ROW (list)->state = GTK_STATE_SELECTED; + g_signal_emit (GTK_OBJECT (clist), + clist_signals[UNSELECT_ROW], 0, + i, -1, event); + clist->undo_selection = + g_list_prepend (clist->undo_selection, + GINT_TO_POINTER (i)); + } + } + else if (GTK_CMCLIST_ROW (list)->state == GTK_STATE_SELECTED) + { + GTK_CMCLIST_ROW (list)->state = GTK_STATE_NORMAL; + clist->undo_unselection = + g_list_prepend (clist->undo_unselection, + GINT_TO_POINTER (i)); + } + } + } + else + { + for (list = g_list_nth (clist->row_list, e); i <= e; + e--, list = list->prev) + if (GTK_CMCLIST_ROW (list)->selectable) + { + if (g_list_find (clist->selection, GINT_TO_POINTER(e))) + { + if (GTK_CMCLIST_ROW (list)->state == GTK_STATE_NORMAL) + { + GTK_CMCLIST_ROW (list)->state = GTK_STATE_SELECTED; + g_signal_emit (GTK_OBJECT (clist), + clist_signals[UNSELECT_ROW], 0, + e, -1, event); + clist->undo_selection = + g_list_prepend (clist->undo_selection, + GINT_TO_POINTER (e)); + } + } + else if (GTK_CMCLIST_ROW (list)->state == GTK_STATE_SELECTED) + { + GTK_CMCLIST_ROW (list)->state = GTK_STATE_NORMAL; + clist->undo_unselection = + g_list_prepend (clist->undo_unselection, + GINT_TO_POINTER (e)); + } + } + } + + clist->undo_unselection = g_list_reverse (clist->undo_unselection); + for (list = clist->undo_unselection; list; list = list->next) + g_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], 0, + GPOINTER_TO_INT (list->data), -1, event); + + clist->anchor = -1; + clist->drag_pos = -1; + + gtk_cmclist_thaw (clist); +} + +static void +update_extended_selection (GtkCMCList *clist, + gint row) +{ + gint i; + GList *list; + GdkRectangle area; + gint s1 = -1; + gint s2 = -1; + gint e1 = -1; + gint e2 = -1; + gint y1 = clist->clist_window_height; + gint y2 = clist->clist_window_height; + gint h1 = 0; + gint h2 = 0; + gint top; + + if (clist->selection_mode != GTK_SELECTION_MULTIPLE || clist->anchor == -1) + return; + + if (row < 0) + row = 0; + if (row >= clist->rows) + row = clist->rows - 1; + + /* extending downwards */ + if (row > clist->drag_pos && clist->anchor <= clist->drag_pos) + { + s2 = clist->drag_pos + 1; + e2 = row; + } + /* extending upwards */ + else if (row < clist->drag_pos && clist->anchor >= clist->drag_pos) + { + s2 = row; + e2 = clist->drag_pos - 1; + } + else if (row < clist->drag_pos && clist->anchor < clist->drag_pos) + { + e1 = clist->drag_pos; + /* row and drag_pos on different sides of anchor : + take back the selection between anchor and drag_pos, + select between anchor and row */ + if (row < clist->anchor) + { + s1 = clist->anchor + 1; + s2 = row; + e2 = clist->anchor - 1; + } + /* take back the selection between anchor and drag_pos */ + else + s1 = row + 1; + } + else if (row > clist->drag_pos && clist->anchor > clist->drag_pos) + { + s1 = clist->drag_pos; + /* row and drag_pos on different sides of anchor : + take back the selection between anchor and drag_pos, + select between anchor and row */ + if (row > clist->anchor) + { + e1 = clist->anchor - 1; + s2 = clist->anchor + 1; + e2 = row; + } + /* take back the selection between anchor and drag_pos */ + else + e1 = row - 1; + } + + clist->drag_pos = row; + + area.x = 0; + area.width = clist->clist_window_width; + + /* restore the elements between s1 and e1 */ + if (s1 >= 0) + { + for (i = s1, list = g_list_nth (clist->row_list, i); i <= e1; + i++, list = list->next) + if (GTK_CMCLIST_ROW (list)->selectable) + { + if (GTK_CMCLIST_GET_CLASS (clist)->selection_find (clist, i, list)) + GTK_CMCLIST_ROW (list)->state = GTK_STATE_SELECTED; + else + GTK_CMCLIST_ROW (list)->state = GTK_STATE_NORMAL; + } + + top = ROW_TOP_YPIXEL (clist, clist->focus_row); + + if (top + clist->row_height <= 0) + { + area.y = 0; + area.height = ROW_TOP_YPIXEL (clist, e1) + clist->row_height; + draw_rows (clist, &area); + gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0); + } + else if (top >= clist->clist_window_height) + { + area.y = ROW_TOP_YPIXEL (clist, s1) - 1; + area.height = clist->clist_window_height - area.y; + draw_rows (clist, &area); + gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0); + } + else if (top < 0) + gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0); + else if (top + clist->row_height > clist->clist_window_height) + gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0); + + y1 = ROW_TOP_YPIXEL (clist, s1) - 1; + h1 = (e1 - s1 + 1) * (clist->row_height + CELL_SPACING); + } + + /* extend the selection between s2 and e2 */ + if (s2 >= 0) + { + for (i = s2, list = g_list_nth (clist->row_list, i); i <= e2; + i++, list = list->next) + if (GTK_CMCLIST_ROW (list)->selectable && + GTK_CMCLIST_ROW (list)->state != clist->anchor_state) + GTK_CMCLIST_ROW (list)->state = clist->anchor_state; + + top = ROW_TOP_YPIXEL (clist, clist->focus_row); + + if (top + clist->row_height <= 0) + { + area.y = 0; + area.height = ROW_TOP_YPIXEL (clist, e2) + clist->row_height; + draw_rows (clist, &area); + gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0); + } + else if (top >= clist->clist_window_height) + { + area.y = ROW_TOP_YPIXEL (clist, s2) - 1; + area.height = clist->clist_window_height - area.y; + draw_rows (clist, &area); + gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0); + } + else if (top < 0) + gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0); + else if (top + clist->row_height > clist->clist_window_height) + gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0); + + y2 = ROW_TOP_YPIXEL (clist, s2) - 1; + h2 = (e2 - s2 + 1) * (clist->row_height + CELL_SPACING); + } + + area.y = MAX (0, MIN (y1, y2)); + if (area.y > clist->clist_window_height) + area.y = 0; + area.height = MIN (clist->clist_window_height, h1 + h2); + if (s1 >= 0 && s2 >= 0) + area.height += (clist->row_height + CELL_SPACING); + draw_rows (clist, &area); +} + +static void +start_selection (GtkCMCList *clist) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (clist_has_grab (clist)) + return; + + set_anchor (clist, GTK_CMCLIST_ADD_MODE(clist), clist->focus_row, + clist->focus_row); +} + +static void +end_selection (GtkCMCList *clist) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (clist))) && + GTK_WIDGET_HAS_FOCUS (clist)) + return; + + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); +} + +static void +extend_selection (GtkCMCList *clist, + GtkScrollType scroll_type, + gfloat position, + gboolean auto_start_selection) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (clist_has_grab (clist) || + clist->selection_mode != GTK_SELECTION_MULTIPLE) + return; + + if (auto_start_selection) + set_anchor (clist, GTK_CMCLIST_ADD_MODE(clist), clist->focus_row, + clist->focus_row); + else if (clist->anchor == -1) + return; + + move_focus_row (clist, scroll_type, position); + + if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > + clist->clist_window_height) + gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0); + else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) + gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0); + + update_extended_selection (clist, clist->focus_row); +} + +static void +sync_selection (GtkCMCList *clist, + gint row, + gint mode) +{ + GList *list; + gint d; + + if (mode == SYNC_INSERT) + d = 1; + else + d = -1; + + if (clist->focus_row >= row) + { + if (d > 0 || clist->focus_row > row) + clist->focus_row += d; + if (clist->focus_row == -1 && clist->rows >= 1) + clist->focus_row = 0; + else if (d < 0 && clist->focus_row >= clist->rows - 1) + clist->focus_row = clist->rows - 2; + else if (clist->focus_row >= clist->rows) /* Paranoia */ + clist->focus_row = clist->rows - 1; + } + + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + + clist->anchor = -1; + clist->drag_pos = -1; + clist->undo_anchor = clist->focus_row; + + list = clist->selection; + + while (list) + { + if (GPOINTER_TO_INT (list->data) >= row) + list->data = ((gchar*) list->data) + d; + list = list->next; + } +} + +/* GTKOBJECT + * gtk_cmclist_destroy + * gtk_cmclist_finalize + */ +static void +gtk_cmclist_destroy (GtkObject *object) +{ + gint i; + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCLIST (object)); + + clist = GTK_CMCLIST (object); + + /* freeze the list */ + clist->freeze_count++; + + /* get rid of all the rows */ + gtk_cmclist_clear (clist); + + /* Since we don't have a _remove method, unparent the children + * instead of destroying them so the focus will be unset properly. + * (For other containers, the _remove method takes care of the + * unparent) The destroy will happen when the refcount drops + * to zero. + */ + + /* unref adjustments */ + if (clist->hadjustment) + { + g_signal_handlers_disconnect_matched(GTK_OBJECT (clist->hadjustment), G_SIGNAL_MATCH_DATA, + 0, 0, 0, 0, clist); + g_object_unref (GTK_OBJECT (clist->hadjustment)); + clist->hadjustment = NULL; + } + if (clist->vadjustment) + { + g_signal_handlers_disconnect_matched(GTK_OBJECT (clist->vadjustment), G_SIGNAL_MATCH_DATA, + 0, 0, 0, 0, clist); + g_object_unref (GTK_OBJECT (clist->vadjustment)); + clist->vadjustment = NULL; + } + + remove_grab (clist); + + /* destroy the column buttons */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button) + { + gtk_widget_unparent (clist->column[i].button); + clist->column[i].button = NULL; + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (*GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_cmclist_finalize (GObject *object) +{ + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCLIST (object)); + + clist = GTK_CMCLIST (object); + + columns_delete (clist); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +/* GTKWIDGET + * gtk_cmclist_realize + * gtk_cmclist_unrealize + * gtk_cmclist_map + * gtk_cmclist_unmap + * gtk_cmclist_expose + * gtk_cmclist_style_set + * gtk_cmclist_button_press + * gtk_cmclist_button_release + * gtk_cmclist_motion + * gtk_cmclist_size_request + * gtk_cmclist_size_allocate + */ +static void +gtk_cmclist_realize (GtkWidget *widget) +{ + GtkCMCList *clist; + GdkWindowAttr attributes; + GdkGCValues values; + GtkCMCListRow *clist_row; + GList *list; + gint attributes_mask; + gint border_width; + gint i; + gint j; + + g_return_if_fail (GTK_IS_CMCLIST (widget)); + + clist = GTK_CMCLIST (widget); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + border_width = GTK_CONTAINER (widget)->border_width; + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x + border_width; + attributes.y = widget->allocation.y + border_width; + attributes.width = widget->allocation.width - border_width * 2; + attributes.height = widget->allocation.height - border_width * 2; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_KEY_RELEASE_MASK); + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + /* main window */ + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, clist); + + widget->style = gtk_style_attach (widget->style, widget->window); + + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); + + /* column-title window */ + + attributes.x = clist->column_title_area.x; + attributes.y = clist->column_title_area.y; + attributes.width = clist->column_title_area.width; + attributes.height = clist->column_title_area.height; + + clist->title_window = gdk_window_new (widget->window, &attributes, + attributes_mask); + gdk_window_set_user_data (clist->title_window, clist); + + gtk_style_set_background (widget->style, clist->title_window, + GTK_STATE_NORMAL); + gdk_window_show (clist->title_window); + + /* set things up so column buttons are drawn in title window */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button) + gtk_widget_set_parent_window (clist->column[i].button, + clist->title_window); + + /* clist-window */ + attributes.x = (clist->internal_allocation.x + + widget->style->xthickness); + attributes.y = (clist->internal_allocation.y + + widget->style->ythickness + + clist->column_title_area.height); + attributes.width = clist->clist_window_width; + attributes.height = clist->clist_window_height; + + clist->clist_window = gdk_window_new (widget->window, &attributes, + attributes_mask); + gdk_window_set_user_data (clist->clist_window, clist); + + gdk_window_set_background (clist->clist_window, + &widget->style->base[GTK_STATE_NORMAL]); + gdk_window_show (clist->clist_window); + gdk_drawable_get_size (clist->clist_window, &clist->clist_window_width, + &clist->clist_window_height); + + /* create resize windows */ + attributes.wclass = GDK_INPUT_ONLY; + attributes.event_mask = (GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + attributes_mask = GDK_WA_CURSOR; + attributes.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), + GDK_SB_H_DOUBLE_ARROW); + clist->cursor_drag = attributes.cursor; + + attributes.x = LIST_WIDTH (clist) + 1; + attributes.y = 0; + attributes.width = 0; + attributes.height = 0; + + for (i = 0; i < clist->columns; i++) + { + clist->column[i].window = gdk_window_new (clist->title_window, + &attributes, attributes_mask); + gdk_window_set_user_data (clist->column[i].window, clist); + } + + /* This is slightly less efficient than creating them with the + * right size to begin with, but easier + */ + size_allocate_title_buttons (clist); + + /* GCs */ + clist->fg_gc = gdk_gc_new (widget->window); + clist->bg_gc = gdk_gc_new (widget->window); + + /* We'll use this gc to do scrolling as well */ + gdk_gc_set_exposures (clist->fg_gc, TRUE); + + values.foreground = (widget->style->white.pixel==0 ? + widget->style->black:widget->style->white); + values.function = GDK_XOR; + values.subwindow_mode = GDK_INCLUDE_INFERIORS; + clist->xor_gc = gdk_gc_new_with_values (widget->window, + &values, + GDK_GC_FOREGROUND | + GDK_GC_FUNCTION | + GDK_GC_SUBWINDOW); + + /* attach optional row/cell styles, allocate foreground/background colors */ + list = clist->row_list; + for (i = 0; i < clist->rows; i++) + { + clist_row = list->data; + list = list->next; + + if (clist_row->style) + clist_row->style = gtk_style_attach (clist_row->style, + clist->clist_window); + + if (clist_row->fg_set || clist_row->bg_set) + { + GdkColormap *colormap; + + colormap = gtk_widget_get_colormap (widget); + if (clist_row->fg_set) + gdk_colormap_alloc_color (colormap, &clist_row->foreground, TRUE, TRUE); + if (clist_row->bg_set) + gdk_colormap_alloc_color (colormap, &clist_row->background, TRUE, TRUE); + } + + for (j = 0; j < clist->columns; j++) + if (clist_row->cell[j].style) + clist_row->cell[j].style = + gtk_style_attach (clist_row->cell[j].style, clist->clist_window); + } +} + +static void +gtk_cmclist_unrealize (GtkWidget *widget) +{ + gint i; + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCLIST (widget)); + + clist = GTK_CMCLIST (widget); + + /* freeze the list */ + clist->freeze_count++; + + if (GTK_WIDGET_MAPPED (widget)) + gtk_cmclist_unmap (widget); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + + /* detach optional row/cell styles */ + if (GTK_WIDGET_REALIZED (widget)) + { + GtkCMCListRow *clist_row; + GList *list; + gint j; + + list = clist->row_list; + for (i = 0; i < clist->rows; i++) + { + clist_row = list->data; + list = list->next; + + if (clist_row->style) + gtk_style_detach (clist_row->style); + for (j = 0; j < clist->columns; j++) + if (clist_row->cell[j].style) + gtk_style_detach (clist_row->cell[j].style); + } + } + + gdk_cursor_unref (clist->cursor_drag); + g_object_unref (clist->xor_gc); + g_object_unref (clist->fg_gc); + g_object_unref (clist->bg_gc); + + for (i = 0; i < clist->columns; i++) + { + if (clist->column[i].button) + gtk_widget_unrealize (clist->column[i].button); + if (clist->column[i].window) + { + gdk_window_set_user_data (clist->column[i].window, NULL); + gdk_window_destroy (clist->column[i].window); + clist->column[i].window = NULL; + } + } + + gdk_window_set_user_data (clist->clist_window, NULL); + gdk_window_destroy (clist->clist_window); + clist->clist_window = NULL; + + gdk_window_set_user_data (clist->title_window, NULL); + gdk_window_destroy (clist->title_window); + clist->title_window = NULL; + + clist->cursor_drag = NULL; + clist->xor_gc = NULL; + clist->fg_gc = NULL; + clist->bg_gc = NULL; + + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +} + +static void +gtk_cmclist_map (GtkWidget *widget) +{ + gint i; + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCLIST (widget)); + + clist = GTK_CMCLIST (widget); + + if (!GTK_WIDGET_MAPPED (widget)) + { + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + /* map column buttons */ + for (i = 0; i < clist->columns; i++) + { + if (clist->column[i].button && + GTK_WIDGET_VISIBLE (clist->column[i].button) && + !GTK_WIDGET_MAPPED (clist->column[i].button)) + gtk_widget_map (clist->column[i].button); + } + + for (i = 0; i < clist->columns; i++) + if (clist->column[i].window && clist->column[i].button) + { + gdk_window_raise (clist->column[i].window); + gdk_window_show (clist->column[i].window); + } + + gdk_window_show (clist->title_window); + gdk_window_show (clist->clist_window); + gdk_window_show (widget->window); + + /* unfreeze the list */ + clist->freeze_count = 0; + } +} + +static void +gtk_cmclist_unmap (GtkWidget *widget) +{ + gint i; + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCLIST (widget)); + + clist = GTK_CMCLIST (widget); + + if (GTK_WIDGET_MAPPED (widget)) + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + + if (clist_has_grab (clist)) + { + remove_grab (clist); + + GTK_CMCLIST_GET_CLASS (widget)->resync_selection (clist, NULL); + + clist->click_cell.row = -1; + clist->click_cell.column = -1; + clist->drag_button = 0; + + if (GTK_CMCLIST_IN_DRAG(clist)) + { + gpointer drag_data; + + GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_IN_DRAG); + drag_data = g_object_get_data (G_OBJECT (clist), + "gtk-site-data"); + if (drag_data) + g_signal_handlers_unblock_matched(G_OBJECT(clist), G_SIGNAL_MATCH_DATA, + 0, 0, 0, 0, drag_data); + } + } + + for (i = 0; i < clist->columns; i++) + if (clist->column[i].window) + gdk_window_hide (clist->column[i].window); + + gdk_window_hide (clist->clist_window); + gdk_window_hide (clist->title_window); + gdk_window_hide (widget->window); + + /* unmap column buttons */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button && + GTK_WIDGET_MAPPED (clist->column[i].button)) + gtk_widget_unmap (clist->column[i].button); + + /* freeze the list */ + clist->freeze_count++; + } +} + +static gint +gtk_cmclist_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkCMCList *clist; + + g_return_val_if_fail (GTK_IS_CMCLIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + clist = GTK_CMCLIST (widget); + + /* draw border */ + if (event->window == widget->window) + gtk_paint_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, clist->shadow_type, + NULL, NULL, NULL, + 0, 0, + clist->clist_window_width + + (2 * widget->style->xthickness), + clist->clist_window_height + + (2 * widget->style->ythickness) + + clist->column_title_area.height); + + /* exposure events on the list */ + if (event->window == clist->clist_window) + draw_rows (clist, &event->area); + + if (event->window == clist->clist_window && + clist->drag_highlight_row >= 0) + GTK_CMCLIST_GET_CLASS (clist)->draw_drag_highlight + (clist, g_list_nth (clist->row_list, + clist->drag_highlight_row)->data, + clist->drag_highlight_row, clist->drag_highlight_pos); + + if (event->window == clist->title_window) + { + gint i; + + for (i = 0; i < clist->columns; i++) + { + if (clist->column[i].button) + gtk_container_propagate_expose (GTK_CONTAINER (clist), + clist->column[i].button, + event); + } + } + } + + return FALSE; +} + +static void +gtk_cmclist_style_set (GtkWidget *widget, + GtkStyle *previous_style) +{ + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCLIST (widget)); + + if (GTK_WIDGET_CLASS (parent_class)->style_set) + (*GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style); + + clist = GTK_CMCLIST (widget); + + if (GTK_WIDGET_REALIZED (widget)) + { + gtk_style_set_background (widget->style, widget->window, widget->state); + gtk_style_set_background (widget->style, clist->title_window, GTK_STATE_NORMAL); + gdk_window_set_background (clist->clist_window, &widget->style->base[GTK_STATE_NORMAL]); + } + + /* Fill in data after widget has correct style */ + + /* text properties */ + if (!GTK_CMCLIST_ROW_HEIGHT_SET(clist)) + /* Reset clist->row_height */ + gtk_cmclist_set_row_height (clist, 0); + + /* Column widths */ + if (!GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + { + gint width; + gint i; + + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + { + width = gtk_cmclist_optimal_column_width (clist, i); + if (width != clist->column[i].width) + gtk_cmclist_set_column_width (clist, i, width); + } + } +} + +static gint +gtk_cmclist_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + gint i; + GtkCMCList *clist; + gint x; + gint y; + gint row; + gint column; + gint button_actions; + + g_return_val_if_fail (GTK_IS_CMCLIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + clist = GTK_CMCLIST (widget); + + button_actions = clist->button_actions[event->button - 1]; + + if (button_actions == GTK_CMBUTTON_IGNORED) + return FALSE; + + /* selections on the list */ + if (event->window == clist->clist_window) + { + x = event->x; + y = event->y; + + if (get_selection_info (clist, x, y, &row, &column)) + { + gint old_row = clist->focus_row; + + if (clist->focus_row == -1) + old_row = row; + + if (event->type == GDK_BUTTON_PRESS) + { + GdkEventMask mask = ((1 << (4 + event->button)) | + GDK_POINTER_MOTION_HINT_MASK | + GDK_BUTTON_RELEASE_MASK); + + if (gdk_pointer_grab (clist->clist_window, FALSE, mask, + NULL, NULL, event->time)) + return FALSE; + gtk_grab_add (widget); + + clist->click_cell.row = row; + clist->click_cell.column = column; + clist->drag_button = event->button; + } + else + { + clist->click_cell.row = -1; + clist->click_cell.column = -1; + + clist->drag_button = 0; + remove_grab (clist); + } + + if (button_actions & GTK_CMBUTTON_SELECTS) + { + if (GTK_CMCLIST_ADD_MODE(clist)) + { + GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_ADD_MODE); + if (GTK_WIDGET_HAS_FOCUS(widget)) + { + gtk_cmclist_draw_focus (widget); + gdk_gc_set_line_attributes (clist->xor_gc, 1, + GDK_LINE_SOLID, 0, 0); + clist->focus_row = row; + gtk_cmclist_draw_focus (widget); + } + else + { + gdk_gc_set_line_attributes (clist->xor_gc, 1, + GDK_LINE_SOLID, 0, 0); + clist->focus_row = row; + } + } + else if (row != clist->focus_row) + { + if (GTK_WIDGET_HAS_FOCUS(widget)) + { + gtk_cmclist_draw_focus (widget); + clist->focus_row = row; + gtk_cmclist_draw_focus (widget); + } + else + clist->focus_row = row; + } + } + + if (!GTK_WIDGET_HAS_FOCUS(widget)) + gtk_widget_grab_focus (widget); + + if (button_actions & GTK_CMBUTTON_SELECTS) + { + switch (clist->selection_mode) + { + case GTK_SELECTION_SINGLE: + if (event->type != GDK_BUTTON_PRESS) + { + g_signal_emit (GTK_OBJECT (clist), + clist_signals[SELECT_ROW], 0, + row, column, event); + clist->anchor = -1; + } + else + clist->anchor = row; + break; + case GTK_SELECTION_BROWSE: + g_signal_emit (GTK_OBJECT (clist), + clist_signals[SELECT_ROW], 0, + row, column, event); + break; + case GTK_SELECTION_MULTIPLE: + if (event->type != GDK_BUTTON_PRESS) + { + if (clist->anchor != -1) + { + update_extended_selection (clist, clist->focus_row); + GTK_CMCLIST_GET_CLASS (clist)->resync_selection + (clist, (GdkEvent *) event); + } + g_signal_emit (GTK_OBJECT (clist), + clist_signals[SELECT_ROW], 0, + row, column, event); + break; + } + + if (event->state & GDK_CONTROL_MASK) + { + if (event->state & GDK_SHIFT_MASK) + { + if (clist->anchor < 0) + { + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + clist->anchor = old_row; + clist->drag_pos = old_row; + clist->undo_anchor = old_row; + } + update_extended_selection (clist, clist->focus_row); + } + else + { + if (clist->anchor == -1) + set_anchor (clist, TRUE, row, old_row); + else + update_extended_selection (clist, + clist->focus_row); + } + break; + } + + if (event->state & GDK_SHIFT_MASK) + { + set_anchor (clist, FALSE, old_row, old_row); + update_extended_selection (clist, clist->focus_row); + break; + } + + if (clist->anchor == -1) + set_anchor (clist, FALSE, row, old_row); + else + update_extended_selection (clist, clist->focus_row); + break; + default: + break; + } + } + } + return TRUE; + } + + /* press on resize windows */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].resizeable && clist->column[i].window && + event->window == clist->column[i].window) + { + gpointer drag_data; + + if (gdk_pointer_grab (clist->column[i].window, FALSE, + GDK_POINTER_MOTION_HINT_MASK | + GDK_BUTTON1_MOTION_MASK | + GDK_BUTTON_RELEASE_MASK, + NULL, NULL, event->time)) + return FALSE; + + gtk_grab_add (widget); + GTK_CMCLIST_SET_FLAG (clist, CMCLIST_IN_DRAG); + + /* block attached dnd signal handler */ + drag_data = g_object_get_data (G_OBJECT (clist), "gtk-site-data"); + if (drag_data) + g_signal_handlers_block_matched(G_OBJECT(clist), G_SIGNAL_MATCH_DATA, + 0, 0, 0, 0, drag_data); + + if (!GTK_WIDGET_HAS_FOCUS(widget)) + gtk_widget_grab_focus (widget); + + clist->drag_pos = i; + clist->x_drag = (COLUMN_LEFT_XPIXEL(clist, i) + COLUMN_INSET + + clist->column[i].area.width + CELL_SPACING); + + if (GTK_CMCLIST_ADD_MODE(clist)) + gdk_gc_set_line_attributes (clist->xor_gc, 1, GDK_LINE_SOLID, 0, 0); + draw_xor_line (clist); + + return TRUE; + } + + return FALSE; +} + +static gint +gtk_cmclist_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + GtkCMCList *clist; + gint button_actions; + + g_return_val_if_fail (GTK_IS_CMCLIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + clist = GTK_CMCLIST (widget); + + button_actions = clist->button_actions[event->button - 1]; + if (button_actions == GTK_CMBUTTON_IGNORED) + return FALSE; + + /* release on resize windows */ + if (GTK_CMCLIST_IN_DRAG(clist)) + { + gpointer drag_data; + gint width; + gint x; + gint i; + + i = clist->drag_pos; + clist->drag_pos = -1; + + /* unblock attached dnd signal handler */ + drag_data = g_object_get_data (G_OBJECT (clist), "gtk-site-data"); + if (drag_data) + g_signal_handlers_unblock_matched(G_OBJECT(clist), G_SIGNAL_MATCH_DATA, + 0, 0, 0, 0, drag_data); + + GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_IN_DRAG); + gtk_widget_get_pointer (widget, &x, NULL); + gtk_grab_remove (widget); + gdk_display_pointer_ungrab (gtk_widget_get_display (widget), event->time); + + if (clist->x_drag >= 0) + draw_xor_line (clist); + + if (GTK_CMCLIST_ADD_MODE(clist)) + { + gdk_gc_set_line_attributes (clist->xor_gc, 1, + GDK_LINE_ON_OFF_DASH, 0, 0); + gdk_gc_set_dashes (clist->xor_gc, 0, "\4\4", 2); + } + + width = new_column_width (clist, i, &x); + gtk_cmclist_set_column_width (clist, i, width); + + return TRUE; + } + + if (clist->drag_button == event->button) + { + gint row; + gint column; + + clist->drag_button = 0; + clist->click_cell.row = -1; + clist->click_cell.column = -1; + + remove_grab (clist); + + if (button_actions & GTK_CMBUTTON_SELECTS) + { + switch (clist->selection_mode) + { + case GTK_SELECTION_MULTIPLE: + if (!(event->state & GDK_SHIFT_MASK) || + !GTK_WIDGET_CAN_FOCUS (widget) || + event->x < 0 || event->x >= clist->clist_window_width || + event->y < 0 || event->y >= clist->clist_window_height) + GTK_CMCLIST_GET_CLASS (clist)->resync_selection + (clist, (GdkEvent *) event); + break; + case GTK_SELECTION_SINGLE: + if (get_selection_info (clist, event->x, event->y, + &row, &column)) + { + if (row >= 0 && row < clist->rows && clist->anchor == row) + toggle_row (clist, row, column, (GdkEvent *) event); + } + clist->anchor = -1; + break; + default: + break; + } + } + + return TRUE; + } + + return FALSE; +} + +static gint +gtk_cmclist_motion (GtkWidget *widget, + GdkEventMotion *event) +{ + GtkCMCList *clist; + gint x; + gint y; + gint row; + gint new_width; + gint button_actions = 0; + + g_return_val_if_fail (GTK_IS_CMCLIST (widget), FALSE); + + clist = GTK_CMCLIST (widget); + if (!clist_has_grab (clist)) + return FALSE; + + if (clist->drag_button > 0) + button_actions = clist->button_actions[clist->drag_button - 1]; + + if (GTK_CMCLIST_IN_DRAG(clist)) + { + if (event->is_hint || event->window != widget->window) + gtk_widget_get_pointer (widget, &x, NULL); + else + x = event->x; + + new_width = new_column_width (clist, clist->drag_pos, &x); + if (x != clist->x_drag) + { + /* x_drag < 0 indicates that the xor line is already invisible */ + if (clist->x_drag >= 0) + draw_xor_line (clist); + + clist->x_drag = x; + + if (clist->x_drag >= 0) + draw_xor_line (clist); + } + + if (new_width <= MAX (COLUMN_MIN_WIDTH + 1, + clist->column[clist->drag_pos].min_width + 1)) + { + if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) < 0 && x < 0) + gtk_cmclist_moveto (clist, -1, clist->drag_pos, 0, 0); + return FALSE; + } + if (clist->column[clist->drag_pos].max_width >= COLUMN_MIN_WIDTH && + new_width >= clist->column[clist->drag_pos].max_width) + { + if (COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) + new_width > + clist->clist_window_width && x < 0) + move_horizontal (clist, + COLUMN_LEFT_XPIXEL (clist, clist->drag_pos) + + new_width - clist->clist_window_width + + COLUMN_INSET + CELL_SPACING); + return FALSE; + } + } + + if (event->is_hint || event->window != clist->clist_window) + gdk_window_get_pointer (clist->clist_window, &x, &y, NULL); + else + { + x = event->x; + y = event->y; + } + + if (GTK_CMCLIST_REORDERABLE(clist) && button_actions & GTK_CMBUTTON_DRAGS) + { + /* delayed drag start */ + if (event->window == clist->clist_window && + clist->click_cell.row >= 0 && clist->click_cell.column >= 0 && + (y < 0 || y >= clist->clist_window_height || + x < 0 || x >= clist->clist_window_width || + y < ROW_TOP_YPIXEL (clist, clist->click_cell.row) || + y >= (ROW_TOP_YPIXEL (clist, clist->click_cell.row) + + clist->row_height) || + x < COLUMN_LEFT_XPIXEL (clist, clist->click_cell.column) || + x >= (COLUMN_LEFT_XPIXEL(clist, clist->click_cell.column) + + clist->column[clist->click_cell.column].area.width))) + { + GtkTargetList *target_list; + + target_list = gtk_target_list_new (&clist_target_table, 1); + gtk_drag_begin (widget, target_list, GDK_ACTION_MOVE, + clist->drag_button, (GdkEvent *)event); + + } + return TRUE; + } + + /* horizontal autoscrolling */ + if (clist->hadjustment && LIST_WIDTH (clist) > clist->clist_window_width && + (x < 0 || x >= clist->clist_window_width)) + { + if (clist->htimer) + return FALSE; + + clist->htimer = gdk_threads_add_timeout + (SCROLL_TIME, (GSourceFunc) horizontal_timeout, clist); + + if (!((x < 0 && clist->hadjustment->value == 0) || + (x >= clist->clist_window_width && + clist->hadjustment->value == + LIST_WIDTH (clist) - clist->clist_window_width))) + { + if (x < 0) + move_horizontal (clist, -1 + (x/2)); + else + move_horizontal (clist, 1 + (x - clist->clist_window_width) / 2); + } + } + + if (GTK_CMCLIST_IN_DRAG(clist)) + return FALSE; + + /* vertical autoscrolling */ + row = ROW_FROM_YPIXEL (clist, y); + + /* don't scroll on last pixel row if it's a cell spacing */ + if (y == clist->clist_window_height - 1 && + y == ROW_TOP_YPIXEL (clist, row-1) + clist->row_height) + return FALSE; + + if (LIST_HEIGHT (clist) > clist->clist_window_height && + (y < 0 || y >= clist->clist_window_height)) + { + if (clist->vtimer) + return FALSE; + + clist->vtimer = gdk_threads_add_timeout (SCROLL_TIME, + (GSourceFunc) vertical_timeout, clist); + + if (clist->drag_button && + ((y < 0 && clist->focus_row == 0) || + (y >= clist->clist_window_height && + clist->focus_row == clist->rows - 1))) + return FALSE; + } + + row = CLAMP (row, 0, clist->rows - 1); + + if (button_actions & GTK_CMBUTTON_SELECTS & + !g_object_get_data (G_OBJECT (widget), "gtk-site-data")) + { + if (row == clist->focus_row) + return FALSE; + + gtk_cmclist_draw_focus (widget); + clist->focus_row = row; + gtk_cmclist_draw_focus (widget); + + switch (clist->selection_mode) + { + case GTK_SELECTION_BROWSE: + g_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], 0, + clist->focus_row, -1, event); + break; + case GTK_SELECTION_MULTIPLE: + update_extended_selection (clist, clist->focus_row); + break; + default: + break; + } + } + + if (ROW_TOP_YPIXEL(clist, row) < 0) + move_vertical (clist, row, 0); + else if (ROW_TOP_YPIXEL(clist, row) + clist->row_height > + clist->clist_window_height) + move_vertical (clist, row, 1); + + return FALSE; +} + +static void +gtk_cmclist_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkCMCList *clist; + gint i; + gint font_height = 0; + g_return_if_fail (GTK_IS_CMCLIST (widget)); + g_return_if_fail (requisition != NULL); + + clist = GTK_CMCLIST (widget); + + requisition->width = 0; + requisition->height = 0; + + /* compute the size of the column title (title) area */ + clist->column_title_area.height = 0; + if (GTK_CMCLIST_SHOW_TITLES(clist)) { + font_height = (pango_font_description_get_size((GTK_WIDGET(clist)->style)->font_desc)/PANGO_SCALE)*2+4; + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button) + { + GtkRequisition child_requisition; + + gtk_widget_size_request (clist->column[i].button, + &child_requisition); + clist->column_title_area.height = + MAX (clist->column_title_area.height, + child_requisition.height - 2); + } + clist->column_title_area.height = font_height; + } + requisition->width += (widget->style->xthickness + + GTK_CONTAINER (widget)->border_width) * 2; + requisition->height += (clist->column_title_area.height + + (widget->style->ythickness + + GTK_CONTAINER (widget)->border_width) * 2); + + /* if (!clist->hadjustment) */ + requisition->width += list_requisition_width (clist); + /* if (!clist->vadjustment) */ + requisition->height += LIST_HEIGHT (clist); +} + +static void +gtk_cmclist_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkCMCList *clist; + GtkAllocation clist_allocation; + gint border_width; + + g_return_if_fail (GTK_IS_CMCLIST (widget)); + g_return_if_fail (allocation != NULL); + + clist = GTK_CMCLIST (widget); + widget->allocation = *allocation; + border_width = GTK_CONTAINER (widget)->border_width; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x + border_width, + allocation->y + border_width, + allocation->width - border_width * 2, + allocation->height - border_width * 2); + } + + /* use internal allocation structure for all the math + * because it's easier than always subtracting the container + * border width */ + clist->internal_allocation.x = 0; + clist->internal_allocation.y = 0; + clist->internal_allocation.width = MAX (1, (gint)allocation->width - + border_width * 2); + clist->internal_allocation.height = MAX (1, (gint)allocation->height - + border_width * 2); + + /* allocate clist window assuming no scrollbars */ + clist_allocation.x = (clist->internal_allocation.x + + widget->style->xthickness); + clist_allocation.y = (clist->internal_allocation.y + + widget->style->ythickness + + clist->column_title_area.height); + clist_allocation.width = MAX (1, (gint)clist->internal_allocation.width - + (2 * (gint)widget->style->xthickness)); + clist_allocation.height = MAX (1, (gint)clist->internal_allocation.height - + (2 * (gint)widget->style->ythickness) - + (gint)clist->column_title_area.height); + + clist->clist_window_width = clist_allocation.width; + clist->clist_window_height = clist_allocation.height; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (clist->clist_window, + clist_allocation.x, + clist_allocation.y, + clist_allocation.width, + clist_allocation.height); + } + + /* position the window which holds the column title buttons */ + clist->column_title_area.x = widget->style->xthickness; + clist->column_title_area.y = widget->style->ythickness; + clist->column_title_area.width = clist_allocation.width; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (clist->title_window, + clist->column_title_area.x, + clist->column_title_area.y, + clist->column_title_area.width, + clist->column_title_area.height); + } + + /* column button allocation */ + size_allocate_columns (clist, FALSE); + size_allocate_title_buttons (clist); + + adjust_adjustments (clist, TRUE); +} + +/* GTKCONTAINER + * gtk_cmclist_forall + */ +static void +gtk_cmclist_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + GtkCMCList *clist; + guint i; + + g_return_if_fail (GTK_IS_CMCLIST (container)); + g_return_if_fail (callback != NULL); + + if (!include_internals) + return; + + clist = GTK_CMCLIST (container); + + /* callback for the column buttons */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button) + (*callback) (clist->column[i].button, callback_data); +} + +/* PRIVATE DRAWING FUNCTIONS + * get_cell_style + * draw_cell_pixmap + * draw_row + * draw_rows + * draw_xor_line + * clist_refresh + */ +static void +get_cell_style (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint state, + gint column, + GtkStyle **style, + GdkGC **fg_gc, + GdkGC **bg_gc) +{ + gint fg_state; + + if ((state == GTK_STATE_NORMAL) && + (GTK_WIDGET (clist)->state == GTK_STATE_INSENSITIVE)) + fg_state = GTK_STATE_INSENSITIVE; + else + fg_state = state; + + if (clist_row->cell[column].style) + { + if (style) + *style = clist_row->cell[column].style; + if (fg_gc) + *fg_gc = clist_row->cell[column].style->fg_gc[fg_state]; + if (bg_gc) { + if (state == GTK_STATE_SELECTED) + *bg_gc = clist_row->cell[column].style->bg_gc[state]; + else + *bg_gc = clist_row->cell[column].style->base_gc[state]; + } + } + else if (clist_row->style) + { + if (style) + *style = clist_row->style; + if (fg_gc) + *fg_gc = clist_row->style->fg_gc[fg_state]; + if (bg_gc) { + if (state == GTK_STATE_SELECTED) + *bg_gc = clist_row->style->bg_gc[state]; + else + *bg_gc = clist_row->style->base_gc[state]; + } + } + else + { + if (style) + *style = GTK_WIDGET (clist)->style; + if (fg_gc) + *fg_gc = GTK_WIDGET (clist)->style->fg_gc[fg_state]; + if (bg_gc) { + if (state == GTK_STATE_SELECTED) + *bg_gc = GTK_WIDGET (clist)->style->bg_gc[state]; + else + *bg_gc = GTK_WIDGET (clist)->style->base_gc[state]; + } + + if (state != GTK_STATE_SELECTED) + { + if (fg_gc && clist_row->fg_set) + *fg_gc = clist->fg_gc; + if (bg_gc && clist_row->bg_set) + *bg_gc = clist->bg_gc; + } + } +} + +static gint +draw_cell_pixmap (GdkWindow *window, + GdkRectangle *clip_rectangle, + GdkGC *fg_gc, + GdkPixmap *pixmap, + GdkBitmap *mask, + gint x, + gint y, + gint width, + gint height) +{ + gint xsrc = 0; + gint ysrc = 0; + + if (mask) + { + gdk_gc_set_clip_mask (fg_gc, mask); + gdk_gc_set_clip_origin (fg_gc, x, y); + } + + if (x < clip_rectangle->x) + { + xsrc = clip_rectangle->x - x; + width -= xsrc; + x = clip_rectangle->x; + } + if (x + width > clip_rectangle->x + clip_rectangle->width) + width = clip_rectangle->x + clip_rectangle->width - x; + + if (y < clip_rectangle->y) + { + ysrc = clip_rectangle->y - y; + height -= ysrc; + y = clip_rectangle->y; + } + if (y + height > clip_rectangle->y + clip_rectangle->height) + height = clip_rectangle->y + clip_rectangle->height - y; + + gdk_draw_drawable (window, fg_gc, pixmap, xsrc, ysrc, x, y, width, height); + gdk_gc_set_clip_origin (fg_gc, 0, 0); + if (mask) + gdk_gc_set_clip_mask (fg_gc, NULL); + + return x + MAX (width, 0); +} + +static void +draw_row (GtkCMCList *clist, + GdkRectangle *area, + gint row, + GtkCMCListRow *clist_row) +{ + GtkWidget *widget; + GdkRectangle *rect; + GdkRectangle row_rectangle; + GdkRectangle cell_rectangle; + GdkRectangle clip_rectangle; + GdkRectangle intersect_rectangle; + gint last_column; + gint state; + gint i; + + g_return_if_fail (clist != NULL); + + /* bail now if we arn't drawable yet */ + if (!GTK_WIDGET_DRAWABLE (clist) || row < 0 || row >= clist->rows) + return; + + widget = GTK_WIDGET (clist); + + /* if the function is passed the pointer to the row instead of null, + * it avoids this expensive lookup */ + if (!clist_row) + clist_row = ROW_ELEMENT (clist, row)->data; + + /* rectangle of the entire row */ + row_rectangle.x = 0; + row_rectangle.y = ROW_TOP_YPIXEL (clist, row); + row_rectangle.width = clist->clist_window_width; + row_rectangle.height = clist->row_height; + + /* rectangle of the cell spacing above the row */ + cell_rectangle.x = 0; + cell_rectangle.y = row_rectangle.y - CELL_SPACING; + cell_rectangle.width = row_rectangle.width; + cell_rectangle.height = CELL_SPACING; + + /* rectangle used to clip drawing operations, its y and height + * positions only need to be set once, so we set them once here. + * the x and width are set withing the drawing loop below once per + * column */ + clip_rectangle.y = row_rectangle.y; + clip_rectangle.height = row_rectangle.height; + + if (clist_row->state == GTK_STATE_NORMAL) + { + if (clist_row->fg_set) + gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground); + if (clist_row->bg_set) + gdk_gc_set_foreground (clist->bg_gc, &clist_row->background); + } + + state = clist_row->state; + + /* draw the cell borders and background */ + if (area) + { + rect = &intersect_rectangle; + if (gdk_rectangle_intersect (area, &cell_rectangle, + &intersect_rectangle)) + gdk_draw_rectangle (clist->clist_window, + widget->style->base_gc[GTK_STATE_NORMAL], + TRUE, + intersect_rectangle.x, + intersect_rectangle.y, + intersect_rectangle.width, + intersect_rectangle.height); + + /* the last row has to clear its bottom cell spacing too */ + if (clist_row == clist->row_list_end->data) + { + cell_rectangle.y += clist->row_height + CELL_SPACING; + + if (gdk_rectangle_intersect (area, &cell_rectangle, + &intersect_rectangle)) + gdk_draw_rectangle (clist->clist_window, + widget->style->base_gc[GTK_STATE_NORMAL], + TRUE, + intersect_rectangle.x, + intersect_rectangle.y, + intersect_rectangle.width, + intersect_rectangle.height); + } + + if (!gdk_rectangle_intersect (area, &row_rectangle,&intersect_rectangle)) + return; + + } + else + { + rect = &clip_rectangle; + gdk_draw_rectangle (clist->clist_window, + widget->style->base_gc[GTK_STATE_NORMAL], + TRUE, + cell_rectangle.x, + cell_rectangle.y, + cell_rectangle.width, + cell_rectangle.height); + + /* the last row has to clear its bottom cell spacing too */ + if (clist_row == clist->row_list_end->data) + { + cell_rectangle.y += clist->row_height + CELL_SPACING; + + gdk_draw_rectangle (clist->clist_window, + widget->style->base_gc[GTK_STATE_NORMAL], + TRUE, + cell_rectangle.x, + cell_rectangle.y, + cell_rectangle.width, + cell_rectangle.height); + } + } + + for (last_column = clist->columns - 1; + last_column >= 0 && !clist->column[last_column].visible; last_column--) + ; + + /* iterate and draw all the columns (row cells) and draw their contents */ + for (i = 0; i < clist->columns; i++) + { + GtkStyle *style; + GdkGC *fg_gc; + GdkGC *bg_gc; + PangoLayout *layout; + PangoRectangle logical_rect; + + gint width; + gint height; + gint pixmap_width; + gint offset = 0; + + if (!clist->column[i].visible) + continue; + + get_cell_style (clist, clist_row, state, i, &style, &fg_gc, &bg_gc); + + clip_rectangle.x = clist->column[i].area.x + clist->hoffset; + clip_rectangle.width = clist->column[i].area.width; + + /* calculate clipping region clipping region */ + clip_rectangle.x -= COLUMN_INSET + CELL_SPACING; + clip_rectangle.width += (2 * COLUMN_INSET + CELL_SPACING + + (i == last_column) * CELL_SPACING); + + if (area && !gdk_rectangle_intersect (area, &clip_rectangle, + &intersect_rectangle)) + continue; + + gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE, + rect->x, rect->y, rect->width, rect->height); + + clip_rectangle.x += COLUMN_INSET + CELL_SPACING; + clip_rectangle.width -= (2 * COLUMN_INSET + CELL_SPACING + + (i == last_column) * CELL_SPACING); + + + /* calculate real width for column justification */ + + layout = _gtk_cmclist_create_cell_layout (clist, clist_row, i); + if (layout) + { + pango_layout_get_pixel_extents (layout, NULL, &logical_rect); + width = logical_rect.width; + } + else + width = 0; + + pixmap_width = 0; + offset = 0; + switch (clist_row->cell[i].type) + { + case GTK_CMCELL_PIXMAP: + gdk_drawable_get_size (GTK_CMCELL_PIXMAP (clist_row->cell[i])->pixmap, + &pixmap_width, &height); + width += pixmap_width; + break; + case GTK_CMCELL_PIXTEXT: + gdk_drawable_get_size (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap, + &pixmap_width, &height); + width += pixmap_width + GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing; + break; + default: + break; + } + + switch (clist->column[i].justification) + { + case GTK_JUSTIFY_LEFT: + offset = clip_rectangle.x + clist_row->cell[i].horizontal; + break; + case GTK_JUSTIFY_RIGHT: + offset = (clip_rectangle.x + clist_row->cell[i].horizontal + + clip_rectangle.width - width); + break; + case GTK_JUSTIFY_CENTER: + case GTK_JUSTIFY_FILL: + offset = (clip_rectangle.x + clist_row->cell[i].horizontal + + (clip_rectangle.width / 2) - (width / 2)); + break; + }; + + /* Draw Text and/or Pixmap */ + switch (clist_row->cell[i].type) + { + case GTK_CMCELL_PIXMAP: + draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc, + GTK_CMCELL_PIXMAP (clist_row->cell[i])->pixmap, + GTK_CMCELL_PIXMAP (clist_row->cell[i])->mask, + offset, + clip_rectangle.y + clist_row->cell[i].vertical + + (clip_rectangle.height - height) / 2, + pixmap_width, height); + break; + case GTK_CMCELL_PIXTEXT: + offset = + draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc, + GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap, + GTK_CMCELL_PIXTEXT (clist_row->cell[i])->mask, + offset, + clip_rectangle.y + clist_row->cell[i].vertical+ + (clip_rectangle.height - height) / 2, + pixmap_width, height); + offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing; + + /* Fall through */ + case GTK_CMCELL_TEXT: + if (layout) + { + gint row_center_offset = (clist->row_height - logical_rect.height - 1) / 2; + + gdk_gc_set_clip_rectangle (fg_gc, &clip_rectangle); + gdk_draw_layout (clist->clist_window, fg_gc, + offset, + row_rectangle.y + row_center_offset + clist_row->cell[i].vertical, + layout); + g_object_unref (G_OBJECT (layout)); + gdk_gc_set_clip_rectangle (fg_gc, NULL); + } + break; + default: + break; + } + } + + /* draw focus rectangle */ + if (clist->focus_row == row && + GTK_WIDGET_CAN_FOCUS (widget) && GTK_WIDGET_HAS_FOCUS(widget)) + { + if (!area) + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, + row_rectangle.x, row_rectangle.y, + row_rectangle.width - 1, row_rectangle.height - 1); + else if (gdk_rectangle_intersect (area, &row_rectangle, + &intersect_rectangle)) + { + gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle); + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, + row_rectangle.x, row_rectangle.y, + row_rectangle.width - 1, + row_rectangle.height - 1); + gdk_gc_set_clip_rectangle (clist->xor_gc, NULL); + } + } +} + +static void +draw_rows (GtkCMCList *clist, + GdkRectangle *area) +{ + GList *list; + GtkCMCListRow *clist_row; + gint i; + gint first_row; + gint last_row; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (clist->row_height == 0 || + !GTK_WIDGET_DRAWABLE (clist)) + return; + + if (area) + { + first_row = ROW_FROM_YPIXEL (clist, area->y); + last_row = ROW_FROM_YPIXEL (clist, area->y + area->height); + } + else + { + first_row = ROW_FROM_YPIXEL (clist, 0); + last_row = ROW_FROM_YPIXEL (clist, clist->clist_window_height); + } + + /* this is a small special case which exposes the bottom cell line + * on the last row -- it might go away if I change the wall the cell + * spacings are drawn + */ + if (clist->rows == first_row) + first_row--; + + list = ROW_ELEMENT (clist, first_row); + i = first_row; + while (list) + { + clist_row = list->data; + list = list->next; + + if (i > last_row) + return; + + GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, area, i, clist_row); + i++; + } + + if (!area) + gdk_window_clear_area (clist->clist_window, 0, + ROW_TOP_YPIXEL (clist, i), 0, 0); +} + +static void +draw_xor_line (GtkCMCList *clist) +{ + GtkWidget *widget; + + g_return_if_fail (clist != NULL); + + widget = GTK_WIDGET (clist); + + gdk_draw_line (widget->window, clist->xor_gc, + clist->x_drag, + widget->style->ythickness, + clist->x_drag, + clist->column_title_area.height + + clist->clist_window_height + 1); +} + +static void +clist_refresh (GtkCMCList *clist) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (CLIST_UNFROZEN (clist)) + { + adjust_adjustments (clist, FALSE); + draw_rows (clist, NULL); + } +} + +/* get cell from coordinates + * get_selection_info + * gtk_cmclist_get_selection_info + */ +static gint +get_selection_info (GtkCMCList *clist, + gint x, + gint y, + gint *row, + gint *column) +{ + gint trow, tcol; + + g_return_val_if_fail (GTK_IS_CMCLIST (clist), 0); + + /* bounds checking, return false if the user clicked + * on a blank area */ + trow = ROW_FROM_YPIXEL (clist, y); + if (trow >= clist->rows) + return 0; + + if (row) + *row = trow; + + tcol = COLUMN_FROM_XPIXEL (clist, x); + if (tcol >= clist->columns) + return 0; + + if (column) + *column = tcol; + + return 1; +} + +gint +gtk_cmclist_get_selection_info (GtkCMCList *clist, + gint x, + gint y, + gint *row, + gint *column) +{ + g_return_val_if_fail (GTK_IS_CMCLIST (clist), 0); + return get_selection_info (clist, x, y, row, column); +} + +/* PRIVATE ADJUSTMENT FUNCTIONS + * adjust_adjustments + * vadjustment_changed + * hadjustment_changed + * vadjustment_value_changed + * hadjustment_value_changed + * check_exposures + */ +static void +adjust_adjustments (GtkCMCList *clist, + gboolean block_resize) +{ + if (clist->vadjustment) + { + clist->vadjustment->page_size = clist->clist_window_height; + clist->vadjustment->step_increment = clist->row_height; + clist->vadjustment->page_increment = + MAX (clist->vadjustment->page_size - clist->vadjustment->step_increment, + clist->vadjustment->page_size / 2); + clist->vadjustment->lower = 0; + clist->vadjustment->upper = LIST_HEIGHT (clist); + + if (clist->clist_window_height - clist->voffset > LIST_HEIGHT (clist) || + (clist->voffset + (gint)clist->vadjustment->value) != 0) + { + clist->vadjustment->value = MAX (0, (LIST_HEIGHT (clist) - + clist->clist_window_height)); + g_signal_emit_by_name (GTK_OBJECT (clist->vadjustment), + "value_changed"); + } + g_signal_emit_by_name (GTK_OBJECT (clist->vadjustment), "changed"); + } + + if (clist->hadjustment) + { + clist->hadjustment->page_size = clist->clist_window_width; + clist->hadjustment->step_increment = 10; + clist->hadjustment->page_increment = + MAX (clist->hadjustment->page_size - clist->hadjustment->step_increment, + clist->hadjustment->page_size / 2); + clist->hadjustment->lower = 0; + clist->hadjustment->upper = LIST_WIDTH (clist); + + if (clist->clist_window_width - clist->hoffset > LIST_WIDTH (clist) || + (clist->hoffset + (gint)clist->hadjustment->value) != 0) + { + clist->hadjustment->value = MAX (0, (LIST_WIDTH (clist) - + clist->clist_window_width)); + g_signal_emit_by_name (GTK_OBJECT (clist->hadjustment), + "value_changed"); + } + g_signal_emit_by_name (GTK_OBJECT (clist->hadjustment), "changed"); + } + + if (!block_resize && (!clist->vadjustment || !clist->hadjustment)) + { + GtkWidget *widget; + GtkRequisition requisition; + + widget = GTK_WIDGET (clist); + gtk_widget_size_request (widget, &requisition); + + if ((!clist->hadjustment && + requisition.width != widget->allocation.width) || + (!clist->vadjustment && + requisition.height != widget->allocation.height)) + gtk_widget_queue_resize (widget); + } +} + +static void +vadjustment_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkCMCList *clist; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + + clist = GTK_CMCLIST (data); +} + +static void +hadjustment_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkCMCList *clist; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + + clist = GTK_CMCLIST (data); +} + +static void +vadjustment_value_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkCMCList *clist; + gint dy, value; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (GTK_IS_CMCLIST (data)); + + clist = GTK_CMCLIST (data); + + if (adjustment != clist->vadjustment) + return; + + value = -adjustment->value; + dy = value - clist->voffset; + clist->voffset = value; + + if (GTK_WIDGET_DRAWABLE (clist)) + { + gdk_window_scroll (clist->clist_window, 0, dy); + gdk_window_process_updates (clist->clist_window, FALSE); + } + + return; +} + +typedef struct +{ + GdkWindow *window; + gint dx; +} ScrollData; + +/* The window to which widget->window is relative */ +#define ALLOCATION_WINDOW(widget) \ + (GTK_WIDGET_NO_WINDOW (widget) ? \ + (widget)->window : \ + gdk_window_get_parent ((widget)->window)) + +static void +adjust_allocation_recurse (GtkWidget *widget, + gpointer data) +{ + ScrollData *scroll_data = data; + + if (!GTK_WIDGET_REALIZED (widget)) + { + if (GTK_WIDGET_VISIBLE (widget)) + { + GdkRectangle tmp_rectangle = widget->allocation; + tmp_rectangle.x += scroll_data->dx; + + gtk_widget_size_allocate (widget, &tmp_rectangle); + } + } + else + { + if (ALLOCATION_WINDOW (widget) == scroll_data->window) + { + widget->allocation.x += scroll_data->dx; + + if (GTK_IS_CONTAINER (widget)) + gtk_container_forall (GTK_CONTAINER (widget), + adjust_allocation_recurse, + data); + } + } +} + +static void +adjust_allocation (GtkWidget *widget, + gint dx) +{ + ScrollData scroll_data; + + if (GTK_WIDGET_REALIZED (widget)) + scroll_data.window = ALLOCATION_WINDOW (widget); + else + scroll_data.window = NULL; + + scroll_data.dx = dx; + + adjust_allocation_recurse (widget, &scroll_data); +} + +static void +hadjustment_value_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkCMCList *clist; + GtkContainer *container; + GdkRectangle area; + gint i; + gint y = 0; + gint value; + gint dx; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (GTK_IS_CMCLIST (data)); + + clist = GTK_CMCLIST (data); + container = GTK_CONTAINER (data); + + if (adjustment != clist->hadjustment) + return; + + value = adjustment->value; + + dx = -value - clist->hoffset; + + if (GTK_WIDGET_REALIZED (clist)) + gdk_window_scroll (clist->title_window, dx, 0); + + /* adjust the column button's allocations */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button) + adjust_allocation (clist->column[i].button, dx); + + clist->hoffset = -value; + + if (GTK_WIDGET_DRAWABLE (clist)) + { + if (GTK_WIDGET_CAN_FOCUS(clist) && GTK_WIDGET_HAS_FOCUS(clist) && + !container->focus_child && GTK_CMCLIST_ADD_MODE(clist)) + { + y = ROW_TOP_YPIXEL (clist, clist->focus_row); + + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y, + clist->clist_window_width - 1, + clist->row_height - 1); + } + + gdk_window_scroll (clist->clist_window, dx, 0); + gdk_window_process_updates (clist->clist_window, FALSE); + + if (GTK_WIDGET_CAN_FOCUS(clist) && GTK_WIDGET_HAS_FOCUS(clist) && + !container->focus_child) + { + if (GTK_CMCLIST_ADD_MODE(clist)) + { + gint focus_row; + + focus_row = clist->focus_row; + clist->focus_row = -1; + draw_rows (clist, &area); + clist->focus_row = focus_row; + + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, + FALSE, 0, y, clist->clist_window_width - 1, + clist->row_height - 1); + return; + } + else if (ABS(dx) < clist->clist_window_width - 1) + { + gint x0; + gint x1; + + if (dx > 0) + { + x0 = clist->clist_window_width - 1; + x1 = dx; + } + else + { + x0 = 0; + x1 = clist->clist_window_width - 1 + dx; + } + + y = ROW_TOP_YPIXEL (clist, clist->focus_row); + gdk_draw_line (clist->clist_window, clist->xor_gc, + x0, y + 1, x0, y + clist->row_height - 2); + gdk_draw_line (clist->clist_window, clist->xor_gc, + x1, y + 1, x1, y + clist->row_height - 2); + } + } + } +} + +/* PRIVATE + * Memory Allocation/Distruction Routines for GtkCMCList stuctures + * + * functions: + * columns_new + * column_title_new + * columns_delete + * row_new + * row_delete + */ +static GtkCMCListColumn * +columns_new (GtkCMCList *clist) +{ + GtkCMCListColumn *column; + gint i; + + column = g_new (GtkCMCListColumn, clist->columns); + + for (i = 0; i < clist->columns; i++) + { + column[i].area.x = 0; + column[i].area.y = 0; + column[i].area.width = 0; + column[i].area.height = 0; + column[i].title = NULL; + column[i].button = NULL; + column[i].window = NULL; + column[i].width = 0; + column[i].min_width = -1; + column[i].max_width = -1; + column[i].visible = TRUE; + column[i].width_set = FALSE; + column[i].resizeable = TRUE; + column[i].auto_resize = FALSE; + column[i].button_passive = FALSE; + column[i].justification = GTK_JUSTIFY_LEFT; + } + + return column; +} + +static void +column_title_new (GtkCMCList *clist, + gint column, + const gchar *title) +{ + g_free (clist->column[column].title); + + clist->column[column].title = g_strdup (title); +} + +static void +columns_delete (GtkCMCList *clist) +{ + gint i; + + for (i = 0; i < clist->columns; i++) + g_free (clist->column[i].title); + + g_free (clist->column); +} + +static GtkCMCListRow * +row_new (GtkCMCList *clist) +{ + int i; + GtkCMCListRow *clist_row; + + clist_row = g_slice_new (GtkCMCListRow); + clist_row->cell = g_slice_alloc (sizeof (GtkCMCell) * clist->columns); + + for (i = 0; i < clist->columns; i++) + { + clist_row->cell[i].type = GTK_CMCELL_EMPTY; + clist_row->cell[i].vertical = 0; + clist_row->cell[i].horizontal = 0; + clist_row->cell[i].style = NULL; + } + + clist_row->fg_set = FALSE; + clist_row->bg_set = FALSE; + clist_row->style = NULL; + clist_row->selectable = TRUE; + clist_row->state = GTK_STATE_NORMAL; + clist_row->data = NULL; + clist_row->destroy = NULL; + + return clist_row; +} + +static void +row_delete (GtkCMCList *clist, + GtkCMCListRow *clist_row) +{ + gint i; + + for (i = 0; i < clist->columns; i++) + { + GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents + (clist, clist_row, i, GTK_CMCELL_EMPTY, NULL, 0, NULL, NULL); + if (clist_row->cell[i].style) + { + if (GTK_WIDGET_REALIZED (clist)) + gtk_style_detach (clist_row->cell[i].style); + g_object_unref (clist_row->cell[i].style); + } + } + + if (clist_row->style) + { + if (GTK_WIDGET_REALIZED (clist)) + gtk_style_detach (clist_row->style); + g_object_unref (clist_row->style); + } + + if (clist_row->destroy) + clist_row->destroy (clist_row->data); + + g_slice_free1 (sizeof (GtkCMCell) * clist->columns, clist_row->cell); + g_slice_free (GtkCMCListRow, clist_row); +} + +/* FOCUS FUNCTIONS + * gtk_cmclist_focus_content_area + * gtk_cmclist_focus + * gtk_cmclist_draw_focus + * gtk_cmclist_focus_in + * gtk_cmclist_focus_out + * title_focus + */ +static void +gtk_cmclist_focus_content_area (GtkCMCList *clist) +{ + if (clist->focus_row < 0) + { + clist->focus_row = 0; + + if ((clist->selection_mode == GTK_SELECTION_BROWSE || + clist->selection_mode == GTK_SELECTION_MULTIPLE) && + !clist->selection) + g_signal_emit (GTK_OBJECT (clist), + clist_signals[SELECT_ROW], 0, + clist->focus_row, -1, NULL); + } + gtk_widget_grab_focus (GTK_WIDGET (clist)); +} + +static gboolean +gtk_cmclist_focus (GtkWidget *widget, + GtkDirectionType direction) +{ + GtkCMCList *clist = GTK_CMCLIST (widget); + GtkWidget *focus_child; + gboolean is_current_focus; + + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + return FALSE; + + focus_child = GTK_CONTAINER (widget)->focus_child; + + is_current_focus = gtk_widget_is_focus (GTK_WIDGET (clist)); + + if (focus_child && + gtk_widget_child_focus (focus_child, direction)) + return TRUE; + + switch (direction) + { + case GTK_DIR_LEFT: + case GTK_DIR_RIGHT: + if (focus_child) + { + if (title_focus_move (clist, direction)) + return TRUE; + } + else if (!is_current_focus) + { + gtk_cmclist_focus_content_area (clist); + return TRUE; + } + break; + case GTK_DIR_DOWN: + case GTK_DIR_TAB_FORWARD: + if (!focus_child && !is_current_focus) + { + if (title_focus_in (clist, direction)) + return TRUE; + } + + if (!is_current_focus && clist->rows) + { + gtk_cmclist_focus_content_area (clist); + return TRUE; + } + break; + case GTK_DIR_UP: + case GTK_DIR_TAB_BACKWARD: + if (!focus_child && is_current_focus) + { + if (title_focus_in (clist, direction)) + return TRUE; + } + + if (!is_current_focus && !focus_child && clist->rows) + { + gtk_cmclist_focus_content_area (clist); + return TRUE; + } + break; + default: + break; + } + + return FALSE; +} + +static void +gtk_cmclist_set_focus_child (GtkContainer *container, + GtkWidget *child) +{ + GtkCMCList *clist = GTK_CMCLIST (container); + gint i; + + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button == child) + clist->focus_header_column = i; + + parent_class->set_focus_child (container, child); +} + +static void +gtk_cmclist_draw_focus (GtkWidget *widget) +{ + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCLIST (widget)); + + if (!GTK_WIDGET_DRAWABLE (widget) || !GTK_WIDGET_CAN_FOCUS (widget)) + return; + + clist = GTK_CMCLIST (widget); + if (clist->focus_row >= 0) + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, + 0, ROW_TOP_YPIXEL(clist, clist->focus_row), + clist->clist_window_width - 1, + clist->row_height - 1); +} + +static gint +gtk_cmclist_focus_in (GtkWidget *widget, + GdkEventFocus *event) +{ + GtkCMCList *clist = GTK_CMCLIST (widget); + + if (clist->selection_mode == GTK_SELECTION_BROWSE && + clist->selection == NULL && clist->focus_row > -1) + { + GList *list; + + list = g_list_nth (clist->row_list, clist->focus_row); + if (list && GTK_CMCLIST_ROW (list)->selectable) + g_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], 0, + clist->focus_row, -1, event); + else + gtk_cmclist_draw_focus (widget); + } + else + gtk_cmclist_draw_focus (widget); + + return FALSE; +} + +static gint +gtk_cmclist_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + GtkCMCList *clist = GTK_CMCLIST (widget); + + gtk_cmclist_draw_focus (widget); + + GTK_CMCLIST_GET_CLASS (widget)->resync_selection (clist, (GdkEvent *) event); + + return FALSE; +} + +static gboolean +focus_column (GtkCMCList *clist, gint column, gint dir) +{ + GtkWidget *child = clist->column[column].button; + + if (gtk_widget_child_focus (child, dir)) + { + return TRUE; + } + else if (GTK_WIDGET_CAN_FOCUS (child)) + { + gtk_widget_grab_focus (child); + return TRUE; + } + + return FALSE; +} + +/* Focus moved onto the headers. Focus first focusable and visible child. + * (FIXME: focus the last focused child if visible) + */ +static gboolean +title_focus_in (GtkCMCList *clist, gint dir) +{ + gint i; + gint left, right; + + if (!GTK_CMCLIST_SHOW_TITLES (clist)) + return FALSE; + + /* Check last focused column */ + if (clist->focus_header_column != -1) + { + i = clist->focus_header_column; + + left = COLUMN_LEFT_XPIXEL (clist, i); + right = left + clist->column[i].area.width; + + if (left >= 0 && right <= clist->clist_window_width) + { + if (focus_column (clist, i, dir)) + return TRUE; + } + } + + /* Check fully visible columns */ + for (i = 0 ; i < clist->columns ; i++) + { + left = COLUMN_LEFT_XPIXEL (clist, i); + right = left + clist->column[i].area.width; + + if (left >= 0 && right <= clist->clist_window_width) + { + if (focus_column (clist, i, dir)) + return TRUE; + } + } + + /* Check partially visible columns */ + for (i = 0 ; i < clist->columns ; i++) + { + left = COLUMN_LEFT_XPIXEL (clist, i); + right = left + clist->column[i].area.width; + + if ((left < 0 && right > 0) || + (left < clist->clist_window_width && right > clist->clist_window_width)) + { + if (focus_column (clist, i, dir)) + return TRUE; + } + } + + return FALSE; +} + +/* Move the focus right or left within the title buttons, scrolling + * as necessary to keep the focused child visible. + */ +static gboolean +title_focus_move (GtkCMCList *clist, + gint dir) +{ + GtkWidget *focus_child; + gboolean return_val = FALSE; + gint d = 0; + gint i = -1; + gint j; + + if (!GTK_CMCLIST_SHOW_TITLES(clist)) + return FALSE; + + focus_child = GTK_CONTAINER (clist)->focus_child; + g_assert (focus_child); + + /* Movement direction within headers + */ + switch (dir) + { + case GTK_DIR_RIGHT: + d = 1; + break; + case GTK_DIR_LEFT: + d = -1; + break; + } + + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button == focus_child) + break; + + g_assert (i != -1); /* Have a starting column */ + + j = i + d; + while (!return_val && j >= 0 && j < clist->columns) + { + if (clist->column[j].button && + GTK_WIDGET_VISIBLE (clist->column[j].button)) + { + if (focus_column (clist, j, dir)) + { + return_val = TRUE; + break; + } + } + j += d; + } + + /* If we didn't find it, wrap around and keep looking + */ + if (!return_val) + { + j = d > 0 ? 0 : clist->columns - 1; + + while (!return_val && j != i) + { + if (clist->column[j].button && + GTK_WIDGET_VISIBLE (clist->column[j].button)) + { + if (focus_column (clist, j, dir)) + { + return_val = TRUE; + break; + } + } + j += d; + } + } + + /* Scroll horizontally so focused column is visible + */ + if (return_val) + { + if (COLUMN_LEFT_XPIXEL (clist, j) < CELL_SPACING + COLUMN_INSET) + gtk_cmclist_moveto (clist, -1, j, 0, 0); + else if (COLUMN_LEFT_XPIXEL(clist, j) + clist->column[j].area.width > + clist->clist_window_width) + { + gint last_column; + + for (last_column = clist->columns - 1; + last_column >= 0 && !clist->column[last_column].visible; last_column--); + + if (j == last_column) + gtk_cmclist_moveto (clist, -1, j, 0, 0); + else + gtk_cmclist_moveto (clist, -1, j, 0, 1); + } + } + return TRUE; /* Even if we didn't find a new one, we can keep the + * focus in the same place. + */ +} + +/* PRIVATE SCROLLING FUNCTIONS + * move_focus_row + * scroll_horizontal + * scroll_vertical + * move_horizontal + * move_vertical + * horizontal_timeout + * vertical_timeout + * remove_grab + */ +static void +move_focus_row (GtkCMCList *clist, + GtkScrollType scroll_type, + gfloat position) +{ + GtkWidget *widget; + + g_return_if_fail (clist != 0); + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + widget = GTK_WIDGET (clist); + + switch (scroll_type) + { + case GTK_SCROLL_STEP_UP: + case GTK_SCROLL_STEP_BACKWARD: + if (clist->focus_row <= 0) + return; + gtk_cmclist_draw_focus (widget); + clist->focus_row--; + gtk_cmclist_draw_focus (widget); + break; + + case GTK_SCROLL_STEP_DOWN: + case GTK_SCROLL_STEP_FORWARD: + if (clist->focus_row >= clist->rows - 1) + return; + gtk_cmclist_draw_focus (widget); + clist->focus_row++; + gtk_cmclist_draw_focus (widget); + break; + case GTK_SCROLL_PAGE_UP: + case GTK_SCROLL_PAGE_BACKWARD: + if (clist->focus_row <= 0) + return; + gtk_cmclist_draw_focus (widget); + clist->focus_row = MAX (0, clist->focus_row - + (2 * clist->clist_window_height - + clist->row_height - CELL_SPACING) / + (2 * (clist->row_height + CELL_SPACING))); + gtk_cmclist_draw_focus (widget); + break; + case GTK_SCROLL_PAGE_DOWN: + case GTK_SCROLL_PAGE_FORWARD: + if (clist->focus_row >= clist->rows - 1) + return; + gtk_cmclist_draw_focus (widget); + clist->focus_row = MIN (clist->rows - 1, clist->focus_row + + (2 * clist->clist_window_height - + clist->row_height - CELL_SPACING) / + (2 * (clist->row_height + CELL_SPACING))); + gtk_cmclist_draw_focus (widget); + break; + case GTK_SCROLL_JUMP: + if (position >= 0 && position <= 1) + { + gtk_cmclist_draw_focus (widget); + clist->focus_row = position * (clist->rows - 1); + gtk_cmclist_draw_focus (widget); + } + break; + default: + break; + } +} + +static void +scroll_horizontal (GtkCMCList *clist, + GtkScrollType scroll_type, + gfloat position) +{ + gint column = 0; + gint last_column; + + g_return_if_fail (clist != 0); + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (clist_has_grab (clist)) + return; + + for (last_column = clist->columns - 1; + last_column >= 0 && !clist->column[last_column].visible; last_column--) + ; + + switch (scroll_type) + { + case GTK_SCROLL_STEP_BACKWARD: + column = COLUMN_FROM_XPIXEL (clist, 0); + if (COLUMN_LEFT_XPIXEL (clist, column) - CELL_SPACING - COLUMN_INSET >= 0 + && column > 0) + column--; + break; + case GTK_SCROLL_STEP_FORWARD: + column = COLUMN_FROM_XPIXEL (clist, clist->clist_window_width); + if (column < 0) + return; + if (COLUMN_LEFT_XPIXEL (clist, column) + + clist->column[column].area.width + + CELL_SPACING + COLUMN_INSET - 1 <= clist->clist_window_width && + column < last_column) + column++; + break; + case GTK_SCROLL_PAGE_BACKWARD: + case GTK_SCROLL_PAGE_FORWARD: + return; + case GTK_SCROLL_JUMP: + if (position >= 0 && position <= 1) + { + gint vis_columns = 0; + gint i; + + for (i = 0; i <= last_column; i++) + if (clist->column[i].visible) + vis_columns++; + + column = position * vis_columns; + + for (i = 0; i <= last_column && column > 0; i++) + if (clist->column[i].visible) + column--; + + column = i; + } + else + return; + break; + default: + break; + } + + if (COLUMN_LEFT_XPIXEL (clist, column) < CELL_SPACING + COLUMN_INSET) + gtk_cmclist_moveto (clist, -1, column, 0, 0); + else if (COLUMN_LEFT_XPIXEL (clist, column) + CELL_SPACING + COLUMN_INSET - 1 + + clist->column[column].area.width > clist->clist_window_width) + { + if (column == last_column) + gtk_cmclist_moveto (clist, -1, column, 0, 0); + else + gtk_cmclist_moveto (clist, -1, column, 0, 1); + } +} + +static void +scroll_vertical (GtkCMCList *clist, + GtkScrollType scroll_type, + gfloat position) +{ + gint old_focus_row; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (clist_has_grab (clist)) + return; + + switch (clist->selection_mode) + { + case GTK_SELECTION_MULTIPLE: + if (clist->anchor >= 0) + return; + case GTK_SELECTION_BROWSE: + + old_focus_row = clist->focus_row; + move_focus_row (clist, scroll_type, position); + + if (old_focus_row != clist->focus_row) + { + if (clist->selection_mode == GTK_SELECTION_BROWSE) + g_signal_emit (GTK_OBJECT (clist), clist_signals[UNSELECT_ROW], 0, + old_focus_row, -1, NULL); + else if (!GTK_CMCLIST_ADD_MODE(clist)) + { + gtk_cmclist_unselect_all (clist); + clist->undo_anchor = old_focus_row; + } + } + + switch (gtk_cmclist_row_is_visible (clist, clist->focus_row)) + { + case GTK_VISIBILITY_NONE: + if (old_focus_row != clist->focus_row && + !(clist->selection_mode == GTK_SELECTION_MULTIPLE && + GTK_CMCLIST_ADD_MODE(clist))) + g_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], 0, + clist->focus_row, -1, NULL); + switch (scroll_type) + { + case GTK_SCROLL_PAGE_UP: + case GTK_SCROLL_STEP_UP: + case GTK_SCROLL_STEP_BACKWARD: + case GTK_SCROLL_PAGE_BACKWARD: + gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0); + break; + case GTK_SCROLL_PAGE_DOWN: + case GTK_SCROLL_STEP_DOWN: + case GTK_SCROLL_STEP_FORWARD: + case GTK_SCROLL_PAGE_FORWARD: + gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0); + break; + case GTK_SCROLL_JUMP: + gtk_cmclist_moveto (clist, clist->focus_row, -1, 0.5, 0); + break; + default: + break; + } + break; + case GTK_VISIBILITY_PARTIAL: + switch (scroll_type) + { + case GTK_SCROLL_STEP_BACKWARD: + case GTK_SCROLL_PAGE_BACKWARD: + gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0); + break; + case GTK_SCROLL_STEP_FORWARD: + case GTK_SCROLL_PAGE_FORWARD: + gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0); + break; + case GTK_SCROLL_JUMP: + gtk_cmclist_moveto (clist, clist->focus_row, -1, 0.5, 0); + break; + default: + break; + } + default: + if (old_focus_row != clist->focus_row && + !(clist->selection_mode == GTK_SELECTION_MULTIPLE && + GTK_CMCLIST_ADD_MODE(clist))) + g_signal_emit (GTK_OBJECT (clist), clist_signals[SELECT_ROW], 0, + clist->focus_row, -1, NULL); + break; + } + break; + default: + move_focus_row (clist, scroll_type, position); + + if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > + clist->clist_window_height) + gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0); + else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) + gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0); + break; + } +} + +static void +move_horizontal (GtkCMCList *clist, + gint diff) +{ + gdouble value; + + if (!clist->hadjustment) + return; + + value = CLAMP (clist->hadjustment->value + diff, 0.0, + clist->hadjustment->upper - clist->hadjustment->page_size); + gtk_adjustment_set_value (clist->hadjustment, value); +} + +static void +move_vertical (GtkCMCList *clist, + gint row, + gfloat align) +{ + gdouble value; + + if (!clist->vadjustment) + return; + + value = (ROW_TOP_YPIXEL (clist, row) - clist->voffset - + align * (clist->clist_window_height - clist->row_height) + + (2 * align - 1) * CELL_SPACING); + + if (value + clist->vadjustment->page_size > clist->vadjustment->upper) + value = clist->vadjustment->upper - clist->vadjustment->page_size; + + gtk_adjustment_set_value (clist->vadjustment, value); +} + +static void +do_fake_motion (GtkWidget *widget) +{ + GdkEvent *event = gdk_event_new (GDK_MOTION_NOTIFY); + + event->motion.send_event = TRUE; + + gtk_cmclist_motion (widget, (GdkEventMotion *)event); + gdk_event_free (event); +} + +static gint +horizontal_timeout (GtkCMCList *clist) +{ + clist->htimer = 0; + do_fake_motion (GTK_WIDGET (clist)); + + return FALSE; +} + +static gint +vertical_timeout (GtkCMCList *clist) +{ + clist->vtimer = 0; + do_fake_motion (GTK_WIDGET (clist)); + + return FALSE; +} + +static void +remove_grab (GtkCMCList *clist) +{ + GtkWidget *widget = GTK_WIDGET (clist); + + if (GTK_WIDGET_HAS_GRAB (clist)) + { + GdkDisplay *display = gtk_widget_get_display (widget); + + gtk_grab_remove (widget); + if (gdk_display_pointer_is_grabbed (display)) + gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME); + } + + if (clist->htimer) + { + g_source_remove (clist->htimer); + clist->htimer = 0; + } + + if (clist->vtimer) + { + g_source_remove (clist->vtimer); + clist->vtimer = 0; + } +} + +/* PUBLIC SORTING FUNCTIONS + * gtk_cmclist_sort + * gtk_cmclist_set_compare_func + * gtk_cmclist_set_auto_sort + * gtk_cmclist_set_sort_type + * gtk_cmclist_set_sort_column + */ +void +gtk_cmclist_sort (GtkCMCList *clist) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + GTK_CMCLIST_GET_CLASS (clist)->sort_list (clist); +} + +void +gtk_cmclist_set_compare_func (GtkCMCList *clist, + GtkCMCListCompareFunc cmp_func) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + clist->compare = (cmp_func) ? cmp_func : default_compare; +} + +void +gtk_cmclist_set_auto_sort (GtkCMCList *clist, + gboolean auto_sort) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (GTK_CMCLIST_AUTO_SORT(clist) && !auto_sort) + GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_SORT); + else if (!GTK_CMCLIST_AUTO_SORT(clist) && auto_sort) + { + GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_SORT); + gtk_cmclist_sort (clist); + } +} + +void +gtk_cmclist_set_sort_type (GtkCMCList *clist, + GtkSortType sort_type) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + clist->sort_type = sort_type; +} + +void +gtk_cmclist_set_sort_column (GtkCMCList *clist, + gint column) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (column < 0 || column >= clist->columns) + return; + + clist->sort_column = column; +} + +/* PRIVATE SORTING FUNCTIONS + * default_compare + * real_sort_list + * gtk_cmclist_merge + * gtk_cmclist_mergesort + */ +static gint +default_compare (GtkCMCList *clist, + gconstpointer ptr1, + gconstpointer ptr2) +{ + char *text1 = NULL; + char *text2 = NULL; + + GtkCMCListRow *row1 = (GtkCMCListRow *) ptr1; + GtkCMCListRow *row2 = (GtkCMCListRow *) ptr2; + + switch (row1->cell[clist->sort_column].type) + { + case GTK_CMCELL_TEXT: + text1 = GTK_CMCELL_TEXT (row1->cell[clist->sort_column])->text; + break; + case GTK_CMCELL_PIXTEXT: + text1 = GTK_CMCELL_PIXTEXT (row1->cell[clist->sort_column])->text; + break; + default: + break; + } + + switch (row2->cell[clist->sort_column].type) + { + case GTK_CMCELL_TEXT: + text2 = GTK_CMCELL_TEXT (row2->cell[clist->sort_column])->text; + break; + case GTK_CMCELL_PIXTEXT: + text2 = GTK_CMCELL_PIXTEXT (row2->cell[clist->sort_column])->text; + break; + default: + break; + } + + if (!text2) + return (text1 != NULL); + + if (!text1) + return -1; + + return strcmp (text1, text2); +} + +static void +real_sort_list (GtkCMCList *clist) +{ + GList *list; + GList *work; + gint i; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (clist->rows <= 1) + return; + + if (clist_has_grab (clist)) + return; + + gtk_cmclist_freeze (clist); + + if (clist->anchor != -1 && clist->selection_mode == GTK_SELECTION_MULTIPLE) + { + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + } + + clist->row_list = gtk_cmclist_mergesort (clist, clist->row_list, clist->rows); + + work = clist->selection; + + for (i = 0, list = clist->row_list; i < clist->rows; i++, list = list->next) + { + if (GTK_CMCLIST_ROW (list)->state == GTK_STATE_SELECTED) + { + work->data = GINT_TO_POINTER (i); + work = work->next; + } + + if (i == clist->rows - 1) + clist->row_list_end = list; + } + + gtk_cmclist_thaw (clist); +} + +static GList * +gtk_cmclist_merge (GtkCMCList *clist, + GList *a, /* first list to merge */ + GList *b) /* second list to merge */ +{ + GList z = { 0 }; /* auxiliary node */ + GList *c; + gint cmp; + + c = &z; + + while (a || b) + { + if (a && !b) + { + c->next = a; + a->prev = c; + c = a; + a = a->next; + break; + } + else if (!a && b) + { + c->next = b; + b->prev = c; + c = b; + b = b->next; + break; + } + else /* a && b */ + { + cmp = clist->compare (clist, GTK_CMCLIST_ROW (a), GTK_CMCLIST_ROW (b)); + if ((cmp >= 0 && clist->sort_type == GTK_SORT_DESCENDING) || + (cmp <= 0 && clist->sort_type == GTK_SORT_ASCENDING) || + (a && !b)) + { + c->next = a; + a->prev = c; + c = a; + a = a->next; + } + else + { + c->next = b; + b->prev = c; + c = b; + b = b->next; + } + } + } + + z.next->prev = NULL; + return z.next; +} + +static GList * +gtk_cmclist_mergesort (GtkCMCList *clist, + GList *list, /* the list to sort */ + gint num) /* the list's length */ +{ + GList *half; + gint i; + + if (num <= 1) + { + return list; + } + else + { + /* move "half" to the middle */ + half = list; + for (i = 0; i < num / 2; i++) + half = half->next; + + /* cut the list in two */ + half->prev->next = NULL; + half->prev = NULL; + + /* recursively sort both lists */ + return gtk_cmclist_merge (clist, + gtk_cmclist_mergesort (clist, list, num / 2), + gtk_cmclist_mergesort (clist, half, num - num / 2)); + } +} + +/************************/ + +static void +drag_source_info_destroy (gpointer data) +{ + GtkCMCListCellInfo *info = data; + + g_free (info); +} + +static void +drag_dest_info_destroy (gpointer data) +{ + GtkCMCListDestInfo *info = data; + + g_free (info); +} + +static void +drag_dest_cell (GtkCMCList *clist, + gint x, + gint y, + GtkCMCListDestInfo *dest_info) +{ + GtkWidget *widget; + + widget = GTK_WIDGET (clist); + + dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE; + + y -= (GTK_CONTAINER (clist)->border_width + + widget->style->ythickness + + clist->column_title_area.height); + + dest_info->cell.row = ROW_FROM_YPIXEL (clist, y); + if (dest_info->cell.row >= clist->rows) + { + dest_info->cell.row = clist->rows - 1; + y = ROW_TOP_YPIXEL (clist, dest_info->cell.row) + clist->row_height; + } + if (dest_info->cell.row < -1) + dest_info->cell.row = -1; + + x -= GTK_CONTAINER (widget)->border_width + widget->style->xthickness; + + dest_info->cell.column = COLUMN_FROM_XPIXEL (clist, x); + + if (dest_info->cell.row >= 0) + { + gint y_delta; + gint h = 0; + + y_delta = y - ROW_TOP_YPIXEL (clist, dest_info->cell.row); + + if (GTK_CMCLIST_DRAW_DRAG_RECT(clist)) + { + dest_info->insert_pos = GTK_CMCLIST_DRAG_INTO; + h = clist->row_height / 4; + } + else if (GTK_CMCLIST_DRAW_DRAG_LINE(clist)) + { + dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE; + h = clist->row_height / 2; + } + + if (GTK_CMCLIST_DRAW_DRAG_LINE(clist)) + { + if (y_delta < h) + dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE; + else if (clist->row_height - y_delta < h) + dest_info->insert_pos = GTK_CMCLIST_DRAG_AFTER; + } + } +} + +static void +gtk_cmclist_drag_begin (GtkWidget *widget, + GdkDragContext *context) +{ + GtkCMCList *clist; + GtkCMCListCellInfo *info; + + g_return_if_fail (GTK_IS_CMCLIST (widget)); + g_return_if_fail (context != NULL); + + clist = GTK_CMCLIST (widget); + + clist->drag_button = 0; + remove_grab (clist); + + switch (clist->selection_mode) + { + case GTK_SELECTION_MULTIPLE: + update_extended_selection (clist, clist->focus_row); + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + break; + case GTK_SELECTION_SINGLE: + clist->anchor = -1; + case GTK_SELECTION_BROWSE: + break; + default: + g_assert_not_reached (); + } + + info = g_dataset_get_data (context, "gtk-clist-drag-source"); + + if (!info) + { + info = g_new (GtkCMCListCellInfo, 1); + + if (clist->click_cell.row < 0) + clist->click_cell.row = 0; + else if (clist->click_cell.row >= clist->rows) + clist->click_cell.row = clist->rows - 1; + info->row = clist->click_cell.row; + info->column = clist->click_cell.column; + + g_dataset_set_data_full (context, "gtk-clist-drag-source", info, + drag_source_info_destroy); + } + + if (GTK_CMCLIST_USE_DRAG_ICONS (clist)) + gtk_drag_set_icon_default (context); +} + +static void +gtk_cmclist_drag_end (GtkWidget *widget, + GdkDragContext *context) +{ + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCLIST (widget)); + g_return_if_fail (context != NULL); + + clist = GTK_CMCLIST (widget); + + clist->click_cell.row = -1; + clist->click_cell.column = -1; +} + +static void +gtk_cmclist_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time) +{ + GtkCMCList *clist; + GtkCMCListDestInfo *dest_info; + + g_return_if_fail (GTK_IS_CMCLIST (widget)); + g_return_if_fail (context != NULL); + + clist = GTK_CMCLIST (widget); + + dest_info = g_dataset_get_data (context, "gtk-clist-drag-dest"); + + if (dest_info) + { + if (dest_info->cell.row >= 0 && + GTK_CMCLIST_REORDERABLE(clist) && + gtk_drag_get_source_widget (context) == widget) + { + GList *list; + GdkAtom atom = gdk_atom_intern_static_string ("gtk-clist-drag-reorder"); + + list = context->targets; + while (list) + { + if (atom == GDK_POINTER_TO_ATOM (list->data)) + { + GTK_CMCLIST_GET_CLASS (clist)->draw_drag_highlight + (clist, + g_list_nth (clist->row_list, dest_info->cell.row)->data, + dest_info->cell.row, dest_info->insert_pos); + clist->drag_highlight_row = -1; + break; + } + list = list->next; + } + } + g_dataset_remove_data (context, "gtk-clist-drag-dest"); + } +} + +static gint +gtk_cmclist_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time) +{ + GtkCMCList *clist; + GtkCMCListDestInfo new_info; + GtkCMCListDestInfo *dest_info; + + g_return_val_if_fail (GTK_IS_CMCLIST (widget), FALSE); + + clist = GTK_CMCLIST (widget); + + dest_info = g_dataset_get_data (context, "gtk-clist-drag-dest"); + + if (!dest_info) + { + dest_info = g_new (GtkCMCListDestInfo, 1); + + dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE; + dest_info->cell.row = -1; + dest_info->cell.column = -1; + + g_dataset_set_data_full (context, "gtk-clist-drag-dest", dest_info, + drag_dest_info_destroy); + } + + drag_dest_cell (clist, x, y, &new_info); + + if (GTK_CMCLIST_REORDERABLE (clist)) + { + GList *list; + GdkAtom atom = gdk_atom_intern_static_string ("gtk-clist-drag-reorder"); + + list = context->targets; + while (list) + { + if (atom == GDK_POINTER_TO_ATOM (list->data)) + break; + list = list->next; + } + + if (list) + { + if (gtk_drag_get_source_widget (context) != widget || + new_info.insert_pos == GTK_CMCLIST_DRAG_NONE || + new_info.cell.row == clist->click_cell.row || + (new_info.cell.row == clist->click_cell.row - 1 && + new_info.insert_pos == GTK_CMCLIST_DRAG_AFTER) || + (new_info.cell.row == clist->click_cell.row + 1 && + new_info.insert_pos == GTK_CMCLIST_DRAG_BEFORE)) + { + if (dest_info->cell.row < 0) + { + gdk_drag_status (context, GDK_ACTION_DEFAULT, time); + return FALSE; + } + return TRUE; + } + + if (new_info.cell.row != dest_info->cell.row || + (new_info.cell.row == dest_info->cell.row && + dest_info->insert_pos != new_info.insert_pos)) + { + if (dest_info->cell.row >= 0) + GTK_CMCLIST_GET_CLASS (clist)->draw_drag_highlight + (clist, g_list_nth (clist->row_list, + dest_info->cell.row)->data, + dest_info->cell.row, dest_info->insert_pos); + + dest_info->insert_pos = new_info.insert_pos; + dest_info->cell.row = new_info.cell.row; + dest_info->cell.column = new_info.cell.column; + + GTK_CMCLIST_GET_CLASS (clist)->draw_drag_highlight + (clist, g_list_nth (clist->row_list, + dest_info->cell.row)->data, + dest_info->cell.row, dest_info->insert_pos); + + clist->drag_highlight_row = dest_info->cell.row; + clist->drag_highlight_pos = dest_info->insert_pos; + + gdk_drag_status (context, context->suggested_action, time); + } + return TRUE; + } + } + + dest_info->insert_pos = new_info.insert_pos; + dest_info->cell.row = new_info.cell.row; + dest_info->cell.column = new_info.cell.column; + return TRUE; +} + +static gboolean +gtk_cmclist_drag_drop (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time) +{ + g_return_val_if_fail (GTK_IS_CMCLIST (widget), FALSE); + g_return_val_if_fail (context != NULL, FALSE); + + if (GTK_CMCLIST_REORDERABLE (widget) && + gtk_drag_get_source_widget (context) == widget) + { + GList *list; + GdkAtom atom = gdk_atom_intern_static_string ("gtk-clist-drag-reorder"); + + list = context->targets; + while (list) + { + if (atom == GDK_POINTER_TO_ATOM (list->data)) + return TRUE; + list = list->next; + } + } + return FALSE; +} + +static void +gtk_cmclist_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCLIST (widget)); + g_return_if_fail (context != NULL); + g_return_if_fail (selection_data != NULL); + + clist = GTK_CMCLIST (widget); + + if (GTK_CMCLIST_REORDERABLE (clist) && + gtk_drag_get_source_widget (context) == widget && + selection_data->target == + gdk_atom_intern_static_string ("gtk-clist-drag-reorder") && + selection_data->format == 8 && + selection_data->length == sizeof (GtkCMCListCellInfo)) + { + GtkCMCListCellInfo *source_info; + + source_info = (GtkCMCListCellInfo *)(selection_data->data); + if (source_info) + { + GtkCMCListDestInfo dest_info; + + drag_dest_cell (clist, x, y, &dest_info); + + if (dest_info.insert_pos == GTK_CMCLIST_DRAG_AFTER) + dest_info.cell.row++; + if (source_info->row < dest_info.cell.row) + dest_info.cell.row--; + if (dest_info.cell.row != source_info->row) + gtk_cmclist_row_move (clist, source_info->row, dest_info.cell.row); + + g_dataset_remove_data (context, "gtk-clist-drag-dest"); + } + } +} + +static void +gtk_cmclist_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + g_return_if_fail (GTK_IS_CMCLIST (widget)); + g_return_if_fail (context != NULL); + g_return_if_fail (selection_data != NULL); + + if (selection_data->target == gdk_atom_intern_static_string ("gtk-clist-drag-reorder")) + { + GtkCMCListCellInfo *info; + + info = g_dataset_get_data (context, "gtk-clist-drag-source"); + + if (info) + { + GtkCMCListCellInfo ret_info; + + ret_info.row = info->row; + ret_info.column = info->column; + + gtk_selection_data_set (selection_data, selection_data->target, + 8, (guchar *) &ret_info, + sizeof (GtkCMCListCellInfo)); + } + } +} + +static void +draw_drag_highlight (GtkCMCList *clist, + GtkCMCListRow *dest_row, + gint dest_row_number, + GtkCMCListDragPos drag_pos) +{ + gint y; + + y = ROW_TOP_YPIXEL (clist, dest_row_number) - 1; + + switch (drag_pos) + { + case GTK_CMCLIST_DRAG_NONE: + break; + case GTK_CMCLIST_DRAG_AFTER: + y += clist->row_height + 1; + case GTK_CMCLIST_DRAG_BEFORE: + gdk_draw_line (clist->clist_window, clist->xor_gc, + 0, y, clist->clist_window_width, y); + break; + case GTK_CMCLIST_DRAG_INTO: + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, 0, y, + clist->clist_window_width - 1, clist->row_height); + break; + } +} + +void +gtk_cmclist_set_reorderable (GtkCMCList *clist, + gboolean reorderable) +{ + GtkWidget *widget; + + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if ((GTK_CMCLIST_REORDERABLE(clist) != 0) == reorderable) + return; + + widget = GTK_WIDGET (clist); + + if (reorderable) + { + GTK_CMCLIST_SET_FLAG (clist, CMCLIST_REORDERABLE); + gtk_drag_dest_set (widget, + GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, + &clist_target_table, 1, GDK_ACTION_MOVE); + } + else + { + GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_REORDERABLE); + gtk_drag_dest_unset (GTK_WIDGET (clist)); + } +} + +void +gtk_cmclist_set_use_drag_icons (GtkCMCList *clist, + gboolean use_icons) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (use_icons != 0) + GTK_CMCLIST_SET_FLAG (clist, CMCLIST_USE_DRAG_ICONS); + else + GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_USE_DRAG_ICONS); +} + +void +gtk_cmclist_set_button_actions (GtkCMCList *clist, + guint button, + guint8 button_actions) +{ + g_return_if_fail (GTK_IS_CMCLIST (clist)); + + if (button < MAX_BUTTON) + { + if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (clist))) || + GTK_WIDGET_HAS_GRAB (clist)) + { + remove_grab (clist); + clist->drag_button = 0; + } + + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + + clist->button_actions[button] = button_actions; + } +} diff --git a/src/gtk/gtkcmclist.h b/src/gtk/gtkcmclist.h @@ -0,0 +1,789 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald + * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __GTK_CMCLIST_H__ +#define __GTK_CMCLIST_H__ + +#include <gdk/gdk.h> +#include <gtk/gtksignal.h> +#include <gtk/gtkalignment.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkbutton.h> +#include <gtk/gtkhscrollbar.h> +#include <gtk/gtkvscrollbar.h> +#include <gtk/gtkenums.h> + + +G_BEGIN_DECLS + + +/* clist flags */ +enum { + GTK_CMCLIST_IN_DRAG = 1 << 0, + GTK_CMCLIST_ROW_HEIGHT_SET = 1 << 1, + GTK_CMCLIST_SHOW_TITLES = 1 << 2, + /* Unused */ + GTK_CMCLIST_ADD_MODE = 1 << 4, + GTK_CMCLIST_AUTO_SORT = 1 << 5, + GTK_CMCLIST_AUTO_RESIZE_BLOCKED = 1 << 6, + GTK_CMCLIST_REORDERABLE = 1 << 7, + GTK_CMCLIST_USE_DRAG_ICONS = 1 << 8, + GTK_CMCLIST_DRAW_DRAG_LINE = 1 << 9, + GTK_CMCLIST_DRAW_DRAG_RECT = 1 << 10 +}; + +/* cell types */ +typedef enum +{ + GTK_CMCELL_EMPTY, + GTK_CMCELL_TEXT, + GTK_CMCELL_PIXMAP, + GTK_CMCELL_PIXTEXT, + GTK_CMCELL_WIDGET +} GtkCMCellType; + +typedef enum +{ + GTK_CMCLIST_DRAG_NONE, + GTK_CMCLIST_DRAG_BEFORE, + GTK_CMCLIST_DRAG_INTO, + GTK_CMCLIST_DRAG_AFTER +} GtkCMCListDragPos; + +typedef enum +{ + GTK_CMBUTTON_IGNORED = 0, + GTK_CMBUTTON_SELECTS = 1 << 0, + GTK_CMBUTTON_DRAGS = 1 << 1, + GTK_CMBUTTON_EXPANDS = 1 << 2 +} GtkCMButtonAction; + +#define GTK_TYPE_CMCLIST (gtk_cmclist_get_type ()) +#define GTK_CMCLIST(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_CMCLIST, GtkCMCList)) +#define GTK_CMCLIST_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_CMCLIST, GtkCMCListClass)) +#define GTK_IS_CMCLIST(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_CMCLIST)) +#define GTK_IS_CMCLIST_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CMCLIST)) +#define GTK_CMCLIST_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_CMCLIST, GtkCMCListClass)) + + +#define GTK_CMCLIST_FLAGS(clist) (GTK_CMCLIST (clist)->flags) +#define GTK_CMCLIST_SET_FLAG(clist,flag) (GTK_CMCLIST_FLAGS (clist) |= (GTK_ ## flag)) +#define GTK_CMCLIST_UNSET_FLAG(clist,flag) (GTK_CMCLIST_FLAGS (clist) &= ~(GTK_ ## flag)) + +#define GTK_CMCLIST_IN_DRAG(clist) (GTK_CMCLIST_FLAGS (clist) & GTK_CMCLIST_IN_DRAG) +#define GTK_CMCLIST_ROW_HEIGHT_SET(clist) (GTK_CMCLIST_FLAGS (clist) & GTK_CMCLIST_ROW_HEIGHT_SET) +#define GTK_CMCLIST_SHOW_TITLES(clist) (GTK_CMCLIST_FLAGS (clist) & GTK_CMCLIST_SHOW_TITLES) +#define GTK_CMCLIST_ADD_MODE(clist) (GTK_CMCLIST_FLAGS (clist) & GTK_CMCLIST_ADD_MODE) +#define GTK_CMCLIST_AUTO_SORT(clist) (GTK_CMCLIST_FLAGS (clist) & GTK_CMCLIST_AUTO_SORT) +#define GTK_CMCLIST_AUTO_RESIZE_BLOCKED(clist) (GTK_CMCLIST_FLAGS (clist) & GTK_CMCLIST_AUTO_RESIZE_BLOCKED) +#define GTK_CMCLIST_REORDERABLE(clist) (GTK_CMCLIST_FLAGS (clist) & GTK_CMCLIST_REORDERABLE) +#define GTK_CMCLIST_USE_DRAG_ICONS(clist) (GTK_CMCLIST_FLAGS (clist) & GTK_CMCLIST_USE_DRAG_ICONS) +#define GTK_CMCLIST_DRAW_DRAG_LINE(clist) (GTK_CMCLIST_FLAGS (clist) & GTK_CMCLIST_DRAW_DRAG_LINE) +#define GTK_CMCLIST_DRAW_DRAG_RECT(clist) (GTK_CMCLIST_FLAGS (clist) & GTK_CMCLIST_DRAW_DRAG_RECT) + +#define GTK_CMCLIST_ROW(_glist_) ((GtkCMCListRow *)((_glist_)->data)) + +/* pointer casting for cells */ +#define GTK_CMCELL_TEXT(cell) (((GtkCMCellText *) &(cell))) +#define GTK_CMCELL_PIXMAP(cell) (((GtkCMCellPixmap *) &(cell))) +#define GTK_CMCELL_PIXTEXT(cell) (((GtkCMCellPixText *) &(cell))) +#define GTK_CMCELL_WIDGET(cell) (((GtkCMCellWidget *) &(cell))) + +typedef struct _GtkCMCList GtkCMCList; +typedef struct _GtkCMCListClass GtkCMCListClass; +typedef struct _GtkCMCListColumn GtkCMCListColumn; +typedef struct _GtkCMCListRow GtkCMCListRow; + +typedef struct _GtkCMCell GtkCMCell; +typedef struct _GtkCMCellText GtkCMCellText; +typedef struct _GtkCMCellPixmap GtkCMCellPixmap; +typedef struct _GtkCMCellPixText GtkCMCellPixText; +typedef struct _GtkCMCellWidget GtkCMCellWidget; + +typedef gint (*GtkCMCListCompareFunc) (GtkCMCList *clist, + gconstpointer ptr1, + gconstpointer ptr2); + +typedef struct _GtkCMCListCellInfo GtkCMCListCellInfo; +typedef struct _GtkCMCListDestInfo GtkCMCListDestInfo; + +struct _GtkCMCListCellInfo +{ + gint row; + gint column; +}; + +struct _GtkCMCListDestInfo +{ + GtkCMCListCellInfo cell; + GtkCMCListDragPos insert_pos; +}; + +struct _GtkCMCList +{ + GtkContainer container; + + guint16 flags; + + gpointer reserved1; + gpointer reserved2; + + guint freeze_count; + + /* allocation rectangle after the conatiner_border_width + * and the width of the shadow border */ + GdkRectangle internal_allocation; + + /* rows */ + gint rows; + gint row_height; + GList *row_list; + GList *row_list_end; + + /* columns */ + gint columns; + GdkRectangle column_title_area; + GdkWindow *title_window; + + /* dynamicly allocated array of column structures */ + GtkCMCListColumn *column; + + /* the scrolling window and its height and width to + * make things a little speedier */ + GdkWindow *clist_window; + gint clist_window_width; + gint clist_window_height; + + /* offsets for scrolling */ + gint hoffset; + gint voffset; + + /* border shadow style */ + GtkShadowType shadow_type; + + /* the list's selection mode (gtkenums.h) */ + GtkSelectionMode selection_mode; + + /* list of selected rows */ + GList *selection; + GList *selection_end; + + GList *undo_selection; + GList *undo_unselection; + gint undo_anchor; + + /* mouse buttons */ + guint8 button_actions[5]; + + guint8 drag_button; + + /* dnd */ + GtkCMCListCellInfo click_cell; + + /* scroll adjustments */ + GtkAdjustment *hadjustment; + GtkAdjustment *vadjustment; + + /* xor GC for the vertical drag line */ + GdkGC *xor_gc; + + /* gc for drawing unselected cells */ + GdkGC *fg_gc; + GdkGC *bg_gc; + + /* cursor used to indicate dragging */ + GdkCursor *cursor_drag; + + /* the current x-pixel location of the xor-drag line */ + gint x_drag; + + /* focus handling */ + gint focus_row; + + gint focus_header_column; + + /* dragging the selection */ + gint anchor; + GtkStateType anchor_state; + gint drag_pos; + gint htimer; + gint vtimer; + + GtkSortType sort_type; + GtkCMCListCompareFunc compare; + gint sort_column; + + gint drag_highlight_row; + GtkCMCListDragPos drag_highlight_pos; +}; + +struct _GtkCMCListClass +{ + GtkContainerClass parent_class; + + void (*set_scroll_adjustments) (GtkCMCList *clist, + GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment); + void (*refresh) (GtkCMCList *clist); + void (*select_row) (GtkCMCList *clist, + gint row, + gint column, + GdkEvent *event); + void (*unselect_row) (GtkCMCList *clist, + gint row, + gint column, + GdkEvent *event); + void (*row_move) (GtkCMCList *clist, + gint source_row, + gint dest_row); + void (*click_column) (GtkCMCList *clist, + gint column); + void (*resize_column) (GtkCMCList *clist, + gint column, + gint width); + void (*toggle_focus_row) (GtkCMCList *clist); + void (*select_all) (GtkCMCList *clist); + void (*unselect_all) (GtkCMCList *clist); + void (*undo_selection) (GtkCMCList *clist); + void (*start_selection) (GtkCMCList *clist); + void (*end_selection) (GtkCMCList *clist); + void (*extend_selection) (GtkCMCList *clist, + GtkScrollType scroll_type, + gfloat position, + gboolean auto_start_selection); + void (*scroll_horizontal) (GtkCMCList *clist, + GtkScrollType scroll_type, + gfloat position); + void (*scroll_vertical) (GtkCMCList *clist, + GtkScrollType scroll_type, + gfloat position); + void (*toggle_add_mode) (GtkCMCList *clist); + void (*abort_column_resize) (GtkCMCList *clist); + void (*resync_selection) (GtkCMCList *clist, + GdkEvent *event); + GList* (*selection_find) (GtkCMCList *clist, + gint row_number, + GList *row_list_element); + void (*draw_row) (GtkCMCList *clist, + GdkRectangle *area, + gint row, + GtkCMCListRow *clist_row); + void (*draw_drag_highlight) (GtkCMCList *clist, + GtkCMCListRow *target_row, + gint target_row_number, + GtkCMCListDragPos drag_pos); + void (*clear) (GtkCMCList *clist); + void (*fake_unselect_all) (GtkCMCList *clist, + gint row); + void (*sort_list) (GtkCMCList *clist); + gint (*insert_row) (GtkCMCList *clist, + gint row, + gchar *text[]); + void (*remove_row) (GtkCMCList *clist, + gint row); + void (*set_cell_contents) (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint column, + GtkCMCellType type, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap, + GdkBitmap *mask); + void (*cell_size_request) (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint column, + GtkRequisition *requisition); + +}; + +struct _GtkCMCListColumn +{ + gchar *title; + GdkRectangle area; + + GtkWidget *button; + GdkWindow *window; + + gint width; + gint min_width; + gint max_width; + GtkJustification justification; + + guint visible : 1; + guint width_set : 1; + guint resizeable : 1; + guint auto_resize : 1; + guint button_passive : 1; +}; + +struct _GtkCMCListRow +{ + GtkCMCell *cell; + GtkStateType state; + + GdkColor foreground; + GdkColor background; + + GtkStyle *style; + + gpointer data; + GtkDestroyNotify destroy; + + guint fg_set : 1; + guint bg_set : 1; + guint selectable : 1; +}; + +/* Cell Structures */ +struct _GtkCMCellText +{ + GtkCMCellType type; + + gint16 vertical; + gint16 horizontal; + + GtkStyle *style; + + gchar *text; +}; + +struct _GtkCMCellPixmap +{ + GtkCMCellType type; + + gint16 vertical; + gint16 horizontal; + + GtkStyle *style; + + GdkPixmap *pixmap; + GdkBitmap *mask; +}; + +struct _GtkCMCellPixText +{ + GtkCMCellType type; + + gint16 vertical; + gint16 horizontal; + + GtkStyle *style; + + gchar *text; + guint8 spacing; + GdkPixmap *pixmap; + GdkBitmap *mask; +}; + +struct _GtkCMCellWidget +{ + GtkCMCellType type; + + gint16 vertical; + gint16 horizontal; + + GtkStyle *style; + + GtkWidget *widget; +}; + +struct _GtkCMCell +{ + GtkCMCellType type; + + gint16 vertical; + gint16 horizontal; + + GtkStyle *style; + + union { + gchar *text; + + struct { + GdkPixmap *pixmap; + GdkBitmap *mask; + } pm; + + struct { + gchar *text; + guint8 spacing; + GdkPixmap *pixmap; + GdkBitmap *mask; + } pt; + + GtkWidget *widget; + } u; +}; + +GType gtk_cmclist_get_type (void); + +/* create a new GtkCMCList */ +GtkWidget* gtk_cmclist_new (gint columns); +GtkWidget* gtk_cmclist_new_with_titles (gint columns, + gchar *titles[]); + +/* set adjustments of clist */ +void gtk_cmclist_set_hadjustment (GtkCMCList *clist, + GtkAdjustment *adjustment); +void gtk_cmclist_set_vadjustment (GtkCMCList *clist, + GtkAdjustment *adjustment); + +/* get adjustments of clist */ +GtkAdjustment* gtk_cmclist_get_hadjustment (GtkCMCList *clist); +GtkAdjustment* gtk_cmclist_get_vadjustment (GtkCMCList *clist); + +/* set the border style of the clist */ +void gtk_cmclist_set_shadow_type (GtkCMCList *clist, + GtkShadowType type); + +/* set the clist's selection mode */ +void gtk_cmclist_set_selection_mode (GtkCMCList *clist, + GtkSelectionMode mode); + +/* enable clists reorder ability */ +void gtk_cmclist_set_reorderable (GtkCMCList *clist, + gboolean reorderable); +void gtk_cmclist_set_use_drag_icons (GtkCMCList *clist, + gboolean use_icons); +void gtk_cmclist_set_button_actions (GtkCMCList *clist, + guint button, + guint8 button_actions); + +/* freeze all visual updates of the list, and then thaw the list after + * you have made a number of changes and the updates wil occure in a + * more efficent mannor than if you made them on a unfrozen list + */ +void gtk_cmclist_freeze (GtkCMCList *clist); +void gtk_cmclist_thaw (GtkCMCList *clist); + +/* show and hide the column title buttons */ +void gtk_cmclist_column_titles_show (GtkCMCList *clist); +void gtk_cmclist_column_titles_hide (GtkCMCList *clist); + +/* set the column title to be a active title (responds to button presses, + * prelights, and grabs keyboard focus), or passive where it acts as just + * a title + */ +void gtk_cmclist_column_title_active (GtkCMCList *clist, + gint column); +void gtk_cmclist_column_title_passive (GtkCMCList *clist, + gint column); +void gtk_cmclist_column_titles_active (GtkCMCList *clist); +void gtk_cmclist_column_titles_passive (GtkCMCList *clist); + +/* set the title in the column title button */ +void gtk_cmclist_set_column_title (GtkCMCList *clist, + gint column, + const gchar *title); + +/* returns the title of column. Returns NULL if title is not set */ +gchar * gtk_cmclist_get_column_title (GtkCMCList *clist, + gint column); + +/* set a widget instead of a title for the column title button */ +void gtk_cmclist_set_column_widget (GtkCMCList *clist, + gint column, + GtkWidget *widget); + +/* returns the column widget */ +GtkWidget * gtk_cmclist_get_column_widget (GtkCMCList *clist, + gint column); + +/* set the justification on a column */ +void gtk_cmclist_set_column_justification (GtkCMCList *clist, + gint column, + GtkJustification justification); + +/* set visibility of a column */ +void gtk_cmclist_set_column_visibility (GtkCMCList *clist, + gint column, + gboolean visible); + +/* enable/disable column resize operations by mouse */ +void gtk_cmclist_set_column_resizeable (GtkCMCList *clist, + gint column, + gboolean resizeable); + +/* resize column automatically to its optimal width */ +void gtk_cmclist_set_column_auto_resize (GtkCMCList *clist, + gint column, + gboolean auto_resize); + +gint gtk_cmclist_columns_autosize (GtkCMCList *clist); + +/* return the optimal column width, i.e. maximum of all cell widths */ +gint gtk_cmclist_optimal_column_width (GtkCMCList *clist, + gint column); + +/* set the pixel width of a column; this is a necessary step in + * creating a CList because otherwise the column width is chozen from + * the width of the column title, which will never be right + */ +void gtk_cmclist_set_column_width (GtkCMCList *clist, + gint column, + gint width); + +/* set column minimum/maximum width. min/max_width < 0 => no restriction */ +void gtk_cmclist_set_column_min_width (GtkCMCList *clist, + gint column, + gint min_width); +void gtk_cmclist_set_column_max_width (GtkCMCList *clist, + gint column, + gint max_width); + +/* change the height of the rows, the default (height=0) is + * the hight of the current font. + */ +void gtk_cmclist_set_row_height (GtkCMCList *clist, + guint height); + +/* scroll the viewing area of the list to the given column and row; + * row_align and col_align are between 0-1 representing the location the + * row should appear on the screnn, 0.0 being top or left, 1.0 being + * bottom or right; if row or column is -1 then then there is no change + */ +void gtk_cmclist_moveto (GtkCMCList *clist, + gint row, + gint column, + gfloat row_align, + gfloat col_align); + +/* returns whether the row is visible */ +GtkVisibility gtk_cmclist_row_is_visible (GtkCMCList *clist, + gint row); + +/* returns the cell type */ +GtkCMCellType gtk_cmclist_get_cell_type (GtkCMCList *clist, + gint row, + gint column); + +/* sets a given cell's text, replacing its current contents */ +void gtk_cmclist_set_text (GtkCMCList *clist, + gint row, + gint column, + const gchar *text); + +/* for the "get" functions, any of the return pointer can be + * NULL if you are not interested + */ +gint gtk_cmclist_get_text (GtkCMCList *clist, + gint row, + gint column, + gchar **text); + +/* sets a given cell's pixmap, replacing its current contents */ +void gtk_cmclist_set_pixmap (GtkCMCList *clist, + gint row, + gint column, + GdkPixmap *pixmap, + GdkBitmap *mask); + +gint gtk_cmclist_get_pixmap (GtkCMCList *clist, + gint row, + gint column, + GdkPixmap **pixmap, + GdkBitmap **mask); + +/* sets a given cell's pixmap and text, replacing its current contents */ +void gtk_cmclist_set_pixtext (GtkCMCList *clist, + gint row, + gint column, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap, + GdkBitmap *mask); + +gint gtk_cmclist_get_pixtext (GtkCMCList *clist, + gint row, + gint column, + gchar **text, + guint8 *spacing, + GdkPixmap **pixmap, + GdkBitmap **mask); + +/* sets the foreground color of a row, the color must already + * be allocated + */ +void gtk_cmclist_set_foreground (GtkCMCList *clist, + gint row, + const GdkColor *color); + +/* sets the background color of a row, the color must already + * be allocated + */ +void gtk_cmclist_set_background (GtkCMCList *clist, + gint row, + const GdkColor *color); + +/* set / get cell styles */ +void gtk_cmclist_set_cell_style (GtkCMCList *clist, + gint row, + gint column, + GtkStyle *style); + +GtkStyle *gtk_cmclist_get_cell_style (GtkCMCList *clist, + gint row, + gint column); + +void gtk_cmclist_set_row_style (GtkCMCList *clist, + gint row, + GtkStyle *style); + +GtkStyle *gtk_cmclist_get_row_style (GtkCMCList *clist, + gint row); + +/* this sets a horizontal and vertical shift for drawing + * the contents of a cell; it can be positive or negitive; + * this is particulary useful for indenting items in a column + */ +void gtk_cmclist_set_shift (GtkCMCList *clist, + gint row, + gint column, + gint vertical, + gint horizontal); + +/* set/get selectable flag of a single row */ +void gtk_cmclist_set_selectable (GtkCMCList *clist, + gint row, + gboolean selectable); +gboolean gtk_cmclist_get_selectable (GtkCMCList *clist, + gint row); + +/* prepend/append returns the index of the row you just added, + * making it easier to append and modify a row + */ +gint gtk_cmclist_prepend (GtkCMCList *clist, + gchar *text[]); +gint gtk_cmclist_append (GtkCMCList *clist, + gchar *text[]); + +/* inserts a row at index row and returns the row where it was + * actually inserted (may be different from "row" in auto_sort mode) + */ +gint gtk_cmclist_insert (GtkCMCList *clist, + gint row, + gchar *text[]); + +/* removes row at index row */ +void gtk_cmclist_remove (GtkCMCList *clist, + gint row); + +/* sets a arbitrary data pointer for a given row */ +void gtk_cmclist_set_row_data (GtkCMCList *clist, + gint row, + gpointer data); + +/* sets a data pointer for a given row with destroy notification */ +void gtk_cmclist_set_row_data_full (GtkCMCList *clist, + gint row, + gpointer data, + GtkDestroyNotify destroy); + +/* returns the data set for a row */ +gpointer gtk_cmclist_get_row_data (GtkCMCList *clist, + gint row); + +/* givin a data pointer, find the first (and hopefully only!) + * row that points to that data, or -1 if none do + */ +gint gtk_cmclist_find_row_from_data (GtkCMCList *clist, + gpointer data); + +/* force selection of a row */ +void gtk_cmclist_select_row (GtkCMCList *clist, + gint row, + gint column); + +/* force unselection of a row */ +void gtk_cmclist_unselect_row (GtkCMCList *clist, + gint row, + gint column); + +/* undo the last select/unselect operation */ +void gtk_cmclist_undo_selection (GtkCMCList *clist); + +/* clear the entire list -- this is much faster than removing + * each item with gtk_cmclist_remove + */ +void gtk_cmclist_clear (GtkCMCList *clist); + +/* return the row column corresponding to the x and y coordinates, + * the returned values are only valid if the x and y coordinates + * are respectively to a window == clist->clist_window + */ +gint gtk_cmclist_get_selection_info (GtkCMCList *clist, + gint x, + gint y, + gint *row, + gint *column); + +/* in multiple or extended mode, select all rows */ +void gtk_cmclist_select_all (GtkCMCList *clist); + +/* in all modes except browse mode, deselect all rows */ +void gtk_cmclist_unselect_all (GtkCMCList *clist); + +/* swap the position of two rows */ +void gtk_cmclist_swap_rows (GtkCMCList *clist, + gint row1, + gint row2); + +/* move row from source_row position to dest_row position */ +void gtk_cmclist_row_move (GtkCMCList *clist, + gint source_row, + gint dest_row); + +/* sets a compare function different to the default */ +void gtk_cmclist_set_compare_func (GtkCMCList *clist, + GtkCMCListCompareFunc cmp_func); + +/* the column to sort by */ +void gtk_cmclist_set_sort_column (GtkCMCList *clist, + gint column); + +/* how to sort : ascending or descending */ +void gtk_cmclist_set_sort_type (GtkCMCList *clist, + GtkSortType sort_type); + +/* sort the list with the current compare function */ +void gtk_cmclist_sort (GtkCMCList *clist); + +/* Automatically sort upon insertion */ +void gtk_cmclist_set_auto_sort (GtkCMCList *clist, + gboolean auto_sort); + +/* Private function for clist, ctree */ + +PangoLayout *_gtk_cmclist_create_cell_layout (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint column); + + +G_END_DECLS + + +#endif /* __GTK_CMCLIST_H__ */ diff --git a/src/gtk/gtkcmctree.c b/src/gtk/gtkcmctree.c @@ -0,0 +1,6198 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald, + * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org> + * + * GtkCMCTree widget for GTK+ + * Copyright (C) 1998 Lars Hamann and Stefan Jeske + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include <config.h> +#include <stdlib.h> +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> +#include "gtkcmctree.h" +#include "claws-marshal.h" + +#define PM_SIZE 8 +#define TAB_SIZE (PM_SIZE + 6) +#define CELL_SPACING 1 +#define CLIST_OPTIMUM_SIZE 64 +#define COLUMN_INSET 3 +#define DRAG_WIDTH 6 + +#define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \ + (((row) + 1) * CELL_SPACING) + \ + (clist)->voffset) +#define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \ + ((clist)->row_height + CELL_SPACING)) +#define COLUMN_LEFT_XPIXEL(clist, col) ((clist)->column[(col)].area.x \ + + (clist)->hoffset) +#define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x) + +GType +gtk_cmctree_pos_get_type (void) +{ + static GType etype = 0; + if (etype == 0) { + static const GEnumValue values[] = { + { GTK_CMCTREE_POS_BEFORE, "GTK_CMCTREE_POS_BEFORE", "before" }, + { GTK_CMCTREE_POS_AS_CHILD, "GTK_CMCTREE_POS_AS_CHILD", "as-child" }, + { GTK_CMCTREE_POS_AFTER, "GTK_CMCTREE_POS_AFTER", "after" }, + { 0, NULL, NULL } + }; + etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreePos"), values); + } + return etype; +} +GType +gtk_cmctree_line_style_get_type (void) +{ + static GType etype = 0; + if (etype == 0) { + static const GEnumValue values[] = { + { GTK_CMCTREE_LINES_NONE, "GTK_CMCTREE_LINES_NONE", "none" }, + { GTK_CMCTREE_LINES_SOLID, "GTK_CMCTREE_LINES_SOLID", "solid" }, + { GTK_CMCTREE_LINES_DOTTED, "GTK_CMCTREE_LINES_DOTTED", "dotted" }, + { GTK_CMCTREE_LINES_TABBED, "GTK_CMCTREE_LINES_TABBED", "tabbed" }, + { 0, NULL, NULL } + }; + etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreeLineStyle"), values); + } + return etype; +} +GType +gtk_cmctree_expander_style_get_type (void) +{ + static GType etype = 0; + if (etype == 0) { + static const GEnumValue values[] = { + { GTK_CMCTREE_EXPANDER_NONE, "GTK_CMCTREE_EXPANDER_NONE", "none" }, + { GTK_CMCTREE_EXPANDER_SQUARE, "GTK_CMCTREE_EXPANDER_SQUARE", "square" }, + { GTK_CMCTREE_EXPANDER_TRIANGLE, "GTK_CMCTREE_EXPANDER_TRIANGLE", "triangle" }, + { GTK_CMCTREE_EXPANDER_CIRCULAR, "GTK_CMCTREE_EXPANDER_CIRCULAR", "circular" }, + { 0, NULL, NULL } + }; + etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreeExpanderStyle"), values); + } + return etype; +} +GType +gtk_cmctree_expansion_type_get_type (void) +{ + static GType etype = 0; + if (etype == 0) { + static const GEnumValue values[] = { + { GTK_CMCTREE_EXPANSION_EXPAND, "GTK_CMCTREE_EXPANSION_EXPAND", "expand" }, + { GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE, "GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE", "expand-recursive" }, + { GTK_CMCTREE_EXPANSION_COLLAPSE, "GTK_CMCTREE_EXPANSION_COLLAPSE", "collapse" }, + { GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE, "GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE", "collapse-recursive" }, + { GTK_CMCTREE_EXPANSION_TOGGLE, "GTK_CMCTREE_EXPANSION_TOGGLE", "toggle" }, + { GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE, "GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE", "toggle-recursive" }, + { 0, NULL, NULL } + }; + etype = g_enum_register_static (g_intern_static_string ("GtkCMCTreeExpansionType"), values); + } + return etype; +} + + +static inline gint +COLUMN_FROM_XPIXEL (GtkCMCList * clist, + gint x) +{ + gint i, cx; + + for (i = 0; i < clist->columns; i++) + if (clist->column[i].visible) + { + cx = clist->column[i].area.x + clist->hoffset; + + if (x >= (cx - (COLUMN_INSET + CELL_SPACING)) && + x <= (cx + clist->column[i].area.width + COLUMN_INSET)) + return i; + } + + /* no match */ + return -1; +} + +#define CLIST_UNFROZEN(clist) (((GtkCMCList*) (clist))->freeze_count == 0) +#define CLIST_REFRESH(clist) G_STMT_START { \ + if (CLIST_UNFROZEN (clist)) \ + GTK_CMCLIST_GET_CLASS (clist)->refresh ((GtkCMCList*) (clist)); \ +} G_STMT_END + + +enum { + ARG_0, + ARG_N_COLUMNS, + ARG_TREE_COLUMN, + ARG_INDENT, + ARG_SPACING, + ARG_SHOW_STUB, + ARG_LINE_STYLE, + ARG_EXPANDER_STYLE +}; + + +static void gtk_cmctree_class_init (GtkCMCTreeClass *klass); +static void gtk_cmctree_init (GtkCMCTree *ctree); +static GObject* gtk_cmctree_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_params); +static void gtk_cmctree_set_arg (GObject *object, + guint arg_id, + const GValue *value, + GParamSpec *spec); +static void gtk_cmctree_get_arg (GObject *object, + guint arg_id, + GValue *value, + GParamSpec *spec); +static void gtk_cmctree_realize (GtkWidget *widget); +static void gtk_cmctree_unrealize (GtkWidget *widget); +static gint gtk_cmctree_button_press (GtkWidget *widget, + GdkEventButton *event); +static void ctree_attach_styles (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data); +static void ctree_detach_styles (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data); +static gint draw_cell_pixmap (GdkWindow *window, + GdkRectangle *clip_rectangle, + GdkGC *fg_gc, + GdkPixmap *pixmap, + GdkBitmap *mask, + gint x, + gint y, + gint width, + gint height); +static void get_cell_style (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint state, + gint column, + GtkStyle **style, + GdkGC **fg_gc, + GdkGC **bg_gc); +static gint gtk_cmctree_draw_expander (GtkCMCTree *ctree, + GtkCMCTreeRow *ctree_row, + GtkStyle *style, + GdkRectangle *clip_rectangle, + gint x); +static gint gtk_cmctree_draw_lines (GtkCMCTree *ctree, + GtkCMCTreeRow *ctree_row, + gint row, + gint column, + gint state, + GdkRectangle *clip_rectangle, + GdkRectangle *cell_rectangle, + GdkRectangle *crect, + GdkRectangle *area, + GtkStyle *style); +static void draw_row (GtkCMCList *clist, + GdkRectangle *area, + gint row, + GtkCMCListRow *clist_row); +static void draw_drag_highlight (GtkCMCList *clist, + GtkCMCListRow *dest_row, + gint dest_row_number, + GtkCMCListDragPos drag_pos); +static void tree_draw_node (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +static void set_cell_contents (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint column, + GtkCMCellType type, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap, + GdkBitmap *mask); +static void set_node_info (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap_closed, + GdkBitmap *mask_closed, + GdkPixmap *pixmap_opened, + GdkBitmap *mask_opened, + gboolean is_leaf, + gboolean expanded); +static GtkCMCTreeRow *row_new (GtkCMCTree *ctree); +static void row_delete (GtkCMCTree *ctree, + GtkCMCTreeRow *ctree_row); +static void tree_delete (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data); +static void tree_delete_row (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data); +static void real_clear (GtkCMCList *clist); +static void tree_update_level (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data); +static void tree_select (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data); +static void tree_unselect (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data); +static void real_select_all (GtkCMCList *clist); +static void real_unselect_all (GtkCMCList *clist); +static void tree_expand (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data); +static void tree_collapse (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data); +static void tree_collapse_to_depth (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint depth); +static void tree_toggle_expansion (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data); +static void change_focus_row_expansion (GtkCMCTree *ctree, + GtkCMCTreeExpansionType expansion); +static void real_select_row (GtkCMCList *clist, + gint row, + gint column, + GdkEvent *event); +static void real_unselect_row (GtkCMCList *clist, + gint row, + gint column, + GdkEvent *event); +static void real_tree_select (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column); +static void real_tree_unselect (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column); +static void real_tree_expand (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +static void real_tree_collapse (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +static void real_tree_move (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeNode *new_parent, + GtkCMCTreeNode *new_sibling); +static void real_row_move (GtkCMCList *clist, + gint source_row, + gint dest_row); +static void gtk_cmctree_link (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeNode *parent, + GtkCMCTreeNode *sibling, + gboolean update_focus_row); +static void gtk_cmctree_unlink (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gboolean update_focus_row); +static GtkCMCTreeNode * gtk_cmctree_last_visible (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +static gboolean ctree_is_hot_spot (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint row, + gint x, + gint y); +static void tree_sort (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data); +static void fake_unselect_all (GtkCMCList *clist, + gint row); +static GList * selection_find (GtkCMCList *clist, + gint row_number, + GList *row_list_element); +static void resync_selection (GtkCMCList *clist, + GdkEvent *event); +static void real_undo_selection (GtkCMCList *clist); +static void select_row_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data); +static gint real_insert_row (GtkCMCList *clist, + gint row, + gchar *text[]); +static void real_remove_row (GtkCMCList *clist, + gint row); +static void real_sort_list (GtkCMCList *clist); +static void cell_size_request (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint column, + GtkRequisition *requisition); +static void column_auto_resize (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint column, + gint old_width); +static void auto_resize_columns (GtkCMCList *clist); + + +static gboolean check_drag (GtkCMCTree *ctree, + GtkCMCTreeNode *drag_source, + GtkCMCTreeNode *drag_target, + GtkCMCListDragPos insert_pos); +static void gtk_cmctree_drag_begin (GtkWidget *widget, + GdkDragContext *context); +static gint gtk_cmctree_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time); +static void gtk_cmctree_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint32 time); +static void remove_grab (GtkCMCList *clist); +static void drag_dest_cell (GtkCMCList *clist, + gint x, + gint y, + GtkCMCListDestInfo *dest_info); + + +enum +{ + TREE_SELECT_ROW, + TREE_UNSELECT_ROW, + TREE_EXPAND, + TREE_COLLAPSE, + TREE_MOVE, + CHANGE_FOCUS_ROW_EXPANSION, + LAST_SIGNAL +}; + +static GtkCMCListClass *parent_class = NULL; +static GtkContainerClass *container_class = NULL; +static guint ctree_signals[LAST_SIGNAL] = {0}; + + +GType +gtk_cmctree_get_type (void) +{ + static GType ctree_type = 0; + + if (!ctree_type) + { + static const GTypeInfo ctree_info = + { + sizeof (GtkCMCTreeClass), + + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + + (GClassInitFunc) gtk_cmctree_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + + sizeof (GtkCMCTree), + 0, /* n_preallocs */ + (GInstanceInitFunc) gtk_cmctree_init, + }; + + ctree_type = g_type_register_static (GTK_TYPE_CMCLIST, "GtkCMCTree", &ctree_info, (GTypeFlags)0); + } + + return ctree_type; +} + +static void +gtk_cmctree_class_init (GtkCMCTreeClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkCMCListClass *clist_class; + GtkBindingSet *binding_set; + + gobject_class->constructor = gtk_cmctree_constructor; + + object_class = (GtkObjectClass *) klass; + widget_class = (GtkWidgetClass *) klass; + container_class = (GtkContainerClass *) klass; + clist_class = (GtkCMCListClass *) klass; + + parent_class = gtk_type_class (GTK_TYPE_CMCLIST); + container_class = gtk_type_class (GTK_TYPE_CONTAINER); + + gobject_class->set_property = gtk_cmctree_set_arg; + gobject_class->get_property = gtk_cmctree_get_arg; + + widget_class->realize = gtk_cmctree_realize; + widget_class->unrealize = gtk_cmctree_unrealize; + widget_class->button_press_event = gtk_cmctree_button_press; + + widget_class->drag_begin = gtk_cmctree_drag_begin; + widget_class->drag_motion = gtk_cmctree_drag_motion; + widget_class->drag_data_received = gtk_cmctree_drag_data_received; + + clist_class->select_row = real_select_row; + clist_class->unselect_row = real_unselect_row; + clist_class->row_move = real_row_move; + clist_class->undo_selection = real_undo_selection; + clist_class->resync_selection = resync_selection; + clist_class->selection_find = selection_find; + clist_class->click_column = NULL; + clist_class->draw_row = draw_row; + clist_class->draw_drag_highlight = draw_drag_highlight; + clist_class->clear = real_clear; + clist_class->select_all = real_select_all; + clist_class->unselect_all = real_unselect_all; + clist_class->fake_unselect_all = fake_unselect_all; + clist_class->insert_row = real_insert_row; + clist_class->remove_row = real_remove_row; + clist_class->sort_list = real_sort_list; + clist_class->set_cell_contents = set_cell_contents; + clist_class->cell_size_request = cell_size_request; + + klass->tree_select_row = real_tree_select; + klass->tree_unselect_row = real_tree_unselect; + klass->tree_expand = real_tree_expand; + klass->tree_collapse = real_tree_collapse; + klass->tree_move = real_tree_move; + klass->change_focus_row_expansion = change_focus_row_expansion; + + g_object_class_install_property (gobject_class, + ARG_N_COLUMNS, + g_param_spec_uint ("n-columns", + "N-Columns", + "N-Columns", + 1, + G_MAXINT, + 1, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (gobject_class, + ARG_TREE_COLUMN, + g_param_spec_uint ("tree-column", + "tree-column", + "tree-column", + 0, + G_MAXINT, + 0, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (gobject_class, + ARG_INDENT, + g_param_spec_uint ("indent", + "indent", + "indent", + 1, + G_MAXINT, + 1, + G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + ARG_SPACING, + g_param_spec_uint ("spacing", + "spacing", + "spacing", + 1, + G_MAXINT, + 1, + G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + ARG_SHOW_STUB, + g_param_spec_boolean ("show-stub", + "show-stub", + "show-stub", + TRUE, + G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + ARG_LINE_STYLE, + g_param_spec_enum ("line-style", + "line-style", + "line-style", + GTK_TYPE_CMCTREE_LINE_STYLE, 0, + G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + ARG_EXPANDER_STYLE, + g_param_spec_enum ("expander-style", + "expander-style", + "expander-style", + GTK_TYPE_CMCTREE_EXPANDER_STYLE, 0, + G_PARAM_READWRITE)); + + ctree_signals[TREE_SELECT_ROW] = + g_signal_new ("tree_select_row", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkCMCTreeClass, tree_select_row), + NULL, NULL, + claws_marshal_VOID__POINTER_INT, + G_TYPE_NONE, 2, + GTK_TYPE_CMCTREE_NODE, + G_TYPE_INT); + ctree_signals[TREE_UNSELECT_ROW] = + g_signal_new ("tree_unselect_row", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkCMCTreeClass, tree_unselect_row), + NULL, NULL, + claws_marshal_VOID__POINTER_INT, + G_TYPE_NONE, 2, + GTK_TYPE_CMCTREE_NODE, + G_TYPE_INT); + ctree_signals[TREE_EXPAND] = + g_signal_new ("tree_expand", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkCMCTreeClass, tree_expand), + NULL, NULL, + claws_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + GTK_TYPE_CMCTREE_NODE); + ctree_signals[TREE_COLLAPSE] = + g_signal_new ("tree_collapse", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkCMCTreeClass, tree_collapse), + NULL, NULL, + claws_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + GTK_TYPE_CMCTREE_NODE); + ctree_signals[TREE_MOVE] = + g_signal_new ("tree_move", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkCMCTreeClass, tree_move), + NULL, NULL, + claws_marshal_VOID__POINTER_POINTER_POINTER, + G_TYPE_NONE, 3, + GTK_TYPE_CMCTREE_NODE,GTK_TYPE_CMCTREE_NODE,GTK_TYPE_CMCTREE_NODE); + ctree_signals[CHANGE_FOCUS_ROW_EXPANSION] = + g_signal_new ("change_focus_row_expansion", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkCMCTreeClass, change_focus_row_expansion), + NULL, NULL, + claws_marshal_VOID__ENUM, + G_TYPE_NONE, 1, GTK_TYPE_CMCTREE_EXPANSION_TYPE); + + binding_set = gtk_binding_set_by_class (klass); + gtk_binding_entry_add_signal (binding_set, + GDK_plus, 0, + "change_focus_row_expansion", 1, + G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND); + gtk_binding_entry_add_signal (binding_set, + GDK_plus, GDK_CONTROL_MASK, + "change_focus_row_expansion", 1, + G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE); + + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Add, 0, + "change_focus_row_expansion", 1, + G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND); + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Add, GDK_CONTROL_MASK, + "change_focus_row_expansion", 1, + G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE); + + gtk_binding_entry_add_signal (binding_set, + GDK_minus, 0, + "change_focus_row_expansion", 1, + G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_COLLAPSE); + gtk_binding_entry_add_signal (binding_set, + GDK_minus, GDK_CONTROL_MASK, + "change_focus_row_expansion", 1, + G_TYPE_ENUM, + GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE); + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Subtract, 0, + "change_focus_row_expansion", 1, + G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_COLLAPSE); + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Subtract, GDK_CONTROL_MASK, + "change_focus_row_expansion", 1, + G_TYPE_ENUM, + GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE); + gtk_binding_entry_add_signal (binding_set, + GDK_equal, 0, + "change_focus_row_expansion", 1, + G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE); + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Equal, 0, + "change_focus_row_expansion", 1, + G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE); + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Multiply, 0, + "change_focus_row_expansion", 1, + G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE); + gtk_binding_entry_add_signal (binding_set, + GDK_asterisk, 0, + "change_focus_row_expansion", 1, + G_TYPE_ENUM, GTK_CMCTREE_EXPANSION_TOGGLE); + gtk_binding_entry_add_signal (binding_set, + GDK_KP_Multiply, GDK_CONTROL_MASK, + "change_focus_row_expansion", 1, + G_TYPE_ENUM, + GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE); + gtk_binding_entry_add_signal (binding_set, + GDK_asterisk, GDK_CONTROL_MASK, + "change_focus_row_expansion", 1, + G_TYPE_ENUM, + GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE); +} + +static void +gtk_cmctree_set_arg (GObject *object, + guint arg_id, + const GValue *value, + GParamSpec *spec) +{ + GtkCMCTree *ctree; + GtkCMCList *clist; + + ctree = GTK_CMCTREE (object); + clist = GTK_CMCLIST (ctree); + + switch (arg_id) + { + case ARG_N_COLUMNS: /* construct-only arg, only set at construction time */ + clist->columns = MAX (1, g_value_get_uint (value)); + ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns); + break; + case ARG_TREE_COLUMN: /* construct-only arg, only set at construction time */ + ctree->tree_column = g_value_get_uint (value); + ctree->tree_column = CLAMP (ctree->tree_column, 0, clist->columns); + break; + case ARG_INDENT: + gtk_cmctree_set_indent (ctree, g_value_get_uint (value)); + break; + case ARG_SPACING: + gtk_cmctree_set_spacing (ctree, g_value_get_uint (value)); + break; + case ARG_SHOW_STUB: + gtk_cmctree_set_show_stub (ctree, g_value_get_boolean (value)); + break; + case ARG_LINE_STYLE: + gtk_cmctree_set_line_style (ctree, g_value_get_enum (value)); + break; + case ARG_EXPANDER_STYLE: + gtk_cmctree_set_expander_style (ctree, g_value_get_enum (value)); + break; + default: + break; + } +} + +static void +gtk_cmctree_get_arg (GObject *object, + guint arg_id, + GValue *value, + GParamSpec *spec) +{ + GtkCMCTree *ctree; + + ctree = GTK_CMCTREE (object); + + switch (arg_id) + { + case ARG_N_COLUMNS: + g_value_set_uint(value, GTK_CMCLIST (ctree)->columns); + break; + case ARG_TREE_COLUMN: + g_value_set_uint(value, ctree->tree_column); + break; + case ARG_INDENT: + g_value_set_uint(value, ctree->tree_indent); + break; + case ARG_SPACING: + g_value_set_uint(value, ctree->tree_spacing); + break; + case ARG_SHOW_STUB: + g_value_set_boolean(value, ctree->show_stub); + break; + case ARG_LINE_STYLE: + g_value_set_enum(value, ctree->line_style); + break; + case ARG_EXPANDER_STYLE: + g_value_set_enum(value, ctree->expander_style); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, spec); + break; + } +} + +static void +gtk_cmctree_init (GtkCMCTree *ctree) +{ + GtkCMCList *clist; + + GTK_CMCLIST_SET_FLAG (ctree, CMCLIST_DRAW_DRAG_RECT); + GTK_CMCLIST_SET_FLAG (ctree, CMCLIST_DRAW_DRAG_LINE); + + clist = GTK_CMCLIST (ctree); + + ctree->tree_indent = 20; + ctree->tree_spacing = 5; + ctree->tree_column = 0; + ctree->line_style = GTK_CMCTREE_LINES_SOLID; + ctree->expander_style = GTK_CMCTREE_EXPANDER_SQUARE; + ctree->drag_compare = NULL; + ctree->show_stub = TRUE; + + clist->button_actions[0] |= GTK_CMBUTTON_EXPANDS; +} + +static void +ctree_attach_styles (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data) +{ + GtkCMCList *clist; + gint i; + + clist = GTK_CMCLIST (ctree); + + if (GTK_CMCTREE_ROW (node)->row.style) + GTK_CMCTREE_ROW (node)->row.style = + gtk_style_attach (GTK_CMCTREE_ROW (node)->row.style, clist->clist_window); + + if (GTK_CMCTREE_ROW (node)->row.fg_set || GTK_CMCTREE_ROW (node)->row.bg_set) + { + GdkColormap *colormap; + + colormap = gtk_widget_get_colormap (GTK_WIDGET (ctree)); + if (GTK_CMCTREE_ROW (node)->row.fg_set) + gdk_colormap_alloc_color (colormap, &(GTK_CMCTREE_ROW (node)->row.foreground), TRUE, TRUE); + if (GTK_CMCTREE_ROW (node)->row.bg_set) + gdk_colormap_alloc_color (colormap, &(GTK_CMCTREE_ROW (node)->row.background), TRUE, TRUE); + } + + for (i = 0; i < clist->columns; i++) + if (GTK_CMCTREE_ROW (node)->row.cell[i].style) + GTK_CMCTREE_ROW (node)->row.cell[i].style = + gtk_style_attach (GTK_CMCTREE_ROW (node)->row.cell[i].style, + clist->clist_window); +} + +static void +ctree_detach_styles (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data) +{ + GtkCMCList *clist; + gint i; + + clist = GTK_CMCLIST (ctree); + + if (GTK_CMCTREE_ROW (node)->row.style) + gtk_style_detach (GTK_CMCTREE_ROW (node)->row.style); + for (i = 0; i < clist->columns; i++) + if (GTK_CMCTREE_ROW (node)->row.cell[i].style) + gtk_style_detach (GTK_CMCTREE_ROW (node)->row.cell[i].style); +} + +static void +gtk_cmctree_realize (GtkWidget *widget) +{ + GtkCMCTree *ctree; + GtkCMCList *clist; + GdkGCValues values; + GtkCMCTreeNode *node; + GtkCMCTreeNode *child; + gint i; + + g_return_if_fail (GTK_IS_CMCTREE (widget)); + + GTK_WIDGET_CLASS (parent_class)->realize (widget); + + ctree = GTK_CMCTREE (widget); + clist = GTK_CMCLIST (widget); + + node = GTK_CMCTREE_NODE (clist->row_list); + for (i = 0; i < clist->rows; i++) + { + if (GTK_CMCTREE_ROW (node)->children && !GTK_CMCTREE_ROW (node)->expanded) + for (child = GTK_CMCTREE_ROW (node)->children; child; + child = GTK_CMCTREE_ROW (child)->sibling) + gtk_cmctree_pre_recursive (ctree, child, ctree_attach_styles, NULL); + node = GTK_CMCTREE_NODE_NEXT (node); + } + + values.foreground = widget->style->fg[GTK_STATE_NORMAL]; + values.background = widget->style->base[GTK_STATE_NORMAL]; + values.subwindow_mode = GDK_INCLUDE_INFERIORS; + values.line_style = GDK_LINE_SOLID; + ctree->lines_gc = gdk_gc_new_with_values (GTK_CMCLIST(widget)->clist_window, + &values, + GDK_GC_FOREGROUND | + GDK_GC_BACKGROUND | + GDK_GC_SUBWINDOW | + GDK_GC_LINE_STYLE); + + if (ctree->line_style == GTK_CMCTREE_LINES_DOTTED) + { + gdk_gc_set_line_attributes (ctree->lines_gc, 1, + GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER); + gdk_gc_set_dashes (ctree->lines_gc, 0, "\1\1", 2); + } +} + +static void +gtk_cmctree_unrealize (GtkWidget *widget) +{ + GtkCMCTree *ctree; + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCTREE (widget)); + + GTK_WIDGET_CLASS (parent_class)->unrealize (widget); + + ctree = GTK_CMCTREE (widget); + clist = GTK_CMCLIST (widget); + + if (GTK_WIDGET_REALIZED (widget)) + { + GtkCMCTreeNode *node; + GtkCMCTreeNode *child; + gint i; + + node = GTK_CMCTREE_NODE (clist->row_list); + for (i = 0; i < clist->rows; i++) + { + if (GTK_CMCTREE_ROW (node)->children && + !GTK_CMCTREE_ROW (node)->expanded) + for (child = GTK_CMCTREE_ROW (node)->children; child; + child = GTK_CMCTREE_ROW (child)->sibling) + gtk_cmctree_pre_recursive(ctree, child, ctree_detach_styles, NULL); + node = GTK_CMCTREE_NODE_NEXT (node); + } + } + + g_object_unref (ctree->lines_gc); +} + +static gint +gtk_cmctree_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkCMCTree *ctree; + GtkCMCList *clist; + gint button_actions; + + g_return_val_if_fail (GTK_IS_CMCTREE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + ctree = GTK_CMCTREE (widget); + clist = GTK_CMCLIST (widget); + + button_actions = clist->button_actions[event->button - 1]; + + if (button_actions == GTK_CMBUTTON_IGNORED) + return FALSE; + + if (event->window == clist->clist_window) + { + GtkCMCTreeNode *work; + gint x; + gint y; + gint row; + gint column; + + x = event->x; + y = event->y; + + if (!gtk_cmclist_get_selection_info (clist, x, y, &row, &column)) + return FALSE; + + work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row)); + + if (button_actions & GTK_CMBUTTON_EXPANDS && + (GTK_CMCTREE_ROW (work)->children && !GTK_CMCTREE_ROW (work)->is_leaf && + (event->type == GDK_2BUTTON_PRESS || + ctree_is_hot_spot (ctree, work, row, x, y)))) + { + if (GTK_CMCTREE_ROW (work)->expanded) + gtk_cmctree_collapse (ctree, work); + else + gtk_cmctree_expand (ctree, work); + + return TRUE; + } + } + + return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event); +} + +static void +draw_drag_highlight (GtkCMCList *clist, + GtkCMCListRow *dest_row, + gint dest_row_number, + GtkCMCListDragPos drag_pos) +{ + GtkCMCTree *ctree; + GdkPoint points[4]; + gint level; + gint i; + gint y = 0; + + g_return_if_fail (GTK_IS_CMCTREE (clist)); + + ctree = GTK_CMCTREE (clist); + + level = ((GtkCMCTreeRow *)(dest_row))->level; + + y = ROW_TOP_YPIXEL (clist, dest_row_number) - 1; + + switch (drag_pos) + { + case GTK_CMCLIST_DRAG_NONE: + break; + case GTK_CMCLIST_DRAG_AFTER: + y += clist->row_height + 1; + case GTK_CMCLIST_DRAG_BEFORE: + + if (clist->column[ctree->tree_column].visible) + switch (clist->column[ctree->tree_column].justification) + { + case GTK_JUSTIFY_CENTER: + case GTK_JUSTIFY_FILL: + case GTK_JUSTIFY_LEFT: + if (ctree->tree_column > 0) + gdk_draw_line (clist->clist_window, clist->xor_gc, + COLUMN_LEFT_XPIXEL(clist, 0), y, + COLUMN_LEFT_XPIXEL(clist, ctree->tree_column - 1)+ + clist->column[ctree->tree_column - 1].area.width, + y); + + gdk_draw_line (clist->clist_window, clist->xor_gc, + COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) + + ctree->tree_indent * level - + (ctree->tree_indent - PM_SIZE) / 2, y, + GTK_WIDGET (ctree)->allocation.width, y); + break; + case GTK_JUSTIFY_RIGHT: + if (ctree->tree_column < clist->columns - 1) + gdk_draw_line (clist->clist_window, clist->xor_gc, + COLUMN_LEFT_XPIXEL(clist, ctree->tree_column + 1), + y, + COLUMN_LEFT_XPIXEL(clist, clist->columns - 1) + + clist->column[clist->columns - 1].area.width, y); + + gdk_draw_line (clist->clist_window, clist->xor_gc, + 0, y, COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) + + clist->column[ctree->tree_column].area.width - + ctree->tree_indent * level + + (ctree->tree_indent - PM_SIZE) / 2, y); + break; + } + else + gdk_draw_line (clist->clist_window, clist->xor_gc, + 0, y, clist->clist_window_width, y); + break; + case GTK_CMCLIST_DRAG_INTO: + y = ROW_TOP_YPIXEL (clist, dest_row_number) + clist->row_height; + + if (clist->column[ctree->tree_column].visible) + switch (clist->column[ctree->tree_column].justification) + { + case GTK_JUSTIFY_CENTER: + case GTK_JUSTIFY_FILL: + case GTK_JUSTIFY_LEFT: + points[0].x = COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) + + ctree->tree_indent * level - (ctree->tree_indent - PM_SIZE) / 2; + points[0].y = y; + points[3].x = points[0].x; + points[3].y = y - clist->row_height - 1; + points[1].x = clist->clist_window_width - 1; + points[1].y = points[0].y; + points[2].x = points[1].x; + points[2].y = points[3].y; + + for (i = 0; i < 3; i++) + gdk_draw_line (clist->clist_window, clist->xor_gc, + points[i].x, points[i].y, + points[i+1].x, points[i+1].y); + + if (ctree->tree_column > 0) + { + points[0].x = COLUMN_LEFT_XPIXEL(clist, + ctree->tree_column - 1) + + clist->column[ctree->tree_column - 1].area.width ; + points[0].y = y; + points[3].x = points[0].x; + points[3].y = y - clist->row_height - 1; + points[1].x = 0; + points[1].y = points[0].y; + points[2].x = 0; + points[2].y = points[3].y; + + for (i = 0; i < 3; i++) + gdk_draw_line (clist->clist_window, clist->xor_gc, + points[i].x, points[i].y, points[i+1].x, + points[i+1].y); + } + break; + case GTK_JUSTIFY_RIGHT: + points[0].x = COLUMN_LEFT_XPIXEL(clist, ctree->tree_column) - + ctree->tree_indent * level + (ctree->tree_indent - PM_SIZE) / 2 + + clist->column[ctree->tree_column].area.width; + points[0].y = y; + points[3].x = points[0].x; + points[3].y = y - clist->row_height - 1; + points[1].x = 0; + points[1].y = points[0].y; + points[2].x = 0; + points[2].y = points[3].y; + + for (i = 0; i < 3; i++) + gdk_draw_line (clist->clist_window, clist->xor_gc, + points[i].x, points[i].y, + points[i+1].x, points[i+1].y); + + if (ctree->tree_column < clist->columns - 1) + { + points[0].x = COLUMN_LEFT_XPIXEL(clist, ctree->tree_column +1); + points[0].y = y; + points[3].x = points[0].x; + points[3].y = y - clist->row_height - 1; + points[1].x = clist->clist_window_width - 1; + points[1].y = points[0].y; + points[2].x = points[1].x; + points[2].y = points[3].y; + + for (i = 0; i < 3; i++) + gdk_draw_line (clist->clist_window, clist->xor_gc, + points[i].x, points[i].y, + points[i+1].x, points[i+1].y); + } + break; + } + else + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, + 0, y - clist->row_height, + clist->clist_window_width - 1, clist->row_height); + break; + } +} + +static gint +draw_cell_pixmap (GdkWindow *window, + GdkRectangle *clip_rectangle, + GdkGC *fg_gc, + GdkPixmap *pixmap, + GdkBitmap *mask, + gint x, + gint y, + gint width, + gint height) +{ + gint xsrc = 0; + gint ysrc = 0; + + if (mask) + { + gdk_gc_set_clip_mask (fg_gc, mask); + gdk_gc_set_clip_origin (fg_gc, x, y); + } + if (x < clip_rectangle->x) + { + xsrc = clip_rectangle->x - x; + width -= xsrc; + x = clip_rectangle->x; + } + if (x + width > clip_rectangle->x + clip_rectangle->width) + width = clip_rectangle->x + clip_rectangle->width - x; + + if (y < clip_rectangle->y) + { + ysrc = clip_rectangle->y - y; + height -= ysrc; + y = clip_rectangle->y; + } + if (y + height > clip_rectangle->y + clip_rectangle->height) + height = clip_rectangle->y + clip_rectangle->height - y; + + if (width > 0 && height > 0) + gdk_draw_drawable (window, fg_gc, pixmap, xsrc, ysrc, x, y, width, height); + + if (mask) + { + gdk_gc_set_clip_rectangle (fg_gc, NULL); + gdk_gc_set_clip_origin (fg_gc, 0, 0); + } + + return x + MAX (width, 0); +} + +static void +get_cell_style (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint state, + gint column, + GtkStyle **style, + GdkGC **fg_gc, + GdkGC **bg_gc) +{ + gint fg_state; + + if ((state == GTK_STATE_NORMAL) && + (GTK_WIDGET (clist)->state == GTK_STATE_INSENSITIVE)) + fg_state = GTK_STATE_INSENSITIVE; + else + fg_state = state; + + if (clist_row->cell[column].style) + { + if (style) + *style = clist_row->cell[column].style; + if (fg_gc) + *fg_gc = clist_row->cell[column].style->fg_gc[fg_state]; + if (bg_gc) { + if (state == GTK_STATE_SELECTED) + *bg_gc = clist_row->cell[column].style->bg_gc[state]; + else + *bg_gc = clist_row->cell[column].style->base_gc[state]; + } + } + else if (clist_row->style) + { + if (style) + *style = clist_row->style; + if (fg_gc) + *fg_gc = clist_row->style->fg_gc[fg_state]; + if (bg_gc) { + if (state == GTK_STATE_SELECTED) + *bg_gc = clist_row->style->bg_gc[state]; + else + *bg_gc = clist_row->style->base_gc[state]; + } + } + else + { + if (style) + *style = GTK_WIDGET (clist)->style; + if (fg_gc) + *fg_gc = GTK_WIDGET (clist)->style->fg_gc[fg_state]; + if (bg_gc) { + if (state == GTK_STATE_SELECTED) + *bg_gc = GTK_WIDGET (clist)->style->bg_gc[state]; + else + *bg_gc = GTK_WIDGET (clist)->style->base_gc[state]; + } + + if (state != GTK_STATE_SELECTED) + { + if (fg_gc && clist_row->fg_set) + *fg_gc = clist->fg_gc; + if (bg_gc && clist_row->bg_set) + *bg_gc = clist->bg_gc; + } + } +} + +static gint +gtk_cmctree_draw_expander (GtkCMCTree *ctree, + GtkCMCTreeRow *ctree_row, + GtkStyle *style, + GdkRectangle *clip_rectangle, + gint x) +{ + GtkCMCList *clist; + GdkPoint points[3]; + gint justification_factor; + gint y; + + if (ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE) + return x; + + clist = GTK_CMCLIST (ctree); + if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT) + justification_factor = -1; + else + justification_factor = 1; + y = (clip_rectangle->y + (clip_rectangle->height - PM_SIZE) / 2 - + (clip_rectangle->height + 1) % 2); + + if (!ctree_row->children) + { + switch (ctree->expander_style) + { + case GTK_CMCTREE_EXPANDER_NONE: + return x; + case GTK_CMCTREE_EXPANDER_TRIANGLE: + return x + justification_factor * (PM_SIZE + 3); + case GTK_CMCTREE_EXPANDER_SQUARE: + case GTK_CMCTREE_EXPANDER_CIRCULAR: + return x + justification_factor * (PM_SIZE + 1); + } + } + + gdk_gc_set_clip_rectangle (style->fg_gc[GTK_STATE_NORMAL], clip_rectangle); + gdk_gc_set_clip_rectangle (style->base_gc[GTK_STATE_NORMAL], clip_rectangle); + + switch (ctree->expander_style) + { + case GTK_CMCTREE_EXPANDER_NONE: + break; + case GTK_CMCTREE_EXPANDER_TRIANGLE: + if (ctree_row->expanded) + { + points[0].x = x; + points[0].y = y + (PM_SIZE + 2) / 6; + points[1].x = points[0].x + justification_factor * (PM_SIZE + 2); + points[1].y = points[0].y; + points[2].x = (points[0].x + + justification_factor * (PM_SIZE + 2) / 2); + points[2].y = y + 2 * (PM_SIZE + 2) / 3; + } + else + { + points[0].x = x + justification_factor * ((PM_SIZE + 2) / 6 + 2); + points[0].y = y - 1; + points[1].x = points[0].x; + points[1].y = points[0].y + (PM_SIZE + 2); + points[2].x = (points[0].x + + justification_factor * (2 * (PM_SIZE + 2) / 3 - 1)); + points[2].y = points[0].y + (PM_SIZE + 2) / 2; + } + + gdk_draw_polygon (clist->clist_window, style->base_gc[GTK_STATE_NORMAL], + TRUE, points, 3); + gdk_draw_polygon (clist->clist_window, style->fg_gc[GTK_STATE_NORMAL], + FALSE, points, 3); + + x += justification_factor * (PM_SIZE + 3); + break; + case GTK_CMCTREE_EXPANDER_SQUARE: + case GTK_CMCTREE_EXPANDER_CIRCULAR: + if (justification_factor == -1) + x += justification_factor * (PM_SIZE + 1); + + if (ctree->expander_style == GTK_CMCTREE_EXPANDER_CIRCULAR) + { + gdk_draw_arc (clist->clist_window, style->base_gc[GTK_STATE_NORMAL], + TRUE, x, y, PM_SIZE, PM_SIZE, 0, 360 * 64); + gdk_draw_arc (clist->clist_window, style->fg_gc[GTK_STATE_NORMAL], + FALSE, x, y, PM_SIZE, PM_SIZE, 0, 360 * 64); + } + else + { + gdk_draw_rectangle (clist->clist_window, + style->base_gc[GTK_STATE_NORMAL], TRUE, + x, y, PM_SIZE, PM_SIZE); + gdk_draw_rectangle (clist->clist_window, + style->fg_gc[GTK_STATE_NORMAL], FALSE, + x, y, PM_SIZE, PM_SIZE); + } + + gdk_draw_line (clist->clist_window, style->fg_gc[GTK_STATE_NORMAL], + x + 2, y + PM_SIZE / 2, x + PM_SIZE - 2, y + PM_SIZE / 2); + + if (!ctree_row->expanded) + gdk_draw_line (clist->clist_window, style->fg_gc[GTK_STATE_NORMAL], + x + PM_SIZE / 2, y + 2, + x + PM_SIZE / 2, y + PM_SIZE - 2); + + if (justification_factor == 1) + x += justification_factor * (PM_SIZE + 1); + break; + } + + gdk_gc_set_clip_rectangle (style->fg_gc[GTK_STATE_NORMAL], NULL); + gdk_gc_set_clip_rectangle (style->base_gc[GTK_STATE_NORMAL], NULL); + + return x; +} + + +static gint +gtk_cmctree_draw_lines (GtkCMCTree *ctree, + GtkCMCTreeRow *ctree_row, + gint row, + gint column, + gint state, + GdkRectangle *clip_rectangle, + GdkRectangle *cell_rectangle, + GdkRectangle *crect, + GdkRectangle *area, + GtkStyle *style) +{ + GtkCMCList *clist; + GtkCMCTreeNode *node; + GtkCMCTreeNode *parent; + GdkRectangle tree_rectangle; + GdkRectangle tc_rectangle; + GdkGC *bg_gc; + gint offset; + gint offset_x; + gint offset_y; + gint xcenter; + gint ycenter; + gint next_level; + gint column_right; + gint column_left; + gint justify_right; + gint justification_factor; + + clist = GTK_CMCLIST (ctree); + ycenter = clip_rectangle->y + (clip_rectangle->height / 2); + justify_right = (clist->column[column].justification == GTK_JUSTIFY_RIGHT); + + if (justify_right) + { + offset = (clip_rectangle->x + clip_rectangle->width - 1 - + ctree->tree_indent * (ctree_row->level - 1)); + justification_factor = -1; + } + else + { + offset = clip_rectangle->x + ctree->tree_indent * (ctree_row->level - 1); + justification_factor = 1; + } + + switch (ctree->line_style) + { + case GTK_CMCTREE_LINES_NONE: + break; + case GTK_CMCTREE_LINES_TABBED: + xcenter = offset + justification_factor * TAB_SIZE; + + column_right = (COLUMN_LEFT_XPIXEL (clist, ctree->tree_column) + + clist->column[ctree->tree_column].area.width + + COLUMN_INSET); + column_left = (COLUMN_LEFT_XPIXEL (clist, ctree->tree_column) - + COLUMN_INSET - CELL_SPACING); + + if (area) + { + tree_rectangle.y = crect->y; + tree_rectangle.height = crect->height; + + if (justify_right) + { + tree_rectangle.x = xcenter; + tree_rectangle.width = column_right - xcenter; + } + else + { + tree_rectangle.x = column_left; + tree_rectangle.width = xcenter - column_left; + } + + if (!gdk_rectangle_intersect (area, &tree_rectangle, &tc_rectangle)) + { + offset += justification_factor * 3; + break; + } + } + + gdk_gc_set_clip_rectangle (ctree->lines_gc, crect); + + next_level = ctree_row->level; + + if (!ctree_row->sibling || (ctree_row->children && ctree_row->expanded)) + { + node = gtk_cmctree_find_node_ptr (ctree, ctree_row); + if (GTK_CMCTREE_NODE_NEXT (node)) + next_level = GTK_CMCTREE_ROW (GTK_CMCTREE_NODE_NEXT (node))->level; + else + next_level = 0; + } + + if (ctree->tree_indent > 0) + { + node = ctree_row->parent; + while (node) + { + xcenter -= (justification_factor * ctree->tree_indent); + + if ((justify_right && xcenter < column_left) || + (!justify_right && xcenter > column_right)) + { + node = GTK_CMCTREE_ROW (node)->parent; + continue; + } + + tree_rectangle.y = cell_rectangle->y; + tree_rectangle.height = cell_rectangle->height; + if (justify_right) + { + tree_rectangle.x = MAX (xcenter - ctree->tree_indent + 1, + column_left); + tree_rectangle.width = MIN (xcenter - column_left, + ctree->tree_indent); + } + else + { + tree_rectangle.x = xcenter; + tree_rectangle.width = MIN (column_right - xcenter, + ctree->tree_indent); + } + + if (!area || gdk_rectangle_intersect (area, &tree_rectangle, + &tc_rectangle)) + { + get_cell_style (clist, &GTK_CMCTREE_ROW (node)->row, + state, column, NULL, NULL, &bg_gc); + + if (bg_gc == clist->bg_gc) + gdk_gc_set_foreground + (clist->bg_gc, &GTK_CMCTREE_ROW (node)->row.background); + + if (!area) + gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE, + tree_rectangle.x, + tree_rectangle.y, + tree_rectangle.width, + tree_rectangle.height); + else + gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE, + tc_rectangle.x, + tc_rectangle.y, + tc_rectangle.width, + tc_rectangle.height); + } + if (next_level > GTK_CMCTREE_ROW (node)->level) + gdk_draw_line (clist->clist_window, ctree->lines_gc, + xcenter, crect->y, + xcenter, crect->y + crect->height); + else + { + gint width; + + offset_x = MIN (ctree->tree_indent, 2 * TAB_SIZE); + width = offset_x / 2 + offset_x % 2; + + parent = GTK_CMCTREE_ROW (node)->parent; + + tree_rectangle.y = ycenter; + tree_rectangle.height = (cell_rectangle->y - ycenter + + cell_rectangle->height); + + if (justify_right) + { + tree_rectangle.x = MAX(xcenter + 1 - width, column_left); + tree_rectangle.width = MIN (xcenter + 1 - column_left, + width); + } + else + { + tree_rectangle.x = xcenter; + tree_rectangle.width = MIN (column_right - xcenter, + width); + } + + if (!area || + gdk_rectangle_intersect (area, &tree_rectangle, + &tc_rectangle)) + { + if (parent) + { + get_cell_style (clist, &GTK_CMCTREE_ROW (parent)->row, + state, column, NULL, NULL, &bg_gc); + if (bg_gc == clist->bg_gc) + gdk_gc_set_foreground + (clist->bg_gc, + &GTK_CMCTREE_ROW (parent)->row.background); + } + else if (state == GTK_STATE_SELECTED) + bg_gc = style->base_gc[state]; + else + bg_gc = GTK_WIDGET (clist)->style->base_gc[state]; + + if (!area) + gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE, + tree_rectangle.x, + tree_rectangle.y, + tree_rectangle.width, + tree_rectangle.height); + else + gdk_draw_rectangle (clist->clist_window, + bg_gc, TRUE, + tc_rectangle.x, + tc_rectangle.y, + tc_rectangle.width, + tc_rectangle.height); + } + + get_cell_style (clist, &GTK_CMCTREE_ROW (node)->row, + state, column, NULL, NULL, &bg_gc); + if (bg_gc == clist->bg_gc) + gdk_gc_set_foreground + (clist->bg_gc, &GTK_CMCTREE_ROW (node)->row.background); + + gdk_gc_set_clip_rectangle (bg_gc, crect); + gdk_draw_arc (clist->clist_window, bg_gc, TRUE, + xcenter - (justify_right * offset_x), + cell_rectangle->y, + offset_x, clist->row_height, + (180 + (justify_right * 90)) * 64, 90 * 64); + gdk_gc_set_clip_rectangle (bg_gc, NULL); + + gdk_draw_line (clist->clist_window, ctree->lines_gc, + xcenter, cell_rectangle->y, xcenter, ycenter); + + if (justify_right) + gdk_draw_arc (clist->clist_window, ctree->lines_gc, FALSE, + xcenter - offset_x, cell_rectangle->y, + offset_x, clist->row_height, + 270 * 64, 90 * 64); + else + gdk_draw_arc (clist->clist_window, ctree->lines_gc, FALSE, + xcenter, cell_rectangle->y, + offset_x, clist->row_height, + 180 * 64, 90 * 64); + } + node = GTK_CMCTREE_ROW (node)->parent; + } + } + + if (state != GTK_STATE_SELECTED) + { + tree_rectangle.y = clip_rectangle->y; + tree_rectangle.height = clip_rectangle->height; + tree_rectangle.width = COLUMN_INSET + CELL_SPACING + + MIN (clist->column[ctree->tree_column].area.width + COLUMN_INSET, + TAB_SIZE); + + if (justify_right) + tree_rectangle.x = MAX (xcenter + 1, column_left); + else + tree_rectangle.x = column_left; + + if (!area) + gdk_draw_rectangle (clist->clist_window, + GTK_WIDGET + (ctree)->style->base_gc[GTK_STATE_NORMAL], + TRUE, + tree_rectangle.x, + tree_rectangle.y, + tree_rectangle.width, + tree_rectangle.height); + else if (gdk_rectangle_intersect (area, &tree_rectangle, + &tc_rectangle)) + gdk_draw_rectangle (clist->clist_window, + GTK_WIDGET + (ctree)->style->base_gc[GTK_STATE_NORMAL], + TRUE, + tc_rectangle.x, + tc_rectangle.y, + tc_rectangle.width, + tc_rectangle.height); + } + + xcenter = offset + (justification_factor * ctree->tree_indent / 2); + + get_cell_style (clist, &ctree_row->row, state, column, NULL, NULL, + &bg_gc); + if (bg_gc == clist->bg_gc) + gdk_gc_set_foreground (clist->bg_gc, &ctree_row->row.background); + + gdk_gc_set_clip_rectangle (bg_gc, crect); + if (ctree_row->is_leaf) + { + GdkPoint points[6]; + + points[0].x = offset + justification_factor * TAB_SIZE; + points[0].y = cell_rectangle->y; + + points[1].x = points[0].x - justification_factor * 4; + points[1].y = points[0].y; + + points[2].x = points[1].x - justification_factor * 2; + points[2].y = points[1].y + 3; + + points[3].x = points[2].x; + points[3].y = points[2].y + clist->row_height - 5; + + points[4].x = points[3].x + justification_factor * 2; + points[4].y = points[3].y + 3; + + points[5].x = points[4].x + justification_factor * 4; + points[5].y = points[4].y; + + gdk_draw_polygon (clist->clist_window, bg_gc, TRUE, points, 6); + gdk_draw_lines (clist->clist_window, ctree->lines_gc, points, 6); + } + else + { + gdk_draw_arc (clist->clist_window, bg_gc, TRUE, + offset - (justify_right * 2 * TAB_SIZE), + cell_rectangle->y, + 2 * TAB_SIZE, clist->row_height, + (90 + (180 * justify_right)) * 64, 180 * 64); + gdk_draw_arc (clist->clist_window, ctree->lines_gc, FALSE, + offset - (justify_right * 2 * TAB_SIZE), + cell_rectangle->y, + 2 * TAB_SIZE, clist->row_height, + (90 + (180 * justify_right)) * 64, 180 * 64); + } + gdk_gc_set_clip_rectangle (bg_gc, NULL); + gdk_gc_set_clip_rectangle (ctree->lines_gc, NULL); + + offset += justification_factor * 3; + break; + default: + xcenter = offset + justification_factor * PM_SIZE / 2; + + if (area) + { + tree_rectangle.y = crect->y; + tree_rectangle.height = crect->height; + + if (justify_right) + { + tree_rectangle.x = xcenter - PM_SIZE / 2 - 2; + tree_rectangle.width = (clip_rectangle->x + + clip_rectangle->width -tree_rectangle.x); + } + else + { + tree_rectangle.x = clip_rectangle->x + PM_SIZE / 2; + tree_rectangle.width = (xcenter + PM_SIZE / 2 + 2 - + clip_rectangle->x); + } + + if (!gdk_rectangle_intersect (area, &tree_rectangle, &tc_rectangle)) + break; + } + + offset_x = 1; + offset_y = 0; + if (ctree->line_style == GTK_CMCTREE_LINES_DOTTED) + { + offset_x += abs((clip_rectangle->x + clist->hoffset) % 2); + offset_y = abs((cell_rectangle->y + clist->voffset) % 2); + } + + clip_rectangle->y--; + clip_rectangle->height++; + gdk_gc_set_clip_rectangle (ctree->lines_gc, clip_rectangle); + gdk_draw_line (clist->clist_window, ctree->lines_gc, + xcenter, + (ctree->show_stub || clist->row_list->data != ctree_row) ? + cell_rectangle->y + offset_y : ycenter, + xcenter, + (ctree_row->sibling) ? crect->y +crect->height : ycenter); + + gdk_draw_line (clist->clist_window, ctree->lines_gc, + xcenter + (justification_factor * offset_x), ycenter, + xcenter + (justification_factor * (PM_SIZE / 2 + 2)), + ycenter); + + node = ctree_row->parent; + while (node) + { + xcenter -= (justification_factor * ctree->tree_indent); + + if (GTK_CMCTREE_ROW (node)->sibling) + gdk_draw_line (clist->clist_window, ctree->lines_gc, + xcenter, cell_rectangle->y + offset_y, + xcenter, crect->y + crect->height); + node = GTK_CMCTREE_ROW (node)->parent; + } + gdk_gc_set_clip_rectangle (ctree->lines_gc, NULL); + clip_rectangle->y++; + clip_rectangle->height--; + break; + } + return offset; +} + +static void +draw_row (GtkCMCList *clist, + GdkRectangle *area, + gint row, + GtkCMCListRow *clist_row) +{ + GtkWidget *widget; + GtkCMCTree *ctree; + GdkRectangle *crect; + GdkRectangle row_rectangle; + GdkRectangle cell_rectangle; + GdkRectangle clip_rectangle; + GdkRectangle intersect_rectangle; + gint last_column; + gint column_left = 0; + gint column_right = 0; + gint offset = 0; + gint state; + gint i; + + g_return_if_fail (clist != NULL); + + /* bail now if we arn't drawable yet */ + if (!GTK_WIDGET_DRAWABLE (clist) || row < 0 || row >= clist->rows) + return; + + widget = GTK_WIDGET (clist); + ctree = GTK_CMCTREE (clist); + + /* if the function is passed the pointer to the row instead of null, + * it avoids this expensive lookup */ + if (!clist_row) + clist_row = (g_list_nth (clist->row_list, row))->data; + + /* rectangle of the entire row */ + row_rectangle.x = 0; + row_rectangle.y = ROW_TOP_YPIXEL (clist, row); + row_rectangle.width = clist->clist_window_width; + row_rectangle.height = clist->row_height; + + /* rectangle of the cell spacing above the row */ + cell_rectangle.x = 0; + cell_rectangle.y = row_rectangle.y - CELL_SPACING; + cell_rectangle.width = row_rectangle.width; + cell_rectangle.height = CELL_SPACING; + + /* rectangle used to clip drawing operations, its y and height + * positions only need to be set once, so we set them once here. + * the x and width are set withing the drawing loop below once per + * column */ + clip_rectangle.y = row_rectangle.y; + clip_rectangle.height = row_rectangle.height; + + if (clist_row->state == GTK_STATE_NORMAL) + { + if (clist_row->fg_set) + gdk_gc_set_foreground (clist->fg_gc, &clist_row->foreground); + if (clist_row->bg_set) + gdk_gc_set_foreground (clist->bg_gc, &clist_row->background); + } + + state = clist_row->state; + + gdk_gc_set_foreground (ctree->lines_gc, + &widget->style->fg[clist_row->state]); + + /* draw the cell borders */ + if (area) + { + crect = &intersect_rectangle; + + if (gdk_rectangle_intersect (area, &cell_rectangle, crect)) + gdk_draw_rectangle (clist->clist_window, + widget->style->base_gc[GTK_STATE_NORMAL], TRUE, + crect->x, crect->y, crect->width, crect->height); + } + else + { + crect = &cell_rectangle; + + gdk_draw_rectangle (clist->clist_window, + widget->style->base_gc[GTK_STATE_NORMAL], TRUE, + crect->x, crect->y, crect->width, crect->height); + } + + /* horizontal black lines */ + if (ctree->line_style == GTK_CMCTREE_LINES_TABBED) + { + + column_right = (COLUMN_LEFT_XPIXEL (clist, ctree->tree_column) + + clist->column[ctree->tree_column].area.width + + COLUMN_INSET); + column_left = (COLUMN_LEFT_XPIXEL (clist, ctree->tree_column) - + COLUMN_INSET - (ctree->tree_column != 0) * CELL_SPACING); + + switch (clist->column[ctree->tree_column].justification) + { + case GTK_JUSTIFY_CENTER: + case GTK_JUSTIFY_FILL: + case GTK_JUSTIFY_LEFT: + offset = (column_left + ctree->tree_indent * + (((GtkCMCTreeRow *)clist_row)->level - 1)); + + gdk_draw_line (clist->clist_window, ctree->lines_gc, + MIN (offset + TAB_SIZE, column_right), + cell_rectangle.y, + clist->clist_window_width, cell_rectangle.y); + break; + case GTK_JUSTIFY_RIGHT: + offset = (column_right - 1 - ctree->tree_indent * + (((GtkCMCTreeRow *)clist_row)->level - 1)); + + gdk_draw_line (clist->clist_window, ctree->lines_gc, + -1, cell_rectangle.y, + MAX (offset - TAB_SIZE, column_left), + cell_rectangle.y); + break; + } + } + + /* the last row has to clear its bottom cell spacing too */ + if (clist_row == clist->row_list_end->data) + { + cell_rectangle.y += clist->row_height + CELL_SPACING; + + if (!area || gdk_rectangle_intersect (area, &cell_rectangle, crect)) + { + gdk_draw_rectangle (clist->clist_window, + widget->style->base_gc[GTK_STATE_NORMAL], TRUE, + crect->x, crect->y, crect->width, crect->height); + + /* horizontal black lines */ + if (ctree->line_style == GTK_CMCTREE_LINES_TABBED) + { + switch (clist->column[ctree->tree_column].justification) + { + case GTK_JUSTIFY_CENTER: + case GTK_JUSTIFY_FILL: + case GTK_JUSTIFY_LEFT: + gdk_draw_line (clist->clist_window, ctree->lines_gc, + MIN (column_left + TAB_SIZE + COLUMN_INSET + + (((GtkCMCTreeRow *)clist_row)->level > 1) * + MIN (ctree->tree_indent / 2, TAB_SIZE), + column_right), + cell_rectangle.y, + clist->clist_window_width, cell_rectangle.y); + break; + case GTK_JUSTIFY_RIGHT: + gdk_draw_line (clist->clist_window, ctree->lines_gc, + -1, cell_rectangle.y, + MAX (column_right - TAB_SIZE - 1 - + COLUMN_INSET - + (((GtkCMCTreeRow *)clist_row)->level > 1) * + MIN (ctree->tree_indent / 2, TAB_SIZE), + column_left - 1), cell_rectangle.y); + break; + } + } + } + } + + for (last_column = clist->columns - 1; + last_column >= 0 && !clist->column[last_column].visible; last_column--) + ; + + /* iterate and draw all the columns (row cells) and draw their contents */ + for (i = 0; i < clist->columns; i++) + { + GtkStyle *style; + GdkGC *fg_gc; + GdkGC *bg_gc; + PangoLayout *layout = NULL; + PangoRectangle logical_rect; + + gint width; + gint height; + gint pixmap_width; + gint string_width; + gint old_offset; + + if (!clist->column[i].visible) + continue; + + get_cell_style (clist, clist_row, state, i, &style, &fg_gc, &bg_gc); + + /* calculate clipping region */ + clip_rectangle.x = clist->column[i].area.x + clist->hoffset; + clip_rectangle.width = clist->column[i].area.width; + + cell_rectangle.x = clip_rectangle.x - COLUMN_INSET - CELL_SPACING; + cell_rectangle.width = (clip_rectangle.width + 2 * COLUMN_INSET + + (1 + (i == last_column)) * CELL_SPACING); + cell_rectangle.y = clip_rectangle.y; + cell_rectangle.height = clip_rectangle.height; + + string_width = 0; + pixmap_width = 0; + + if (area && !gdk_rectangle_intersect (area, &cell_rectangle, + &intersect_rectangle)) + { + if (i != ctree->tree_column) + continue; + } + else + { + gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE, + crect->x, crect->y, crect->width, crect->height); + + + layout = _gtk_cmclist_create_cell_layout (clist, clist_row, i); + if (layout) + { + pango_layout_get_pixel_extents (layout, NULL, &logical_rect); + width = logical_rect.width; + } + else + width = 0; + + switch (clist_row->cell[i].type) + { + case GTK_CMCELL_PIXMAP: + gdk_drawable_get_size + (GTK_CMCELL_PIXMAP (clist_row->cell[i])->pixmap, &pixmap_width, + &height); + width += pixmap_width; + break; + case GTK_CMCELL_PIXTEXT: + if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap) + { + gdk_drawable_get_size + (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap, + &pixmap_width, &height); + width += pixmap_width; + } + + if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->text && + GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap) + width += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing; + + if (i == ctree->tree_column) + width += (ctree->tree_indent * + ((GtkCMCTreeRow *)clist_row)->level); + break; + default: + break; + } + + switch (clist->column[i].justification) + { + case GTK_JUSTIFY_LEFT: + offset = clip_rectangle.x + clist_row->cell[i].horizontal; + break; + case GTK_JUSTIFY_RIGHT: + offset = (clip_rectangle.x + clist_row->cell[i].horizontal + + clip_rectangle.width - width); + break; + case GTK_JUSTIFY_CENTER: + case GTK_JUSTIFY_FILL: + offset = (clip_rectangle.x + clist_row->cell[i].horizontal + + (clip_rectangle.width / 2) - (width / 2)); + break; + }; + + if (i != ctree->tree_column) + { + offset += clist_row->cell[i].horizontal; + switch (clist_row->cell[i].type) + { + case GTK_CMCELL_PIXMAP: + draw_cell_pixmap + (clist->clist_window, &clip_rectangle, fg_gc, + GTK_CMCELL_PIXMAP (clist_row->cell[i])->pixmap, + GTK_CMCELL_PIXMAP (clist_row->cell[i])->mask, + offset, + clip_rectangle.y + clist_row->cell[i].vertical + + (clip_rectangle.height - height) / 2, + pixmap_width, height); + break; + case GTK_CMCELL_PIXTEXT: + offset = draw_cell_pixmap + (clist->clist_window, &clip_rectangle, fg_gc, + GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap, + GTK_CMCELL_PIXTEXT (clist_row->cell[i])->mask, + offset, + clip_rectangle.y + clist_row->cell[i].vertical + + (clip_rectangle.height - height) / 2, + pixmap_width, height); + offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing; + + /* Fall through */ + case GTK_CMCELL_TEXT: + if (layout) + { + gint row_center_offset = (clist->row_height - logical_rect.height) / 2; + + gdk_gc_set_clip_rectangle (fg_gc, &clip_rectangle); + gdk_draw_layout (clist->clist_window, fg_gc, + offset, + row_rectangle.y + row_center_offset + clist_row->cell[i].vertical, + layout); + gdk_gc_set_clip_rectangle (fg_gc, NULL); + g_object_unref (G_OBJECT (layout)); + } + break; + default: + break; + } + continue; + } + } + + if (bg_gc == clist->bg_gc) + gdk_gc_set_background (ctree->lines_gc, &clist_row->background); + + /* draw ctree->tree_column */ + cell_rectangle.y -= CELL_SPACING; + cell_rectangle.height += CELL_SPACING; + + if (area && !gdk_rectangle_intersect (area, &cell_rectangle, + &intersect_rectangle)) + { + if (layout) + g_object_unref (G_OBJECT (layout)); + continue; + } + + /* draw lines */ + offset = gtk_cmctree_draw_lines (ctree, (GtkCMCTreeRow *)clist_row, row, i, + state, &clip_rectangle, &cell_rectangle, + crect, area, style); + + /* draw expander */ + offset = gtk_cmctree_draw_expander (ctree, (GtkCMCTreeRow *)clist_row, + style, &clip_rectangle, offset); + + if (clist->column[i].justification == GTK_JUSTIFY_RIGHT) + offset -= ctree->tree_spacing; + else + offset += ctree->tree_spacing; + + if (clist->column[i].justification == GTK_JUSTIFY_RIGHT) + offset -= (pixmap_width + clist_row->cell[i].horizontal); + else + offset += clist_row->cell[i].horizontal; + + old_offset = offset; + offset = draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc, + GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap, + GTK_CMCELL_PIXTEXT (clist_row->cell[i])->mask, + offset, + clip_rectangle.y + clist_row->cell[i].vertical + + (clip_rectangle.height - height) / 2, + pixmap_width, height); + + if (layout) + { + gint row_center_offset = (clist->row_height - logical_rect.height) / 2; + + if (clist->column[i].justification == GTK_JUSTIFY_RIGHT) + { + offset = (old_offset - string_width); + if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap) + offset -= GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing; + } + else + { + if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap) + offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing; + } + + gdk_gc_set_clip_rectangle (fg_gc, &clip_rectangle); + gdk_draw_layout (clist->clist_window, fg_gc, + offset, + row_rectangle.y + row_center_offset + clist_row->cell[i].vertical, + layout); + + g_object_unref (G_OBJECT (layout)); + } + gdk_gc_set_clip_rectangle (fg_gc, NULL); + } + + /* draw focus rectangle */ + if (clist->focus_row == row && + GTK_WIDGET_CAN_FOCUS (widget) && GTK_WIDGET_HAS_FOCUS (widget)) + { + if (!area) + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, + row_rectangle.x, row_rectangle.y, + row_rectangle.width - 1, row_rectangle.height - 1); + else if (gdk_rectangle_intersect (area, &row_rectangle, + &intersect_rectangle)) + { + gdk_gc_set_clip_rectangle (clist->xor_gc, &intersect_rectangle); + gdk_draw_rectangle (clist->clist_window, clist->xor_gc, FALSE, + row_rectangle.x, row_rectangle.y, + row_rectangle.width - 1, + row_rectangle.height - 1); + gdk_gc_set_clip_rectangle (clist->xor_gc, NULL); + } + } +} + +static void +tree_draw_node (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + GtkCMCList *clist; + + clist = GTK_CMCLIST (ctree); + + if (CLIST_UNFROZEN (clist) && gtk_cmctree_is_viewable (ctree, node)) + { + GtkCMCTreeNode *work; + gint num = 0; + + work = GTK_CMCTREE_NODE (clist->row_list); + while (work && work != node) + { + work = GTK_CMCTREE_NODE_NEXT (work); + num++; + } + if (work && gtk_cmclist_row_is_visible (clist, num) != GTK_VISIBILITY_NONE) + GTK_CMCLIST_GET_CLASS (clist)->draw_row + (clist, NULL, num, GTK_CMCLIST_ROW ((GList *) node)); + } +} + +static GtkCMCTreeNode * +gtk_cmctree_last_visible (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + GtkCMCTreeNode *work; + + if (!node) + return NULL; + + work = GTK_CMCTREE_ROW (node)->children; + + if (!work || !GTK_CMCTREE_ROW (node)->expanded) + return node; + + while (GTK_CMCTREE_ROW (work)->sibling) + work = GTK_CMCTREE_ROW (work)->sibling; + + return gtk_cmctree_last_visible (ctree, work); +} + +static void +gtk_cmctree_link (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeNode *parent, + GtkCMCTreeNode *sibling, + gboolean update_focus_row) +{ + GtkCMCList *clist; + GList *list_end; + GList *list; + GList *work; + gboolean visible = FALSE; + gint rows = 0; + + if (sibling) + g_return_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent); + g_return_if_fail (node != NULL); + g_return_if_fail (node != sibling); + g_return_if_fail (node != parent); + + clist = GTK_CMCLIST (ctree); + + if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE) + { + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + } + + for (rows = 1, list_end = (GList *)node; list_end->next; + list_end = list_end->next) + rows++; + + GTK_CMCTREE_ROW (node)->parent = parent; + GTK_CMCTREE_ROW (node)->sibling = sibling; + + if (!parent || (parent && (gtk_cmctree_is_viewable (ctree, parent) && + GTK_CMCTREE_ROW (parent)->expanded))) + { + visible = TRUE; + clist->rows += rows; + } + + if (parent) + work = (GList *)(GTK_CMCTREE_ROW (parent)->children); + else + work = clist->row_list; + + if (sibling) + { + if (work != (GList *)sibling) + { + while (GTK_CMCTREE_ROW (work)->sibling != sibling) + work = (GList *)(GTK_CMCTREE_ROW (work)->sibling); + GTK_CMCTREE_ROW (work)->sibling = node; + } + + if (sibling == GTK_CMCTREE_NODE (clist->row_list)) + clist->row_list = (GList *) node; + if (GTK_CMCTREE_NODE_PREV (sibling) && + GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (sibling)) == sibling) + { + list = (GList *)GTK_CMCTREE_NODE_PREV (sibling); + list->next = (GList *)node; + } + + list = (GList *)node; + list->prev = (GList *)GTK_CMCTREE_NODE_PREV (sibling); + list_end->next = (GList *)sibling; + list = (GList *)sibling; + list->prev = list_end; + if (parent && GTK_CMCTREE_ROW (parent)->children == sibling) + GTK_CMCTREE_ROW (parent)->children = node; + } + else + { + if (work) + { + /* find sibling */ + while (GTK_CMCTREE_ROW (work)->sibling) + work = (GList *)(GTK_CMCTREE_ROW (work)->sibling); + GTK_CMCTREE_ROW (work)->sibling = node; + + /* find last visible child of sibling */ + work = (GList *) gtk_cmctree_last_visible (ctree, + GTK_CMCTREE_NODE (work)); + + list_end->next = work->next; + if (work->next) + list = work->next->prev = list_end; + work->next = (GList *)node; + list = (GList *)node; + list->prev = work; + } + else + { + if (parent) + { + GTK_CMCTREE_ROW (parent)->children = node; + list = (GList *)node; + list->prev = (GList *)parent; + if (GTK_CMCTREE_ROW (parent)->expanded) + { + list_end->next = (GList *)GTK_CMCTREE_NODE_NEXT (parent); + if (GTK_CMCTREE_NODE_NEXT(parent)) + { + list = (GList *)GTK_CMCTREE_NODE_NEXT (parent); + list->prev = list_end; + } + list = (GList *)parent; + list->next = (GList *)node; + } + else + list_end->next = NULL; + } + else + { + clist->row_list = (GList *)node; + list = (GList *)node; + list->prev = NULL; + list_end->next = NULL; + } + } + } + + gtk_cmctree_pre_recursive (ctree, node, tree_update_level, NULL); + + if (clist->row_list_end == NULL || + clist->row_list_end->next == (GList *)node) + clist->row_list_end = list_end; + + if (visible && update_focus_row) + { + gint pos; + + pos = g_list_position (clist->row_list, (GList *)node); + + if (pos <= clist->focus_row) + { + clist->focus_row += rows; + clist->undo_anchor = clist->focus_row; + } + } +} + +static void +gtk_cmctree_unlink (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gboolean update_focus_row) +{ + GtkCMCList *clist; + gint rows; + gint level; + gint visible; + GtkCMCTreeNode *work; + GtkCMCTreeNode *parent; + GList *list; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + + clist = GTK_CMCLIST (ctree); + + if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE) + { + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + } + + visible = gtk_cmctree_is_viewable (ctree, node); + + /* clist->row_list_end unlinked ? */ + if (visible && + (GTK_CMCTREE_NODE_NEXT (node) == NULL || + (GTK_CMCTREE_ROW (node)->children && + gtk_cmctree_is_ancestor (ctree, node, + GTK_CMCTREE_NODE (clist->row_list_end))))) + clist->row_list_end = (GList *) (GTK_CMCTREE_NODE_PREV (node)); + + /* update list */ + rows = 0; + level = GTK_CMCTREE_ROW (node)->level; + work = GTK_CMCTREE_NODE_NEXT (node); + while (work && GTK_CMCTREE_ROW (work)->level > level) + { + work = GTK_CMCTREE_NODE_NEXT (work); + rows++; + } + + if (visible) + { + clist->rows -= (rows + 1); + + if (update_focus_row) + { + gint pos; + + pos = g_list_position (clist->row_list, (GList *)node); + if (pos + rows < clist->focus_row) + clist->focus_row -= (rows + 1); + else if (pos <= clist->focus_row) + { + if (!GTK_CMCTREE_ROW (node)->sibling) + clist->focus_row = MAX (pos - 1, 0); + else + clist->focus_row = pos; + + clist->focus_row = MIN (clist->focus_row, clist->rows - 1); + } + clist->undo_anchor = clist->focus_row; + } + } + + if (work) + { + list = (GList *)GTK_CMCTREE_NODE_PREV (work); + list->next = NULL; + list = (GList *)work; + list->prev = (GList *)GTK_CMCTREE_NODE_PREV (node); + } + + if (GTK_CMCTREE_NODE_PREV (node) && + GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (node)) == node) + { + list = (GList *)GTK_CMCTREE_NODE_PREV (node); + list->next = (GList *)work; + } + + /* update tree */ + parent = GTK_CMCTREE_ROW (node)->parent; + if (parent) + { + if (GTK_CMCTREE_ROW (parent)->children == node) + { + GTK_CMCTREE_ROW (parent)->children = GTK_CMCTREE_ROW (node)->sibling; + if (!GTK_CMCTREE_ROW (parent)->children) + gtk_cmctree_collapse (ctree, parent); + } + else + { + GtkCMCTreeNode *sibling; + + sibling = GTK_CMCTREE_ROW (parent)->children; + while (GTK_CMCTREE_ROW (sibling)->sibling != node) + sibling = GTK_CMCTREE_ROW (sibling)->sibling; + GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling; + } + } + else + { + if (clist->row_list == (GList *)node) + clist->row_list = (GList *) (GTK_CMCTREE_ROW (node)->sibling); + else + { + GtkCMCTreeNode *sibling; + + sibling = GTK_CMCTREE_NODE (clist->row_list); + while (GTK_CMCTREE_ROW (sibling)->sibling != node) + sibling = GTK_CMCTREE_ROW (sibling)->sibling; + GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling; + } + } +} + +static void +real_row_move (GtkCMCList *clist, + gint source_row, + gint dest_row) +{ + GtkCMCTree *ctree; + GtkCMCTreeNode *node; + + g_return_if_fail (GTK_IS_CMCTREE (clist)); + + if (GTK_CMCLIST_AUTO_SORT (clist)) + return; + + if (source_row < 0 || source_row >= clist->rows || + dest_row < 0 || dest_row >= clist->rows || + source_row == dest_row) + return; + + ctree = GTK_CMCTREE (clist); + node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, source_row)); + + if (source_row < dest_row) + { + GtkCMCTreeNode *work; + + dest_row++; + work = GTK_CMCTREE_ROW (node)->children; + + while (work && GTK_CMCTREE_ROW (work)->level > GTK_CMCTREE_ROW (node)->level) + { + work = GTK_CMCTREE_NODE_NEXT (work); + dest_row++; + } + + if (dest_row > clist->rows) + dest_row = clist->rows; + } + + if (dest_row < clist->rows) + { + GtkCMCTreeNode *sibling; + + sibling = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, dest_row)); + gtk_cmctree_move (ctree, node, GTK_CMCTREE_ROW (sibling)->parent, sibling); + } + else + gtk_cmctree_move (ctree, node, NULL, NULL); +} + +static void +real_tree_move (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeNode *new_parent, + GtkCMCTreeNode *new_sibling) +{ + GtkCMCList *clist; + GtkCMCTreeNode *work; + gboolean visible = FALSE; + + g_return_if_fail (ctree != NULL); + g_return_if_fail (node != NULL); + g_return_if_fail (!new_sibling || + GTK_CMCTREE_ROW (new_sibling)->parent == new_parent); + + if (new_parent && GTK_CMCTREE_ROW (new_parent)->is_leaf) + return; + + /* new_parent != child of child */ + for (work = new_parent; work; work = GTK_CMCTREE_ROW (work)->parent) + if (work == node) + return; + + clist = GTK_CMCLIST (ctree); + + visible = gtk_cmctree_is_viewable (ctree, node); + + if (clist->selection_mode == GTK_SELECTION_MULTIPLE) + { + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + } + + if (GTK_CMCLIST_AUTO_SORT (clist)) + { + if (new_parent == GTK_CMCTREE_ROW (node)->parent) + return; + + if (new_parent) + new_sibling = GTK_CMCTREE_ROW (new_parent)->children; + else + new_sibling = GTK_CMCTREE_NODE (clist->row_list); + + while (new_sibling && clist->compare + (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (new_sibling)) > 0) + new_sibling = GTK_CMCTREE_ROW (new_sibling)->sibling; + } + + if (new_parent == GTK_CMCTREE_ROW (node)->parent && + new_sibling == GTK_CMCTREE_ROW (node)->sibling) + return; + + gtk_cmclist_freeze (clist); + + work = NULL; + if (gtk_cmctree_is_viewable (ctree, node)) + work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)); + + gtk_cmctree_unlink (ctree, node, FALSE); + gtk_cmctree_link (ctree, node, new_parent, new_sibling, FALSE); + + if (work) + { + while (work && !gtk_cmctree_is_viewable (ctree, work)) + work = GTK_CMCTREE_ROW (work)->parent; + clist->focus_row = g_list_position (clist->row_list, (GList *)work); + clist->undo_anchor = clist->focus_row; + } + + if (clist->column[ctree->tree_column].auto_resize && + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) && + (visible || gtk_cmctree_is_viewable (ctree, node))) + gtk_cmclist_set_column_width + (clist, ctree->tree_column, + gtk_cmclist_optimal_column_width (clist, ctree->tree_column)); + + gtk_cmclist_thaw (clist); +} + +static void +change_focus_row_expansion (GtkCMCTree *ctree, + GtkCMCTreeExpansionType action) +{ + GtkCMCList *clist; + GtkCMCTreeNode *node; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + clist = GTK_CMCLIST (ctree); + + if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (ctree))) && + GTK_WIDGET_HAS_GRAB (ctree)) + return; + + if (!(node = + GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row))) || + GTK_CMCTREE_ROW (node)->is_leaf || !(GTK_CMCTREE_ROW (node)->children)) + return; + + switch (action) + { + case GTK_CMCTREE_EXPANSION_EXPAND: + gtk_cmctree_expand (ctree, node); + break; + case GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE: + gtk_cmctree_expand_recursive (ctree, node); + break; + case GTK_CMCTREE_EXPANSION_COLLAPSE: + gtk_cmctree_collapse (ctree, node); + break; + case GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE: + gtk_cmctree_collapse_recursive (ctree, node); + break; + case GTK_CMCTREE_EXPANSION_TOGGLE: + gtk_cmctree_toggle_expansion (ctree, node); + break; + case GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE: + gtk_cmctree_toggle_expansion_recursive (ctree, node); + break; + } +} + +static void +real_tree_expand (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + GtkCMCList *clist; + GtkCMCTreeNode *work; + GtkRequisition requisition; + gboolean visible; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + if (!node || GTK_CMCTREE_ROW (node)->expanded || GTK_CMCTREE_ROW (node)->is_leaf) + return; + + clist = GTK_CMCLIST (ctree); + + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + + GTK_CMCTREE_ROW (node)->expanded = TRUE; + + visible = gtk_cmctree_is_viewable (ctree, node); + /* get cell width if tree_column is auto resized */ + if (visible && clist->column[ctree->tree_column].auto_resize && + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request + (clist, &GTK_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition); + + /* unref/unset closed pixmap */ + if (GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap) + { + g_object_unref + (GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap); + + GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = NULL; + + if (GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask) + { + g_object_unref + (GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask); + GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask = NULL; + } + } + + /* set/ref opened pixmap */ + if (GTK_CMCTREE_ROW (node)->pixmap_opened) + { + GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = + g_object_ref (GTK_CMCTREE_ROW (node)->pixmap_opened); + + if (GTK_CMCTREE_ROW (node)->mask_opened) + GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask = + g_object_ref (GTK_CMCTREE_ROW (node)->mask_opened); + } + + + work = GTK_CMCTREE_ROW (node)->children; + if (work) + { + GList *list = (GList *)work; + gint *cell_width = NULL; + gint tmp = 0; + gint row; + gint i; + + if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + { + cell_width = g_new0 (gint, clist->columns); + if (clist->column[ctree->tree_column].auto_resize) + cell_width[ctree->tree_column] = requisition.width; + + while (work) + { + /* search maximum cell widths of auto_resize columns */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + { + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request + (clist, &GTK_CMCTREE_ROW (work)->row, i, &requisition); + cell_width[i] = MAX (requisition.width, cell_width[i]); + } + + list = (GList *)work; + work = GTK_CMCTREE_NODE_NEXT (work); + tmp++; + } + } + else + while (work) + { + list = (GList *)work; + work = GTK_CMCTREE_NODE_NEXT (work); + tmp++; + } + + list->next = (GList *)GTK_CMCTREE_NODE_NEXT (node); + + if (GTK_CMCTREE_NODE_NEXT (node)) + { + GList *tmp_list; + + tmp_list = (GList *)GTK_CMCTREE_NODE_NEXT (node); + tmp_list->prev = list; + } + else + clist->row_list_end = list; + + list = (GList *)node; + list->next = (GList *)(GTK_CMCTREE_ROW (node)->children); + + if (visible) + { + /* resize auto_resize columns if needed */ + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize && + cell_width[i] > clist->column[i].width) + gtk_cmclist_set_column_width (clist, i, cell_width[i]); + g_free (cell_width); + + /* update focus_row position */ + row = g_list_position (clist->row_list, (GList *)node); + if (row < clist->focus_row) + clist->focus_row += tmp; + + clist->rows += tmp; + CLIST_REFRESH (clist); + } + } + else if (visible && clist->column[ctree->tree_column].auto_resize) + /* resize tree_column if needed */ + column_auto_resize (clist, &GTK_CMCTREE_ROW (node)->row, ctree->tree_column, + requisition.width); +} + +static void +real_tree_collapse (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + GtkCMCList *clist; + GtkCMCTreeNode *work; + GtkRequisition requisition; + gboolean visible; + gint level; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + if (!node || !GTK_CMCTREE_ROW (node)->expanded || + GTK_CMCTREE_ROW (node)->is_leaf) + return; + + clist = GTK_CMCLIST (ctree); + + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + + GTK_CMCTREE_ROW (node)->expanded = FALSE; + level = GTK_CMCTREE_ROW (node)->level; + + visible = gtk_cmctree_is_viewable (ctree, node); + /* get cell width if tree_column is auto resized */ + if (visible && clist->column[ctree->tree_column].auto_resize && + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request + (clist, &GTK_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition); + + /* unref/unset opened pixmap */ + if (GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap) + { + g_object_unref + (GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap); + + GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = NULL; + + if (GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask) + { + g_object_unref + (GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask); + GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask = NULL; + } + } + + /* set/ref closed pixmap */ + if (GTK_CMCTREE_ROW (node)->pixmap_closed) + { + GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = + g_object_ref (GTK_CMCTREE_ROW (node)->pixmap_closed); + + if (GTK_CMCTREE_ROW (node)->mask_closed) + GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask = + g_object_ref (GTK_CMCTREE_ROW (node)->mask_closed); + } + + work = GTK_CMCTREE_ROW (node)->children; + if (work) + { + gint tmp = 0; + gint row; + GList *list; + + while (work && GTK_CMCTREE_ROW (work)->level > level) + { + work = GTK_CMCTREE_NODE_NEXT (work); + tmp++; + } + + if (work) + { + list = (GList *)node; + list->next = (GList *)work; + list = (GList *)GTK_CMCTREE_NODE_PREV (work); + list->next = NULL; + list = (GList *)work; + list->prev = (GList *)node; + } + else + { + list = (GList *)node; + list->next = NULL; + clist->row_list_end = (GList *)node; + } + + if (visible) + { + /* resize auto_resize columns if needed */ + auto_resize_columns (clist); + + row = g_list_position (clist->row_list, (GList *)node); + if (row < clist->focus_row) + clist->focus_row -= tmp; + clist->rows -= tmp; + CLIST_REFRESH (clist); + } + } + else if (visible && clist->column[ctree->tree_column].auto_resize && + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + /* resize tree_column if needed */ + column_auto_resize (clist, &GTK_CMCTREE_ROW (node)->row, ctree->tree_column, + requisition.width); + +} + +static void +column_auto_resize (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint column, + gint old_width) +{ + /* resize column if needed for auto_resize */ + GtkRequisition requisition; + + if (!clist->column[column].auto_resize || + GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + return; + + if (clist_row) + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row, + column, &requisition); + else + requisition.width = 0; + + if (requisition.width > clist->column[column].width) + gtk_cmclist_set_column_width (clist, column, requisition.width); + else if (requisition.width < old_width && + old_width == clist->column[column].width) + { + GList *list; + gint new_width; + + /* run a "gtk_cmclist_optimal_column_width" but break, if + * the column doesn't shrink */ + if (GTK_CMCLIST_SHOW_TITLES (clist) && clist->column[column].button) + new_width = (clist->column[column].button->requisition.width - + (CELL_SPACING + (2 * COLUMN_INSET))); + else + new_width = 0; + + for (list = clist->row_list; list; list = list->next) + { + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request + (clist, GTK_CMCLIST_ROW (list), column, &requisition); + new_width = MAX (new_width, requisition.width); + if (new_width == clist->column[column].width) + break; + } + if (new_width < clist->column[column].width) + gtk_cmclist_set_column_width (clist, column, new_width); + } +} + +static void +auto_resize_columns (GtkCMCList *clist) +{ + gint i; + + if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + return; + + for (i = 0; i < clist->columns; i++) + column_auto_resize (clist, NULL, i, clist->column[i].width); +} + +static void +cell_size_request (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint column, + GtkRequisition *requisition) +{ + GtkCMCTree *ctree; + gint width; + gint height; + PangoLayout *layout; + PangoRectangle logical_rect; + + g_return_if_fail (GTK_IS_CMCTREE (clist)); + g_return_if_fail (requisition != NULL); + + ctree = GTK_CMCTREE (clist); + + layout = _gtk_cmclist_create_cell_layout (clist, clist_row, column); + if (layout) + { + pango_layout_get_pixel_extents (layout, NULL, &logical_rect); + + requisition->width = logical_rect.width; + requisition->height = logical_rect.height; + + g_object_unref (G_OBJECT (layout)); + } + else + { + requisition->width = 0; + requisition->height = 0; + } + + switch (clist_row->cell[column].type) + { + case GTK_CMCELL_PIXTEXT: + if (GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixmap) + { + gdk_drawable_get_size (GTK_CMCELL_PIXTEXT + (clist_row->cell[column])->pixmap, + &width, &height); + width += GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing; + } + else + width = height = 0; + + requisition->width += width; + requisition->height = MAX (requisition->height, height); + + if (column == ctree->tree_column) + { + requisition->width += (ctree->tree_spacing + ctree->tree_indent * + (((GtkCMCTreeRow *) clist_row)->level - 1)); + switch (ctree->expander_style) + { + case GTK_CMCTREE_EXPANDER_NONE: + break; + case GTK_CMCTREE_EXPANDER_TRIANGLE: + requisition->width += PM_SIZE + 3; + break; + case GTK_CMCTREE_EXPANDER_SQUARE: + case GTK_CMCTREE_EXPANDER_CIRCULAR: + requisition->width += PM_SIZE + 1; + break; + } + if (ctree->line_style == GTK_CMCTREE_LINES_TABBED) + requisition->width += 3; + } + break; + case GTK_CMCELL_PIXMAP: + gdk_drawable_get_size (GTK_CMCELL_PIXMAP (clist_row->cell[column])->pixmap, + &width, &height); + requisition->width += width; + requisition->height = MAX (requisition->height, height); + break; + default: + break; + } + + requisition->width += clist_row->cell[column].horizontal; + requisition->height += clist_row->cell[column].vertical; +} + +static void +set_cell_contents (GtkCMCList *clist, + GtkCMCListRow *clist_row, + gint column, + GtkCMCellType type, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap, + GdkBitmap *mask) +{ + gboolean visible = FALSE; + GtkCMCTree *ctree; + GtkRequisition requisition; + gchar *old_text = NULL; + GdkPixmap *old_pixmap = NULL; + GdkBitmap *old_mask = NULL; + + g_return_if_fail (GTK_IS_CMCTREE (clist)); + g_return_if_fail (clist_row != NULL); + + ctree = GTK_CMCTREE (clist); + + if (clist->column[column].auto_resize && + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + { + GtkCMCTreeNode *parent; + + parent = ((GtkCMCTreeRow *)clist_row)->parent; + if (!parent || (parent && GTK_CMCTREE_ROW (parent)->expanded && + gtk_cmctree_is_viewable (ctree, parent))) + { + visible = TRUE; + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row, + column, &requisition); + } + } + + switch (clist_row->cell[column].type) + { + case GTK_CMCELL_EMPTY: + break; + case GTK_CMCELL_TEXT: + old_text = GTK_CMCELL_TEXT (clist_row->cell[column])->text; + break; + case GTK_CMCELL_PIXMAP: + old_pixmap = GTK_CMCELL_PIXMAP (clist_row->cell[column])->pixmap; + old_mask = GTK_CMCELL_PIXMAP (clist_row->cell[column])->mask; + break; + case GTK_CMCELL_PIXTEXT: + old_text = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text; + old_pixmap = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixmap; + old_mask = GTK_CMCELL_PIXTEXT (clist_row->cell[column])->mask; + break; + case GTK_CMCELL_WIDGET: + /* unimplemented */ + break; + + default: + break; + } + + clist_row->cell[column].type = GTK_CMCELL_EMPTY; + if (column == ctree->tree_column && type != GTK_CMCELL_EMPTY) + type = GTK_CMCELL_PIXTEXT; + + /* Note that pixmap and mask were already ref'ed by the caller + */ + switch (type) + { + case GTK_CMCELL_TEXT: + if (text) + { + clist_row->cell[column].type = GTK_CMCELL_TEXT; + GTK_CMCELL_TEXT (clist_row->cell[column])->text = g_strdup (text); + } + break; + case GTK_CMCELL_PIXMAP: + if (pixmap) + { + clist_row->cell[column].type = GTK_CMCELL_PIXMAP; + GTK_CMCELL_PIXMAP (clist_row->cell[column])->pixmap = pixmap; + /* We set the mask even if it is NULL */ + GTK_CMCELL_PIXMAP (clist_row->cell[column])->mask = mask; + } + break; + case GTK_CMCELL_PIXTEXT: + if (column == ctree->tree_column) + { + clist_row->cell[column].type = GTK_CMCELL_PIXTEXT; + GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing; + if (text) + GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text); + else + GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = NULL; + if (pixmap) + { + GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap; + GTK_CMCELL_PIXTEXT (clist_row->cell[column])->mask = mask; + } + else + { + GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixmap = NULL; + GTK_CMCELL_PIXTEXT (clist_row->cell[column])->mask = NULL; + } + } + else if (text && pixmap) + { + clist_row->cell[column].type = GTK_CMCELL_PIXTEXT; + GTK_CMCELL_PIXTEXT (clist_row->cell[column])->text = g_strdup (text); + GTK_CMCELL_PIXTEXT (clist_row->cell[column])->spacing = spacing; + GTK_CMCELL_PIXTEXT (clist_row->cell[column])->pixmap = pixmap; + GTK_CMCELL_PIXTEXT (clist_row->cell[column])->mask = mask; + } + break; + default: + break; + } + + if (visible && clist->column[column].auto_resize && + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + column_auto_resize (clist, clist_row, column, requisition.width); + + g_free (old_text); + if (old_pixmap) + g_object_unref (old_pixmap); + if (old_mask) + g_object_unref (old_mask); +} + +static void +set_node_info (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap_closed, + GdkBitmap *mask_closed, + GdkPixmap *pixmap_opened, + GdkBitmap *mask_opened, + gboolean is_leaf, + gboolean expanded) +{ + if (GTK_CMCTREE_ROW (node)->pixmap_opened) + { + g_object_unref (GTK_CMCTREE_ROW (node)->pixmap_opened); + if (GTK_CMCTREE_ROW (node)->mask_opened) + g_object_unref (GTK_CMCTREE_ROW (node)->mask_opened); + } + if (GTK_CMCTREE_ROW (node)->pixmap_closed) + { + g_object_unref (GTK_CMCTREE_ROW (node)->pixmap_closed); + if (GTK_CMCTREE_ROW (node)->mask_closed) + g_object_unref (GTK_CMCTREE_ROW (node)->mask_closed); + } + + GTK_CMCTREE_ROW (node)->pixmap_opened = NULL; + GTK_CMCTREE_ROW (node)->mask_opened = NULL; + GTK_CMCTREE_ROW (node)->pixmap_closed = NULL; + GTK_CMCTREE_ROW (node)->mask_closed = NULL; + + if (pixmap_closed) + { + GTK_CMCTREE_ROW (node)->pixmap_closed = g_object_ref (pixmap_closed); + if (mask_closed) + GTK_CMCTREE_ROW (node)->mask_closed = g_object_ref (mask_closed); + } + if (pixmap_opened) + { + GTK_CMCTREE_ROW (node)->pixmap_opened = g_object_ref (pixmap_opened); + if (mask_opened) + GTK_CMCTREE_ROW (node)->mask_opened = g_object_ref (mask_opened); + } + + GTK_CMCTREE_ROW (node)->is_leaf = is_leaf; + GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded; + + if (GTK_CMCTREE_ROW (node)->expanded) + gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column, + text, spacing, pixmap_opened, mask_opened); + else + gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column, + text, spacing, pixmap_closed, mask_closed); +} + +static void +tree_delete (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data) +{ + tree_unselect (ctree, node, NULL); + row_delete (ctree, GTK_CMCTREE_ROW (node)); + g_list_free_1 ((GList *)node); +} + +static void +tree_delete_row (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data) +{ + row_delete (ctree, GTK_CMCTREE_ROW (node)); + g_list_free_1 ((GList *)node); +} + +static void +tree_update_level (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data) +{ + if (!node) + return; + + if (GTK_CMCTREE_ROW (node)->parent) + GTK_CMCTREE_ROW (node)->level = + GTK_CMCTREE_ROW (GTK_CMCTREE_ROW (node)->parent)->level + 1; + else + GTK_CMCTREE_ROW (node)->level = 1; +} + +static void +tree_select (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data) +{ + if (node && GTK_CMCTREE_ROW (node)->row.state != GTK_STATE_SELECTED && + GTK_CMCTREE_ROW (node)->row.selectable) + g_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW], 0, + node, -1); +} + +static void +tree_unselect (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data) +{ + if (node && GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED) + g_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW], 0, + node, -1); +} + +static void +tree_expand (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data) +{ + if (node && !GTK_CMCTREE_ROW (node)->expanded) + g_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0,node); +} + +static void +tree_collapse (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data) +{ + if (node && GTK_CMCTREE_ROW (node)->expanded) + g_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0,node); +} + +static void +tree_collapse_to_depth (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint depth) +{ + if (node && GTK_CMCTREE_ROW (node)->level == depth) + gtk_cmctree_collapse_recursive (ctree, node); +} + +static void +tree_toggle_expansion (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data) +{ + if (!node) + return; + + if (GTK_CMCTREE_ROW (node)->expanded) + g_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0,node); + else + g_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0,node); +} + +static GtkCMCTreeRow * +row_new (GtkCMCTree *ctree) +{ + GtkCMCList *clist; + GtkCMCTreeRow *ctree_row; + int i; + + clist = GTK_CMCLIST (ctree); + ctree_row = g_slice_new (GtkCMCTreeRow); + ctree_row->row.cell = g_slice_alloc (sizeof (GtkCMCell) * clist->columns); + + for (i = 0; i < clist->columns; i++) + { + ctree_row->row.cell[i].type = GTK_CMCELL_EMPTY; + ctree_row->row.cell[i].vertical = 0; + ctree_row->row.cell[i].horizontal = 0; + ctree_row->row.cell[i].style = NULL; + } + + GTK_CMCELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL; + + ctree_row->row.fg_set = FALSE; + ctree_row->row.bg_set = FALSE; + ctree_row->row.style = NULL; + ctree_row->row.selectable = TRUE; + ctree_row->row.state = GTK_STATE_NORMAL; + ctree_row->row.data = NULL; + ctree_row->row.destroy = NULL; + + ctree_row->level = 0; + ctree_row->expanded = FALSE; + ctree_row->parent = NULL; + ctree_row->sibling = NULL; + ctree_row->children = NULL; + ctree_row->pixmap_closed = NULL; + ctree_row->mask_closed = NULL; + ctree_row->pixmap_opened = NULL; + ctree_row->mask_opened = NULL; + + return ctree_row; +} + +static void +row_delete (GtkCMCTree *ctree, + GtkCMCTreeRow *ctree_row) +{ + GtkCMCList *clist; + gint i; + + clist = GTK_CMCLIST (ctree); + + for (i = 0; i < clist->columns; i++) + { + GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents + (clist, &(ctree_row->row), i, GTK_CMCELL_EMPTY, NULL, 0, NULL, NULL); + if (ctree_row->row.cell[i].style) + { + if (GTK_WIDGET_REALIZED (ctree)) + gtk_style_detach (ctree_row->row.cell[i].style); + g_object_unref (ctree_row->row.cell[i].style); + } + } + + if (ctree_row->row.style) + { + if (GTK_WIDGET_REALIZED (ctree)) + gtk_style_detach (ctree_row->row.style); + g_object_unref (ctree_row->row.style); + } + + if (ctree_row->pixmap_closed) + { + g_object_unref (ctree_row->pixmap_closed); + if (ctree_row->mask_closed) + g_object_unref (ctree_row->mask_closed); + } + + if (ctree_row->pixmap_opened) + { + g_object_unref (ctree_row->pixmap_opened); + if (ctree_row->mask_opened) + g_object_unref (ctree_row->mask_opened); + } + + if (ctree_row->row.destroy) + { + GtkDestroyNotify dnotify = ctree_row->row.destroy; + gpointer ddata = ctree_row->row.data; + + ctree_row->row.destroy = NULL; + ctree_row->row.data = NULL; + + dnotify (ddata); + } + + g_slice_free1 (sizeof (GtkCMCell) * clist->columns, ctree_row->row.cell); + g_slice_free (GtkCMCTreeRow, ctree_row); +} + +static void +real_select_row (GtkCMCList *clist, + gint row, + gint column, + GdkEvent *event) +{ + GList *node; + + g_return_if_fail (GTK_IS_CMCTREE (clist)); + + if ((node = g_list_nth (clist->row_list, row)) && + GTK_CMCTREE_ROW (node)->row.selectable) + g_signal_emit (GTK_OBJECT (clist), ctree_signals[TREE_SELECT_ROW],0, + node, column); +} + +static void +real_unselect_row (GtkCMCList *clist, + gint row, + gint column, + GdkEvent *event) +{ + GList *node; + + g_return_if_fail (GTK_IS_CMCTREE (clist)); + + if ((node = g_list_nth (clist->row_list, row))) + g_signal_emit (GTK_OBJECT (clist), ctree_signals[TREE_UNSELECT_ROW],0, + node, column); +} + +static void +real_tree_select (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column) +{ + GtkCMCList *clist; + GList *list; + GtkCMCTreeNode *sel_row; + gboolean node_selected; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + if (!node || GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED || + !GTK_CMCTREE_ROW (node)->row.selectable) + return; + + clist = GTK_CMCLIST (ctree); + + switch (clist->selection_mode) + { + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_BROWSE: + + node_selected = FALSE; + list = clist->selection; + + while (list) + { + sel_row = list->data; + list = list->next; + + if (node == sel_row) + node_selected = TRUE; + else + g_signal_emit (GTK_OBJECT (ctree), + ctree_signals[TREE_UNSELECT_ROW], 0, sel_row, column); + } + + if (node_selected) + return; + + default: + break; + } + + GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED; + + if (!clist->selection) + { + clist->selection = g_list_append (clist->selection, node); + clist->selection_end = clist->selection; + } + else + clist->selection_end = g_list_append (clist->selection_end, node)->next; + + tree_draw_node (ctree, node); +} + +static void +real_tree_unselect (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column) +{ + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + if (!node || GTK_CMCTREE_ROW (node)->row.state != GTK_STATE_SELECTED) + return; + + clist = GTK_CMCLIST (ctree); + + if (clist->selection_end && clist->selection_end->data == node) + clist->selection_end = clist->selection_end->prev; + + clist->selection = g_list_remove (clist->selection, node); + + GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL; + + tree_draw_node (ctree, node); +} + +static void +select_row_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data) +{ + if (!node || GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED || + !GTK_CMCTREE_ROW (node)->row.selectable) + return; + + GTK_CMCLIST (ctree)->undo_unselection = + g_list_prepend (GTK_CMCLIST (ctree)->undo_unselection, node); + gtk_cmctree_select (ctree, node); +} + +static void +real_select_all (GtkCMCList *clist) +{ + GtkCMCTree *ctree; + GtkCMCTreeNode *node; + + g_return_if_fail (GTK_IS_CMCTREE (clist)); + + ctree = GTK_CMCTREE (clist); + + switch (clist->selection_mode) + { + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_BROWSE: + return; + + case GTK_SELECTION_MULTIPLE: + + gtk_cmclist_freeze (clist); + + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + + clist->anchor_state = GTK_STATE_SELECTED; + clist->anchor = -1; + clist->drag_pos = -1; + clist->undo_anchor = clist->focus_row; + + for (node = GTK_CMCTREE_NODE (clist->row_list); node; + node = GTK_CMCTREE_NODE_NEXT (node)) + gtk_cmctree_pre_recursive (ctree, node, select_row_recursive, NULL); + + gtk_cmclist_thaw (clist); + break; + + default: + /* do nothing */ + break; + } +} + +static void +real_unselect_all (GtkCMCList *clist) +{ + GtkCMCTree *ctree; + GtkCMCTreeNode *node; + GList *list; + + g_return_if_fail (GTK_IS_CMCTREE (clist)); + + ctree = GTK_CMCTREE (clist); + + switch (clist->selection_mode) + { + case GTK_SELECTION_BROWSE: + if (clist->focus_row >= 0) + { + gtk_cmctree_select + (ctree, + GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row))); + return; + } + break; + + case GTK_SELECTION_MULTIPLE: + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + + clist->anchor = -1; + clist->drag_pos = -1; + clist->undo_anchor = clist->focus_row; + break; + + default: + break; + } + + list = clist->selection; + + while (list) + { + node = list->data; + list = list->next; + gtk_cmctree_unselect (ctree, node); + } +} + +static gboolean +ctree_is_hot_spot (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint row, + gint x, + gint y) +{ + GtkCMCTreeRow *tree_row; + GtkCMCList *clist; + gint xl; + gint yu; + + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); + g_return_val_if_fail (node != NULL, FALSE); + + clist = GTK_CMCLIST (ctree); + + if (!clist->column[ctree->tree_column].visible || + ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE) + return FALSE; + + tree_row = GTK_CMCTREE_ROW (node); + + yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height - PM_SIZE) / 2 - + (clist->row_height - 1) % 2); + + if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT) + xl = (clist->column[ctree->tree_column].area.x + + clist->column[ctree->tree_column].area.width - 1 + clist->hoffset - + (tree_row->level - 1) * ctree->tree_indent - PM_SIZE - + (ctree->line_style == GTK_CMCTREE_LINES_TABBED) * 3); + else + xl = (clist->column[ctree->tree_column].area.x + clist->hoffset + + (tree_row->level - 1) * ctree->tree_indent + + (ctree->line_style == GTK_CMCTREE_LINES_TABBED) * 3); + + return (x >= xl && x <= xl + PM_SIZE && y >= yu && y <= yu + PM_SIZE); +} + +/*********************************************************** + *********************************************************** + *** Public interface *** + *********************************************************** + ***********************************************************/ + + +/*********************************************************** + * Creation, insertion, deletion * + ***********************************************************/ + +static GObject* +gtk_cmctree_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *object = G_OBJECT_CLASS (parent_class)->constructor (type, + n_construct_properties, + construct_properties); + + return object; +} + +GtkWidget* +gtk_cmctree_new_with_titles (gint columns, + gint tree_column, + gchar *titles[]) +{ + GtkWidget *widget; + + g_return_val_if_fail (columns > 0, NULL); + g_return_val_if_fail (tree_column >= 0 && tree_column < columns, NULL); + + widget = gtk_widget_new (GTK_TYPE_CMCTREE, + "n_columns", columns, + "tree_column", tree_column, + NULL); + if (titles) + { + GtkCMCList *clist = GTK_CMCLIST (widget); + guint i; + + for (i = 0; i < columns; i++) + gtk_cmclist_set_column_title (clist, i, titles[i]); + gtk_cmclist_column_titles_show (clist); + } + + return widget; +} + +GtkWidget * +gtk_cmctree_new (gint columns, + gint tree_column) +{ + return gtk_cmctree_new_with_titles (columns, tree_column, NULL); +} + +static gint +real_insert_row (GtkCMCList *clist, + gint row, + gchar *text[]) +{ + GtkCMCTreeNode *parent = NULL; + GtkCMCTreeNode *sibling; + GtkCMCTreeNode *node; + + g_return_val_if_fail (GTK_IS_CMCTREE (clist), -1); + + sibling = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row)); + if (sibling) + parent = GTK_CMCTREE_ROW (sibling)->parent; + + node = gtk_cmctree_insert_node (GTK_CMCTREE (clist), parent, sibling, text, 5, + NULL, NULL, NULL, NULL, TRUE, FALSE); + + if (GTK_CMCLIST_AUTO_SORT (clist) || !sibling) + return g_list_position (clist->row_list, (GList *) node); + + return row; +} + +GtkCMCTreeNode * +gtk_cmctree_insert_node (GtkCMCTree *ctree, + GtkCMCTreeNode *parent, + GtkCMCTreeNode *sibling, + gchar *text[], + guint8 spacing, + GdkPixmap *pixmap_closed, + GdkBitmap *mask_closed, + GdkPixmap *pixmap_opened, + GdkBitmap *mask_opened, + gboolean is_leaf, + gboolean expanded) +{ + GtkCMCList *clist; + GtkCMCTreeRow *new_row; + GtkCMCTreeNode *node; + GList *list; + gint i; + + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); + if (sibling) + g_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL); + + if (parent && GTK_CMCTREE_ROW (parent)->is_leaf) + return NULL; + + clist = GTK_CMCLIST (ctree); + + /* create the row */ + new_row = row_new (ctree); + list = g_list_alloc (); + list->data = new_row; + node = GTK_CMCTREE_NODE (list); + + if (text) + for (i = 0; i < clist->columns; i++) + if (text[i] && i != ctree->tree_column) + GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents + (clist, &(new_row->row), i, GTK_CMCELL_TEXT, text[i], 0, NULL, NULL); + + set_node_info (ctree, node, text ? + text[ctree->tree_column] : NULL, spacing, pixmap_closed, + mask_closed, pixmap_opened, mask_opened, is_leaf, expanded); + + /* sorted insertion */ + if (GTK_CMCLIST_AUTO_SORT (clist)) + { + if (parent) + sibling = GTK_CMCTREE_ROW (parent)->children; + else + sibling = GTK_CMCTREE_NODE (clist->row_list); + + while (sibling && clist->compare + (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (sibling)) > 0) + sibling = GTK_CMCTREE_ROW (sibling)->sibling; + } + + gtk_cmctree_link (ctree, node, parent, sibling, TRUE); + + if (text && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) && + gtk_cmctree_is_viewable (ctree, node)) + { + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + column_auto_resize (clist, &(new_row->row), i, 0); + } + + if (clist->rows == 1) + { + clist->focus_row = 0; + if (clist->selection_mode == GTK_SELECTION_BROWSE) + gtk_cmctree_select (ctree, node); + } + + + CLIST_REFRESH (clist); + + return node; +} + +GtkCMCTreeNode * +gtk_cmctree_insert_gnode (GtkCMCTree *ctree, + GtkCMCTreeNode *parent, + GtkCMCTreeNode *sibling, + GNode *gnode, + GtkCMCTreeGNodeFunc func, + gpointer data) +{ + GtkCMCList *clist; + GtkCMCTreeNode *cnode = NULL; + GtkCMCTreeNode *child = NULL; + GtkCMCTreeNode *new_child; + GList *list; + GNode *work; + guint depth = 1; + + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); + g_return_val_if_fail (gnode != NULL, NULL); + g_return_val_if_fail (func != NULL, NULL); + if (sibling) + g_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL); + + clist = GTK_CMCLIST (ctree); + + if (parent) + depth = GTK_CMCTREE_ROW (parent)->level + 1; + + list = g_list_alloc (); + list->data = row_new (ctree); + cnode = GTK_CMCTREE_NODE (list); + + gtk_cmclist_freeze (clist); + + set_node_info (ctree, cnode, "", 0, NULL, NULL, NULL, NULL, TRUE, FALSE); + + if (!func (ctree, depth, gnode, cnode, data)) + { + tree_delete_row (ctree, cnode, NULL); + gtk_cmclist_thaw (clist); + return NULL; + } + + if (GTK_CMCLIST_AUTO_SORT (clist)) + { + if (parent) + sibling = GTK_CMCTREE_ROW (parent)->children; + else + sibling = GTK_CMCTREE_NODE (clist->row_list); + + while (sibling && clist->compare + (clist, GTK_CMCTREE_ROW (cnode), GTK_CMCTREE_ROW (sibling)) > 0) + sibling = GTK_CMCTREE_ROW (sibling)->sibling; + } + + gtk_cmctree_link (ctree, cnode, parent, sibling, TRUE); + + for (work = g_node_last_child (gnode); work; work = work->prev) + { + new_child = gtk_cmctree_insert_gnode (ctree, cnode, child, + work, func, data); + if (new_child) + child = new_child; + } + + gtk_cmclist_thaw (clist); + + return cnode; +} + +GNode * +gtk_cmctree_export_to_gnode (GtkCMCTree *ctree, + GNode *parent, + GNode *sibling, + GtkCMCTreeNode *node, + GtkCMCTreeGNodeFunc func, + gpointer data) +{ + GtkCMCTreeNode *work; + GNode *gnode; + gint depth; + + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); + g_return_val_if_fail (node != NULL, NULL); + g_return_val_if_fail (func != NULL, NULL); + if (sibling) + { + g_return_val_if_fail (parent != NULL, NULL); + g_return_val_if_fail (sibling->parent == parent, NULL); + } + + gnode = g_node_new (NULL); + depth = g_node_depth (parent) + 1; + + if (!func (ctree, depth, gnode, node, data)) + { + g_node_destroy (gnode); + return NULL; + } + + if (parent) + g_node_insert_before (parent, sibling, gnode); + + if (!GTK_CMCTREE_ROW (node)->is_leaf) + { + GNode *new_sibling = NULL; + + for (work = GTK_CMCTREE_ROW (node)->children; work; + work = GTK_CMCTREE_ROW (work)->sibling) + new_sibling = gtk_cmctree_export_to_gnode (ctree, gnode, new_sibling, + work, func, data); + + g_node_reverse_children (gnode); + } + + return gnode; +} + +static void +real_remove_row (GtkCMCList *clist, + gint row) +{ + GtkCMCTreeNode *node; + + g_return_if_fail (GTK_IS_CMCTREE (clist)); + + node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, row)); + + if (node) + gtk_cmctree_remove_node (GTK_CMCTREE (clist), node); +} + +void +gtk_cmctree_remove_node (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + clist = GTK_CMCLIST (ctree); + + gtk_cmclist_freeze (clist); + + if (node) + { + gtk_cmctree_unlink (ctree, node, TRUE); + gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_delete), + NULL); + if (clist->selection_mode == GTK_SELECTION_BROWSE && !clist->selection && + clist->focus_row >= 0) + gtk_cmclist_select_row (clist, clist->focus_row, -1); + + auto_resize_columns (clist); + } + else + gtk_cmclist_clear (clist); + + gtk_cmclist_thaw (clist); +} + +static void +real_clear (GtkCMCList *clist) +{ + GtkCMCTree *ctree; + GtkCMCTreeNode *work; + GtkCMCTreeNode *ptr; + + g_return_if_fail (GTK_IS_CMCTREE (clist)); + + ctree = GTK_CMCTREE (clist); + + /* remove all rows */ + work = GTK_CMCTREE_NODE (clist->row_list); + clist->row_list = NULL; + clist->row_list_end = NULL; + + GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED); + while (work) + { + ptr = work; + work = GTK_CMCTREE_ROW (work)->sibling; + gtk_cmctree_post_recursive (ctree, ptr, GTK_CMCTREE_FUNC (tree_delete_row), + NULL); + } + GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED); + + parent_class->clear (clist); +} + + +/*********************************************************** + * Generic recursive functions, querying / finding tree * + * information * + ***********************************************************/ + + +void +gtk_cmctree_post_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeFunc func, + gpointer data) +{ + GtkCMCTreeNode *work; + GtkCMCTreeNode *tmp; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (func != NULL); + + if (node) + work = GTK_CMCTREE_ROW (node)->children; + else + work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); + + while (work) + { + tmp = GTK_CMCTREE_ROW (work)->sibling; + gtk_cmctree_post_recursive (ctree, work, func, data); + work = tmp; + } + + if (node) + func (ctree, node, data); +} + +void +gtk_cmctree_post_recursive_to_depth (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint depth, + GtkCMCTreeFunc func, + gpointer data) +{ + GtkCMCTreeNode *work; + GtkCMCTreeNode *tmp; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (func != NULL); + + if (depth < 0) + { + gtk_cmctree_post_recursive (ctree, node, func, data); + return; + } + + if (node) + work = GTK_CMCTREE_ROW (node)->children; + else + work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); + + if (work && GTK_CMCTREE_ROW (work)->level <= depth) + { + while (work) + { + tmp = GTK_CMCTREE_ROW (work)->sibling; + gtk_cmctree_post_recursive_to_depth (ctree, work, depth, func, data); + work = tmp; + } + } + + if (node && GTK_CMCTREE_ROW (node)->level <= depth) + func (ctree, node, data); +} + +void +gtk_cmctree_pre_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeFunc func, + gpointer data) +{ + GtkCMCTreeNode *work; + GtkCMCTreeNode *tmp; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (func != NULL); + + if (node) + { + work = GTK_CMCTREE_ROW (node)->children; + func (ctree, node, data); + } + else + work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); + + while (work) + { + tmp = GTK_CMCTREE_ROW (work)->sibling; + gtk_cmctree_pre_recursive (ctree, work, func, data); + work = tmp; + } +} + +void +gtk_cmctree_pre_recursive_to_depth (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint depth, + GtkCMCTreeFunc func, + gpointer data) +{ + GtkCMCTreeNode *work; + GtkCMCTreeNode *tmp; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (func != NULL); + + if (depth < 0) + { + gtk_cmctree_pre_recursive (ctree, node, func, data); + return; + } + + if (node) + { + work = GTK_CMCTREE_ROW (node)->children; + if (GTK_CMCTREE_ROW (node)->level <= depth) + func (ctree, node, data); + } + else + work = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); + + if (work && GTK_CMCTREE_ROW (work)->level <= depth) + { + while (work) + { + tmp = GTK_CMCTREE_ROW (work)->sibling; + gtk_cmctree_pre_recursive_to_depth (ctree, work, depth, func, data); + work = tmp; + } + } +} + +gboolean +gtk_cmctree_is_viewable (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + GtkCMCTreeRow *work; + + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); + g_return_val_if_fail (node != NULL, FALSE); + + work = GTK_CMCTREE_ROW (node); + + while (work->parent && GTK_CMCTREE_ROW (work->parent)->expanded) + work = GTK_CMCTREE_ROW (work->parent); + + if (!work->parent) + return TRUE; + + return FALSE; +} + +GtkCMCTreeNode * +gtk_cmctree_last (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); + + if (!node) + return NULL; + + while (GTK_CMCTREE_ROW (node)->sibling) + node = GTK_CMCTREE_ROW (node)->sibling; + + if (GTK_CMCTREE_ROW (node)->children) + return gtk_cmctree_last (ctree, GTK_CMCTREE_ROW (node)->children); + + return node; +} + +GtkCMCTreeNode * +gtk_cmctree_find_node_ptr (GtkCMCTree *ctree, + GtkCMCTreeRow *ctree_row) +{ + GtkCMCTreeNode *node; + + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); + g_return_val_if_fail (ctree_row != NULL, NULL); + + if (ctree_row->parent) + node = GTK_CMCTREE_ROW (ctree_row->parent)->children; + else + node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); + + while (GTK_CMCTREE_ROW (node) != ctree_row) + node = GTK_CMCTREE_ROW (node)->sibling; + + return node; +} + +GtkCMCTreeNode * +gtk_cmctree_node_nth (GtkCMCTree *ctree, + guint row) +{ + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); + + if ((row >= GTK_CMCLIST(ctree)->rows)) + return NULL; + + return GTK_CMCTREE_NODE (g_list_nth (GTK_CMCLIST (ctree)->row_list, row)); +} + +gboolean +gtk_cmctree_find (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeNode *child) +{ + if (!child) + return FALSE; + + if (!node) + node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); + + while (node) + { + if (node == child) + return TRUE; + if (GTK_CMCTREE_ROW (node)->children) + { + if (gtk_cmctree_find (ctree, GTK_CMCTREE_ROW (node)->children, child)) + return TRUE; + } + node = GTK_CMCTREE_ROW (node)->sibling; + } + return FALSE; +} + +gboolean +gtk_cmctree_is_ancestor (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeNode *child) +{ + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); + g_return_val_if_fail (node != NULL, FALSE); + + if (GTK_CMCTREE_ROW (node)->children) + return gtk_cmctree_find (ctree, GTK_CMCTREE_ROW (node)->children, child); + + return FALSE; +} + +GtkCMCTreeNode * +gtk_cmctree_find_by_row_data (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data) +{ + GtkCMCTreeNode *work; + + if (!node) + node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); + + while (node) + { + if (GTK_CMCTREE_ROW (node)->row.data == data) + return node; + if (GTK_CMCTREE_ROW (node)->children && + (work = gtk_cmctree_find_by_row_data + (ctree, GTK_CMCTREE_ROW (node)->children, data))) + return work; + node = GTK_CMCTREE_ROW (node)->sibling; + } + return NULL; +} + +GList * +gtk_cmctree_find_all_by_row_data (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data) +{ + GList *list = NULL; + + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); + + /* if node == NULL then look in the whole tree */ + if (!node) + node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); + + while (node) + { + if (GTK_CMCTREE_ROW (node)->row.data == data) + list = g_list_append (list, node); + + if (GTK_CMCTREE_ROW (node)->children) + { + GList *sub_list; + + sub_list = gtk_cmctree_find_all_by_row_data (ctree, + GTK_CMCTREE_ROW + (node)->children, + data); + list = g_list_concat (list, sub_list); + } + node = GTK_CMCTREE_ROW (node)->sibling; + } + return list; +} + +GtkCMCTreeNode * +gtk_cmctree_find_by_row_data_custom (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data, + GCompareFunc func) +{ + GtkCMCTreeNode *work; + + g_return_val_if_fail (func != NULL, NULL); + + if (!node) + node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); + + while (node) + { + if (!func (GTK_CMCTREE_ROW (node)->row.data, data)) + return node; + if (GTK_CMCTREE_ROW (node)->children && + (work = gtk_cmctree_find_by_row_data_custom + (ctree, GTK_CMCTREE_ROW (node)->children, data, func))) + return work; + node = GTK_CMCTREE_ROW (node)->sibling; + } + return NULL; +} + +GList * +gtk_cmctree_find_all_by_row_data_custom (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data, + GCompareFunc func) +{ + GList *list = NULL; + + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); + g_return_val_if_fail (func != NULL, NULL); + + /* if node == NULL then look in the whole tree */ + if (!node) + node = GTK_CMCTREE_NODE (GTK_CMCLIST (ctree)->row_list); + + while (node) + { + if (!func (GTK_CMCTREE_ROW (node)->row.data, data)) + list = g_list_append (list, node); + + if (GTK_CMCTREE_ROW (node)->children) + { + GList *sub_list; + + sub_list = gtk_cmctree_find_all_by_row_data_custom (ctree, + GTK_CMCTREE_ROW + (node)->children, + data, + func); + list = g_list_concat (list, sub_list); + } + node = GTK_CMCTREE_ROW (node)->sibling; + } + return list; +} + +gboolean +gtk_cmctree_is_hot_spot (GtkCMCTree *ctree, + gint x, + gint y) +{ + GtkCMCTreeNode *node; + gint column; + gint row; + + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); + + if (gtk_cmclist_get_selection_info (GTK_CMCLIST (ctree), x, y, &row, &column)) + if ((node = GTK_CMCTREE_NODE(g_list_nth (GTK_CMCLIST (ctree)->row_list, row)))) + return ctree_is_hot_spot (ctree, node, row, x, y); + + return FALSE; +} + + +/*********************************************************** + * Tree signals : move, expand, collapse, (un)select * + ***********************************************************/ + + +void +gtk_cmctree_move (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeNode *new_parent, + GtkCMCTreeNode *new_sibling) +{ + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + + g_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_MOVE], 0, node, + new_parent, new_sibling); +} + +void +gtk_cmctree_expand (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + + if (GTK_CMCTREE_ROW (node)->is_leaf) + return; + + g_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_EXPAND], 0, node); +} + +void +gtk_cmctree_expand_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + GtkCMCList *clist; + gboolean thaw = FALSE; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + clist = GTK_CMCLIST (ctree); + + if (node && GTK_CMCTREE_ROW (node)->is_leaf) + return; + + if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node))) + { + gtk_cmclist_freeze (clist); + thaw = TRUE; + } + + gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_expand), NULL); + + if (thaw) + gtk_cmclist_thaw (clist); +} + +void +gtk_cmctree_expand_to_depth (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint depth) +{ + GtkCMCList *clist; + gboolean thaw = FALSE; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + clist = GTK_CMCLIST (ctree); + + if (node && GTK_CMCTREE_ROW (node)->is_leaf) + return; + + if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node))) + { + gtk_cmclist_freeze (clist); + thaw = TRUE; + } + + gtk_cmctree_post_recursive_to_depth (ctree, node, depth, + GTK_CMCTREE_FUNC (tree_expand), NULL); + + if (thaw) + gtk_cmclist_thaw (clist); +} + +void +gtk_cmctree_collapse (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + + if (GTK_CMCTREE_ROW (node)->is_leaf) + return; + + g_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_COLLAPSE], 0, node); +} + +void +gtk_cmctree_collapse_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + GtkCMCList *clist; + gboolean thaw = FALSE; + gint i; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + if (node && GTK_CMCTREE_ROW (node)->is_leaf) + return; + + clist = GTK_CMCLIST (ctree); + + if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node))) + { + gtk_cmclist_freeze (clist); + thaw = TRUE; + } + + GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED); + gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_collapse), NULL); + GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED); + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + gtk_cmclist_set_column_width (clist, i, + gtk_cmclist_optimal_column_width (clist, i)); + + if (thaw) + gtk_cmclist_thaw (clist); +} + +void +gtk_cmctree_collapse_to_depth (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint depth) +{ + GtkCMCList *clist; + gboolean thaw = FALSE; + gint i; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + if (node && GTK_CMCTREE_ROW (node)->is_leaf) + return; + + clist = GTK_CMCLIST (ctree); + + if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node))) + { + gtk_cmclist_freeze (clist); + thaw = TRUE; + } + + GTK_CMCLIST_SET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED); + gtk_cmctree_post_recursive_to_depth (ctree, node, depth, + GTK_CMCTREE_FUNC (tree_collapse_to_depth), + GINT_TO_POINTER (depth)); + GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_AUTO_RESIZE_BLOCKED); + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + gtk_cmclist_set_column_width (clist, i, + gtk_cmclist_optimal_column_width (clist, i)); + + if (thaw) + gtk_cmclist_thaw (clist); +} + +void +gtk_cmctree_toggle_expansion (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + + if (GTK_CMCTREE_ROW (node)->is_leaf) + return; + + tree_toggle_expansion (ctree, node, NULL); +} + +void +gtk_cmctree_toggle_expansion_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + GtkCMCList *clist; + gboolean thaw = FALSE; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + if (node && GTK_CMCTREE_ROW (node)->is_leaf) + return; + + clist = GTK_CMCLIST (ctree); + + if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node))) + { + gtk_cmclist_freeze (clist); + thaw = TRUE; + } + + gtk_cmctree_post_recursive (ctree, node, + GTK_CMCTREE_FUNC (tree_toggle_expansion), NULL); + + if (thaw) + gtk_cmclist_thaw (clist); +} + +void +gtk_cmctree_select (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + + if (GTK_CMCTREE_ROW (node)->row.selectable) + g_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_SELECT_ROW], 0, + node, -1); +} + +void +gtk_cmctree_unselect (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + + g_signal_emit (GTK_OBJECT (ctree), ctree_signals[TREE_UNSELECT_ROW], 0, + node, -1); +} + +void +gtk_cmctree_select_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + gtk_cmctree_real_select_recursive (ctree, node, TRUE); +} + +void +gtk_cmctree_unselect_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + gtk_cmctree_real_select_recursive (ctree, node, FALSE); +} + +void +gtk_cmctree_real_select_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint state) +{ + GtkCMCList *clist; + gboolean thaw = FALSE; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + clist = GTK_CMCLIST (ctree); + + if ((state && + (clist->selection_mode == GTK_SELECTION_BROWSE || + clist->selection_mode == GTK_SELECTION_SINGLE)) || + (!state && clist->selection_mode == GTK_SELECTION_BROWSE)) + return; + + if (CLIST_UNFROZEN (clist) && (!node || gtk_cmctree_is_viewable (ctree, node))) + { + gtk_cmclist_freeze (clist); + thaw = TRUE; + } + + if (clist->selection_mode == GTK_SELECTION_MULTIPLE) + { + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + } + + if (state) + gtk_cmctree_post_recursive (ctree, node, + GTK_CMCTREE_FUNC (tree_select), NULL); + else + gtk_cmctree_post_recursive (ctree, node, + GTK_CMCTREE_FUNC (tree_unselect), NULL); + + if (thaw) + gtk_cmclist_thaw (clist); +} + + +/*********************************************************** + * Analogons of GtkCMCList functions * + ***********************************************************/ + + +void +gtk_cmctree_node_set_text (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + const gchar *text) +{ + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + + if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) + return; + + clist = GTK_CMCLIST (ctree); + + GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents + (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_TEXT, + text, 0, NULL, NULL); + + tree_draw_node (ctree, node); +} + +void +gtk_cmctree_node_set_pixmap (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + GdkPixmap *pixmap, + GdkBitmap *mask) +{ + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + g_return_if_fail (pixmap != NULL); + + if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) + return; + + g_object_ref (pixmap); + if (mask) + g_object_ref (mask); + + clist = GTK_CMCLIST (ctree); + + GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents + (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_PIXMAP, + NULL, 0, pixmap, mask); + + tree_draw_node (ctree, node); +} + +void +gtk_cmctree_node_set_pixtext (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap, + GdkBitmap *mask) +{ + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + if (column != ctree->tree_column) + g_return_if_fail (pixmap != NULL); + if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) + return; + + clist = GTK_CMCLIST (ctree); + + if (pixmap) + { + g_object_ref (pixmap); + if (mask) + g_object_ref (mask); + } + + GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents + (clist, &(GTK_CMCTREE_ROW (node)->row), column, GTK_CMCELL_PIXTEXT, + text, spacing, pixmap, mask); + + tree_draw_node (ctree, node); +} + +void +gtk_cmctree_set_node_info (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap_closed, + GdkBitmap *mask_closed, + GdkPixmap *pixmap_opened, + GdkBitmap *mask_opened, + gboolean is_leaf, + gboolean expanded) +{ + gboolean old_leaf; + gboolean old_expanded; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + + old_leaf = GTK_CMCTREE_ROW (node)->is_leaf; + old_expanded = GTK_CMCTREE_ROW (node)->expanded; + + if (is_leaf && GTK_CMCTREE_ROW (node)->children) + { + GtkCMCTreeNode *work; + GtkCMCTreeNode *ptr; + + work = GTK_CMCTREE_ROW (node)->children; + while (work) + { + ptr = work; + work = GTK_CMCTREE_ROW (work)->sibling; + gtk_cmctree_remove_node (ctree, ptr); + } + } + + set_node_info (ctree, node, text, spacing, pixmap_closed, mask_closed, + pixmap_opened, mask_opened, is_leaf, expanded); + + if (!is_leaf && !old_leaf) + { + GTK_CMCTREE_ROW (node)->expanded = old_expanded; + if (expanded && !old_expanded) + gtk_cmctree_expand (ctree, node); + else if (!expanded && old_expanded) + gtk_cmctree_collapse (ctree, node); + } + + GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded; + + tree_draw_node (ctree, node); +} + +void +gtk_cmctree_node_set_shift (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + gint vertical, + gint horizontal) +{ + GtkCMCList *clist; + GtkRequisition requisition; + gboolean visible = FALSE; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + + if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) + return; + + clist = GTK_CMCLIST (ctree); + + if (clist->column[column].auto_resize && + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + { + visible = gtk_cmctree_is_viewable (ctree, node); + if (visible) + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request + (clist, &GTK_CMCTREE_ROW (node)->row, column, &requisition); + } + + GTK_CMCTREE_ROW (node)->row.cell[column].vertical = vertical; + GTK_CMCTREE_ROW (node)->row.cell[column].horizontal = horizontal; + + if (visible) + column_auto_resize (clist, &GTK_CMCTREE_ROW (node)->row, + column, requisition.width); + + tree_draw_node (ctree, node); +} + +static void +remove_grab (GtkCMCList *clist) +{ + if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (clist))) && + GTK_WIDGET_HAS_GRAB (clist)) + { + gtk_grab_remove (GTK_WIDGET (clist)); + gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (clist)), + GDK_CURRENT_TIME); + } + + if (clist->htimer) + { + g_source_remove (clist->htimer); + clist->htimer = 0; + } + + if (clist->vtimer) + { + g_source_remove (clist->vtimer); + clist->vtimer = 0; + } +} + +void +gtk_cmctree_node_set_selectable (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gboolean selectable) +{ + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + + if (selectable == GTK_CMCTREE_ROW (node)->row.selectable) + return; + + GTK_CMCTREE_ROW (node)->row.selectable = selectable; + + if (!selectable && GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED) + { + GtkCMCList *clist; + + clist = GTK_CMCLIST (ctree); + + if (clist->anchor >= 0 && + clist->selection_mode == GTK_SELECTION_MULTIPLE) + { + clist->drag_button = 0; + remove_grab (clist); + + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + } + gtk_cmctree_unselect (ctree, node); + } +} + +gboolean +gtk_cmctree_node_get_selectable (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + g_return_val_if_fail (node != NULL, FALSE); + + return GTK_CMCTREE_ROW (node)->row.selectable; +} + +GtkCMCellType +gtk_cmctree_node_get_cell_type (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column) +{ + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), -1); + g_return_val_if_fail (node != NULL, -1); + + if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) + return -1; + + return GTK_CMCTREE_ROW (node)->row.cell[column].type; +} + +gboolean +gtk_cmctree_node_get_text (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + gchar **text) +{ + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); + g_return_val_if_fail (node != NULL, FALSE); + + if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) + return FALSE; + + if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_TEXT) + return FALSE; + + if (text) + *text = GTK_CMCELL_TEXT (GTK_CMCTREE_ROW (node)->row.cell[column])->text; + + return TRUE; +} + +gboolean +gtk_cmctree_node_get_pixmap (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + GdkPixmap **pixmap, + GdkBitmap **mask) +{ + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); + g_return_val_if_fail (node != NULL, FALSE); + + if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) + return FALSE; + + if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_PIXMAP) + return FALSE; + + if (pixmap) + *pixmap = GTK_CMCELL_PIXMAP (GTK_CMCTREE_ROW (node)->row.cell[column])->pixmap; + if (mask) + *mask = GTK_CMCELL_PIXMAP (GTK_CMCTREE_ROW (node)->row.cell[column])->mask; + + return TRUE; +} + +gboolean +gtk_cmctree_node_get_pixtext (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + gchar **text, + guint8 *spacing, + GdkPixmap **pixmap, + GdkBitmap **mask) +{ + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); + g_return_val_if_fail (node != NULL, FALSE); + + if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) + return FALSE; + + if (GTK_CMCTREE_ROW (node)->row.cell[column].type != GTK_CMCELL_PIXTEXT) + return FALSE; + + if (text) + *text = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW (node)->row.cell[column])->text; + if (spacing) + *spacing = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW + (node)->row.cell[column])->spacing; + if (pixmap) + *pixmap = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW + (node)->row.cell[column])->pixmap; + if (mask) + *mask = GTK_CMCELL_PIXTEXT (GTK_CMCTREE_ROW (node)->row.cell[column])->mask; + + return TRUE; +} + +gboolean +gtk_cmctree_get_node_info (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gchar **text, + guint8 *spacing, + GdkPixmap **pixmap_closed, + GdkBitmap **mask_closed, + GdkPixmap **pixmap_opened, + GdkBitmap **mask_opened, + gboolean *is_leaf, + gboolean *expanded) +{ + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); + g_return_val_if_fail (node != NULL, FALSE); + + if (text) + *text = GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->text; + if (spacing) + *spacing = GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->spacing; + if (pixmap_closed) + *pixmap_closed = GTK_CMCTREE_ROW (node)->pixmap_closed; + if (mask_closed) + *mask_closed = GTK_CMCTREE_ROW (node)->mask_closed; + if (pixmap_opened) + *pixmap_opened = GTK_CMCTREE_ROW (node)->pixmap_opened; + if (mask_opened) + *mask_opened = GTK_CMCTREE_ROW (node)->mask_opened; + if (is_leaf) + *is_leaf = GTK_CMCTREE_ROW (node)->is_leaf; + if (expanded) + *expanded = GTK_CMCTREE_ROW (node)->expanded; + + return TRUE; +} + +void +gtk_cmctree_node_set_cell_style (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + GtkStyle *style) +{ + GtkCMCList *clist; + GtkRequisition requisition; + gboolean visible = FALSE; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + + clist = GTK_CMCLIST (ctree); + + if (column < 0 || column >= clist->columns) + return; + + if (GTK_CMCTREE_ROW (node)->row.cell[column].style == style) + return; + + if (clist->column[column].auto_resize && + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + { + visible = gtk_cmctree_is_viewable (ctree, node); + if (visible) + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request + (clist, &GTK_CMCTREE_ROW (node)->row, column, &requisition); + } + + if (GTK_CMCTREE_ROW (node)->row.cell[column].style) + { + if (GTK_WIDGET_REALIZED (ctree)) + gtk_style_detach (GTK_CMCTREE_ROW (node)->row.cell[column].style); + g_object_unref (GTK_CMCTREE_ROW (node)->row.cell[column].style); + } + + GTK_CMCTREE_ROW (node)->row.cell[column].style = style; + + if (GTK_CMCTREE_ROW (node)->row.cell[column].style) + { + g_object_ref (GTK_CMCTREE_ROW (node)->row.cell[column].style); + + if (GTK_WIDGET_REALIZED (ctree)) + GTK_CMCTREE_ROW (node)->row.cell[column].style = + gtk_style_attach (GTK_CMCTREE_ROW (node)->row.cell[column].style, + clist->clist_window); + } + + if (visible) + column_auto_resize (clist, &GTK_CMCTREE_ROW (node)->row, column, + requisition.width); + + tree_draw_node (ctree, node); +} + +GtkStyle * +gtk_cmctree_node_get_cell_style (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column) +{ + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); + g_return_val_if_fail (node != NULL, NULL); + + if (column < 0 || column >= GTK_CMCLIST (ctree)->columns) + return NULL; + + return GTK_CMCTREE_ROW (node)->row.cell[column].style; +} + +void +gtk_cmctree_node_set_row_style (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkStyle *style) +{ + GtkCMCList *clist; + GtkRequisition requisition; + gboolean visible; + gint *old_width = NULL; + gint i; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + + clist = GTK_CMCLIST (ctree); + + if (GTK_CMCTREE_ROW (node)->row.style == style) + return; + + visible = gtk_cmctree_is_viewable (ctree, node); + if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + { + old_width = g_new (gint, clist->columns); + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + { + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request + (clist, &GTK_CMCTREE_ROW (node)->row, i, &requisition); + old_width[i] = requisition.width; + } + } + + if (GTK_CMCTREE_ROW (node)->row.style) + { + if (GTK_WIDGET_REALIZED (ctree)) + gtk_style_detach (GTK_CMCTREE_ROW (node)->row.style); + g_object_unref (GTK_CMCTREE_ROW (node)->row.style); + } + + GTK_CMCTREE_ROW (node)->row.style = style; + + if (GTK_CMCTREE_ROW (node)->row.style) + { + g_object_ref (GTK_CMCTREE_ROW (node)->row.style); + + if (GTK_WIDGET_REALIZED (ctree)) + GTK_CMCTREE_ROW (node)->row.style = + gtk_style_attach (GTK_CMCTREE_ROW (node)->row.style, + clist->clist_window); + } + + if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + { + for (i = 0; i < clist->columns; i++) + if (clist->column[i].auto_resize) + column_auto_resize (clist, &GTK_CMCTREE_ROW (node)->row, i, + old_width[i]); + g_free (old_width); + } + tree_draw_node (ctree, node); +} + +GtkStyle * +gtk_cmctree_node_get_row_style (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); + g_return_val_if_fail (node != NULL, NULL); + + return GTK_CMCTREE_ROW (node)->row.style; +} + +void +gtk_cmctree_node_set_foreground (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + const GdkColor *color) +{ + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + + if (color) + { + GTK_CMCTREE_ROW (node)->row.foreground = *color; + GTK_CMCTREE_ROW (node)->row.fg_set = TRUE; + if (GTK_WIDGET_REALIZED (ctree)) + gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (ctree)), + &GTK_CMCTREE_ROW (node)->row.foreground, TRUE, TRUE); + } + else + GTK_CMCTREE_ROW (node)->row.fg_set = FALSE; + + tree_draw_node (ctree, node); +} + +void +gtk_cmctree_node_set_background (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + const GdkColor *color) +{ + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + + if (color) + { + GTK_CMCTREE_ROW (node)->row.background = *color; + GTK_CMCTREE_ROW (node)->row.bg_set = TRUE; + if (GTK_WIDGET_REALIZED (ctree)) + gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (ctree)), + &GTK_CMCTREE_ROW (node)->row.background, TRUE, TRUE); + } + else + GTK_CMCTREE_ROW (node)->row.bg_set = FALSE; + + tree_draw_node (ctree, node); +} + +void +gtk_cmctree_node_set_row_data (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data) +{ + gtk_cmctree_node_set_row_data_full (ctree, node, data, NULL); +} + +void +gtk_cmctree_node_set_row_data_full (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data, + GtkDestroyNotify destroy) +{ + GtkDestroyNotify dnotify; + gpointer ddata; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (node != NULL); + + dnotify = GTK_CMCTREE_ROW (node)->row.destroy; + ddata = GTK_CMCTREE_ROW (node)->row.data; + + GTK_CMCTREE_ROW (node)->row.data = data; + GTK_CMCTREE_ROW (node)->row.destroy = destroy; + + if (dnotify) + dnotify (ddata); +} + +gpointer +gtk_cmctree_node_get_row_data (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); + + return node ? GTK_CMCTREE_ROW (node)->row.data : NULL; +} + +void +gtk_cmctree_node_moveto (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + gfloat row_align, + gfloat col_align) +{ + gint row = -1; + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + clist = GTK_CMCLIST (ctree); + + while (node && !gtk_cmctree_is_viewable (ctree, node)) + node = GTK_CMCTREE_ROW (node)->parent; + + if (node) + row = g_list_position (clist->row_list, (GList *)node); + + gtk_cmclist_moveto (clist, row, column, row_align, col_align); +} + +GtkVisibility +gtk_cmctree_node_is_visible (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + gint row; + + g_return_val_if_fail (ctree != NULL, 0); + g_return_val_if_fail (node != NULL, 0); + + row = g_list_position (GTK_CMCLIST (ctree)->row_list, (GList*) node); + return gtk_cmclist_row_is_visible (GTK_CMCLIST (ctree), row); +} + + +/*********************************************************** + * GtkCMCTree specific functions * + ***********************************************************/ + +void +gtk_cmctree_set_indent (GtkCMCTree *ctree, + gint indent) +{ + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (indent >= 0); + + if (indent == ctree->tree_indent) + return; + + clist = GTK_CMCLIST (ctree); + ctree->tree_indent = indent; + + if (clist->column[ctree->tree_column].auto_resize && + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + gtk_cmclist_set_column_width + (clist, ctree->tree_column, + gtk_cmclist_optimal_column_width (clist, ctree->tree_column)); + else + CLIST_REFRESH (ctree); +} + +void +gtk_cmctree_set_spacing (GtkCMCTree *ctree, + gint spacing) +{ + GtkCMCList *clist; + gint old_spacing; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + g_return_if_fail (spacing >= 0); + + if (spacing == ctree->tree_spacing) + return; + + clist = GTK_CMCLIST (ctree); + + old_spacing = ctree->tree_spacing; + ctree->tree_spacing = spacing; + + if (clist->column[ctree->tree_column].auto_resize && + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + gtk_cmclist_set_column_width (clist, ctree->tree_column, + clist->column[ctree->tree_column].width + + spacing - old_spacing); + else + CLIST_REFRESH (ctree); +} + +void +gtk_cmctree_set_show_stub (GtkCMCTree *ctree, + gboolean show_stub) +{ + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + show_stub = show_stub != FALSE; + + if (show_stub != ctree->show_stub) + { + GtkCMCList *clist; + + clist = GTK_CMCLIST (ctree); + ctree->show_stub = show_stub; + + if (CLIST_UNFROZEN (clist) && clist->rows && + gtk_cmclist_row_is_visible (clist, 0) != GTK_VISIBILITY_NONE) + GTK_CMCLIST_GET_CLASS (clist)->draw_row + (clist, NULL, 0, GTK_CMCLIST_ROW (clist->row_list)); + } +} + +void +gtk_cmctree_set_line_style (GtkCMCTree *ctree, + GtkCMCTreeLineStyle line_style) +{ + GtkCMCList *clist; + GtkCMCTreeLineStyle old_style; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + if (line_style == ctree->line_style) + return; + + clist = GTK_CMCLIST (ctree); + + old_style = ctree->line_style; + ctree->line_style = line_style; + + if (clist->column[ctree->tree_column].auto_resize && + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + { + if (old_style == GTK_CMCTREE_LINES_TABBED) + gtk_cmclist_set_column_width + (clist, ctree->tree_column, + clist->column[ctree->tree_column].width - 3); + else if (line_style == GTK_CMCTREE_LINES_TABBED) + gtk_cmclist_set_column_width + (clist, ctree->tree_column, + clist->column[ctree->tree_column].width + 3); + } + + if (GTK_WIDGET_REALIZED (ctree)) + { + switch (line_style) + { + case GTK_CMCTREE_LINES_SOLID: + if (GTK_WIDGET_REALIZED (ctree)) + gdk_gc_set_line_attributes (ctree->lines_gc, 1, GDK_LINE_SOLID, + GDK_CAP_BUTT, GDK_JOIN_MITER); + break; + case GTK_CMCTREE_LINES_DOTTED: + if (GTK_WIDGET_REALIZED (ctree)) + gdk_gc_set_line_attributes (ctree->lines_gc, 1, + GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER); + gdk_gc_set_dashes (ctree->lines_gc, 0, "\1\1", 2); + break; + case GTK_CMCTREE_LINES_TABBED: + if (GTK_WIDGET_REALIZED (ctree)) + gdk_gc_set_line_attributes (ctree->lines_gc, 1, GDK_LINE_SOLID, + GDK_CAP_BUTT, GDK_JOIN_MITER); + break; + case GTK_CMCTREE_LINES_NONE: + break; + default: + return; + } + CLIST_REFRESH (ctree); + } +} + +void +gtk_cmctree_set_expander_style (GtkCMCTree *ctree, + GtkCMCTreeExpanderStyle expander_style) +{ + GtkCMCList *clist; + GtkCMCTreeExpanderStyle old_style; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + if (expander_style == ctree->expander_style) + return; + + clist = GTK_CMCLIST (ctree); + + old_style = ctree->expander_style; + ctree->expander_style = expander_style; + + if (clist->column[ctree->tree_column].auto_resize && + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + { + gint new_width; + + new_width = clist->column[ctree->tree_column].width; + switch (old_style) + { + case GTK_CMCTREE_EXPANDER_NONE: + break; + case GTK_CMCTREE_EXPANDER_TRIANGLE: + new_width -= PM_SIZE + 3; + break; + case GTK_CMCTREE_EXPANDER_SQUARE: + case GTK_CMCTREE_EXPANDER_CIRCULAR: + new_width -= PM_SIZE + 1; + break; + } + + switch (expander_style) + { + case GTK_CMCTREE_EXPANDER_NONE: + break; + case GTK_CMCTREE_EXPANDER_TRIANGLE: + new_width += PM_SIZE + 3; + break; + case GTK_CMCTREE_EXPANDER_SQUARE: + case GTK_CMCTREE_EXPANDER_CIRCULAR: + new_width += PM_SIZE + 1; + break; + } + + gtk_cmclist_set_column_width (clist, ctree->tree_column, new_width); + } + + if (GTK_WIDGET_DRAWABLE (clist)) + CLIST_REFRESH (clist); +} + + +/*********************************************************** + * Tree sorting functions * + ***********************************************************/ + + +static void +tree_sort (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data) +{ + GtkCMCTreeNode *list_start; + GtkCMCTreeNode *cmp; + GtkCMCTreeNode *work; + GtkCMCList *clist; + + clist = GTK_CMCLIST (ctree); + + if (node) + list_start = GTK_CMCTREE_ROW (node)->children; + else + list_start = GTK_CMCTREE_NODE (clist->row_list); + + while (list_start) + { + cmp = list_start; + work = GTK_CMCTREE_ROW (cmp)->sibling; + while (work) + { + if (clist->sort_type == GTK_SORT_ASCENDING) + { + if (clist->compare + (clist, GTK_CMCTREE_ROW (work), GTK_CMCTREE_ROW (cmp)) < 0) + cmp = work; + } + else + { + if (clist->compare + (clist, GTK_CMCTREE_ROW (work), GTK_CMCTREE_ROW (cmp)) > 0) + cmp = work; + } + work = GTK_CMCTREE_ROW (work)->sibling; + } + if (cmp == list_start) + list_start = GTK_CMCTREE_ROW (cmp)->sibling; + else + { + gtk_cmctree_unlink (ctree, cmp, FALSE); + gtk_cmctree_link (ctree, cmp, node, list_start, FALSE); + } + } +} + +void +gtk_cmctree_sort_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + GtkCMCList *clist; + GtkCMCTreeNode *focus_node = NULL; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + clist = GTK_CMCLIST (ctree); + + gtk_cmclist_freeze (clist); + + if (clist->selection_mode == GTK_SELECTION_MULTIPLE) + { + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + } + + if (!node || (node && gtk_cmctree_is_viewable (ctree, node))) + focus_node = + GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)); + + gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (tree_sort), NULL); + + if (!node) + tree_sort (ctree, NULL, NULL); + + if (focus_node) + { + clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node); + clist->undo_anchor = clist->focus_row; + } + + gtk_cmclist_thaw (clist); +} + +static void +real_sort_list (GtkCMCList *clist) +{ + gtk_cmctree_sort_recursive (GTK_CMCTREE (clist), NULL); +} + +void +gtk_cmctree_sort_node (GtkCMCTree *ctree, + GtkCMCTreeNode *node) +{ + GtkCMCList *clist; + GtkCMCTreeNode *focus_node = NULL; + + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + clist = GTK_CMCLIST (ctree); + + gtk_cmclist_freeze (clist); + + if (clist->selection_mode == GTK_SELECTION_MULTIPLE) + { + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + } + + if (!node || (node && gtk_cmctree_is_viewable (ctree, node))) + focus_node = GTK_CMCTREE_NODE + (g_list_nth (clist->row_list, clist->focus_row)); + + tree_sort (ctree, node, NULL); + + if (focus_node) + { + clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node); + clist->undo_anchor = clist->focus_row; + } + + gtk_cmclist_thaw (clist); +} + +/************************************************************************/ + +static void +fake_unselect_all (GtkCMCList *clist, + gint row) +{ + GList *list; + GList *focus_node = NULL; + + if (row >= 0 && (focus_node = g_list_nth (clist->row_list, row))) + { + if (GTK_CMCTREE_ROW (focus_node)->row.state == GTK_STATE_NORMAL && + GTK_CMCTREE_ROW (focus_node)->row.selectable) + { + GTK_CMCTREE_ROW (focus_node)->row.state = GTK_STATE_SELECTED; + + if (CLIST_UNFROZEN (clist) && + gtk_cmclist_row_is_visible (clist, row) != GTK_VISIBILITY_NONE) + GTK_CMCLIST_GET_CLASS (clist)->draw_row (clist, NULL, row, + GTK_CMCLIST_ROW (focus_node)); + } + } + + clist->undo_selection = clist->selection; + clist->selection = NULL; + clist->selection_end = NULL; + + for (list = clist->undo_selection; list; list = list->next) + { + if (list->data == focus_node) + continue; + + GTK_CMCTREE_ROW ((GList *)(list->data))->row.state = GTK_STATE_NORMAL; + tree_draw_node (GTK_CMCTREE (clist), GTK_CMCTREE_NODE (list->data)); + } +} + +static GList * +selection_find (GtkCMCList *clist, + gint row_number, + GList *row_list_element) +{ + return g_list_find (clist->selection, row_list_element); +} + +static void +resync_selection (GtkCMCList *clist, GdkEvent *event) +{ + GtkCMCTree *ctree; + GList *list; + GtkCMCTreeNode *node; + gint i; + gint e; + gint row; + gboolean unselect; + + g_return_if_fail (GTK_IS_CMCTREE (clist)); + + if (clist->selection_mode != GTK_SELECTION_MULTIPLE) + return; + + if (clist->anchor < 0 || clist->drag_pos < 0) + return; + + ctree = GTK_CMCTREE (clist); + + clist->freeze_count++; + + i = MIN (clist->anchor, clist->drag_pos); + e = MAX (clist->anchor, clist->drag_pos); + + if (clist->undo_selection) + { + list = clist->selection; + clist->selection = clist->undo_selection; + clist->selection_end = g_list_last (clist->selection); + clist->undo_selection = list; + list = clist->selection; + + while (list) + { + node = list->data; + list = list->next; + + unselect = TRUE; + + if (gtk_cmctree_is_viewable (ctree, node)) + { + row = g_list_position (clist->row_list, (GList *)node); + if (row >= i && row <= e) + unselect = FALSE; + } + if (unselect && GTK_CMCTREE_ROW (node)->row.selectable) + { + GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED; + gtk_cmctree_unselect (ctree, node); + clist->undo_selection = g_list_prepend (clist->undo_selection, + node); + } + } + } + + if (clist->anchor < clist->drag_pos) + { + for (node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, i)); i <= e; + i++, node = GTK_CMCTREE_NODE_NEXT (node)) + if (GTK_CMCTREE_ROW (node)->row.selectable) + { + if (g_list_find (clist->selection, node)) + { + if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_NORMAL) + { + GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED; + gtk_cmctree_unselect (ctree, node); + clist->undo_selection = + g_list_prepend (clist->undo_selection, node); + } + } + else if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED) + { + GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL; + clist->undo_unselection = + g_list_prepend (clist->undo_unselection, node); + } + } + } + else + { + for (node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, e)); i <= e; + e--, node = GTK_CMCTREE_NODE_PREV (node)) + if (GTK_CMCTREE_ROW (node)->row.selectable) + { + if (g_list_find (clist->selection, node)) + { + if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_NORMAL) + { + GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_SELECTED; + gtk_cmctree_unselect (ctree, node); + clist->undo_selection = + g_list_prepend (clist->undo_selection, node); + } + } + else if (GTK_CMCTREE_ROW (node)->row.state == GTK_STATE_SELECTED) + { + GTK_CMCTREE_ROW (node)->row.state = GTK_STATE_NORMAL; + clist->undo_unselection = + g_list_prepend (clist->undo_unselection, node); + } + } + } + + clist->undo_unselection = g_list_reverse (clist->undo_unselection); + for (list = clist->undo_unselection; list; list = list->next) + gtk_cmctree_select (ctree, list->data); + + clist->anchor = -1; + clist->drag_pos = -1; + + if (!CLIST_UNFROZEN (clist)) + clist->freeze_count--; +} + +static void +real_undo_selection (GtkCMCList *clist) +{ + GtkCMCTree *ctree; + GList *work; + + g_return_if_fail (GTK_IS_CMCTREE (clist)); + + if (clist->selection_mode != GTK_SELECTION_MULTIPLE) + return; + + if (!(clist->undo_selection || clist->undo_unselection)) + { + gtk_cmclist_unselect_all (clist); + return; + } + + ctree = GTK_CMCTREE (clist); + + for (work = clist->undo_selection; work; work = work->next) + if (GTK_CMCTREE_ROW (work->data)->row.selectable) + gtk_cmctree_select (ctree, GTK_CMCTREE_NODE (work->data)); + + for (work = clist->undo_unselection; work; work = work->next) + if (GTK_CMCTREE_ROW (work->data)->row.selectable) + gtk_cmctree_unselect (ctree, GTK_CMCTREE_NODE (work->data)); + + if (GTK_WIDGET_HAS_FOCUS (clist) && clist->focus_row != clist->undo_anchor) + { + clist->focus_row = clist->undo_anchor; + gtk_widget_queue_draw (GTK_WIDGET (clist)); + } + else + clist->focus_row = clist->undo_anchor; + + clist->undo_anchor = -1; + + g_list_free (clist->undo_selection); + g_list_free (clist->undo_unselection); + clist->undo_selection = NULL; + clist->undo_unselection = NULL; + + if (ROW_TOP_YPIXEL (clist, clist->focus_row) + clist->row_height > + clist->clist_window_height) + gtk_cmclist_moveto (clist, clist->focus_row, -1, 1, 0); + else if (ROW_TOP_YPIXEL (clist, clist->focus_row) < 0) + gtk_cmclist_moveto (clist, clist->focus_row, -1, 0, 0); + +} + +void +gtk_cmctree_set_drag_compare_func (GtkCMCTree *ctree, + GtkCMCTreeCompareDragFunc cmp_func) +{ + g_return_if_fail (GTK_IS_CMCTREE (ctree)); + + ctree->drag_compare = cmp_func; +} + +static gboolean +check_drag (GtkCMCTree *ctree, + GtkCMCTreeNode *drag_source, + GtkCMCTreeNode *drag_target, + GtkCMCListDragPos insert_pos) +{ + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), FALSE); + + if (drag_source && drag_source != drag_target && + (!GTK_CMCTREE_ROW (drag_source)->children || + !gtk_cmctree_is_ancestor (ctree, drag_source, drag_target))) + { + switch (insert_pos) + { + case GTK_CMCLIST_DRAG_NONE: + return FALSE; + case GTK_CMCLIST_DRAG_AFTER: + if (GTK_CMCTREE_ROW (drag_target)->sibling != drag_source) + return (!ctree->drag_compare || + ctree->drag_compare (ctree, + drag_source, + GTK_CMCTREE_ROW (drag_target)->parent, + GTK_CMCTREE_ROW (drag_target)->sibling)); + break; + case GTK_CMCLIST_DRAG_BEFORE: + if (GTK_CMCTREE_ROW (drag_source)->sibling != drag_target) + return (!ctree->drag_compare || + ctree->drag_compare (ctree, + drag_source, + GTK_CMCTREE_ROW (drag_target)->parent, + drag_target)); + break; + case GTK_CMCLIST_DRAG_INTO: + if (!GTK_CMCTREE_ROW (drag_target)->is_leaf && + GTK_CMCTREE_ROW (drag_target)->children != drag_source) + return (!ctree->drag_compare || + ctree->drag_compare (ctree, + drag_source, + drag_target, + GTK_CMCTREE_ROW (drag_target)->children)); + break; + } + } + return FALSE; +} + + + +/************************************/ +static void +drag_dest_info_destroy (gpointer data) +{ + GtkCMCListDestInfo *info = data; + + g_free (info); +} + +static void +drag_dest_cell (GtkCMCList *clist, + gint x, + gint y, + GtkCMCListDestInfo *dest_info) +{ + GtkWidget *widget; + + widget = GTK_WIDGET (clist); + + dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE; + + y -= (GTK_CONTAINER (widget)->border_width + + widget->style->ythickness + clist->column_title_area.height); + dest_info->cell.row = ROW_FROM_YPIXEL (clist, y); + + if (dest_info->cell.row >= clist->rows) + { + dest_info->cell.row = clist->rows - 1; + y = ROW_TOP_YPIXEL (clist, dest_info->cell.row) + clist->row_height; + } + if (dest_info->cell.row < -1) + dest_info->cell.row = -1; + + x -= GTK_CONTAINER (widget)->border_width + widget->style->xthickness; + + dest_info->cell.column = COLUMN_FROM_XPIXEL (clist, x); + + if (dest_info->cell.row >= 0) + { + gint y_delta; + gint h = 0; + + y_delta = y - ROW_TOP_YPIXEL (clist, dest_info->cell.row); + + if (GTK_CMCLIST_DRAW_DRAG_RECT(clist) && + !GTK_CMCTREE_ROW (g_list_nth (clist->row_list, + dest_info->cell.row))->is_leaf) + { + dest_info->insert_pos = GTK_CMCLIST_DRAG_INTO; + h = clist->row_height / 4; + } + else if (GTK_CMCLIST_DRAW_DRAG_LINE(clist)) + { + dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE; + h = clist->row_height / 2; + } + + if (GTK_CMCLIST_DRAW_DRAG_LINE(clist)) + { + if (y_delta < h) + dest_info->insert_pos = GTK_CMCLIST_DRAG_BEFORE; + else if (clist->row_height - y_delta < h) + dest_info->insert_pos = GTK_CMCLIST_DRAG_AFTER; + } + } +} + +static void +gtk_cmctree_drag_begin (GtkWidget *widget, + GdkDragContext *context) +{ + GtkCMCList *clist; + GtkCMCTree *ctree; + gboolean use_icons; + + g_return_if_fail (GTK_IS_CMCTREE (widget)); + g_return_if_fail (context != NULL); + + clist = GTK_CMCLIST (widget); + ctree = GTK_CMCTREE (widget); + + use_icons = GTK_CMCLIST_USE_DRAG_ICONS (clist); + GTK_CMCLIST_UNSET_FLAG (clist, CMCLIST_USE_DRAG_ICONS); + GTK_WIDGET_CLASS (parent_class)->drag_begin (widget, context); + + if (use_icons) + { + GtkCMCTreeNode *node; + + GTK_CMCLIST_SET_FLAG (clist, CMCLIST_USE_DRAG_ICONS); + node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, + clist->click_cell.row)); + if (node) + { + if (GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap) + { + gtk_drag_set_icon_pixmap + (context, + gtk_widget_get_colormap (widget), + GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap, + GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask, + -2, -2); + return; + } + } + gtk_drag_set_icon_default (context); + } +} + +static gint +gtk_cmctree_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time) +{ + GtkCMCList *clist; + GtkCMCTree *ctree; + GtkCMCListDestInfo new_info; + GtkCMCListDestInfo *dest_info; + + g_return_val_if_fail (GTK_IS_CMCTREE (widget), FALSE); + + clist = GTK_CMCLIST (widget); + ctree = GTK_CMCTREE (widget); + + dest_info = g_dataset_get_data (context, "gtk-clist-drag-dest"); + + if (!dest_info) + { + dest_info = g_new (GtkCMCListDestInfo, 1); + + dest_info->cell.row = -1; + dest_info->cell.column = -1; + dest_info->insert_pos = GTK_CMCLIST_DRAG_NONE; + + g_dataset_set_data_full (context, "gtk-clist-drag-dest", dest_info, + drag_dest_info_destroy); + } + + drag_dest_cell (clist, x, y, &new_info); + + if (GTK_CMCLIST_REORDERABLE (clist)) + { + GList *list; + GdkAtom atom = gdk_atom_intern_static_string ("gtk-clist-drag-reorder"); + + list = context->targets; + while (list) + { + if (atom == GDK_POINTER_TO_ATOM (list->data)) + break; + list = list->next; + } + + if (list) + { + GtkCMCTreeNode *drag_source; + GtkCMCTreeNode *drag_target; + + drag_source = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, + clist->click_cell.row)); + drag_target = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, + new_info.cell.row)); + + if (gtk_drag_get_source_widget (context) != widget || + !check_drag (ctree, drag_source, drag_target, + new_info.insert_pos)) + { + if (dest_info->cell.row < 0) + { + gdk_drag_status (context, GDK_ACTION_DEFAULT, time); + return FALSE; + } + return TRUE; + } + + if (new_info.cell.row != dest_info->cell.row || + (new_info.cell.row == dest_info->cell.row && + dest_info->insert_pos != new_info.insert_pos)) + { + if (dest_info->cell.row >= 0) + GTK_CMCLIST_GET_CLASS (clist)->draw_drag_highlight + (clist, + g_list_nth (clist->row_list, dest_info->cell.row)->data, + dest_info->cell.row, dest_info->insert_pos); + + dest_info->insert_pos = new_info.insert_pos; + dest_info->cell.row = new_info.cell.row; + dest_info->cell.column = new_info.cell.column; + + GTK_CMCLIST_GET_CLASS (clist)->draw_drag_highlight + (clist, + g_list_nth (clist->row_list, dest_info->cell.row)->data, + dest_info->cell.row, dest_info->insert_pos); + + clist->drag_highlight_row = dest_info->cell.row; + clist->drag_highlight_pos = dest_info->insert_pos; + + gdk_drag_status (context, context->suggested_action, time); + } + return TRUE; + } + } + + dest_info->insert_pos = new_info.insert_pos; + dest_info->cell.row = new_info.cell.row; + dest_info->cell.column = new_info.cell.column; + return TRUE; +} + +static void +gtk_cmctree_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint32 time) +{ + GtkCMCTree *ctree; + GtkCMCList *clist; + + g_return_if_fail (GTK_IS_CMCTREE (widget)); + g_return_if_fail (context != NULL); + g_return_if_fail (selection_data != NULL); + + ctree = GTK_CMCTREE (widget); + clist = GTK_CMCLIST (widget); + + if (GTK_CMCLIST_REORDERABLE (clist) && + gtk_drag_get_source_widget (context) == widget && + selection_data->target == + gdk_atom_intern_static_string ("gtk-clist-drag-reorder") && + selection_data->format == 8 && + selection_data->length == sizeof (GtkCMCListCellInfo)) + { + GtkCMCListCellInfo *source_info; + + source_info = (GtkCMCListCellInfo *)(selection_data->data); + if (source_info) + { + GtkCMCListDestInfo dest_info; + GtkCMCTreeNode *source_node; + GtkCMCTreeNode *dest_node; + + drag_dest_cell (clist, x, y, &dest_info); + + source_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, + source_info->row)); + dest_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, + dest_info.cell.row)); + + if (!source_node || !dest_node) + return; + + switch (dest_info.insert_pos) + { + case GTK_CMCLIST_DRAG_NONE: + break; + case GTK_CMCLIST_DRAG_INTO: + if (check_drag (ctree, source_node, dest_node, + dest_info.insert_pos)) + gtk_cmctree_move (ctree, source_node, dest_node, + GTK_CMCTREE_ROW (dest_node)->children); + g_dataset_remove_data (context, "gtk-clist-drag-dest"); + break; + case GTK_CMCLIST_DRAG_BEFORE: + if (check_drag (ctree, source_node, dest_node, + dest_info.insert_pos)) + gtk_cmctree_move (ctree, source_node, + GTK_CMCTREE_ROW (dest_node)->parent, dest_node); + g_dataset_remove_data (context, "gtk-clist-drag-dest"); + break; + case GTK_CMCLIST_DRAG_AFTER: + if (check_drag (ctree, source_node, dest_node, + dest_info.insert_pos)) + gtk_cmctree_move (ctree, source_node, + GTK_CMCTREE_ROW (dest_node)->parent, + GTK_CMCTREE_ROW (dest_node)->sibling); + g_dataset_remove_data (context, "gtk-clist-drag-dest"); + break; + } + } + } +} + +GType +gtk_cmctree_node_get_type (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_pointer_type_register_static ("GtkCMCTreeNode"); + + return our_type; +} diff --git a/src/gtk/gtkcmctree.h b/src/gtk/gtkcmctree.h @@ -0,0 +1,450 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald + * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org> + * + * GtkCMCTree widget for GTK+ + * Copyright (C) 1998 Lars Hamann and Stefan Jeske + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __GTK_CMCTREE_H__ +#define __GTK_CMCTREE_H__ + +#include "gtkcmclist.h" + +G_BEGIN_DECLS + +#define GTK_TYPE_CMCTREE (gtk_cmctree_get_type ()) +#define GTK_CMCTREE(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_CMCTREE, GtkCMCTree)) +#define GTK_CMCTREE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_CMCTREE, GtkCMCTreeClass)) +#define GTK_IS_CMCTREE(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_CMCTREE)) +#define GTK_IS_CMCTREE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CMCTREE)) +#define GTK_CMCTREE_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_CMCTREE, GtkCMCTreeClass)) + +#define GTK_CMCTREE_ROW(_node_) ((GtkCMCTreeRow *)(((GList *)(_node_))->data)) +#define GTK_CMCTREE_NODE(_node_) ((GtkCMCTreeNode *)((_node_))) +#define GTK_CMCTREE_NODE_NEXT(_nnode_) ((GtkCMCTreeNode *)(((GList *)(_nnode_))->next)) +#define GTK_CMCTREE_NODE_PREV(_pnode_) ((GtkCMCTreeNode *)(((GList *)(_pnode_))->prev)) +#define GTK_CMCTREE_FUNC(_func_) ((GtkCMCTreeFunc)(_func_)) + +#define GTK_TYPE_CMCTREE_NODE (gtk_cmctree_node_get_type ()) + +GType gtk_cmctree_pos_get_type (void) G_GNUC_CONST; +#define GTK_TYPE_CMCTREE_POS (gtk_cmctree_pos_get_type()) +GType gtk_cmctree_line_style_get_type (void) G_GNUC_CONST; +#define GTK_TYPE_CMCTREE_LINE_STYLE (gtk_cmctree_line_style_get_type()) +GType gtk_cmctree_expander_style_get_type (void) G_GNUC_CONST; +#define GTK_TYPE_CMCTREE_EXPANDER_STYLE (gtk_cmctree_expander_style_get_type()) +GType gtk_cmctree_expansion_type_get_type (void) G_GNUC_CONST; +#define GTK_TYPE_CMCTREE_EXPANSION_TYPE (gtk_cmctree_expansion_type_get_type()) + +typedef enum +{ + GTK_CMCTREE_POS_BEFORE, + GTK_CMCTREE_POS_AS_CHILD, + GTK_CMCTREE_POS_AFTER +} GtkCMCTreePos; + +typedef enum +{ + GTK_CMCTREE_LINES_NONE, + GTK_CMCTREE_LINES_SOLID, + GTK_CMCTREE_LINES_DOTTED, + GTK_CMCTREE_LINES_TABBED +} GtkCMCTreeLineStyle; + +typedef enum +{ + GTK_CMCTREE_EXPANDER_NONE, + GTK_CMCTREE_EXPANDER_SQUARE, + GTK_CMCTREE_EXPANDER_TRIANGLE, + GTK_CMCTREE_EXPANDER_CIRCULAR +} GtkCMCTreeExpanderStyle; + +typedef enum +{ + GTK_CMCTREE_EXPANSION_EXPAND, + GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE, + GTK_CMCTREE_EXPANSION_COLLAPSE, + GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE, + GTK_CMCTREE_EXPANSION_TOGGLE, + GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE +} GtkCMCTreeExpansionType; + +typedef struct _GtkCMCTree GtkCMCTree; +typedef struct _GtkCMCTreeClass GtkCMCTreeClass; +typedef struct _GtkCMCTreeRow GtkCMCTreeRow; +typedef struct _GtkCMCTreeNode GtkCMCTreeNode; + +typedef void (*GtkCMCTreeFunc) (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data); + +typedef gboolean (*GtkCMCTreeGNodeFunc) (GtkCMCTree *ctree, + guint depth, + GNode *gnode, + GtkCMCTreeNode *cnode, + gpointer data); + +typedef gboolean (*GtkCMCTreeCompareDragFunc) (GtkCMCTree *ctree, + GtkCMCTreeNode *source_node, + GtkCMCTreeNode *new_parent, + GtkCMCTreeNode *new_sibling); + +struct _GtkCMCTree +{ + GtkCMCList clist; + + GdkGC *lines_gc; + + gint tree_indent; + gint tree_spacing; + gint tree_column; + + guint line_style : 2; + guint expander_style : 2; + guint show_stub : 1; + + GtkCMCTreeCompareDragFunc drag_compare; +}; + +struct _GtkCMCTreeClass +{ + GtkCMCListClass parent_class; + + void (*tree_select_row) (GtkCMCTree *ctree, + GtkCMCTreeNode *row, + gint column); + void (*tree_unselect_row) (GtkCMCTree *ctree, + GtkCMCTreeNode *row, + gint column); + void (*tree_expand) (GtkCMCTree *ctree, + GtkCMCTreeNode *node); + void (*tree_collapse) (GtkCMCTree *ctree, + GtkCMCTreeNode *node); + void (*tree_move) (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeNode *new_parent, + GtkCMCTreeNode *new_sibling); + void (*change_focus_row_expansion) (GtkCMCTree *ctree, + GtkCMCTreeExpansionType action); +}; + +struct _GtkCMCTreeRow +{ + GtkCMCListRow row; + + GtkCMCTreeNode *parent; + GtkCMCTreeNode *sibling; + GtkCMCTreeNode *children; + + GdkPixmap *pixmap_closed; + GdkBitmap *mask_closed; + GdkPixmap *pixmap_opened; + GdkBitmap *mask_opened; + + guint16 level; + + guint is_leaf : 1; + guint expanded : 1; +}; + +struct _GtkCMCTreeNode { + GList list; +}; + + +/*********************************************************** + * Creation, insertion, deletion * + ***********************************************************/ + +GType gtk_cmctree_get_type (void); +GtkWidget * gtk_cmctree_new_with_titles (gint columns, + gint tree_column, + gchar *titles[]); +GtkWidget * gtk_cmctree_new (gint columns, + gint tree_column); +GtkCMCTreeNode * gtk_cmctree_insert_node (GtkCMCTree *ctree, + GtkCMCTreeNode *parent, + GtkCMCTreeNode *sibling, + gchar *text[], + guint8 spacing, + GdkPixmap *pixmap_closed, + GdkBitmap *mask_closed, + GdkPixmap *pixmap_opened, + GdkBitmap *mask_opened, + gboolean is_leaf, + gboolean expanded); +void gtk_cmctree_remove_node (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +GtkCMCTreeNode * gtk_cmctree_insert_gnode (GtkCMCTree *ctree, + GtkCMCTreeNode *parent, + GtkCMCTreeNode *sibling, + GNode *gnode, + GtkCMCTreeGNodeFunc func, + gpointer data); +GNode * gtk_cmctree_export_to_gnode (GtkCMCTree *ctree, + GNode *parent, + GNode *sibling, + GtkCMCTreeNode *node, + GtkCMCTreeGNodeFunc func, + gpointer data); + +/*********************************************************** + * Generic recursive functions, querying / finding tree * + * information * + ***********************************************************/ + +void gtk_cmctree_post_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeFunc func, + gpointer data); +void gtk_cmctree_post_recursive_to_depth (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint depth, + GtkCMCTreeFunc func, + gpointer data); +void gtk_cmctree_pre_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeFunc func, + gpointer data); +void gtk_cmctree_pre_recursive_to_depth (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint depth, + GtkCMCTreeFunc func, + gpointer data); +gboolean gtk_cmctree_is_viewable (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +GtkCMCTreeNode * gtk_cmctree_last (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +GtkCMCTreeNode * gtk_cmctree_find_node_ptr (GtkCMCTree *ctree, + GtkCMCTreeRow *ctree_row); +GtkCMCTreeNode * gtk_cmctree_node_nth (GtkCMCTree *ctree, + guint row); +gboolean gtk_cmctree_find (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeNode *child); +gboolean gtk_cmctree_is_ancestor (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeNode *child); +GtkCMCTreeNode * gtk_cmctree_find_by_row_data (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data); +/* returns a GList of all GtkCMCTreeNodes with row->data == data. */ +GList * gtk_cmctree_find_all_by_row_data (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data); +GtkCMCTreeNode * gtk_cmctree_find_by_row_data_custom (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data, + GCompareFunc func); +/* returns a GList of all GtkCMCTreeNodes with row->data == data. */ +GList * gtk_cmctree_find_all_by_row_data_custom (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data, + GCompareFunc func); +gboolean gtk_cmctree_is_hot_spot (GtkCMCTree *ctree, + gint x, + gint y); + +/*********************************************************** + * Tree signals : move, expand, collapse, (un)select * + ***********************************************************/ + +void gtk_cmctree_move (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeNode *new_parent, + GtkCMCTreeNode *new_sibling); +void gtk_cmctree_expand (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +void gtk_cmctree_expand_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +void gtk_cmctree_expand_to_depth (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint depth); +void gtk_cmctree_collapse (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +void gtk_cmctree_collapse_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +void gtk_cmctree_collapse_to_depth (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint depth); +void gtk_cmctree_toggle_expansion (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +void gtk_cmctree_toggle_expansion_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +void gtk_cmctree_select (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +void gtk_cmctree_select_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +void gtk_cmctree_unselect (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +void gtk_cmctree_unselect_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +void gtk_cmctree_real_select_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint state); + +/*********************************************************** + * Analogons of GtkCMCList functions * + ***********************************************************/ + +void gtk_cmctree_node_set_text (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + const gchar *text); +void gtk_cmctree_node_set_pixmap (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + GdkPixmap *pixmap, + GdkBitmap *mask); +void gtk_cmctree_node_set_pixtext (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap, + GdkBitmap *mask); +void gtk_cmctree_set_node_info (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + const gchar *text, + guint8 spacing, + GdkPixmap *pixmap_closed, + GdkBitmap *mask_closed, + GdkPixmap *pixmap_opened, + GdkBitmap *mask_opened, + gboolean is_leaf, + gboolean expanded); +void gtk_cmctree_node_set_shift (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + gint vertical, + gint horizontal); +void gtk_cmctree_node_set_selectable (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gboolean selectable); +gboolean gtk_cmctree_node_get_selectable (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +GtkCMCellType gtk_cmctree_node_get_cell_type (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column); +gboolean gtk_cmctree_node_get_text (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + gchar **text); +gboolean gtk_cmctree_node_get_pixmap (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + GdkPixmap **pixmap, + GdkBitmap **mask); +gboolean gtk_cmctree_node_get_pixtext (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + gchar **text, + guint8 *spacing, + GdkPixmap **pixmap, + GdkBitmap **mask); +gboolean gtk_cmctree_get_node_info (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gchar **text, + guint8 *spacing, + GdkPixmap **pixmap_closed, + GdkBitmap **mask_closed, + GdkPixmap **pixmap_opened, + GdkBitmap **mask_opened, + gboolean *is_leaf, + gboolean *expanded); +void gtk_cmctree_node_set_row_style (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkStyle *style); +GtkStyle * gtk_cmctree_node_get_row_style (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +void gtk_cmctree_node_set_cell_style (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + GtkStyle *style); +GtkStyle * gtk_cmctree_node_get_cell_style (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column); +void gtk_cmctree_node_set_foreground (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + const GdkColor *color); +void gtk_cmctree_node_set_background (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + const GdkColor *color); +void gtk_cmctree_node_set_row_data (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data); +void gtk_cmctree_node_set_row_data_full (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gpointer data, + GtkDestroyNotify destroy); +gpointer gtk_cmctree_node_get_row_data (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +void gtk_cmctree_node_moveto (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + gint column, + gfloat row_align, + gfloat col_align); +GtkVisibility gtk_cmctree_node_is_visible (GtkCMCTree *ctree, + GtkCMCTreeNode *node); + +/*********************************************************** + * GtkCMCTree specific functions * + ***********************************************************/ + +void gtk_cmctree_set_indent (GtkCMCTree *ctree, + gint indent); +void gtk_cmctree_set_spacing (GtkCMCTree *ctree, + gint spacing); +void gtk_cmctree_set_show_stub (GtkCMCTree *ctree, + gboolean show_stub); +void gtk_cmctree_set_line_style (GtkCMCTree *ctree, + GtkCMCTreeLineStyle line_style); +void gtk_cmctree_set_expander_style (GtkCMCTree *ctree, + GtkCMCTreeExpanderStyle expander_style); +void gtk_cmctree_set_drag_compare_func (GtkCMCTree *ctree, + GtkCMCTreeCompareDragFunc cmp_func); + +/*********************************************************** + * Tree sorting functions * + ***********************************************************/ + +void gtk_cmctree_sort_node (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +void gtk_cmctree_sort_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node); + + +#define gtk_cmctree_set_reorderable(t,r) gtk_cmclist_set_reorderable((GtkCMCList*) (t),(r)) + +/* GType for the GtkCMCTreeNode. This is a boxed type, although it uses + * no-op's for the copy and free routines. It is defined in order to + * provide type information for the signal arguments + */ +GType gtk_cmctree_node_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* __GTK_CMCTREE_H__ */ diff --git a/src/gtk/gtkcmoptionmenu.c b/src/gtk/gtkcmoptionmenu.c @@ -0,0 +1,1025 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Jsh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include <config.h> +#include <glib.h> +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> + +#include "claws-marshal.h" +#include "gtkcmoptionmenu.h" + +#define CHILD_LEFT_SPACING 4 +#define CHILD_RIGHT_SPACING 1 +#define CHILD_TOP_SPACING 1 +#define CHILD_BOTTOM_SPACING 1 + +typedef struct _GtkCMOptionMenuProps GtkCMOptionMenuProps; + +struct _GtkCMOptionMenuProps +{ + gboolean interior_focus; + GtkRequisition indicator_size; + GtkBorder indicator_spacing; + gint focus_width; + gint focus_pad; +}; + +static const GtkCMOptionMenuProps default_props = { + TRUE, + { 7, 13 }, + { 7, 5, 2, 2 }, /* Left, right, top, bottom */ + 1, + 0 +}; + +static void gtk_cmoption_menu_destroy (GtkObject *object); +static void gtk_cmoption_menu_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_cmoption_menu_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void gtk_cmoption_menu_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_cmoption_menu_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_cmoption_menu_paint (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_cmoption_menu_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_cmoption_menu_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_cmoption_menu_key_press (GtkWidget *widget, + GdkEventKey *event); +static void gtk_cmoption_menu_selection_done (GtkMenuShell *menu_shell, + GtkCMOptionMenu *option_menu); +static void gtk_cmoption_menu_update_contents (GtkCMOptionMenu *option_menu); +static void gtk_cmoption_menu_remove_contents (GtkCMOptionMenu *option_menu); +static void gtk_cmoption_menu_calc_size (GtkCMOptionMenu *option_menu); +static void gtk_cmoption_menu_position (GtkMenu *menu, + gint *x, + gint *y, + gint *scroll_offet, + gpointer user_data); +static void gtk_cmoption_menu_show_all (GtkWidget *widget); +static void gtk_cmoption_menu_hide_all (GtkWidget *widget); +static gboolean gtk_cmoption_menu_mnemonic_activate (GtkWidget *widget, + gboolean group_cycling); +static GType gtk_cmoption_menu_child_type (GtkContainer *container); +static gint gtk_cmoption_menu_scroll_event (GtkWidget *widget, + GdkEventScroll *event); + +enum +{ + CHANGED, + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_MENU, + LAST_PROP +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (GtkCMOptionMenu, gtk_cmoption_menu, GTK_TYPE_BUTTON) + +static void +gtk_cmoption_menu_class_init (GtkCMOptionMenuClass *class) +{ + GObjectClass *gobject_class; + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + gobject_class = (GObjectClass*) class; + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + signals[CHANGED] = + g_signal_new (("changed"), + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkCMOptionMenuClass, changed), + NULL, NULL, + claws_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + gobject_class->set_property = gtk_cmoption_menu_set_property; + gobject_class->get_property = gtk_cmoption_menu_get_property; + object_class->destroy = gtk_cmoption_menu_destroy; + + widget_class->size_request = gtk_cmoption_menu_size_request; + widget_class->size_allocate = gtk_cmoption_menu_size_allocate; + widget_class->expose_event = gtk_cmoption_menu_expose; + widget_class->button_press_event = gtk_cmoption_menu_button_press; + widget_class->key_press_event = gtk_cmoption_menu_key_press; + widget_class->scroll_event = gtk_cmoption_menu_scroll_event; + widget_class->show_all = gtk_cmoption_menu_show_all; + widget_class->hide_all = gtk_cmoption_menu_hide_all; + widget_class->mnemonic_activate = gtk_cmoption_menu_mnemonic_activate; + + container_class->child_type = gtk_cmoption_menu_child_type; + + g_object_class_install_property (gobject_class, + PROP_MENU, + g_param_spec_object ("menu", + ("Menu"), + ("The menu of options"), + GTK_TYPE_MENU, + G_PARAM_READWRITE)); + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_boxed ("indicator-size", + ("Indicator Size"), + ("Size of dropdown indicator"), + GTK_TYPE_REQUISITION, + G_PARAM_READABLE)); + gtk_widget_class_install_style_property (widget_class, + g_param_spec_boxed ("indicator-spacing", + ("Indicator Spacing"), + ("Spacing around indicator"), + GTK_TYPE_BORDER, + G_PARAM_READABLE)); +} + +static GType +gtk_cmoption_menu_child_type (GtkContainer *container) +{ + return G_TYPE_NONE; +} + +static void +gtk_cmoption_menu_init (GtkCMOptionMenu *option_menu) +{ + GTK_WIDGET_SET_FLAGS (option_menu, GTK_CAN_FOCUS); + GTK_WIDGET_UNSET_FLAGS (option_menu, GTK_CAN_DEFAULT | GTK_RECEIVES_DEFAULT); + + option_menu->menu = NULL; + option_menu->menu_item = NULL; + option_menu->width = 0; + option_menu->height = 0; +} + +GtkWidget* +gtk_cmoption_menu_new (void) +{ + return g_object_new (GTK_TYPE_CMOPTION_MENU, NULL); +} + +GtkWidget* +gtk_cmoption_menu_get_menu (GtkCMOptionMenu *option_menu) +{ + g_return_val_if_fail (GTK_IS_CMOPTION_MENU (option_menu), NULL); + + return option_menu->menu; +} + +static void +gtk_cmoption_menu_detacher (GtkWidget *widget, + GtkMenu *menu) +{ + GtkCMOptionMenu *option_menu; + + g_return_if_fail (GTK_IS_CMOPTION_MENU (widget)); + + option_menu = GTK_CMOPTION_MENU (widget); + g_return_if_fail (option_menu->menu == (GtkWidget*) menu); + + gtk_cmoption_menu_remove_contents (option_menu); + g_signal_handlers_disconnect_by_func (option_menu->menu, + gtk_cmoption_menu_selection_done, + option_menu); + g_signal_handlers_disconnect_by_func (option_menu->menu, + gtk_cmoption_menu_calc_size, + option_menu); + + option_menu->menu = NULL; + g_object_notify (G_OBJECT (option_menu), "menu"); +} + +void +gtk_cmoption_menu_set_menu (GtkCMOptionMenu *option_menu, + GtkWidget *menu) +{ + g_return_if_fail (GTK_IS_CMOPTION_MENU (option_menu)); + g_return_if_fail (GTK_IS_MENU (menu)); + + if (option_menu->menu != menu) + { + gtk_cmoption_menu_remove_menu (option_menu); + + option_menu->menu = menu; + gtk_menu_attach_to_widget (GTK_MENU (menu), + GTK_WIDGET (option_menu), + gtk_cmoption_menu_detacher); + + gtk_cmoption_menu_calc_size (option_menu); + + g_signal_connect_after (option_menu->menu, "selection-done", + G_CALLBACK (gtk_cmoption_menu_selection_done), + option_menu); + g_signal_connect_swapped (option_menu->menu, "size_request", + G_CALLBACK (gtk_cmoption_menu_calc_size), + option_menu); + + if (GTK_WIDGET (option_menu)->parent) + gtk_widget_queue_resize (GTK_WIDGET (option_menu)); + + gtk_cmoption_menu_update_contents (option_menu); + + g_object_notify (G_OBJECT (option_menu), "menu"); + } +} + +void +gtk_cmoption_menu_remove_menu (GtkCMOptionMenu *option_menu) +{ + g_return_if_fail (GTK_IS_CMOPTION_MENU (option_menu)); + + if (option_menu->menu) + { + if (GTK_MENU_SHELL (option_menu->menu)->active) + gtk_menu_shell_cancel (GTK_MENU_SHELL (option_menu->menu)); + + gtk_menu_detach (GTK_MENU (option_menu->menu)); + } +} + +void +gtk_cmoption_menu_set_history (GtkCMOptionMenu *option_menu, + guint index) +{ + GtkWidget *menu_item; + + g_return_if_fail (GTK_IS_CMOPTION_MENU (option_menu)); + + if (option_menu->menu) + { + gtk_menu_set_active (GTK_MENU (option_menu->menu), index); + menu_item = gtk_menu_get_active (GTK_MENU (option_menu->menu)); + + if (menu_item != option_menu->menu_item) + gtk_cmoption_menu_update_contents (option_menu); + } +} + +/** + * gtk_cmoption_menu_get_history: + * @option_menu: a #GtkCMOptionMenu + * + * Retrieves the index of the currently selected menu item. The menu + * items are numbered from top to bottom, starting with 0. + * + * Return value: index of the selected menu item, or -1 if there are no menu items + * Deprecated: 2.4: Use #GtkComboBox instead. + **/ +gint +gtk_cmoption_menu_get_history (GtkCMOptionMenu *option_menu) +{ + GtkWidget *active_widget; + + g_return_val_if_fail (GTK_IS_CMOPTION_MENU (option_menu), -1); + + if (option_menu->menu) + { + active_widget = gtk_menu_get_active (GTK_MENU (option_menu->menu)); + + if (active_widget) + return g_list_index (GTK_MENU_SHELL (option_menu->menu)->children, + active_widget); + else + return -1; + } + else + return -1; +} + +static void +gtk_cmoption_menu_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkCMOptionMenu *option_menu = GTK_CMOPTION_MENU (object); + + switch (prop_id) + { + case PROP_MENU: + gtk_cmoption_menu_set_menu (option_menu, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_cmoption_menu_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkCMOptionMenu *option_menu = GTK_CMOPTION_MENU (object); + + switch (prop_id) + { + case PROP_MENU: + g_value_set_object (value, option_menu->menu); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_cmoption_menu_destroy (GtkObject *object) +{ + GtkCMOptionMenu *option_menu; + + g_return_if_fail (GTK_IS_CMOPTION_MENU (object)); + + option_menu = GTK_CMOPTION_MENU (object); + + if (option_menu->menu) + gtk_widget_destroy (option_menu->menu); + + if (GTK_OBJECT_CLASS (gtk_cmoption_menu_parent_class)->destroy) + (* GTK_OBJECT_CLASS (gtk_cmoption_menu_parent_class)->destroy) (object); +} + +static void +gtk_cmoption_menu_get_props (GtkCMOptionMenu *option_menu, + GtkCMOptionMenuProps *props) +{ + GtkRequisition *indicator_size; + GtkBorder *indicator_spacing; + + gtk_widget_style_get (GTK_WIDGET (option_menu), + "indicator-size", &indicator_size, + "indicator-spacing", &indicator_spacing, + "interior-focus", &props->interior_focus, + "focus-line-width", &props->focus_width, + "focus-padding", &props->focus_pad, + NULL); + + if (indicator_size) + props->indicator_size = *indicator_size; + else + props->indicator_size = default_props.indicator_size; + + if (indicator_spacing) + props->indicator_spacing = *indicator_spacing; + else + props->indicator_spacing = default_props.indicator_spacing; + + gtk_requisition_free (indicator_size); + gtk_border_free (indicator_spacing); +} + +static void +gtk_cmoption_menu_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkCMOptionMenu *option_menu = GTK_CMOPTION_MENU (widget); + GtkCMOptionMenuProps props; + gint tmp; + GtkRequisition child_requisition = { 0, 0 }; + + gtk_cmoption_menu_get_props (option_menu, &props); + + if (GTK_BIN (option_menu)->child && GTK_WIDGET_VISIBLE (GTK_BIN (option_menu)->child)) + { + gtk_widget_size_request (GTK_BIN (option_menu)->child, &child_requisition); + + requisition->width += child_requisition.width; + requisition->height += child_requisition.height; + } + + requisition->width = ((GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->xthickness + props.focus_pad) * 2 + + MAX (child_requisition.width, option_menu->width) + + props.indicator_size.width + + props.indicator_spacing.left + props.indicator_spacing.right + + CHILD_LEFT_SPACING + CHILD_RIGHT_SPACING + props.focus_width * 2); + requisition->height = ((GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->ythickness + props.focus_pad) * 2 + + MAX (child_requisition.height, option_menu->height) + + CHILD_TOP_SPACING + CHILD_BOTTOM_SPACING + props.focus_width * 2); + + tmp = (requisition->height - MAX (child_requisition.height, option_menu->height) + + props.indicator_size.height + props.indicator_spacing.top + props.indicator_spacing.bottom); + requisition->height = MAX (requisition->height, tmp); +} + +static void +gtk_cmoption_menu_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkWidget *child; + GtkButton *button = GTK_BUTTON (widget); + GtkAllocation child_allocation; + GtkCMOptionMenuProps props; + gint border_width; + + gtk_cmoption_menu_get_props (GTK_CMOPTION_MENU (widget), &props); + border_width = GTK_CONTAINER (widget)->border_width; + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (button->event_window, + allocation->x + border_width, allocation->y + border_width, + allocation->width - border_width * 2, allocation->height - border_width * 2); + + child = GTK_BIN (widget)->child; + if (child && GTK_WIDGET_VISIBLE (child)) + { + gint xthickness = GTK_WIDGET (widget)->style->xthickness; + gint ythickness = GTK_WIDGET (widget)->style->ythickness; + + child_allocation.x = widget->allocation.x + border_width + xthickness + props.focus_width + props.focus_pad + CHILD_LEFT_SPACING; + child_allocation.y = widget->allocation.y + border_width + ythickness + props.focus_width + props.focus_pad + CHILD_TOP_SPACING; + child_allocation.width = MAX (1, allocation->width - (border_width + xthickness + props.focus_width + props.focus_pad) * 2 - + props.indicator_size.width - props.indicator_spacing.left - props.indicator_spacing.right - + CHILD_LEFT_SPACING - CHILD_RIGHT_SPACING); + child_allocation.height = MAX (1, allocation->height - (border_width + ythickness + props.focus_width + props.focus_pad) * 2 - + CHILD_TOP_SPACING - CHILD_BOTTOM_SPACING); + + if (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_RTL) + child_allocation.x += props.indicator_size.width + props.indicator_spacing.left + props.indicator_spacing.right; + + gtk_widget_size_allocate (child, &child_allocation); + } +} + +static void +gtk_cmoption_menu_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GdkRectangle button_area; + GtkCMOptionMenuProps props; + gint border_width; + gint tab_x; + + g_return_if_fail (GTK_IS_CMOPTION_MENU (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + border_width = GTK_CONTAINER (widget)->border_width; + gtk_cmoption_menu_get_props (GTK_CMOPTION_MENU (widget), &props); + + button_area.x = widget->allocation.x + border_width; + button_area.y = widget->allocation.y + border_width; + button_area.width = widget->allocation.width - 2 * border_width; + button_area.height = widget->allocation.height - 2 * border_width; + + if (!props.interior_focus && GTK_WIDGET_HAS_FOCUS (widget)) + { + button_area.x += props.focus_width + props.focus_pad; + button_area.y += props.focus_width + props.focus_pad; + button_area.width -= 2 * (props.focus_width + props.focus_pad); + button_area.height -= 2 * (props.focus_width + props.focus_pad); + } + + gtk_paint_box (widget->style, widget->window, + GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT, + area, widget, "optionmenu", + button_area.x, button_area.y, + button_area.width, button_area.height); + + if (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_RTL) + tab_x = button_area.x + props.indicator_spacing.right + + widget->style->xthickness; + else + tab_x = button_area.x + button_area.width - + props.indicator_size.width - props.indicator_spacing.right - + widget->style->xthickness; + + gtk_paint_tab (widget->style, widget->window, + GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT, + area, widget, "optionmenutab", + tab_x, + button_area.y + (button_area.height - props.indicator_size.height) / 2, + props.indicator_size.width, props.indicator_size.height); + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + if (props.interior_focus) + { + button_area.x += widget->style->xthickness + props.focus_pad; + button_area.y += widget->style->ythickness + props.focus_pad; + button_area.width -= 2 * (widget->style->xthickness + props.focus_pad) + + props.indicator_spacing.left + + props.indicator_spacing.right + + props.indicator_size.width; + button_area.height -= 2 * (widget->style->ythickness + props.focus_pad); + if (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_RTL) + button_area.x += props.indicator_spacing.left + + props.indicator_spacing.right + + props.indicator_size.width; + } + else + { + button_area.x -= props.focus_width + props.focus_pad; + button_area.y -= props.focus_width + props.focus_pad; + button_area.width += 2 * (props.focus_width + props.focus_pad); + button_area.height += 2 * (props.focus_width + props.focus_pad); + } + + gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget), + area, widget, "button", + button_area.x, + button_area.y, + button_area.width, + button_area.height); + } + } +} + +static gint +gtk_cmoption_menu_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + g_return_val_if_fail (GTK_IS_CMOPTION_MENU (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_cmoption_menu_paint (widget, &event->area); + + + /* The following code tries to draw the child in two places at + * once. It fails miserably for several reasons + * + * - If the child is not no-window, removing generates + * more expose events. Bad, bad, bad. + * + * - Even if the child is no-window, removing it now (properly) + * clears the space where it was, so it does no good + */ + +#if 0 + remove_child = FALSE; + child = GTK_BUTTON (widget)->child; + + if (!child) + { + if (!GTK_CMOPTION_MENU (widget)->menu) + return FALSE; + gtk_cmoption_menu_update_contents (GTK_CMOPTION_MENU (widget)); + child = GTK_BUTTON (widget)->child; + if (!child) + return FALSE; + remove_child = TRUE; + } + + child_event = *event; + + if (GTK_WIDGET_NO_WINDOW (child) && + gtk_widget_intersect (child, &event->area, &child_event.area)) + gtk_widget_event (child, (GdkEvent*) &child_event); + + if (remove_child) + gtk_cmoption_menu_remove_contents (GTK_CMOPTION_MENU (widget)); +#else + if (GTK_BIN (widget)->child) + gtk_container_propagate_expose (GTK_CONTAINER (widget), + GTK_BIN (widget)->child, + event); +#endif /* 0 */ + } + + return FALSE; +} + +static gint +gtk_cmoption_menu_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkCMOptionMenu *option_menu; + GtkWidget *menu_item; + + g_return_val_if_fail (GTK_IS_CMOPTION_MENU (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + option_menu = GTK_CMOPTION_MENU (widget); + + if ((event->type == GDK_BUTTON_PRESS) && + (event->button == 1)) + { + gtk_cmoption_menu_remove_contents (option_menu); + gtk_menu_popup (GTK_MENU (option_menu->menu), NULL, NULL, + gtk_cmoption_menu_position, option_menu, + event->button, event->time); + menu_item = gtk_menu_get_active (GTK_MENU (option_menu->menu)); + if (menu_item) + gtk_menu_shell_select_item (GTK_MENU_SHELL (option_menu->menu), menu_item); + return TRUE; + } + + return FALSE; +} + +static gint +gtk_cmoption_menu_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + GtkCMOptionMenu *option_menu; + GtkWidget *menu_item; + + g_return_val_if_fail (GTK_IS_CMOPTION_MENU (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + option_menu = GTK_CMOPTION_MENU (widget); + + switch (event->keyval) + { + case GDK_KP_Space: + case GDK_space: + gtk_cmoption_menu_remove_contents (option_menu); + gtk_menu_popup (GTK_MENU (option_menu->menu), NULL, NULL, + gtk_cmoption_menu_position, option_menu, + 0, event->time); + menu_item = gtk_menu_get_active (GTK_MENU (option_menu->menu)); + if (menu_item) + gtk_menu_shell_select_item (GTK_MENU_SHELL (option_menu->menu), menu_item); + return TRUE; + } + + return FALSE; +} + +static void +gtk_cmoption_menu_selection_done (GtkMenuShell *menu_shell, + GtkCMOptionMenu *option_menu) +{ + g_return_if_fail (menu_shell != NULL); + g_return_if_fail (GTK_IS_CMOPTION_MENU (option_menu)); + + gtk_cmoption_menu_update_contents (option_menu); +} + +static void +gtk_cmoption_menu_changed (GtkCMOptionMenu *option_menu) +{ + g_return_if_fail (GTK_IS_CMOPTION_MENU (option_menu)); + + g_signal_emit (option_menu, signals[CHANGED], 0); +} + +static void +gtk_cmoption_menu_select_first_sensitive (GtkCMOptionMenu *option_menu) +{ + if (option_menu->menu) + { + GList *children = GTK_MENU_SHELL (option_menu->menu)->children; + gint index = 0; + + while (children) + { + if (GTK_WIDGET_SENSITIVE (children->data)) + { + gtk_cmoption_menu_set_history (option_menu, index); + return; + } + + children = children->next; + index++; + } + } +} + +static void +gtk_cmoption_menu_item_state_changed_cb (GtkWidget *widget, + GtkStateType previous_state, + GtkCMOptionMenu *option_menu) +{ + GtkWidget *child = GTK_BIN (option_menu)->child; + + if (child && GTK_WIDGET_SENSITIVE (child) != GTK_WIDGET_IS_SENSITIVE (widget)) + gtk_widget_set_sensitive (child, GTK_WIDGET_IS_SENSITIVE (widget)); +} + +static void +gtk_cmoption_menu_item_destroy_cb (GtkWidget *widget, + GtkCMOptionMenu *option_menu) +{ + GtkWidget *child = GTK_BIN (option_menu)->child; + + if (child) + { + g_object_ref (child); + gtk_cmoption_menu_remove_contents (option_menu); + gtk_widget_destroy (child); + g_object_unref (child); + + gtk_cmoption_menu_select_first_sensitive (option_menu); + } +} + +static void +gtk_cmoption_menu_update_contents (GtkCMOptionMenu *option_menu) +{ + GtkWidget *child; + GtkRequisition child_requisition; + + g_return_if_fail (GTK_IS_CMOPTION_MENU (option_menu)); + + if (option_menu->menu) + { + GtkWidget *old_item = option_menu->menu_item; + + gtk_cmoption_menu_remove_contents (option_menu); + + option_menu->menu_item = gtk_menu_get_active (GTK_MENU (option_menu->menu)); + if (option_menu->menu_item) + { + g_object_ref (option_menu->menu_item); + child = GTK_BIN (option_menu->menu_item)->child; + if (child) + { + if (!GTK_WIDGET_IS_SENSITIVE (option_menu->menu_item)) + gtk_widget_set_sensitive (child, FALSE); + gtk_widget_reparent (child, GTK_WIDGET (option_menu)); + } + + g_signal_connect (option_menu->menu_item, "state_changed", + G_CALLBACK (gtk_cmoption_menu_item_state_changed_cb), option_menu); + g_signal_connect (option_menu->menu_item, "destroy", + G_CALLBACK (gtk_cmoption_menu_item_destroy_cb), option_menu); + + gtk_widget_size_request (child, &child_requisition); + gtk_widget_size_allocate (GTK_WIDGET (option_menu), + &(GTK_WIDGET (option_menu)->allocation)); + + if (GTK_WIDGET_DRAWABLE (option_menu)) + gtk_widget_queue_draw (GTK_WIDGET (option_menu)); + } + + if (old_item != option_menu->menu_item) + gtk_cmoption_menu_changed (option_menu); + } +} + +static void +gtk_cmoption_menu_remove_contents (GtkCMOptionMenu *option_menu) +{ + GtkWidget *child; + + g_return_if_fail (GTK_IS_CMOPTION_MENU (option_menu)); + + if (option_menu->menu_item) + { + child = GTK_BIN (option_menu)->child; + + if (child) + { + gtk_widget_set_sensitive (child, TRUE); + gtk_widget_set_state (child, GTK_STATE_NORMAL); + gtk_widget_reparent (child, option_menu->menu_item); + } + + g_signal_handlers_disconnect_by_func (option_menu->menu_item, + gtk_cmoption_menu_item_state_changed_cb, + option_menu); + g_signal_handlers_disconnect_by_func (option_menu->menu_item, + gtk_cmoption_menu_item_destroy_cb, + option_menu); + + g_object_unref (option_menu->menu_item); + option_menu->menu_item = NULL; + } +} + +static void +gtk_cmoption_menu_calc_size (GtkCMOptionMenu *option_menu) +{ + GtkWidget *child; + GList *children; + GtkRequisition child_requisition; + gint old_width = option_menu->width; + gint old_height = option_menu->height; + + g_return_if_fail (GTK_IS_CMOPTION_MENU (option_menu)); + + option_menu->width = 0; + option_menu->height = 0; + + if (option_menu->menu) + { + children = GTK_MENU_SHELL (option_menu->menu)->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child)) + { + GtkWidget *inner = GTK_BIN (child)->child; + + if (inner) + { + gtk_widget_size_request (inner, &child_requisition); + + option_menu->width = MAX (option_menu->width, child_requisition.width); + option_menu->height = MAX (option_menu->height, child_requisition.height); + } + } + } + } + + if (old_width != option_menu->width || old_height != option_menu->height) + gtk_widget_queue_resize (GTK_WIDGET (option_menu)); +} + +static void +gtk_cmoption_menu_position (GtkMenu *menu, + gint *x, + gint *y, + gboolean *push_in, + gpointer user_data) +{ + GtkCMOptionMenu *option_menu; + GtkWidget *active; + GtkWidget *child; + GtkWidget *widget; + GtkRequisition requisition; + GList *children; + gint screen_width; + gint menu_xpos; + gint menu_ypos; + gint menu_width; + + g_return_if_fail (GTK_IS_CMOPTION_MENU (user_data)); + + option_menu = GTK_CMOPTION_MENU (user_data); + widget = GTK_WIDGET (option_menu); + + gtk_widget_get_child_requisition (GTK_WIDGET (menu), &requisition); + menu_width = requisition.width; + + active = gtk_menu_get_active (GTK_MENU (option_menu->menu)); + gdk_window_get_origin (widget->window, &menu_xpos, &menu_ypos); + + menu_xpos += widget->allocation.x; + menu_ypos += widget->allocation.y + widget->allocation.height / 2 - 2; + + if (active != NULL) + { + gtk_widget_get_child_requisition (active, &requisition); + menu_ypos -= requisition.height / 2; + } + + children = GTK_MENU_SHELL (option_menu->menu)->children; + while (children) + { + child = children->data; + + if (active == child) + break; + + if (GTK_WIDGET_VISIBLE (child)) + { + gtk_widget_get_child_requisition (child, &requisition); + menu_ypos -= requisition.height; + } + + children = children->next; + } + + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) + menu_xpos = menu_xpos + widget->allocation.width - menu_width; + + /* Clamp the position on screen */ + screen_width = gdk_screen_get_width (gtk_widget_get_screen (widget)); + + if (menu_xpos < 0) + menu_xpos = 0; + else if ((menu_xpos + menu_width) > screen_width) + menu_xpos -= ((menu_xpos + menu_width) - screen_width); + + *x = menu_xpos; + *y = menu_ypos; + *push_in = TRUE; +} + + +static void +gtk_cmoption_menu_show_all (GtkWidget *widget) +{ + GtkContainer *container; + GtkCMOptionMenu *option_menu; + + g_return_if_fail (GTK_IS_CMOPTION_MENU (widget)); + container = GTK_CONTAINER (widget); + option_menu = GTK_CMOPTION_MENU (widget); + + gtk_widget_show (widget); + gtk_container_foreach (container, (GtkCallback) gtk_widget_show_all, NULL); + if (option_menu->menu) + gtk_widget_show_all (option_menu->menu); + if (option_menu->menu_item) + gtk_widget_show_all (option_menu->menu_item); +} + + +static void +gtk_cmoption_menu_hide_all (GtkWidget *widget) +{ + GtkContainer *container; + + g_return_if_fail (GTK_IS_CMOPTION_MENU (widget)); + container = GTK_CONTAINER (widget); + + gtk_widget_hide (widget); + gtk_container_foreach (container, (GtkCallback) gtk_widget_hide_all, NULL); +} + +static gboolean +gtk_cmoption_menu_mnemonic_activate (GtkWidget *widget, + gboolean group_cycling) +{ + gtk_widget_grab_focus (widget); + return TRUE; +} + +static gint +gtk_cmoption_menu_scroll_event (GtkWidget *widget, + GdkEventScroll *event) +{ + GtkCMOptionMenu *option_menu = GTK_CMOPTION_MENU (widget); + gint index; + gint n_children; + gint index_dir; + GList *l; + GtkMenuItem *item; + + index = gtk_cmoption_menu_get_history (option_menu); + + if (index != -1) + { + n_children = g_list_length (GTK_MENU_SHELL (option_menu->menu)->children); + + if (event->direction == GDK_SCROLL_UP) + index_dir = -1; + else + index_dir = 1; + + + while (TRUE) + { + index += index_dir; + + if (index < 0) + break; + if (index >= n_children) + break; + + l = g_list_nth (GTK_MENU_SHELL (option_menu->menu)->children, index); + item = GTK_MENU_ITEM (l->data); + if (GTK_WIDGET_VISIBLE (item) && GTK_WIDGET_IS_SENSITIVE (item)) + { + gtk_cmoption_menu_set_history (option_menu, index); + gtk_menu_item_activate (GTK_MENU_ITEM (item)); + break; + } + + } + } + + return TRUE; +} + diff --git a/src/gtk/gtkcmoptionmenu.h b/src/gtk/gtkcmoptionmenu.h @@ -0,0 +1,86 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __GTK_CMOPTION_MENU_H__ +#define __GTK_CMOPTION_MENU_H__ + + +#include <gdk/gdk.h> +#include <gtk/gtkbutton.h> + + +G_BEGIN_DECLS + +#define GTK_TYPE_CMOPTION_MENU (gtk_cmoption_menu_get_type ()) +#define GTK_CMOPTION_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CMOPTION_MENU, GtkCMOptionMenu)) +#define GTK_CMOPTION_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_CMOPTION_MENU, GtkCMOptionMenuClass)) +#define GTK_IS_CMOPTION_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CMOPTION_MENU)) +#define GTK_IS_CMOPTION_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CMOPTION_MENU)) +#define GTK_CMOPTION_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CMOPTION_MENU, GtkCMOptionMenuClass)) + + +typedef struct _GtkCMOptionMenu GtkCMOptionMenu; +typedef struct _GtkCMOptionMenuClass GtkCMOptionMenuClass; + +struct _GtkCMOptionMenu +{ + GtkButton button; + + GtkWidget *menu; + GtkWidget *menu_item; + + guint16 width; + guint16 height; +}; + +struct _GtkCMOptionMenuClass +{ + GtkButtonClass parent_class; + + void (*changed) (GtkCMOptionMenu *option_menu); + + /* Padding for future expansion */ + void (*_gtk_reserved1) (void); + void (*_gtk_reserved2) (void); + void (*_gtk_reserved3) (void); + void (*_gtk_reserved4) (void); +}; + + +GType gtk_cmoption_menu_get_type (void) G_GNUC_CONST; +GtkWidget* gtk_cmoption_menu_new (void); +GtkWidget* gtk_cmoption_menu_get_menu (GtkCMOptionMenu *option_menu); +void gtk_cmoption_menu_set_menu (GtkCMOptionMenu *option_menu, + GtkWidget *menu); +void gtk_cmoption_menu_remove_menu (GtkCMOptionMenu *option_menu); +gint gtk_cmoption_menu_get_history (GtkCMOptionMenu *option_menu); +void gtk_cmoption_menu_set_history (GtkCMOptionMenu *option_menu, + guint index_); + + +G_END_DECLS + +#endif /* __GTK_CMOPTION_MENU_H__ */ diff --git a/src/gtk/gtksctree.c b/src/gtk/gtksctree.c @@ -34,10 +34,10 @@ #include "prefs_common.h" #include "utils.h" -#define CLIST_UNFROZEN(clist) (((GtkCList*) (clist))->freeze_count == 0) +#define CLIST_UNFROZEN(clist) (((GtkCMCList*) (clist))->freeze_count == 0) #define CLIST_REFRESH(clist) G_STMT_START { \ if (CLIST_UNFROZEN (clist)) \ - GTK_CLIST_GET_CLASS (clist)->refresh ((GtkCList*) (clist)); \ + GTK_CMCLIST_GET_CLASS (clist)->refresh ((GtkCMCList*) (clist)); \ } G_STMT_END #define CELL_SPACING 1 #define CLIST_OPTIMUM_SIZE 64 @@ -83,39 +83,39 @@ static void gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *co gint x, gint y, GtkSelectionData *data, guint info, guint time); -static void gtk_sctree_clear (GtkCList *clist); -static void gtk_sctree_real_unselect_all (GtkCList *clist); -static void gtk_sctree_collapse (GtkCTree *ctree, GtkCTreeNode *node); +static void gtk_sctree_clear (GtkCMCList *clist); +static void gtk_sctree_real_unselect_all (GtkCMCList *clist); +static void gtk_sctree_collapse (GtkCMCTree *ctree, GtkCMCTreeNode *node); -static void stree_sort (GtkCTree *ctree, GtkCTreeNode *node, gpointer data); -void gtk_sctree_sort_node (GtkCTree *ctree, GtkCTreeNode *node); -void gtk_sctree_sort_recursive (GtkCTree *ctree, GtkCTreeNode *node); - -static void gtk_sctree_link (GtkCTree *ctree, - GtkCTreeNode *node, - GtkCTreeNode *parent, - GtkCTreeNode *sibling, +static void stree_sort (GtkCMCTree *ctree, GtkCMCTreeNode *node, gpointer data); +void gtk_sctree_sort_node (GtkCMCTree *ctree, GtkCMCTreeNode *node); +void gtk_sctree_sort_recursive (GtkCMCTree *ctree, GtkCMCTreeNode *node); + +static void gtk_sctree_link (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeNode *parent, + GtkCMCTreeNode *sibling, gboolean update_focus_row); -static void gtk_sctree_unlink (GtkCTree *ctree, - GtkCTreeNode *node, +static void gtk_sctree_unlink (GtkCMCTree *ctree, + GtkCMCTreeNode *node, gboolean update_focus_row); -static void stree_update_level (GtkCTree *ctree, - GtkCTreeNode *node, +static void stree_update_level (GtkCMCTree *ctree, + GtkCMCTreeNode *node, gpointer data); -static GtkCTreeNode * gtk_sctree_last_visible (GtkCTree *ctree, - GtkCTreeNode *node); -static void gtk_sctree_real_tree_expand (GtkCTree *ctree, - GtkCTreeNode *node); +static GtkCMCTreeNode * gtk_sctree_last_visible (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +static void gtk_sctree_real_tree_expand (GtkCMCTree *ctree, + GtkCMCTreeNode *node); static void -sreal_tree_move (GtkCTree *ctree, - GtkCTreeNode *node, - GtkCTreeNode *new_parent, - GtkCTreeNode *new_sibling); +sreal_tree_move (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeNode *new_parent, + GtkCMCTreeNode *new_sibling); -static GtkCTreeClass *parent_class; +static GtkCMCTreeClass *parent_class; static guint sctree_signals[LAST_SIGNAL]; @@ -148,7 +148,7 @@ gtk_sctree_get_type (void) (GInstanceInitFunc) gtk_sctree_init, }; - sctree_type = g_type_register_static (GTK_TYPE_CTREE, "GtkSCTree", &sctree_info, (GTypeFlags)0); + sctree_type = g_type_register_static (GTK_TYPE_CMCTREE, "GtkSCTree", &sctree_info, (GTypeFlags)0); } return sctree_type; @@ -192,7 +192,7 @@ gtk_sctree_draw_cell_pixmap (GdkWindow *window, height = clip_rectangle->y + clip_rectangle->height - y; if (width > 0 && height > 0) - gdk_draw_pixmap (window, fg_gc, pixmap, xsrc, ysrc, x, y, width, height); + gdk_draw_drawable (window, fg_gc, pixmap, xsrc, ysrc, x, y, width, height); if (mask) { @@ -204,8 +204,8 @@ gtk_sctree_draw_cell_pixmap (GdkWindow *window, } static void -gtk_sctree_get_cell_style (GtkCList *clist, - GtkCListRow *clist_row, +gtk_sctree_get_cell_style (GtkCMCList *clist, + GtkCMCListRow *clist_row, gint state, gint row, gint column, @@ -270,26 +270,26 @@ gtk_sctree_get_cell_style (GtkCList *clist, } static gint -gtk_sctree_draw_expander (GtkCTree *ctree, - GtkCTreeRow *ctree_row, +gtk_sctree_draw_expander (GtkCMCTree *ctree, + GtkCMCTreeRow *ctree_row, GtkStyle *style, GdkRectangle *clip_rectangle, gint x) { - GtkCList *clist; + GtkCMCList *clist; GdkPoint points[3]; gint justification_factor; gint y; - if (ctree->expander_style == GTK_CTREE_EXPANDER_NONE) + if (ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE) return x; - clist = GTK_CLIST (ctree); + clist = GTK_CMCLIST (ctree); if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT) justification_factor = -1; else justification_factor = 1; - if (!GTK_CLIST_ROW_HEIGHT_SET(GTK_CLIST(clist))) + if (!GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist))) y = (clip_rectangle->y + (clip_rectangle->height - PM_SIZE) / 2 - (clip_rectangle->height + 1) % 2); else @@ -300,12 +300,12 @@ gtk_sctree_draw_expander (GtkCTree *ctree, { switch (ctree->expander_style) { - case GTK_CTREE_EXPANDER_NONE: + case GTK_CMCTREE_EXPANDER_NONE: return x; - case GTK_CTREE_EXPANDER_TRIANGLE: + case GTK_CMCTREE_EXPANDER_TRIANGLE: return x + justification_factor * (PM_SIZE + 3); - case GTK_CTREE_EXPANDER_SQUARE: - case GTK_CTREE_EXPANDER_CIRCULAR: + case GTK_CMCTREE_EXPANDER_SQUARE: + case GTK_CMCTREE_EXPANDER_CIRCULAR: return x + justification_factor * (PM_SIZE + 1); } } @@ -315,9 +315,9 @@ gtk_sctree_draw_expander (GtkCTree *ctree, switch (ctree->expander_style) { - case GTK_CTREE_EXPANDER_NONE: + case GTK_CMCTREE_EXPANDER_NONE: break; - case GTK_CTREE_EXPANDER_TRIANGLE: + case GTK_CMCTREE_EXPANDER_TRIANGLE: if (ctree_row->expanded) { points[0].x = x; @@ -346,12 +346,12 @@ gtk_sctree_draw_expander (GtkCTree *ctree, x += justification_factor * (PM_SIZE + 3); break; - case GTK_CTREE_EXPANDER_SQUARE: - case GTK_CTREE_EXPANDER_CIRCULAR: + case GTK_CMCTREE_EXPANDER_SQUARE: + case GTK_CMCTREE_EXPANDER_CIRCULAR: if (justification_factor == -1) x += justification_factor * (PM_SIZE + 1); - if (ctree->expander_style == GTK_CTREE_EXPANDER_CIRCULAR) + if (ctree->expander_style == GTK_CMCTREE_EXPANDER_CIRCULAR) { gdk_draw_arc (clist->clist_window, style->base_gc[GTK_STATE_NORMAL], TRUE, x, y, PM_SIZE, PM_SIZE, 0, 360 * 64); @@ -388,8 +388,8 @@ gtk_sctree_draw_expander (GtkCTree *ctree, } static gint -gtk_sctree_draw_lines (GtkCTree *ctree, - GtkCTreeRow *ctree_row, +gtk_sctree_draw_lines (GtkCMCTree *ctree, + GtkCMCTreeRow *ctree_row, gint row, gint column, gint state, @@ -399,9 +399,9 @@ gtk_sctree_draw_lines (GtkCTree *ctree, GdkRectangle *area, GtkStyle *style) { - GtkCList *clist; - GtkCTreeNode *node; - GtkCTreeNode *parent; + GtkCMCList *clist; + GtkCMCTreeNode *node; + GtkCMCTreeNode *parent; GdkRectangle tree_rectangle; GdkRectangle tc_rectangle; GdkGC *bg_gc; @@ -416,7 +416,7 @@ gtk_sctree_draw_lines (GtkCTree *ctree, gint justify_right; gint justification_factor; - clist = GTK_CLIST (ctree); + clist = GTK_CMCLIST (ctree); ycenter = clip_rectangle->y + (clip_rectangle->height / 2); justify_right = (clist->column[column].justification == GTK_JUSTIFY_RIGHT); @@ -434,9 +434,9 @@ gtk_sctree_draw_lines (GtkCTree *ctree, switch (ctree->line_style) { - case GTK_CTREE_LINES_NONE: + case GTK_CMCTREE_LINES_NONE: break; - case GTK_CTREE_LINES_TABBED: + case GTK_CMCTREE_LINES_TABBED: xcenter = offset + justification_factor * TAB_SIZE; column_right = (COLUMN_LEFT_XPIXEL (clist, ctree->tree_column) + @@ -474,9 +474,9 @@ gtk_sctree_draw_lines (GtkCTree *ctree, if (!ctree_row->sibling || (ctree_row->children && ctree_row->expanded)) { - node = gtk_ctree_find_node_ptr (ctree, ctree_row); - if (GTK_CTREE_NODE_NEXT (node)) - next_level = GTK_CTREE_ROW (GTK_CTREE_NODE_NEXT (node))->level; + node = gtk_cmctree_find_node_ptr (ctree, ctree_row); + if (GTK_CMCTREE_NODE_NEXT (node)) + next_level = GTK_CMCTREE_ROW (GTK_CMCTREE_NODE_NEXT (node))->level; else next_level = 0; } @@ -491,7 +491,7 @@ gtk_sctree_draw_lines (GtkCTree *ctree, if ((justify_right && xcenter < column_left) || (!justify_right && xcenter > column_right)) { - node = GTK_CTREE_ROW (node)->parent; + node = GTK_CMCTREE_ROW (node)->parent; continue; } @@ -514,12 +514,12 @@ gtk_sctree_draw_lines (GtkCTree *ctree, if (!area || gdk_rectangle_intersect (area, &tree_rectangle, &tc_rectangle)) { - gtk_sctree_get_cell_style (clist, &GTK_CTREE_ROW (node)->row, + gtk_sctree_get_cell_style (clist, &GTK_CMCTREE_ROW (node)->row, state, row, column, NULL, NULL, &bg_gc); if (bg_gc == clist->bg_gc) gdk_gc_set_foreground - (clist->bg_gc, &GTK_CTREE_ROW (node)->row.background); + (clist->bg_gc, &GTK_CMCTREE_ROW (node)->row.background); if (!area) gdk_draw_rectangle (clist->clist_window, bg_gc, TRUE, @@ -534,7 +534,7 @@ gtk_sctree_draw_lines (GtkCTree *ctree, tc_rectangle.width, tc_rectangle.height); } - if (next_level > GTK_CTREE_ROW (node)->level) + if (next_level > GTK_CMCTREE_ROW (node)->level) gdk_draw_line (clist->clist_window, ctree->lines_gc, xcenter, crect->y, xcenter, crect->y + crect->height); @@ -545,7 +545,7 @@ gtk_sctree_draw_lines (GtkCTree *ctree, offset_x = MIN (ctree->tree_indent, 2 * TAB_SIZE); width = offset_x / 2 + offset_x % 2; - parent = GTK_CTREE_ROW (node)->parent; + parent = GTK_CMCTREE_ROW (node)->parent; tree_rectangle.y = ycenter; tree_rectangle.height = (cell_rectangle->y - ycenter + @@ -570,12 +570,12 @@ gtk_sctree_draw_lines (GtkCTree *ctree, { if (parent) { - gtk_sctree_get_cell_style (clist, &GTK_CTREE_ROW (parent)->row, + gtk_sctree_get_cell_style (clist, &GTK_CMCTREE_ROW (parent)->row, state, row, column, NULL, NULL, &bg_gc); if (bg_gc == clist->bg_gc) gdk_gc_set_foreground (clist->bg_gc, - &GTK_CTREE_ROW (parent)->row.background); + &GTK_CMCTREE_ROW (parent)->row.background); } else if (state == GTK_STATE_SELECTED) bg_gc = style->base_gc[state]; @@ -597,11 +597,11 @@ gtk_sctree_draw_lines (GtkCTree *ctree, tc_rectangle.height); } - gtk_sctree_get_cell_style (clist, &GTK_CTREE_ROW (node)->row, + gtk_sctree_get_cell_style (clist, &GTK_CMCTREE_ROW (node)->row, state, row, column, NULL, NULL, &bg_gc); if (bg_gc == clist->bg_gc) gdk_gc_set_foreground - (clist->bg_gc, &GTK_CTREE_ROW (node)->row.background); + (clist->bg_gc, &GTK_CMCTREE_ROW (node)->row.background); gdk_gc_set_clip_rectangle (bg_gc, crect); gdk_draw_arc (clist->clist_window, bg_gc, TRUE, @@ -625,7 +625,7 @@ gtk_sctree_draw_lines (GtkCTree *ctree, offset_x, clist->row_height, 180 * 64, 90 * 64); } - node = GTK_CTREE_ROW (node)->parent; + node = GTK_CMCTREE_ROW (node)->parent; } } @@ -741,7 +741,7 @@ gtk_sctree_draw_lines (GtkCTree *ctree, offset_x = 1; offset_y = 0; - if (ctree->line_style == GTK_CTREE_LINES_DOTTED) + if (ctree->line_style == GTK_CMCTREE_LINES_DOTTED) { offset_x += abs((clip_rectangle->x + clist->hoffset) % 2); offset_y = abs((cell_rectangle->y + clist->voffset) % 2); @@ -767,11 +767,11 @@ gtk_sctree_draw_lines (GtkCTree *ctree, { xcenter -= (justification_factor * ctree->tree_indent); - if (GTK_CTREE_ROW (node)->sibling) + if (GTK_CMCTREE_ROW (node)->sibling) gdk_draw_line (clist->clist_window, ctree->lines_gc, xcenter, cell_rectangle->y + offset_y, xcenter, crect->y + crect->height); - node = GTK_CTREE_ROW (node)->parent; + node = GTK_CMCTREE_ROW (node)->parent; } gdk_gc_set_clip_rectangle (ctree->lines_gc, NULL); clip_rectangle->y++; @@ -791,13 +791,13 @@ static gboolean filter_fg (PangoAttribute *attribute, gpointer data) } static PangoLayout * -sc_gtk_clist_create_cell_layout (GtkCList *clist, - GtkCListRow *clist_row, +sc_gtk_cmclist_create_cell_layout (GtkCMCList *clist, + GtkCMCListRow *clist_row, gint column) { PangoLayout *layout; GtkStyle *style; - GtkCell *cell; + GtkCMCell *cell; gchar *text; gtk_sctree_get_cell_style (clist, clist_row, GTK_STATE_NORMAL, 0, column, &style, @@ -807,20 +807,20 @@ sc_gtk_clist_create_cell_layout (GtkCList *clist, cell = &clist_row->cell[column]; switch (cell->type) { - case GTK_CELL_TEXT: - case GTK_CELL_PIXTEXT: - text = ((cell->type == GTK_CELL_PIXTEXT) ? - GTK_CELL_PIXTEXT (*cell)->text : - GTK_CELL_TEXT (*cell)->text); + case GTK_CMCELL_TEXT: + case GTK_CMCELL_PIXTEXT: + text = ((cell->type == GTK_CMCELL_PIXTEXT) ? + GTK_CMCELL_PIXTEXT (*cell)->text : + GTK_CMCELL_TEXT (*cell)->text); if (!text) return NULL; if (!GTK_SCTREE(clist)->use_markup[column]) { layout = gtk_widget_create_pango_layout (GTK_WIDGET (clist), - ((cell->type == GTK_CELL_PIXTEXT) ? - GTK_CELL_PIXTEXT (*cell)->text : - GTK_CELL_TEXT (*cell)->text)); + ((cell->type == GTK_CMCELL_PIXTEXT) ? + GTK_CMCELL_PIXTEXT (*cell)->text : + GTK_CMCELL_TEXT (*cell)->text)); pango_layout_set_font_description (layout, style->font_desc); } else { PangoContext *context = gtk_widget_get_pango_context (GTK_WIDGET(clist)); @@ -845,13 +845,13 @@ sc_gtk_clist_create_cell_layout (GtkCList *clist, } static void -gtk_sctree_draw_row (GtkCList *clist, +gtk_sctree_draw_row (GtkCMCList *clist, GdkRectangle *area, gint row, - GtkCListRow *clist_row) + GtkCMCListRow *clist_row) { GtkWidget *widget; - GtkCTree *ctree; + GtkCMCTree *ctree; GdkRectangle *rect; GdkRectangle *crect; GdkRectangle row_rectangle; @@ -897,7 +897,7 @@ gtk_sctree_draw_row (GtkCList *clist, return; widget = GTK_WIDGET (clist); - ctree = GTK_CTREE (clist); + ctree = GTK_CMCTREE (clist); /* if the function is passed the pointer to the row instead of null, * it avoids this expensive lookup */ @@ -965,7 +965,7 @@ gtk_sctree_draw_row (GtkCList *clist, } /* horizontal black lines */ - if (ctree->line_style == GTK_CTREE_LINES_TABBED) + if (ctree->line_style == GTK_CMCTREE_LINES_TABBED) { column_right = (COLUMN_LEFT_XPIXEL (clist, ctree->tree_column) + @@ -980,7 +980,7 @@ gtk_sctree_draw_row (GtkCList *clist, case GTK_JUSTIFY_FILL: case GTK_JUSTIFY_LEFT: offset = (column_left + ctree->tree_indent * - (((GtkCTreeRow *)clist_row)->level - 1)); + (((GtkCMCTreeRow *)clist_row)->level - 1)); gdk_draw_line (clist->clist_window, ctree->lines_gc, MIN (offset + TAB_SIZE, column_right), @@ -989,7 +989,7 @@ gtk_sctree_draw_row (GtkCList *clist, break; case GTK_JUSTIFY_RIGHT: offset = (column_right - 1 - ctree->tree_indent * - (((GtkCTreeRow *)clist_row)->level - 1)); + (((GtkCMCTreeRow *)clist_row)->level - 1)); gdk_draw_line (clist->clist_window, ctree->lines_gc, -1, cell_rectangle.y, @@ -1011,7 +1011,7 @@ gtk_sctree_draw_row (GtkCList *clist, crect->x, crect->y, crect->width, crect->height); /* horizontal black lines */ - if (ctree->line_style == GTK_CTREE_LINES_TABBED) + if (ctree->line_style == GTK_CMCTREE_LINES_TABBED) { switch (clist->column[ctree->tree_column].justification) { @@ -1020,7 +1020,7 @@ gtk_sctree_draw_row (GtkCList *clist, case GTK_JUSTIFY_LEFT: gdk_draw_line (clist->clist_window, ctree->lines_gc, MIN (column_left + TAB_SIZE + COLUMN_INSET + - (((GtkCTreeRow *)clist_row)->level > 1) * + (((GtkCMCTreeRow *)clist_row)->level > 1) * MIN (ctree->tree_indent / 2, TAB_SIZE), column_right), cell_rectangle.y, @@ -1031,7 +1031,7 @@ gtk_sctree_draw_row (GtkCList *clist, -1, cell_rectangle.y, MAX (column_right - TAB_SIZE - 1 - COLUMN_INSET - - (((GtkCTreeRow *)clist_row)->level > 1) * + (((GtkCMCTreeRow *)clist_row)->level > 1) * MIN (ctree->tree_indent / 2, TAB_SIZE), column_left - 1), cell_rectangle.y); break; @@ -1089,7 +1089,7 @@ gtk_sctree_draw_row (GtkCList *clist, crect->x, crect->y, crect->width, crect->height); - layout = sc_gtk_clist_create_cell_layout (clist, clist_row, i); + layout = sc_gtk_cmclist_create_cell_layout (clist, clist_row, i); if (layout) { pango_layout_get_pixel_extents (layout, NULL, &logical_rect); @@ -1100,28 +1100,28 @@ gtk_sctree_draw_row (GtkCList *clist, switch (clist_row->cell[i].type) { - case GTK_CELL_PIXMAP: - gdk_window_get_size - (GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, &pixmap_width, + case GTK_CMCELL_PIXMAP: + gdk_drawable_get_size + (GTK_CMCELL_PIXMAP (clist_row->cell[i])->pixmap, &pixmap_width, &height); width += pixmap_width; break; - case GTK_CELL_PIXTEXT: - if (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap) + case GTK_CMCELL_PIXTEXT: + if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap) { - gdk_window_get_size - (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, + gdk_drawable_get_size + (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap, &pixmap_width, &height); width += pixmap_width; } - if (GTK_CELL_PIXTEXT (clist_row->cell[i])->text && - GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap) - width += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing; + if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->text && + GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap) + width += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing; if (i == ctree->tree_column) width += (ctree->tree_indent * - ((GtkCTreeRow *)clist_row)->level); + ((GtkCMCTreeRow *)clist_row)->level); break; default: break; @@ -1146,35 +1146,35 @@ gtk_sctree_draw_row (GtkCList *clist, if (i != ctree->tree_column) { int start_y = (clip_rectangle.height - height) / 2; - if (GTK_CLIST_ROW_HEIGHT_SET(GTK_CLIST(clist))) + if (GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist))) start_y = (clip_rectangle.height/2 - height) / 2; offset += clist_row->cell[i].horizontal; switch (clist_row->cell[i].type) { - case GTK_CELL_PIXMAP: + case GTK_CMCELL_PIXMAP: gtk_sctree_draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc, - GTK_CELL_PIXMAP (clist_row->cell[i])->pixmap, - GTK_CELL_PIXMAP (clist_row->cell[i])->mask, + GTK_CMCELL_PIXMAP (clist_row->cell[i])->pixmap, + GTK_CMCELL_PIXMAP (clist_row->cell[i])->mask, offset, clip_rectangle.y + clist_row->cell[i].vertical + start_y, pixmap_width, height); break; - case GTK_CELL_PIXTEXT: + case GTK_CMCELL_PIXTEXT: offset = gtk_sctree_draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc, - GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, - GTK_CELL_PIXTEXT (clist_row->cell[i])->mask, + GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap, + GTK_CMCELL_PIXTEXT (clist_row->cell[i])->mask, offset, clip_rectangle.y + clist_row->cell[i].vertical + start_y, pixmap_width, height); - offset += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing; + offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing; /* Fall through */ - case GTK_CELL_TEXT: + case GTK_CMCELL_TEXT: if (layout) { gint row_center_offset = (clist->row_height - logical_rect.height) / 2; @@ -1211,12 +1211,12 @@ gtk_sctree_draw_row (GtkCList *clist, } /* draw lines */ - offset = gtk_sctree_draw_lines (ctree, (GtkCTreeRow *)clist_row, row, i, + offset = gtk_sctree_draw_lines (ctree, (GtkCMCTreeRow *)clist_row, row, i, state, &clip_rectangle, &cell_rectangle, crect, area, style); /* draw expander */ - offset = gtk_sctree_draw_expander (ctree, (GtkCTreeRow *)clist_row, + offset = gtk_sctree_draw_expander (ctree, (GtkCMCTreeRow *)clist_row, style, &clip_rectangle, offset); if (clist->column[i].justification == GTK_JUSTIFY_RIGHT) @@ -1231,8 +1231,8 @@ gtk_sctree_draw_row (GtkCList *clist, old_offset = offset; offset = gtk_sctree_draw_cell_pixmap (clist->clist_window, &clip_rectangle, fg_gc, - GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap, - GTK_CELL_PIXTEXT (clist_row->cell[i])->mask, + GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap, + GTK_CMCELL_PIXTEXT (clist_row->cell[i])->mask, offset, clip_rectangle.y + clist_row->cell[i].vertical + (clip_rectangle.height - height) / 2, @@ -1245,13 +1245,13 @@ gtk_sctree_draw_row (GtkCList *clist, if (clist->column[i].justification == GTK_JUSTIFY_RIGHT) { offset = (old_offset - string_width); - if (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap) - offset -= GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing; + if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap) + offset -= GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing; } else { - if (GTK_CELL_PIXTEXT (clist_row->cell[i])->pixmap) - offset += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing; + if (GTK_CMCELL_PIXTEXT (clist_row->cell[i])->pixmap) + offset += GTK_CMCELL_PIXTEXT (clist_row->cell[i])->spacing; } gdk_gc_set_clip_rectangle (fg_gc, &clip_rectangle); @@ -1287,51 +1287,51 @@ gtk_sctree_draw_row (GtkCList *clist, } static void -gtk_sctree_change_focus_row_expansion (GtkCTree *ctree, - GtkCTreeExpansionType action) +gtk_sctree_change_focus_row_expansion (GtkCMCTree *ctree, + GtkCMCTreeExpansionType action) { - GtkCList *clist; - GtkCTreeNode *node; + GtkCMCList *clist; + GtkCMCTreeNode *node; - g_return_if_fail (GTK_IS_CTREE (ctree)); + g_return_if_fail (GTK_IS_CMCTREE (ctree)); - clist = GTK_CLIST (ctree); + clist = GTK_CMCLIST (ctree); if (gdk_display_pointer_is_grabbed (gtk_widget_get_display (GTK_WIDGET (ctree))) && GTK_WIDGET_HAS_GRAB (ctree)) return; if (!(node = - GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row))) || - GTK_CTREE_ROW (node)->is_leaf || !(GTK_CTREE_ROW (node)->children)) + GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row))) || + GTK_CMCTREE_ROW (node)->is_leaf || !(GTK_CMCTREE_ROW (node)->children)) return; switch (action) { - case GTK_CTREE_EXPANSION_EXPAND: + case GTK_CMCTREE_EXPANSION_EXPAND: if (GTK_SCTREE(ctree)->always_expand_recursively) - gtk_ctree_expand_recursive (ctree, node); + gtk_cmctree_expand_recursive (ctree, node); else - gtk_ctree_expand (ctree, node); + gtk_cmctree_expand (ctree, node); break; - case GTK_CTREE_EXPANSION_EXPAND_RECURSIVE: - gtk_ctree_expand_recursive (ctree, node); + case GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE: + gtk_cmctree_expand_recursive (ctree, node); break; - case GTK_CTREE_EXPANSION_COLLAPSE: - gtk_ctree_collapse (ctree, node); + case GTK_CMCTREE_EXPANSION_COLLAPSE: + gtk_cmctree_collapse (ctree, node); break; - case GTK_CTREE_EXPANSION_COLLAPSE_RECURSIVE: - gtk_ctree_collapse_recursive (ctree, node); + case GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE: + gtk_cmctree_collapse_recursive (ctree, node); break; - case GTK_CTREE_EXPANSION_TOGGLE: + case GTK_CMCTREE_EXPANSION_TOGGLE: if (GTK_SCTREE(ctree)->always_expand_recursively) - gtk_ctree_toggle_expansion_recursive (ctree, node); + gtk_cmctree_toggle_expansion_recursive (ctree, node); else - gtk_ctree_toggle_expansion (ctree, node); + gtk_cmctree_toggle_expansion (ctree, node); break; - case GTK_CTREE_EXPANSION_TOGGLE_RECURSIVE: - gtk_ctree_toggle_expansion_recursive (ctree, node); + case GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE: + gtk_cmctree_toggle_expansion_recursive (ctree, node); break; } } @@ -1351,15 +1351,15 @@ gtk_sctree_class_init (GtkSCTreeClass *klass) GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkObjectClass *object_class; GtkWidgetClass *widget_class; - GtkCListClass *clist_class; - GtkCTreeClass *ctree_class; + GtkCMCListClass *clist_class; + GtkCMCTreeClass *ctree_class; object_class = (GtkObjectClass *) klass; widget_class = (GtkWidgetClass *) klass; - clist_class = (GtkCListClass *) klass; - ctree_class = (GtkCTreeClass *) klass; + clist_class = (GtkCMCListClass *) klass; + ctree_class = (GtkCMCTreeClass *) klass; - parent_class = gtk_type_class (gtk_ctree_get_type ()); + parent_class = gtk_type_class (gtk_cmctree_get_type ()); sctree_signals[ROW_POPUP_MENU] = g_signal_new ("row_popup_menu", @@ -1428,7 +1428,7 @@ gtk_sctree_init (GtkSCTree *sctree) { sctree->anchor_row = NULL; - /* GtkCTree does not specify pointer motion by default */ + /* GtkCMCTree does not specify pointer motion by default */ gtk_widget_add_events (GTK_WIDGET (sctree), GDK_POINTER_MOTION_MASK); gtk_widget_add_events (GTK_WIDGET (sctree), GDK_POINTER_MOTION_MASK); } @@ -1438,8 +1438,8 @@ gtk_sctree_init (GtkSCTree *sctree) static gboolean row_is_selected(GtkSCTree *sctree, gint row) { - GtkCListRow *clist_row; - clist_row = g_list_nth (GTK_CLIST(sctree)->row_list, row)->data; + GtkCMCListRow *clist_row; + clist_row = g_list_nth (GTK_CMCLIST(sctree)->row_list, row)->data; return clist_row ? clist_row->state == GTK_STATE_SELECTED : FALSE; } @@ -1453,15 +1453,15 @@ select_range (GtkSCTree *sctree, gint row) GList *node; if (sctree->anchor_row == NULL) { prev_row = row; - sctree->anchor_row = gtk_ctree_node_nth(GTK_CTREE(sctree), row); + sctree->anchor_row = gtk_cmctree_node_nth(GTK_CMCTREE(sctree), row); } else - prev_row = g_list_position(GTK_CLIST(sctree)->row_list, + prev_row = g_list_position(GTK_CMCLIST(sctree)->row_list, (GList *)sctree->anchor_row); if (row < prev_row) { min = row; max = prev_row; - GTK_CLIST(sctree)->focus_row = max; + GTK_CMCLIST(sctree)->focus_row = max; } else { min = prev_row; max = row; @@ -1475,60 +1475,60 @@ select_range (GtkSCTree *sctree, gint row) } if (max - min > 10) - gtk_clist_freeze(GTK_CLIST(sctree)); + gtk_cmclist_freeze(GTK_CMCLIST(sctree)); - node = g_list_nth((GTK_CLIST(sctree))->row_list, min); + node = g_list_nth((GTK_CMCLIST(sctree))->row_list, min); for (i = min; i < max; i++) { - if (node && GTK_CTREE_ROW (node)->row.selectable) { + if (node && GTK_CMCTREE_ROW (node)->row.selectable) { g_signal_emit_by_name(G_OBJECT(sctree), "tree_select_row", node, -1); } node = node->next; } if (max - min > 10) - gtk_clist_thaw(GTK_CLIST(sctree)); + gtk_cmclist_thaw(GTK_CMCLIST(sctree)); sctree->selecting_range--; - gtk_clist_select_row (GTK_CLIST (sctree), max, -1); + gtk_cmclist_select_row (GTK_CMCLIST (sctree), max, -1); } /* Handles row selection according to the specified modifier state */ -/* in certain cases, we arrive here from a function knowing the GtkCTreeNode, and having +/* in certain cases, we arrive here from a function knowing the GtkCMCTreeNode, and having * already slowly found row using g_list_position. In which case, _node will be non-NULL * to avoid this function having to slowly find it with g_list_nth. */ static void -select_row (GtkSCTree *sctree, gint row, gint col, guint state, GtkCTreeNode *_node) +select_row (GtkSCTree *sctree, gint row, gint col, guint state, GtkCMCTreeNode *_node) { gboolean range, additive; g_return_if_fail (sctree != NULL); g_return_if_fail (GTK_IS_SCTREE (sctree)); range = ((state & GDK_SHIFT_MASK) != 0) && - (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) && - (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE); + (GTK_CMCLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) && + (GTK_CMCLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE); additive = ((state & GDK_CONTROL_MASK) != 0) && - (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) && - (GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE); + (GTK_CMCLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) && + (GTK_CMCLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE); if (!range && !additive && sctree->force_additive_sel) additive = TRUE; - GTK_CLIST(sctree)->focus_row = row; + GTK_CMCLIST(sctree)->focus_row = row; if (!additive) { - gtk_clist_unselect_all (GTK_CLIST (sctree)); + gtk_cmclist_unselect_all (GTK_CMCLIST (sctree)); } if (!range) { - GtkCTreeNode *node; + GtkCMCTreeNode *node; - node = _node ? _node : gtk_ctree_node_nth (GTK_CTREE(sctree), row); + node = _node ? _node : gtk_cmctree_node_nth (GTK_CMCTREE(sctree), row); /*No need to manage overlapped list*/ if (additive) { if (row_is_selected(sctree, row)) - gtk_clist_unselect_row (GTK_CLIST (sctree), row, col); + gtk_cmclist_unselect_row (GTK_CMCLIST (sctree), row, col); else g_signal_emit_by_name (G_OBJECT (sctree), @@ -1545,33 +1545,33 @@ select_row (GtkSCTree *sctree, gint row, gint col, guint state, GtkCTreeNode *_n static gboolean sctree_is_hot_spot (GtkSCTree *sctree, - GtkCTreeNode *node, + GtkCMCTreeNode *node, gint row, gint x, gint y) { - GtkCTreeRow *tree_row; - GtkCList *clist; - GtkCTree *ctree; - GtkCellPixText *cell; + GtkCMCTreeRow *tree_row; + GtkCMCList *clist; + GtkCMCTree *ctree; + GtkCMCellPixText *cell; gint xl, xmax; gint yu; g_return_val_if_fail (GTK_IS_SCTREE (sctree), FALSE); g_return_val_if_fail (node != NULL, FALSE); - clist = GTK_CLIST (sctree); - ctree = GTK_CTREE (sctree); + clist = GTK_CMCLIST (sctree); + ctree = GTK_CMCTREE (sctree); if (!clist->column[ctree->tree_column].visible || - ctree->expander_style == GTK_CTREE_EXPANDER_NONE) + ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE) return FALSE; - tree_row = GTK_CTREE_ROW (node); + tree_row = GTK_CMCTREE_ROW (node); - cell = GTK_CELL_PIXTEXT (tree_row->row.cell[ctree->tree_column]); + cell = GTK_CMCELL_PIXTEXT (tree_row->row.cell[ctree->tree_column]); - if (!GTK_CLIST_ROW_HEIGHT_SET(GTK_CLIST(clist))) + if (!GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist))) yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height - PM_SIZE) / 2 - (clist->row_height - 1) % 2); else @@ -1583,11 +1583,11 @@ sctree_is_hot_spot (GtkSCTree *sctree, xl = (clist->column[ctree->tree_column].area.x + clist->column[ctree->tree_column].area.width - 1 + clist->hoffset - (tree_row->level - 1) * ctree->tree_indent - PM_SIZE - - (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3); + (ctree->line_style == GTK_CMCTREE_LINES_TABBED) * 3); else xl = (clist->column[ctree->tree_column].area.x + clist->hoffset + (tree_row->level - 1) * ctree->tree_indent + - (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3); + (ctree->line_style == GTK_CMCTREE_LINES_TABBED) * 3); xmax = xl + PM_SIZE; #else @@ -1595,19 +1595,19 @@ sctree_is_hot_spot (GtkSCTree *sctree, xl = (clist->column[ctree->tree_column].area.x + clist->column[ctree->tree_column].area.width - 1 + clist->hoffset - (tree_row->level - 1) * ctree->tree_indent - PM_SIZE - - (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3); + (ctree->line_style == GTK_CMCTREE_LINES_TABBED) * 3); xmax = xl + PM_SIZE; } else if (ctree->tree_column == 0) { xl = (clist->column[ctree->tree_column].area.x + clist->hoffset + - (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3); + (ctree->line_style == GTK_CMCTREE_LINES_TABBED) * 3); xmax = (clist->column[ctree->tree_column].area.x + clist->hoffset + (tree_row->level - 1) * ctree->tree_indent + - (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3) + + (ctree->line_style == GTK_CMCTREE_LINES_TABBED) * 3) + PM_SIZE; } else { xl = (clist->column[ctree->tree_column].area.x + clist->hoffset + (tree_row->level - 1) * ctree->tree_indent + - (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3); + (ctree->line_style == GTK_CMCTREE_LINES_TABBED) * 3); xmax = xl + PM_SIZE; } #endif @@ -1619,27 +1619,27 @@ gtk_sctree_is_hot_spot (GtkSCTree *ctree, gint x, gint y) { - GtkCTreeNode *node; + GtkCMCTreeNode *node; gint column; gint row; g_return_val_if_fail (GTK_IS_SCTREE (ctree), FALSE); - if (gtk_clist_get_selection_info (GTK_CLIST (ctree), x, y, &row, &column)) - if ((node = GTK_CTREE_NODE(g_list_nth (GTK_CLIST (ctree)->row_list, row)))) + if (gtk_cmclist_get_selection_info (GTK_CMCLIST (ctree), x, y, &row, &column)) + if ((node = GTK_CMCTREE_NODE(g_list_nth (GTK_CMCLIST (ctree)->row_list, row)))) return sctree_is_hot_spot (ctree, node, row, x, y); return FALSE; } -/* Our handler for button_press events. We override all of GtkCList's broken +/* Our handler for button_press events. We override all of GtkCMCList's broken * behavior. */ static gint gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event) { GtkSCTree *sctree; - GtkCList *clist; + GtkCMCList *clist; gboolean on_row; gint row; gint col; @@ -1650,25 +1650,25 @@ gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event) g_return_val_if_fail (event != NULL, FALSE); sctree = GTK_SCTREE (widget); - clist = GTK_CLIST (widget); + clist = GTK_CMCLIST (widget); retval = FALSE; if (event->window != clist->clist_window) return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event); - on_row = gtk_clist_get_selection_info (clist, event->x, event->y, &row, &col); + on_row = gtk_cmclist_get_selection_info (clist, event->x, event->y, &row, &col); if (on_row && !GTK_WIDGET_HAS_FOCUS(widget)) gtk_widget_grab_focus (widget); if (gtk_sctree_is_hot_spot (GTK_SCTREE(sctree), event->x, event->y)) { - GtkCTreeNode *node = gtk_ctree_node_nth(GTK_CTREE(sctree), row); - if (GTK_CTREE_ROW (node)->expanded) - gtk_ctree_collapse(GTK_CTREE(sctree), node); + GtkCMCTreeNode *node = gtk_cmctree_node_nth(GTK_CMCTREE(sctree), row); + if (GTK_CMCTREE_ROW (node)->expanded) + gtk_cmctree_collapse(GTK_CMCTREE(sctree), node); else if (GTK_SCTREE(sctree)->always_expand_recursively) - gtk_ctree_expand_recursive (GTK_CTREE(sctree), node); + gtk_cmctree_expand_recursive (GTK_CMCTREE(sctree), node); else - gtk_ctree_expand(GTK_CTREE(sctree), node); + gtk_cmctree_expand(GTK_CMCTREE(sctree), node); return TRUE; } @@ -1695,7 +1695,7 @@ gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event) select_row (sctree, row, col, event->state, NULL); } } else { - gtk_clist_unselect_all (clist); + gtk_cmclist_unselect_all (clist); } retval = TRUE; @@ -1708,7 +1708,7 @@ gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event) sctree_signals[ROW_POPUP_MENU], 0, event); } else { - gtk_clist_unselect_all(clist); + gtk_cmclist_unselect_all(clist); g_signal_emit (G_OBJECT (sctree), sctree_signals[EMPTY_POPUP_MENU], 0, event); @@ -1739,14 +1739,14 @@ gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event) return retval; } -/* Our handler for button_release events. We override all of GtkCList's broken +/* Our handler for button_release events. We override all of GtkCMCList's broken * behavior. */ static gint gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event) { GtkSCTree *sctree; - GtkCList *clist; + GtkCMCList *clist; gint on_row; gint row, col; gint retval; @@ -1756,13 +1756,13 @@ gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event) g_return_val_if_fail (event != NULL, FALSE); sctree = GTK_SCTREE (widget); - clist = GTK_CLIST (widget); + clist = GTK_CMCLIST (widget); retval = FALSE; if (event->window != clist->clist_window) return (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event); - on_row = gtk_clist_get_selection_info (clist, event->x, event->y, &row, &col); + on_row = gtk_cmclist_get_selection_info (clist, event->x, event->y, &row, &col); if (!(event->button == 1 || event->button == 2)) return FALSE; @@ -1784,21 +1784,21 @@ gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event) return retval; } -/* Our handler for motion_notify events. We override all of GtkCList's broken +/* Our handler for motion_notify events. We override all of GtkCMCList's broken * behavior. */ static gint gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event) { GtkSCTree *sctree; - GtkCList *clist; + GtkCMCList *clist; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); sctree = GTK_SCTREE (widget); - clist = GTK_CLIST (widget); + clist = GTK_CMCLIST (widget); if (event->window != clist->clist_window) return (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) (widget, event); @@ -1898,7 +1898,7 @@ gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *context, * to null. */ static void -gtk_sctree_clear (GtkCList *clist) +gtk_sctree_clear (GtkCMCList *clist) { GtkSCTree *sctree; @@ -1908,12 +1908,12 @@ gtk_sctree_clear (GtkCList *clist) sctree = GTK_SCTREE (clist); sctree->anchor_row = NULL; - if (((GtkCListClass *)parent_class)->clear) - (* ((GtkCListClass *)parent_class)->clear) (clist); + if (((GtkCMCListClass *)parent_class)->clear) + (* ((GtkCMCListClass *)parent_class)->clear) (clist); } static void -gtk_sctree_real_unselect_all (GtkCList *clist) +gtk_sctree_real_unselect_all (GtkCMCList *clist) { GtkSCTree *sctree; gboolean should_freeze = FALSE; @@ -1923,17 +1923,17 @@ gtk_sctree_real_unselect_all (GtkCList *clist) sctree = GTK_SCTREE (clist); - if (sc_g_list_bigger(GTK_CLIST(sctree)->selection, 10)) { + if (sc_g_list_bigger(GTK_CMCLIST(sctree)->selection, 10)) { should_freeze = TRUE; sctree->selecting_range++; - gtk_clist_freeze (GTK_CLIST (sctree)); + gtk_cmclist_freeze (GTK_CMCLIST (sctree)); } - if (((GtkCListClass *)parent_class)->unselect_all) - (* ((GtkCListClass *)parent_class)->unselect_all) (clist); + if (((GtkCMCListClass *)parent_class)->unselect_all) + (* ((GtkCMCListClass *)parent_class)->unselect_all) (clist); if (should_freeze) { - gtk_clist_thaw (GTK_CLIST (sctree)); + gtk_cmclist_thaw (GTK_CMCLIST (sctree)); sctree->selecting_range--; } } @@ -1942,14 +1942,14 @@ gtk_sctree_real_unselect_all (GtkCList *clist) We have to set the anchor to parent visible node. */ static void -gtk_sctree_collapse (GtkCTree *ctree, GtkCTreeNode *node) +gtk_sctree_collapse (GtkCMCTree *ctree, GtkCMCTreeNode *node) { g_return_if_fail (ctree != NULL); g_return_if_fail (GTK_IS_SCTREE (ctree)); (* parent_class->tree_collapse) (ctree, node); GTK_SCTREE(ctree)->anchor_row = - gtk_ctree_node_nth(ctree, GTK_CLIST(ctree)->focus_row); + gtk_cmctree_node_nth(ctree, GTK_CMCLIST(ctree)->focus_row); } GtkWidget *gtk_sctree_new_with_titles (gint columns, gint tree_column, @@ -1965,12 +1965,12 @@ GtkWidget *gtk_sctree_new_with_titles (gint columns, gint tree_column, "tree_column", tree_column, NULL); if (titles) { - GtkCList *clist = GTK_CLIST (widget); + GtkCMCList *clist = GTK_CMCLIST (widget); guint i; for (i = 0; i < columns; i++) - gtk_clist_set_column_title (clist, i, titles[i]); - gtk_clist_column_titles_show (clist); + gtk_cmclist_set_column_title (clist, i, titles[i]); + gtk_cmclist_column_titles_show (clist); } GTK_SCTREE(widget)->show_stripes = TRUE; @@ -2001,36 +2001,36 @@ void gtk_sctree_set_use_markup (GtkSCTree *sctree, sctree->use_markup[column] = markup; } -void gtk_sctree_select (GtkSCTree *sctree, GtkCTreeNode *node) +void gtk_sctree_select (GtkSCTree *sctree, GtkCMCTreeNode *node) { select_row(sctree, - g_list_position(GTK_CLIST(sctree)->row_list, (GList *)node), + g_list_position(GTK_CMCLIST(sctree)->row_list, (GList *)node), -1, 0, node); } -void gtk_sctree_select_with_state (GtkSCTree *sctree, GtkCTreeNode *node, int state) +void gtk_sctree_select_with_state (GtkSCTree *sctree, GtkCMCTreeNode *node, int state) { select_row(sctree, - g_list_position(GTK_CLIST(sctree)->row_list, (GList *)node), + g_list_position(GTK_CMCLIST(sctree)->row_list, (GList *)node), -1, state, node); } void gtk_sctree_unselect_all (GtkSCTree *sctree) { - gtk_clist_unselect_all(GTK_CLIST(sctree)); + gtk_cmclist_unselect_all(GTK_CMCLIST(sctree)); sctree->anchor_row = NULL; } -void gtk_sctree_set_anchor_row (GtkSCTree *sctree, GtkCTreeNode *node) +void gtk_sctree_set_anchor_row (GtkSCTree *sctree, GtkCMCTreeNode *node) { sctree->anchor_row = node; } -void gtk_sctree_remove_node (GtkSCTree *sctree, GtkCTreeNode *node) +void gtk_sctree_remove_node (GtkSCTree *sctree, GtkCMCTreeNode *node) { if (sctree->anchor_row == node) sctree->anchor_row = NULL; - gtk_ctree_remove_node(GTK_CTREE(sctree), node); + gtk_cmctree_remove_node(GTK_CMCTREE(sctree), node); } void gtk_sctree_set_stripes(GtkSCTree *sctree, gboolean show_stripes) @@ -2047,10 +2047,10 @@ void gtk_sctree_set_recursive_expand(GtkSCTree *sctree, gboolean rec_exp) * Tree sorting functions * ***********************************************************/ -static void sink(GtkCList *clist, GPtrArray *numbers, gint root, gint bottom) +static void sink(GtkCMCList *clist, GPtrArray *numbers, gint root, gint bottom) { gint j, k ; - GtkCTreeNode *temp; + GtkCMCTreeNode *temp; j = 2 * root; k = j + 1; @@ -2058,12 +2058,12 @@ static void sink(GtkCList *clist, GPtrArray *numbers, gint root, gint bottom) /* find the maximum element of numbers[root], numbers[2*root] and numbers[2*root+1] */ if (j <= bottom) { - if (clist->compare( clist, GTK_CTREE_ROW (g_ptr_array_index(numbers, root)), - GTK_CTREE_ROW(g_ptr_array_index( numbers, j))) >= 0) + if (clist->compare( clist, GTK_CMCTREE_ROW (g_ptr_array_index(numbers, root)), + GTK_CMCTREE_ROW(g_ptr_array_index( numbers, j))) >= 0) j = root; if (k <= bottom) - if (clist->compare( clist, GTK_CTREE_ROW (g_ptr_array_index(numbers, k)), - GTK_CTREE_ROW (g_ptr_array_index( numbers, j))) > 0) + if (clist->compare( clist, GTK_CMCTREE_ROW (g_ptr_array_index(numbers, k)), + GTK_CMCTREE_ROW (g_ptr_array_index( numbers, j))) > 0) j = k; /* if numbers[root] wasn't the maximum element then sink again */ @@ -2076,10 +2076,10 @@ static void sink(GtkCList *clist, GPtrArray *numbers, gint root, gint bottom) } } -static void heap_sort(GtkCList *clist, GPtrArray *numbers, gint array_size) +static void heap_sort(GtkCMCList *clist, GPtrArray *numbers, gint array_size) { gint i; - GtkCTreeNode *temp; + GtkCMCTreeNode *temp; /* build the Heap */ for (i = (array_size / 2); i >= 1; i--) @@ -2094,21 +2094,21 @@ static void heap_sort(GtkCList *clist, GPtrArray *numbers, gint array_size) } static void -stree_sort (GtkCTree *ctree, - GtkCTreeNode *node, +stree_sort (GtkCMCTree *ctree, + GtkCMCTreeNode *node, gpointer data) { - GtkCTreeNode *list_start, *work, *next; + GtkCMCTreeNode *list_start, *work, *next; GPtrArray *row_array, *viewable_array; - GtkCList *clist; + GtkCMCList *clist; gint i; - clist = GTK_CLIST (ctree); + clist = GTK_CMCLIST (ctree); if (node) - work = GTK_CTREE_ROW (node)->children; + work = GTK_CMCTREE_ROW (node)->children; else - work = GTK_CTREE_NODE (clist->row_list); + work = GTK_CMCTREE_NODE (clist->row_list); row_array = g_ptr_array_new(); viewable_array = g_ptr_array_new(); @@ -2118,9 +2118,9 @@ stree_sort (GtkCTree *ctree, while (work) { /* add all rows to row_array */ g_ptr_array_add( row_array, work); - if (GTK_CTREE_ROW (work)->parent && gtk_ctree_is_viewable( ctree, work)) - g_ptr_array_add( viewable_array, GTK_CTREE_ROW (work)->parent); - next = GTK_CTREE_ROW (work)->sibling; + if (GTK_CMCTREE_ROW (work)->parent && gtk_cmctree_is_viewable( ctree, work)) + g_ptr_array_add( viewable_array, GTK_CMCTREE_ROW (work)->parent); + next = GTK_CMCTREE_ROW (work)->sibling; gtk_sctree_unlink( ctree, work, FALSE); work = next; } @@ -2128,9 +2128,9 @@ stree_sort (GtkCTree *ctree, heap_sort( clist, row_array, (row_array->len)-1); if (node) - list_start = GTK_CTREE_ROW (node)->children; + list_start = GTK_CMCTREE_ROW (node)->children; else - list_start = GTK_CTREE_NODE (clist->row_list); + list_start = GTK_CMCTREE_NODE (clist->row_list); if (clist->sort_type == GTK_SORT_ASCENDING) { for (i=(row_array->len)-1; i>=1; i--) { @@ -2149,7 +2149,7 @@ stree_sort (GtkCTree *ctree, } for (i=0; i<viewable_array->len; i++) { - gtk_ctree_expand( ctree, g_ptr_array_index( viewable_array, i)); + gtk_cmctree_expand( ctree, g_ptr_array_index( viewable_array, i)); } } @@ -2158,21 +2158,21 @@ stree_sort (GtkCTree *ctree, } void -gtk_sctree_sort_recursive (GtkCTree *ctree, - GtkCTreeNode *node) +gtk_sctree_sort_recursive (GtkCMCTree *ctree, + GtkCMCTreeNode *node) { - GtkCList *clist; - GtkCTreeNode *focus_node = NULL; + GtkCMCList *clist; + GtkCMCTreeNode *focus_node = NULL; g_return_if_fail (ctree != NULL); - g_return_if_fail (GTK_IS_CTREE (ctree)); + g_return_if_fail (GTK_IS_CMCTREE (ctree)); - clist = GTK_CLIST (ctree); + clist = GTK_CMCLIST (ctree); - gtk_clist_freeze (clist); + gtk_cmclist_freeze (clist); if (clist->selection_mode == GTK_SELECTION_EXTENDED) { - GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); g_list_free (clist->undo_selection); g_list_free (clist->undo_unselection); @@ -2180,12 +2180,12 @@ gtk_sctree_sort_recursive (GtkCTree *ctree, clist->undo_unselection = NULL; } - if (!node || (node && gtk_ctree_is_viewable (ctree, node))) - focus_node = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)); + if (!node || (node && gtk_cmctree_is_viewable (ctree, node))) + focus_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)); GTK_SCTREE(ctree)->sorting = TRUE; - gtk_ctree_post_recursive (ctree, node, GTK_CTREE_FUNC (stree_sort), NULL); + gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (stree_sort), NULL); if (!node) stree_sort (ctree, NULL, NULL); @@ -2197,25 +2197,25 @@ gtk_sctree_sort_recursive (GtkCTree *ctree, clist->undo_anchor = clist->focus_row; } - gtk_clist_thaw (clist); + gtk_cmclist_thaw (clist); } void -gtk_sctree_sort_node (GtkCTree *ctree, - GtkCTreeNode *node) +gtk_sctree_sort_node (GtkCMCTree *ctree, + GtkCMCTreeNode *node) { - GtkCList *clist; - GtkCTreeNode *focus_node = NULL; + GtkCMCList *clist; + GtkCMCTreeNode *focus_node = NULL; g_return_if_fail (ctree != NULL); - g_return_if_fail (GTK_IS_CTREE (ctree)); + g_return_if_fail (GTK_IS_CMCTREE (ctree)); - clist = GTK_CLIST (ctree); + clist = GTK_CMCLIST (ctree); - gtk_clist_freeze (clist); + gtk_cmclist_freeze (clist); if (clist->selection_mode == GTK_SELECTION_EXTENDED) { - GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); g_list_free (clist->undo_selection); g_list_free (clist->undo_unselection); @@ -2223,8 +2223,8 @@ gtk_sctree_sort_node (GtkCTree *ctree, clist->undo_unselection = NULL; } - if (!node || (node && gtk_ctree_is_viewable (ctree, node))) - focus_node = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)); + if (!node || (node && gtk_cmctree_is_viewable (ctree, node))) + focus_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)); GTK_SCTREE(ctree)->sorting = TRUE; @@ -2237,32 +2237,32 @@ gtk_sctree_sort_node (GtkCTree *ctree, clist->undo_anchor = clist->focus_row; } - gtk_clist_thaw (clist); + gtk_cmclist_thaw (clist); } /************************************************************************/ static void -gtk_sctree_unlink (GtkCTree *ctree, - GtkCTreeNode *node, +gtk_sctree_unlink (GtkCMCTree *ctree, + GtkCMCTreeNode *node, gboolean update_focus_row) { - GtkCList *clist; + GtkCMCList *clist; gint rows; gint level; gint visible; - GtkCTreeNode *work; - GtkCTreeNode *parent; + GtkCMCTreeNode *work; + GtkCMCTreeNode *parent; GList *list; g_return_if_fail (ctree != NULL); - g_return_if_fail (GTK_IS_CTREE (ctree)); + g_return_if_fail (GTK_IS_CMCTREE (ctree)); g_return_if_fail (node != NULL); - clist = GTK_CLIST (ctree); + clist = GTK_CMCLIST (ctree); if (update_focus_row && clist->selection_mode == GTK_SELECTION_EXTENDED) { - GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); g_list_free (clist->undo_selection); g_list_free (clist->undo_unselection); @@ -2270,20 +2270,20 @@ gtk_sctree_unlink (GtkCTree *ctree, clist->undo_unselection = NULL; } - visible = gtk_ctree_is_viewable (ctree, node); + visible = gtk_cmctree_is_viewable (ctree, node); /* clist->row_list_end unlinked ? */ - if (visible && (GTK_CTREE_NODE_NEXT (node) == NULL || - (GTK_CTREE_ROW (node)->children && gtk_ctree_is_ancestor (ctree, node, - GTK_CTREE_NODE (clist->row_list_end))))) - clist->row_list_end = (GList *) (GTK_CTREE_NODE_PREV (node)); + if (visible && (GTK_CMCTREE_NODE_NEXT (node) == NULL || + (GTK_CMCTREE_ROW (node)->children && gtk_cmctree_is_ancestor (ctree, node, + GTK_CMCTREE_NODE (clist->row_list_end))))) + clist->row_list_end = (GList *) (GTK_CMCTREE_NODE_PREV (node)); /* update list */ rows = 0; - level = GTK_CTREE_ROW (node)->level; - work = GTK_CTREE_NODE_NEXT (node); - while (work && GTK_CTREE_ROW (work)->level > level) { - work = GTK_CTREE_NODE_NEXT (work); + level = GTK_CMCTREE_ROW (node)->level; + work = GTK_CMCTREE_NODE_NEXT (node); + while (work && GTK_CMCTREE_ROW (work)->level > level) { + work = GTK_CMCTREE_NODE_NEXT (work); rows++; } @@ -2296,7 +2296,7 @@ gtk_sctree_unlink (GtkCTree *ctree, if (pos + rows < clist->focus_row) clist->focus_row -= (rows + 1); else if (pos <= clist->focus_row) { - if (!GTK_CTREE_ROW (node)->sibling) + if (!GTK_CMCTREE_ROW (node)->sibling) clist->focus_row = MAX (pos - 1, 0); else clist->focus_row = pos; @@ -2308,55 +2308,55 @@ gtk_sctree_unlink (GtkCTree *ctree, } if (work) { - list = (GList *)GTK_CTREE_NODE_PREV (work); + list = (GList *)GTK_CMCTREE_NODE_PREV (work); list->next = NULL; list = (GList *)work; - list->prev = (GList *)GTK_CTREE_NODE_PREV (node); + list->prev = (GList *)GTK_CMCTREE_NODE_PREV (node); } - if (GTK_CTREE_NODE_PREV (node) && - GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (node)) == node) { - list = (GList *)GTK_CTREE_NODE_PREV (node); + if (GTK_CMCTREE_NODE_PREV (node) && + GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (node)) == node) { + list = (GList *)GTK_CMCTREE_NODE_PREV (node); list->next = (GList *)work; } /* update tree */ - parent = GTK_CTREE_ROW (node)->parent; + parent = GTK_CMCTREE_ROW (node)->parent; if (parent) { - if (GTK_CTREE_ROW (parent)->children == node) { - GTK_CTREE_ROW (parent)->children = GTK_CTREE_ROW (node)->sibling; + if (GTK_CMCTREE_ROW (parent)->children == node) { + GTK_CMCTREE_ROW (parent)->children = GTK_CMCTREE_ROW (node)->sibling; } else { - GtkCTreeNode *sibling; + GtkCMCTreeNode *sibling; - sibling = GTK_CTREE_ROW (parent)->children; - while (GTK_CTREE_ROW (sibling)->sibling != node) - sibling = GTK_CTREE_ROW (sibling)->sibling; - GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling; + sibling = GTK_CMCTREE_ROW (parent)->children; + while (GTK_CMCTREE_ROW (sibling)->sibling != node) + sibling = GTK_CMCTREE_ROW (sibling)->sibling; + GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling; } } else { if (clist->row_list == (GList *)node) - clist->row_list = (GList *) (GTK_CTREE_ROW (node)->sibling); + clist->row_list = (GList *) (GTK_CMCTREE_ROW (node)->sibling); else { - GtkCTreeNode *sibling; + GtkCMCTreeNode *sibling; - sibling = GTK_CTREE_NODE (clist->row_list); - while (GTK_CTREE_ROW (sibling)->sibling != node) - sibling = GTK_CTREE_ROW (sibling)->sibling; - GTK_CTREE_ROW (sibling)->sibling = GTK_CTREE_ROW (node)->sibling; + sibling = GTK_CMCTREE_NODE (clist->row_list); + while (GTK_CMCTREE_ROW (sibling)->sibling != node) + sibling = GTK_CMCTREE_ROW (sibling)->sibling; + GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling; } } } static void -gtk_sctree_link (GtkCTree *ctree, - GtkCTreeNode *node, - GtkCTreeNode *parent, - GtkCTreeNode *sibling, +gtk_sctree_link (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeNode *parent, + GtkCMCTreeNode *sibling, gboolean update_focus_row) { - GtkCList *clist; + GtkCMCList *clist; GList *list_end; GList *list; GList *work; @@ -2364,15 +2364,15 @@ gtk_sctree_link (GtkCTree *ctree, gint rows = 0; if (sibling) - g_return_if_fail (GTK_CTREE_ROW (sibling)->parent == parent); + g_return_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent); g_return_if_fail (node != NULL); g_return_if_fail (node != sibling); g_return_if_fail (node != parent); - clist = GTK_CLIST (ctree); + clist = GTK_CMCLIST (ctree); if (update_focus_row && clist->selection_mode == GTK_SELECTION_EXTENDED) { - GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); g_list_free (clist->undo_selection); g_list_free (clist->undo_unselection); @@ -2384,53 +2384,53 @@ gtk_sctree_link (GtkCTree *ctree, list_end = list_end->next) rows++; - GTK_CTREE_ROW (node)->parent = parent; - GTK_CTREE_ROW (node)->sibling = sibling; + GTK_CMCTREE_ROW (node)->parent = parent; + GTK_CMCTREE_ROW (node)->sibling = sibling; - if (!parent || (parent && (gtk_ctree_is_viewable (ctree, parent) && - GTK_CTREE_ROW (parent)->expanded))) { + if (!parent || (parent && (gtk_cmctree_is_viewable (ctree, parent) && + GTK_CMCTREE_ROW (parent)->expanded))) { visible = TRUE; clist->rows += rows; } if (parent) - work = (GList *)(GTK_CTREE_ROW (parent)->children); + work = (GList *)(GTK_CMCTREE_ROW (parent)->children); else work = clist->row_list; if (sibling) { if (work != (GList *)sibling) { - while (GTK_CTREE_ROW (work)->sibling != sibling) - work = (GList *)(GTK_CTREE_ROW (work)->sibling); - GTK_CTREE_ROW (work)->sibling = node; + while (GTK_CMCTREE_ROW (work)->sibling != sibling) + work = (GList *)(GTK_CMCTREE_ROW (work)->sibling); + GTK_CMCTREE_ROW (work)->sibling = node; } - if (sibling == GTK_CTREE_NODE (clist->row_list)) + if (sibling == GTK_CMCTREE_NODE (clist->row_list)) clist->row_list = (GList *) node; - if (GTK_CTREE_NODE_PREV (sibling) && - GTK_CTREE_NODE_NEXT (GTK_CTREE_NODE_PREV (sibling)) == sibling) { - list = (GList *)GTK_CTREE_NODE_PREV (sibling); + if (GTK_CMCTREE_NODE_PREV (sibling) && + GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (sibling)) == sibling) { + list = (GList *)GTK_CMCTREE_NODE_PREV (sibling); list->next = (GList *)node; } list = (GList *)node; - list->prev = (GList *)GTK_CTREE_NODE_PREV (sibling); + list->prev = (GList *)GTK_CMCTREE_NODE_PREV (sibling); list_end->next = (GList *)sibling; list = (GList *)sibling; list->prev = list_end; - if (parent && GTK_CTREE_ROW (parent)->children == sibling) - GTK_CTREE_ROW (parent)->children = node; + if (parent && GTK_CMCTREE_ROW (parent)->children == sibling) + GTK_CMCTREE_ROW (parent)->children = node; } else { if (work) { /* find sibling */ - while (GTK_CTREE_ROW (work)->sibling) - work = (GList *)(GTK_CTREE_ROW (work)->sibling); - GTK_CTREE_ROW (work)->sibling = node; + while (GTK_CMCTREE_ROW (work)->sibling) + work = (GList *)(GTK_CMCTREE_ROW (work)->sibling); + GTK_CMCTREE_ROW (work)->sibling = node; /* find last visible child of sibling */ work = (GList *) gtk_sctree_last_visible (ctree, - GTK_CTREE_NODE (work)); + GTK_CMCTREE_NODE (work)); list_end->next = work->next; if (work->next) @@ -2441,13 +2441,13 @@ gtk_sctree_link (GtkCTree *ctree, } else { if (parent) { - GTK_CTREE_ROW (parent)->children = node; + GTK_CMCTREE_ROW (parent)->children = node; list = (GList *)node; list->prev = (GList *)parent; - if (GTK_CTREE_ROW (parent)->expanded) { - list_end->next = (GList *)GTK_CTREE_NODE_NEXT (parent); - if (GTK_CTREE_NODE_NEXT(parent)) { - list = (GList *)GTK_CTREE_NODE_NEXT (parent); + if (GTK_CMCTREE_ROW (parent)->expanded) { + list_end->next = (GList *)GTK_CMCTREE_NODE_NEXT (parent); + if (GTK_CMCTREE_NODE_NEXT(parent)) { + list = (GList *)GTK_CMCTREE_NODE_NEXT (parent); list->prev = list_end; } list = (GList *)parent; @@ -2465,7 +2465,7 @@ gtk_sctree_link (GtkCTree *ctree, } } - gtk_ctree_pre_recursive (ctree, node, stree_update_level, NULL); + gtk_cmctree_pre_recursive (ctree, node, stree_update_level, NULL); if (clist->row_list_end == NULL || clist->row_list_end->next == (GList *)node) @@ -2483,36 +2483,36 @@ gtk_sctree_link (GtkCTree *ctree, } static void -stree_update_level (GtkCTree *ctree, - GtkCTreeNode *node, +stree_update_level (GtkCMCTree *ctree, + GtkCMCTreeNode *node, gpointer data) { if (!node) return; - if (GTK_CTREE_ROW (node)->parent) - GTK_CTREE_ROW (node)->level = - GTK_CTREE_ROW (GTK_CTREE_ROW (node)->parent)->level + 1; + if (GTK_CMCTREE_ROW (node)->parent) + GTK_CMCTREE_ROW (node)->level = + GTK_CMCTREE_ROW (GTK_CMCTREE_ROW (node)->parent)->level + 1; else - GTK_CTREE_ROW (node)->level = 1; + GTK_CMCTREE_ROW (node)->level = 1; } -static GtkCTreeNode * -gtk_sctree_last_visible (GtkCTree *ctree, - GtkCTreeNode *node) +static GtkCMCTreeNode * +gtk_sctree_last_visible (GtkCMCTree *ctree, + GtkCMCTreeNode *node) { - GtkCTreeNode *work; + GtkCMCTreeNode *work; if (!node) return NULL; - work = GTK_CTREE_ROW (node)->children; + work = GTK_CMCTREE_ROW (node)->children; - if (!work || !GTK_CTREE_ROW (node)->expanded) + if (!work || !GTK_CMCTREE_ROW (node)->expanded) return node; - while (GTK_CTREE_ROW (work)->sibling) - work = GTK_CTREE_ROW (work)->sibling; + while (GTK_CMCTREE_ROW (work)->sibling) + work = GTK_CMCTREE_ROW (work)->sibling; return gtk_sctree_last_visible (ctree, work); } @@ -2522,9 +2522,9 @@ gtk_sctree_last_visible (GtkCTree *ctree, * around a memory problem deep inside gtk, * revealed by valgrind. */ -/*GtkCTreeNode* gtk_sctree_insert_node (GtkCTree *ctree, - GtkCTreeNode *parent, - GtkCTreeNode *sibling, +/*GtkCMCTreeNode* gtk_sctree_insert_node (GtkCMCTree *ctree, + GtkCMCTreeNode *parent, + GtkCMCTreeNode *sibling, gchar *text[], guint8 spacing, GdkPixmap *pixmap_closed, @@ -2546,14 +2546,14 @@ gtk_sctree_last_visible (GtkCTree *ctree, pixmap_opened = emptyxpm; mask_opened = emptyxpmmask; } - return gtk_ctree_insert_node(ctree, parent, sibling, text,spacing, + return gtk_cmctree_insert_node(ctree, parent, sibling, text,spacing, pixmap_closed, mask_closed, pixmap_opened, mask_opened, is_leaf, expanded); }*/ static void -sset_node_info (GtkCTree *ctree, - GtkCTreeNode *node, +sset_node_info (GtkCMCTree *ctree, + GtkCMCTreeNode *node, const gchar *text, guint8 spacing, GdkPixmap *pixmap_closed, @@ -2563,70 +2563,70 @@ sset_node_info (GtkCTree *ctree, gboolean is_leaf, gboolean expanded) { - if (GTK_CTREE_ROW (node)->pixmap_opened) + if (GTK_CMCTREE_ROW (node)->pixmap_opened) { - gdk_pixmap_unref (GTK_CTREE_ROW (node)->pixmap_opened); - if (GTK_CTREE_ROW (node)->mask_opened) - gdk_bitmap_unref (GTK_CTREE_ROW (node)->mask_opened); + g_object_unref (GTK_CMCTREE_ROW (node)->pixmap_opened); + if (GTK_CMCTREE_ROW (node)->mask_opened) + g_object_unref (GTK_CMCTREE_ROW (node)->mask_opened); } - if (GTK_CTREE_ROW (node)->pixmap_closed) + if (GTK_CMCTREE_ROW (node)->pixmap_closed) { - gdk_pixmap_unref (GTK_CTREE_ROW (node)->pixmap_closed); - if (GTK_CTREE_ROW (node)->mask_closed) - gdk_bitmap_unref (GTK_CTREE_ROW (node)->mask_closed); + g_object_unref (GTK_CMCTREE_ROW (node)->pixmap_closed); + if (GTK_CMCTREE_ROW (node)->mask_closed) + g_object_unref (GTK_CMCTREE_ROW (node)->mask_closed); } - GTK_CTREE_ROW (node)->pixmap_opened = NULL; - GTK_CTREE_ROW (node)->mask_opened = NULL; - GTK_CTREE_ROW (node)->pixmap_closed = NULL; - GTK_CTREE_ROW (node)->mask_closed = NULL; + GTK_CMCTREE_ROW (node)->pixmap_opened = NULL; + GTK_CMCTREE_ROW (node)->mask_opened = NULL; + GTK_CMCTREE_ROW (node)->pixmap_closed = NULL; + GTK_CMCTREE_ROW (node)->mask_closed = NULL; if (pixmap_closed) { - GTK_CTREE_ROW (node)->pixmap_closed = gdk_pixmap_ref (pixmap_closed); + GTK_CMCTREE_ROW (node)->pixmap_closed = g_object_ref (pixmap_closed); if (mask_closed) - GTK_CTREE_ROW (node)->mask_closed = gdk_bitmap_ref (mask_closed); + GTK_CMCTREE_ROW (node)->mask_closed = g_object_ref (mask_closed); } if (pixmap_opened) { - GTK_CTREE_ROW (node)->pixmap_opened = gdk_pixmap_ref (pixmap_opened); + GTK_CMCTREE_ROW (node)->pixmap_opened = g_object_ref (pixmap_opened); if (mask_opened) - GTK_CTREE_ROW (node)->mask_opened = gdk_bitmap_ref (mask_opened); + GTK_CMCTREE_ROW (node)->mask_opened = g_object_ref (mask_opened); } - GTK_CTREE_ROW (node)->is_leaf = is_leaf; - GTK_CTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded; + GTK_CMCTREE_ROW (node)->is_leaf = is_leaf; + GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded; - if (GTK_CTREE_ROW (node)->expanded) - gtk_ctree_node_set_pixtext (ctree, node, ctree->tree_column, + if (GTK_CMCTREE_ROW (node)->expanded) + gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column, text, spacing, pixmap_opened, mask_opened); else - gtk_ctree_node_set_pixtext (ctree, node, ctree->tree_column, + gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column, text, spacing, pixmap_closed, mask_closed); } static void -stree_draw_node (GtkCTree *ctree, - GtkCTreeNode *node) +stree_draw_node (GtkCMCTree *ctree, + GtkCMCTreeNode *node) { - GtkCList *clist; + GtkCMCList *clist; - clist = GTK_CLIST (ctree); + clist = GTK_CMCLIST (ctree); - if (CLIST_UNFROZEN (clist) && gtk_ctree_is_viewable (ctree, node)) + if (CLIST_UNFROZEN (clist) && gtk_cmctree_is_viewable (ctree, node)) { - GtkCTreeNode *work; + GtkCMCTreeNode *work; gint num = 0; - work = GTK_CTREE_NODE (clist->row_list); + work = GTK_CMCTREE_NODE (clist->row_list); while (work && work != node) { - work = GTK_CTREE_NODE_NEXT (work); + work = GTK_CMCTREE_NODE_NEXT (work); num++; } - if (work && gtk_clist_row_is_visible (clist, num) != GTK_VISIBILITY_NONE) - GTK_CLIST_GET_CLASS (clist)->draw_row - (clist, NULL, num, GTK_CLIST_ROW ((GList *) node)); + if (work && gtk_cmclist_row_is_visible (clist, num) != GTK_VISIBILITY_NONE) + GTK_CMCLIST_GET_CLASS (clist)->draw_row + (clist, NULL, num, GTK_CMCLIST_ROW ((GList *) node)); } } @@ -2635,8 +2635,8 @@ stree_draw_node (GtkCTree *ctree, * around a memory problem deep inside gtk, * revealed by valgrind. */ -void gtk_sctree_set_node_info (GtkCTree *ctree, - GtkCTreeNode *node, +void gtk_sctree_set_node_info (GtkCMCTree *ctree, + GtkCMCTreeNode *node, const gchar *text, guint8 spacing, GdkPixmap *pixmap_closed, @@ -2648,7 +2648,7 @@ void gtk_sctree_set_node_info (GtkCTree *ctree, { gboolean old_leaf; gboolean old_expanded; - GtkCTreeNode *work; + GtkCMCTreeNode *work; if (!emptyxpm) { stock_pixmap_gdk(GTK_WIDGET(ctree), STOCK_PIXMAP_EMPTY, @@ -2663,20 +2663,20 @@ void gtk_sctree_set_node_info (GtkCTree *ctree, mask_opened = emptyxpmmask; } - if (!GTK_IS_CTREE (ctree) || !node) return; + if (!GTK_IS_CMCTREE (ctree) || !node) return; - old_leaf = GTK_CTREE_ROW (node)->is_leaf; - old_expanded = GTK_CTREE_ROW (node)->expanded; + old_leaf = GTK_CMCTREE_ROW (node)->is_leaf; + old_expanded = GTK_CMCTREE_ROW (node)->expanded; - if (is_leaf && (work = GTK_CTREE_ROW (node)->children) != NULL) + if (is_leaf && (work = GTK_CMCTREE_ROW (node)->children) != NULL) { - GtkCTreeNode *ptr; + GtkCMCTreeNode *ptr; while (work) { ptr = work; - work = GTK_CTREE_ROW (work)->sibling; - gtk_ctree_remove_node (ctree, ptr); + work = GTK_CMCTREE_ROW (work)->sibling; + gtk_cmctree_remove_node (ctree, ptr); } } @@ -2685,42 +2685,42 @@ void gtk_sctree_set_node_info (GtkCTree *ctree, if (!is_leaf && !old_leaf) { - GTK_CTREE_ROW (node)->expanded = old_expanded; + GTK_CMCTREE_ROW (node)->expanded = old_expanded; if (expanded && !old_expanded) - gtk_ctree_expand (ctree, node); + gtk_cmctree_expand (ctree, node); else if (!expanded && old_expanded) - gtk_ctree_collapse (ctree, node); + gtk_cmctree_collapse (ctree, node); } - GTK_CTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded; + GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded; stree_draw_node (ctree, node); } -static GtkCTreeRow * -srow_new (GtkCTree *ctree) +static GtkCMCTreeRow * +srow_new (GtkCMCTree *ctree) { - GtkCList *clist; - GtkCTreeRow *ctree_row; + GtkCMCList *clist; + GtkCMCTreeRow *ctree_row; int i; - clist = GTK_CLIST (ctree); + clist = GTK_CMCLIST (ctree); #if GTK_CHECK_VERSION(2,9,0) - ctree_row = g_slice_new (GtkCTreeRow); - ctree_row->row.cell = g_slice_alloc (sizeof (GtkCell) * clist->columns); + ctree_row = g_slice_new (GtkCMCTreeRow); + ctree_row->row.cell = g_slice_alloc (sizeof (GtkCMCell) * clist->columns); #else - ctree_row = g_chunk_new (GtkCTreeRow, (GMemChunk *)clist->row_mem_chunk); - ctree_row->row.cell = g_chunk_new (GtkCell, (GMemChunk *)clist->cell_mem_chunk); + ctree_row = g_chunk_new (GtkCMCTreeRow, (GMemChunk *)clist->row_mem_chunk); + ctree_row->row.cell = g_chunk_new (GtkCMCell, (GMemChunk *)clist->cell_mem_chunk); #endif for (i = 0; i < clist->columns; i++) { - ctree_row->row.cell[i].type = GTK_CELL_EMPTY; + ctree_row->row.cell[i].type = GTK_CMCELL_EMPTY; ctree_row->row.cell[i].vertical = 0; ctree_row->row.cell[i].horizontal = 0; ctree_row->row.cell[i].style = NULL; } - GTK_CELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL; + GTK_CMCELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL; ctree_row->row.fg_set = FALSE; ctree_row->row.bg_set = FALSE; @@ -2744,18 +2744,18 @@ srow_new (GtkCTree *ctree) } static void -srow_delete (GtkCTree *ctree, - GtkCTreeRow *ctree_row) +srow_delete (GtkCMCTree *ctree, + GtkCMCTreeRow *ctree_row) { - GtkCList *clist; + GtkCMCList *clist; gint i; - clist = GTK_CLIST (ctree); + clist = GTK_CMCLIST (ctree); for (i = 0; i < clist->columns; i++) { - GTK_CLIST_GET_CLASS (clist)->set_cell_contents - (clist, &(ctree_row->row), i, GTK_CELL_EMPTY, NULL, 0, NULL, NULL); + GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents + (clist, &(ctree_row->row), i, GTK_CMCELL_EMPTY, NULL, 0, NULL, NULL); if (ctree_row->row.cell[i].style) { if (GTK_WIDGET_REALIZED (ctree)) @@ -2773,16 +2773,16 @@ srow_delete (GtkCTree *ctree, if (ctree_row->pixmap_closed) { - gdk_pixmap_unref (ctree_row->pixmap_closed); + g_object_unref (ctree_row->pixmap_closed); if (ctree_row->mask_closed) - gdk_bitmap_unref (ctree_row->mask_closed); + g_object_unref (ctree_row->mask_closed); } if (ctree_row->pixmap_opened) { - gdk_pixmap_unref (ctree_row->pixmap_opened); + g_object_unref (ctree_row->pixmap_opened); if (ctree_row->mask_opened) - gdk_bitmap_unref (ctree_row->mask_opened); + g_object_unref (ctree_row->mask_opened); } if (ctree_row->row.destroy) @@ -2797,8 +2797,8 @@ srow_delete (GtkCTree *ctree, } #if GTK_CHECK_VERSION(2,9,0) - g_slice_free1 (sizeof (GtkCell) * clist->columns, ctree_row->row.cell); - g_slice_free (GtkCTreeRow, ctree_row); + g_slice_free1 (sizeof (GtkCMCell) * clist->columns, ctree_row->row.cell); + g_slice_free (GtkCMCTreeRow, ctree_row); #else g_mem_chunk_free ((GMemChunk *)clist->cell_mem_chunk, ctree_row->row.cell); g_mem_chunk_free ((GMemChunk *)clist->row_mem_chunk, ctree_row); @@ -2806,17 +2806,17 @@ srow_delete (GtkCTree *ctree, } static void -stree_delete_row (GtkCTree *ctree, - GtkCTreeNode *node, +stree_delete_row (GtkCMCTree *ctree, + GtkCMCTreeNode *node, gpointer data) { - srow_delete (ctree, GTK_CTREE_ROW (node)); + srow_delete (ctree, GTK_CMCTREE_ROW (node)); g_list_free_1 ((GList *)node); } static void -gtk_sctree_column_auto_resize (GtkCList *clist, - GtkCListRow *clist_row, +gtk_sctree_column_auto_resize (GtkCMCList *clist, + GtkCMCListRow *clist_row, gint column, gint old_width) { @@ -2824,26 +2824,26 @@ gtk_sctree_column_auto_resize (GtkCList *clist, GtkRequisition requisition; if (!clist->column[column].auto_resize || - GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) return; if (clist_row) - GTK_CLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row, + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row, column, &requisition); else requisition.width = 0; if (requisition.width > clist->column[column].width) - gtk_clist_set_column_width (clist, column, requisition.width); + gtk_cmclist_set_column_width (clist, column, requisition.width); else if (requisition.width < old_width && old_width == clist->column[column].width) { GList *list; gint new_width; - /* run a "gtk_clist_optimal_column_width" but break, if + /* run a "gtk_cmclist_optimal_column_width" but break, if * the column doesn't shrink */ - if (GTK_CLIST_SHOW_TITLES (clist) && clist->column[column].button) + if (GTK_CMCLIST_SHOW_TITLES (clist) && clist->column[column].button) new_width = (clist->column[column].button->requisition.width - (CELL_SPACING + (2 * COLUMN_INSET))); else @@ -2851,84 +2851,84 @@ gtk_sctree_column_auto_resize (GtkCList *clist, for (list = clist->row_list; list; list = list->next) { - GTK_CLIST_GET_CLASS (clist)->cell_size_request - (clist, GTK_CLIST_ROW (list), column, &requisition); + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request + (clist, GTK_CMCLIST_ROW (list), column, &requisition); new_width = MAX (new_width, requisition.width); if (new_width == clist->column[column].width) break; } if (new_width < clist->column[column].width) - gtk_clist_set_column_width (clist, column, new_width); + gtk_cmclist_set_column_width (clist, column, new_width); } } static void -gtk_sctree_real_tree_expand (GtkCTree *ctree, - GtkCTreeNode *node) +gtk_sctree_real_tree_expand (GtkCMCTree *ctree, + GtkCMCTreeNode *node) { - GtkCList *clist; - GtkCTreeNode *work; + GtkCMCList *clist; + GtkCMCTreeNode *work; GtkRequisition requisition; gboolean visible; gint level; - g_return_if_fail (GTK_IS_CTREE (ctree)); + g_return_if_fail (GTK_IS_CMCTREE (ctree)); - if (!node || GTK_CTREE_ROW (node)->expanded || GTK_CTREE_ROW (node)->is_leaf) + if (!node || GTK_CMCTREE_ROW (node)->expanded || GTK_CMCTREE_ROW (node)->is_leaf) return; - clist = GTK_CLIST (ctree); + clist = GTK_CMCLIST (ctree); - GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); - GTK_CTREE_ROW (node)->expanded = TRUE; - level = GTK_CTREE_ROW (node)->level; + GTK_CMCTREE_ROW (node)->expanded = TRUE; + level = GTK_CMCTREE_ROW (node)->level; - visible = gtk_ctree_is_viewable (ctree, node); + visible = gtk_cmctree_is_viewable (ctree, node); /* get cell width if tree_column is auto resized */ if (visible && clist->column[ctree->tree_column].auto_resize && - !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) - GTK_CLIST_GET_CLASS (clist)->cell_size_request - (clist, &GTK_CTREE_ROW (node)->row, ctree->tree_column, &requisition); + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request + (clist, &GTK_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition); /* unref/unset closed pixmap */ - if (GTK_CELL_PIXTEXT - (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap) + if (GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap) { - gdk_pixmap_unref - (GTK_CELL_PIXTEXT - (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap); + g_object_unref + (GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap); - GTK_CELL_PIXTEXT - (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = NULL; + GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = NULL; - if (GTK_CELL_PIXTEXT - (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask) + if (GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask) { - gdk_pixmap_unref - (GTK_CELL_PIXTEXT - (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask); - GTK_CELL_PIXTEXT - (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask = NULL; + g_object_unref + (GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask); + GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask = NULL; } } /* set/ref opened pixmap */ - if (GTK_CTREE_ROW (node)->pixmap_opened) + if (GTK_CMCTREE_ROW (node)->pixmap_opened) { - GTK_CELL_PIXTEXT - (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = - gdk_pixmap_ref (GTK_CTREE_ROW (node)->pixmap_opened); - - if (GTK_CTREE_ROW (node)->mask_opened) - GTK_CELL_PIXTEXT - (GTK_CTREE_ROW (node)->row.cell[ctree->tree_column])->mask = - gdk_pixmap_ref (GTK_CTREE_ROW (node)->mask_opened); + GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixmap = + g_object_ref (GTK_CMCTREE_ROW (node)->pixmap_opened); + + if (GTK_CMCTREE_ROW (node)->mask_opened) + GTK_CMCELL_PIXTEXT + (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->mask = + g_object_ref (GTK_CMCTREE_ROW (node)->mask_opened); } - work = GTK_CTREE_ROW (node)->children; + work = GTK_CMCTREE_ROW (node)->children; if (work) { GList *list = (GList *)work; @@ -2937,7 +2937,7 @@ gtk_sctree_real_tree_expand (GtkCTree *ctree, gint row; gint i; - if (visible && !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist)) + if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) { cell_width = g_new0 (gint, clist->columns); if (clist->column[ctree->tree_column].auto_resize) @@ -2949,13 +2949,13 @@ gtk_sctree_real_tree_expand (GtkCTree *ctree, for (i = 0; i < clist->columns; i++) if (clist->column[i].auto_resize) { - GTK_CLIST_GET_CLASS (clist)->cell_size_request - (clist, &GTK_CTREE_ROW (work)->row, i, &requisition); + GTK_CMCLIST_GET_CLASS (clist)->cell_size_request + (clist, &GTK_CMCTREE_ROW (work)->row, i, &requisition); cell_width[i] = MAX (requisition.width, cell_width[i]); } list = (GList *)work; - work = GTK_CTREE_NODE_NEXT (work); + work = GTK_CMCTREE_NODE_NEXT (work); tmp++; } } @@ -2963,27 +2963,27 @@ gtk_sctree_real_tree_expand (GtkCTree *ctree, while (work) { list = (GList *)work; - work = GTK_CTREE_NODE_NEXT (work); + work = GTK_CMCTREE_NODE_NEXT (work); tmp++; } - list->next = (GList *)GTK_CTREE_NODE_NEXT (node); + list->next = (GList *)GTK_CMCTREE_NODE_NEXT (node); - if (GTK_CTREE_NODE_NEXT (node)) + if (GTK_CMCTREE_NODE_NEXT (node)) { GList *tmp_list; if (clist->row_list_end == list) clist->row_list_end = g_list_last(list); - tmp_list = (GList *)GTK_CTREE_NODE_NEXT (node); + tmp_list = (GList *)GTK_CMCTREE_NODE_NEXT (node); tmp_list->prev = list; } else clist->row_list_end = list; list = (GList *)node; - list->next = (GList *)(GTK_CTREE_ROW (node)->children); + list->next = (GList *)(GTK_CMCTREE_ROW (node)->children); if (visible) { @@ -2991,7 +2991,7 @@ gtk_sctree_real_tree_expand (GtkCTree *ctree, for (i = 0; i < clist->columns; i++) if (clist->column[i].auto_resize && cell_width[i] > clist->column[i].width) - gtk_clist_set_column_width (clist, i, cell_width[i]); + gtk_cmclist_set_column_width (clist, i, cell_width[i]); g_free (cell_width); if (!GTK_SCTREE(ctree)->sorting) { @@ -3006,15 +3006,15 @@ gtk_sctree_real_tree_expand (GtkCTree *ctree, } else if (visible && clist->column[ctree->tree_column].auto_resize) /* resize tree_column if needed */ - gtk_sctree_column_auto_resize (clist, &GTK_CTREE_ROW (node)->row, ctree->tree_column, + gtk_sctree_column_auto_resize (clist, &GTK_CMCTREE_ROW (node)->row, ctree->tree_column, requisition.width); } -GtkCTreeNode * -gtk_sctree_insert_node (GtkCTree *ctree, - GtkCTreeNode *parent, - GtkCTreeNode *sibling, +GtkCMCTreeNode * +gtk_sctree_insert_node (GtkCMCTree *ctree, + GtkCMCTreeNode *parent, + GtkCMCTreeNode *sibling, gchar *text[], guint8 spacing, GdkPixmap *pixmap_closed, @@ -3024,9 +3024,9 @@ gtk_sctree_insert_node (GtkCTree *ctree, gboolean is_leaf, gboolean expanded) { - GtkCList *clist; - GtkCTreeRow *new_row; - GtkCTreeNode *node; + GtkCMCList *clist; + GtkCMCTreeRow *new_row; + GtkCMCTreeNode *node; GList *list; gint i; @@ -3042,48 +3042,48 @@ gtk_sctree_insert_node (GtkCTree *ctree, pixmap_opened = emptyxpm; mask_opened = emptyxpmmask; } - g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL); + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); if (sibling) - g_return_val_if_fail (GTK_CTREE_ROW (sibling)->parent == parent, NULL); + g_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL); - if (parent && GTK_CTREE_ROW (parent)->is_leaf) + if (parent && GTK_CMCTREE_ROW (parent)->is_leaf) return NULL; - clist = GTK_CLIST (ctree); + clist = GTK_CMCLIST (ctree); /* create the row */ new_row = srow_new (ctree); list = g_list_alloc (); list->data = new_row; - node = GTK_CTREE_NODE (list); + node = GTK_CMCTREE_NODE (list); if (text) for (i = 0; i < clist->columns; i++) if (text[i] && i != ctree->tree_column) - GTK_CLIST_GET_CLASS (clist)->set_cell_contents - (clist, &(new_row->row), i, GTK_CELL_TEXT, text[i], 0, NULL, NULL); + GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents + (clist, &(new_row->row), i, GTK_CMCELL_TEXT, text[i], 0, NULL, NULL); sset_node_info (ctree, node, text ? text[ctree->tree_column] : NULL, spacing, pixmap_closed, mask_closed, pixmap_opened, mask_opened, is_leaf, expanded); /* sorted insertion */ - if (GTK_CLIST_AUTO_SORT (clist)) + if (GTK_CMCLIST_AUTO_SORT (clist)) { if (parent) - sibling = GTK_CTREE_ROW (parent)->children; + sibling = GTK_CMCTREE_ROW (parent)->children; else - sibling = GTK_CTREE_NODE (clist->row_list); + sibling = GTK_CMCTREE_NODE (clist->row_list); while (sibling && clist->compare - (clist, GTK_CTREE_ROW (node), GTK_CTREE_ROW (sibling)) > 0) - sibling = GTK_CTREE_ROW (sibling)->sibling; + (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (sibling)) > 0) + sibling = GTK_CMCTREE_ROW (sibling)->sibling; } gtk_sctree_link (ctree, node, parent, sibling, FALSE); - if (text && !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist) && - gtk_ctree_is_viewable (ctree, node)) + if (text && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) && + gtk_cmctree_is_viewable (ctree, node)) { for (i = 0; i < clist->columns; i++) if (clist->column[i].auto_resize) @@ -3103,58 +3103,58 @@ gtk_sctree_insert_node (GtkCTree *ctree, return node; } -GtkCTreeNode * -gtk_sctree_insert_gnode (GtkCTree *ctree, - GtkCTreeNode *parent, - GtkCTreeNode *sibling, +GtkCMCTreeNode * +gtk_sctree_insert_gnode (GtkCMCTree *ctree, + GtkCMCTreeNode *parent, + GtkCMCTreeNode *sibling, GNode *gnode, - GtkCTreeGNodeFunc func, + GtkCMCTreeGNodeFunc func, gpointer data) { - GtkCList *clist; - GtkCTreeNode *cnode = NULL; - GtkCTreeNode *child = NULL; - GtkCTreeNode *new_child; + GtkCMCList *clist; + GtkCMCTreeNode *cnode = NULL; + GtkCMCTreeNode *child = NULL; + GtkCMCTreeNode *new_child; GList *list; GNode *work; guint depth = 1; - g_return_val_if_fail (GTK_IS_CTREE (ctree), NULL); + g_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); g_return_val_if_fail (gnode != NULL, NULL); g_return_val_if_fail (func != NULL, NULL); if (sibling) - g_return_val_if_fail (GTK_CTREE_ROW (sibling)->parent == parent, NULL); + g_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL); - clist = GTK_CLIST (ctree); + clist = GTK_CMCLIST (ctree); if (parent) - depth = GTK_CTREE_ROW (parent)->level + 1; + depth = GTK_CMCTREE_ROW (parent)->level + 1; list = g_list_alloc (); list->data = srow_new (ctree); - cnode = GTK_CTREE_NODE (list); + cnode = GTK_CMCTREE_NODE (list); - gtk_clist_freeze (clist); + gtk_cmclist_freeze (clist); sset_node_info (ctree, cnode, "", 0, NULL, NULL, NULL, NULL, TRUE, FALSE); if (!func (ctree, depth, gnode, cnode, data)) { stree_delete_row (ctree, cnode, NULL); - gtk_clist_thaw (clist); + gtk_cmclist_thaw (clist); return NULL; } - if (GTK_CLIST_AUTO_SORT (clist)) + if (GTK_CMCLIST_AUTO_SORT (clist)) { if (parent) - sibling = GTK_CTREE_ROW (parent)->children; + sibling = GTK_CMCTREE_ROW (parent)->children; else - sibling = GTK_CTREE_NODE (clist->row_list); + sibling = GTK_CMCTREE_NODE (clist->row_list); while (sibling && clist->compare - (clist, GTK_CTREE_ROW (cnode), GTK_CTREE_ROW (sibling)) > 0) - sibling = GTK_CTREE_ROW (sibling)->sibling; + (clist, GTK_CMCTREE_ROW (cnode), GTK_CMCTREE_ROW (sibling)) > 0) + sibling = GTK_CMCTREE_ROW (sibling)->sibling; } gtk_sctree_link (ctree, cnode, parent, sibling, FALSE); @@ -3167,41 +3167,41 @@ gtk_sctree_insert_gnode (GtkCTree *ctree, child = new_child; } - gtk_clist_thaw (clist); + gtk_cmclist_thaw (clist); return cnode; } static void -sreal_tree_move (GtkCTree *ctree, - GtkCTreeNode *node, - GtkCTreeNode *new_parent, - GtkCTreeNode *new_sibling) +sreal_tree_move (GtkCMCTree *ctree, + GtkCMCTreeNode *node, + GtkCMCTreeNode *new_parent, + GtkCMCTreeNode *new_sibling) { - GtkCList *clist; - GtkCTreeNode *work; + GtkCMCList *clist; + GtkCMCTreeNode *work; gboolean visible = FALSE; g_return_if_fail (ctree != NULL); g_return_if_fail (node != NULL); g_return_if_fail (!new_sibling || - GTK_CTREE_ROW (new_sibling)->parent == new_parent); + GTK_CMCTREE_ROW (new_sibling)->parent == new_parent); - if (new_parent && GTK_CTREE_ROW (new_parent)->is_leaf) + if (new_parent && GTK_CMCTREE_ROW (new_parent)->is_leaf) return; /* new_parent != child of child */ - for (work = new_parent; work; work = GTK_CTREE_ROW (work)->parent) + for (work = new_parent; work; work = GTK_CMCTREE_ROW (work)->parent) if (work == node) return; - clist = GTK_CLIST (ctree); + clist = GTK_CMCLIST (ctree); - visible = gtk_ctree_is_viewable (ctree, node); + visible = gtk_cmctree_is_viewable (ctree, node); if (clist->selection_mode == GTK_SELECTION_MULTIPLE) { - GTK_CLIST_GET_CLASS (clist)->resync_selection (clist, NULL); + GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); g_list_free (clist->undo_selection); g_list_free (clist->undo_unselection); @@ -3209,51 +3209,51 @@ sreal_tree_move (GtkCTree *ctree, clist->undo_unselection = NULL; } - if (GTK_CLIST_AUTO_SORT (clist)) + if (GTK_CMCLIST_AUTO_SORT (clist)) { - if (new_parent == GTK_CTREE_ROW (node)->parent) + if (new_parent == GTK_CMCTREE_ROW (node)->parent) return; if (new_parent) - new_sibling = GTK_CTREE_ROW (new_parent)->children; + new_sibling = GTK_CMCTREE_ROW (new_parent)->children; else - new_sibling = GTK_CTREE_NODE (clist->row_list); + new_sibling = GTK_CMCTREE_NODE (clist->row_list); while (new_sibling && clist->compare - (clist, GTK_CTREE_ROW (node), GTK_CTREE_ROW (new_sibling)) > 0) - new_sibling = GTK_CTREE_ROW (new_sibling)->sibling; + (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (new_sibling)) > 0) + new_sibling = GTK_CMCTREE_ROW (new_sibling)->sibling; } - if (new_parent == GTK_CTREE_ROW (node)->parent && - new_sibling == GTK_CTREE_ROW (node)->sibling) + if (new_parent == GTK_CMCTREE_ROW (node)->parent && + new_sibling == GTK_CMCTREE_ROW (node)->sibling) return; - gtk_clist_freeze (clist); + gtk_cmclist_freeze (clist); work = NULL; - if (!GTK_SCTREE(ctree)->sorting && gtk_ctree_is_viewable (ctree, node)) - work = GTK_CTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)); + if (!GTK_SCTREE(ctree)->sorting && gtk_cmctree_is_viewable (ctree, node)) + work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)); gtk_sctree_unlink (ctree, node, FALSE); gtk_sctree_link (ctree, node, new_parent, new_sibling, FALSE); if (!GTK_SCTREE(ctree)->sorting && work) { - while (work && !gtk_ctree_is_viewable (ctree, work)) - work = GTK_CTREE_ROW (work)->parent; + while (work && !gtk_cmctree_is_viewable (ctree, work)) + work = GTK_CMCTREE_ROW (work)->parent; clist->focus_row = g_list_position (clist->row_list, (GList *)work); clist->undo_anchor = clist->focus_row; } if (clist->column[ctree->tree_column].auto_resize && - !GTK_CLIST_AUTO_RESIZE_BLOCKED (clist) && - (visible || gtk_ctree_is_viewable (ctree, node))) - gtk_clist_set_column_width + !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) && + (visible || gtk_cmctree_is_viewable (ctree, node))) + gtk_cmclist_set_column_width (clist, ctree->tree_column, - gtk_clist_optimal_column_width (clist, ctree->tree_column)); + gtk_cmclist_optimal_column_width (clist, ctree->tree_column)); - gtk_clist_thaw (clist); + gtk_cmclist_thaw (clist); } void gtk_sctree_set_column_tooltip (GtkSCTree *sctree, @@ -3267,7 +3267,7 @@ void gtk_sctree_set_column_tooltip (GtkSCTree *sctree, tips = sctree->tips; #endif - CLAWS_SET_TIP(GTK_CLIST(sctree)->column[column].button, + CLAWS_SET_TIP(GTK_CMCLIST(sctree)->column[column].button, tip); } diff --git a/src/gtk/gtksctree.h b/src/gtk/gtksctree.h @@ -4,8 +4,7 @@ #define __GTK_SCTREE_H__ #include <gtk/gtk.h> -#include <gtk/gtkclist.h> -#include <gtk/gtkctree.h> +#include "gtk/gtkcmctree.h" /* This code is based on "gtkflist.{h,c}" from mc-4.5.42 .*/ @@ -20,10 +19,10 @@ typedef struct _GtkSCTree GtkSCTree; typedef struct _GtkSCTreeClass GtkSCTreeClass; struct _GtkSCTree { - GtkCTree ctree; + GtkCMCTree ctree; /* The anchor row for range selections */ - GtkCTreeNode *anchor_row; + GtkCMCTreeNode *anchor_row; /* Mouse button and position saved on button press */ gint dnd_press_button; @@ -38,14 +37,16 @@ struct _GtkSCTree { /* (dis)allow fancy color stripes */ gboolean show_stripes; - GtkTooltips *tips; +#if !GTK_CHECK_VERSION(2,12,0) + GtkTooltips *tooltips; +#endif gboolean always_expand_recursively; gboolean force_additive_sel; gboolean *use_markup; }; struct _GtkSCTreeClass { - GtkCTreeClass parent_class; + GtkCMCTreeClass parent_class; /* Signal: invoke the popup menu for rows */ void (* row_popup_menu) (GtkSCTree *sctree, GdkEventButton *event); @@ -67,17 +68,17 @@ GtkWidget *gtk_sctree_new_with_titles (gint columns, gint tree_column, gchar *titles[]); void gtk_sctree_select (GtkSCTree *sctree, - GtkCTreeNode *node); + GtkCMCTreeNode *node); void gtk_sctree_select_with_state (GtkSCTree *sctree, - GtkCTreeNode *node, + GtkCMCTreeNode *node, int state); void gtk_sctree_unselect_all (GtkSCTree *sctree); void gtk_sctree_set_anchor_row (GtkSCTree *sctree, - GtkCTreeNode *node); + GtkCMCTreeNode *node); void gtk_sctree_remove_node (GtkSCTree *sctree, - GtkCTreeNode *node); + GtkCMCTreeNode *node); void gtk_sctree_set_stripes(GtkSCTree *sctree, gboolean show_stripes); void gtk_sctree_set_recursive_expand(GtkSCTree *sctree, gboolean rec_exp); @@ -86,13 +87,13 @@ void gtk_sctree_set_recursive_expand(GtkSCTree *sctree, gboolean rec_exp); * Tree sorting functions * ***********************************************************/ -void gtk_sctree_sort_node (GtkCTree *ctree, GtkCTreeNode *node); +void gtk_sctree_sort_node (GtkCMCTree *ctree, GtkCMCTreeNode *node); -void gtk_sctree_sort_recursive (GtkCTree *ctree, GtkCTreeNode *node); +void gtk_sctree_sort_recursive (GtkCMCTree *ctree, GtkCMCTreeNode *node); -GtkCTreeNode* gtk_sctree_insert_node (GtkCTree *ctree, - GtkCTreeNode *parent, - GtkCTreeNode *sibling, +GtkCMCTreeNode* gtk_sctree_insert_node (GtkCMCTree *ctree, + GtkCMCTreeNode *parent, + GtkCMCTreeNode *sibling, gchar *text[], guint8 spacing, GdkPixmap *pixmap_closed, @@ -101,8 +102,8 @@ GtkCTreeNode* gtk_sctree_insert_node (GtkCTree *ctree, GdkBitmap *mask_opened, gboolean is_leaf, gboolean expanded); -void gtk_sctree_set_node_info (GtkCTree *ctree, - GtkCTreeNode *node, +void gtk_sctree_set_node_info (GtkCMCTree *ctree, + GtkCMCTreeNode *node, const gchar *text, guint8 spacing, GdkPixmap *pixmap_closed, @@ -111,12 +112,12 @@ void gtk_sctree_set_node_info (GtkCTree *ctree, GdkBitmap *mask_opened, gboolean is_leaf, gboolean expanded); -GtkCTreeNode * -gtk_sctree_insert_gnode (GtkCTree *ctree, - GtkCTreeNode *parent, - GtkCTreeNode *sibling, +GtkCMCTreeNode * +gtk_sctree_insert_gnode (GtkCMCTree *ctree, + GtkCMCTreeNode *parent, + GtkCMCTreeNode *sibling, GNode *gnode, - GtkCTreeGNodeFunc func, + GtkCMCTreeGNodeFunc func, gpointer data); void gtk_sctree_set_column_tooltip (GtkSCTree *sctree, diff --git a/src/gtk/gtkutils.c b/src/gtk/gtkutils.c @@ -25,13 +25,8 @@ #include <glib/gi18n.h> #include <gdk/gdkkeysyms.h> #include <gdk/gdk.h> -#include <gtk/gtkwidget.h> -#include <gtk/gtkhbbox.h> -#include <gtk/gtkbutton.h> -#include <gtk/gtkctree.h> -#include <gtk/gtkcombo.h> -#include <gtk/gtkbindings.h> -#include <gtk/gtkitemfactory.h> +#include <gtk/gtk.h> +#include "gtk/gtksctree.h" #include <stdlib.h> #include <stdarg.h> #include <sys/stat.h> @@ -221,9 +216,9 @@ void gtkut_stock_with_text_button_set_create(GtkWidget **bbox, #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \ ((clist)->row_height + CELL_SPACING)) -void gtkut_ctree_node_move_if_on_the_edge(GtkCTree *ctree, GtkCTreeNode *node, gint _row) +void gtkut_ctree_node_move_if_on_the_edge(GtkCMCTree *ctree, GtkCMCTreeNode *node, gint _row) { - GtkCList *clist = GTK_CLIST(ctree); + GtkCMCList *clist = GTK_CMCLIST(ctree); gint row; GtkVisibility row_visibility, prev_row_visibility, next_row_visibility; @@ -233,12 +228,12 @@ void gtkut_ctree_node_move_if_on_the_edge(GtkCTree *ctree, GtkCTreeNode *node, g row = (_row != -1 ? _row : g_list_position(clist->row_list, (GList *)node)); if (row < 0 || row >= clist->rows || clist->row_height == 0) return; - row_visibility = gtk_clist_row_is_visible(clist, row); - prev_row_visibility = gtk_clist_row_is_visible(clist, row - 1); - next_row_visibility = gtk_clist_row_is_visible(clist, row + 1); + row_visibility = gtk_cmclist_row_is_visible(clist, row); + prev_row_visibility = gtk_cmclist_row_is_visible(clist, row - 1); + next_row_visibility = gtk_cmclist_row_is_visible(clist, row + 1); if (row_visibility == GTK_VISIBILITY_NONE) { - gtk_clist_moveto(clist, row, -1, 0.5, 0); + gtk_cmclist_moveto(clist, row, -1, 0.5, 0); return; } if (row_visibility == GTK_VISIBILITY_FULL && @@ -250,11 +245,11 @@ void gtkut_ctree_node_move_if_on_the_edge(GtkCTree *ctree, GtkCTreeNode *node, g return; if (prev_row_visibility != GTK_VISIBILITY_FULL) { - gtk_clist_moveto(clist, row, -1, 0.2, 0); + gtk_cmclist_moveto(clist, row, -1, 0.2, 0); return; } if (next_row_visibility != GTK_VISIBILITY_FULL) { - gtk_clist_moveto(clist, row, -1, 0.8, 0); + gtk_cmclist_moveto(clist, row, -1, 0.8, 0); return; } } @@ -263,115 +258,115 @@ void gtkut_ctree_node_move_if_on_the_edge(GtkCTree *ctree, GtkCTreeNode *node, g #undef ROW_TOP_YPIXEL #undef ROW_FROM_YPIXEL -gint gtkut_ctree_get_nth_from_node(GtkCTree *ctree, GtkCTreeNode *node) +gint gtkut_ctree_get_nth_from_node(GtkCMCTree *ctree, GtkCMCTreeNode *node) { g_return_val_if_fail(ctree != NULL, -1); g_return_val_if_fail(node != NULL, -1); - return g_list_position(GTK_CLIST(ctree)->row_list, (GList *)node); + return g_list_position(GTK_CMCLIST(ctree)->row_list, (GList *)node); } /* get the next node, including the invisible one */ -GtkCTreeNode *gtkut_ctree_node_next(GtkCTree *ctree, GtkCTreeNode *node) +GtkCMCTreeNode *gtkut_ctree_node_next(GtkCMCTree *ctree, GtkCMCTreeNode *node) { - GtkCTreeNode *parent; + GtkCMCTreeNode *parent; if (!node) return NULL; - if (GTK_CTREE_ROW(node)->children) - return GTK_CTREE_ROW(node)->children; + if (GTK_CMCTREE_ROW(node)->children) + return GTK_CMCTREE_ROW(node)->children; - if (GTK_CTREE_ROW(node)->sibling) - return GTK_CTREE_ROW(node)->sibling; + if (GTK_CMCTREE_ROW(node)->sibling) + return GTK_CMCTREE_ROW(node)->sibling; - for (parent = GTK_CTREE_ROW(node)->parent; parent != NULL; - parent = GTK_CTREE_ROW(parent)->parent) { - if (GTK_CTREE_ROW(parent)->sibling) - return GTK_CTREE_ROW(parent)->sibling; + for (parent = GTK_CMCTREE_ROW(node)->parent; parent != NULL; + parent = GTK_CMCTREE_ROW(parent)->parent) { + if (GTK_CMCTREE_ROW(parent)->sibling) + return GTK_CMCTREE_ROW(parent)->sibling; } return NULL; } /* get the previous node, including the invisible one */ -GtkCTreeNode *gtkut_ctree_node_prev(GtkCTree *ctree, GtkCTreeNode *node) +GtkCMCTreeNode *gtkut_ctree_node_prev(GtkCMCTree *ctree, GtkCMCTreeNode *node) { - GtkCTreeNode *prev; - GtkCTreeNode *child; + GtkCMCTreeNode *prev; + GtkCMCTreeNode *child; if (!node) return NULL; - prev = GTK_CTREE_NODE_PREV(node); - if (prev == GTK_CTREE_ROW(node)->parent) + prev = GTK_CMCTREE_NODE_PREV(node); + if (prev == GTK_CMCTREE_ROW(node)->parent) return prev; child = prev; - while (GTK_CTREE_ROW(child)->children != NULL) { - child = GTK_CTREE_ROW(child)->children; - while (GTK_CTREE_ROW(child)->sibling != NULL) - child = GTK_CTREE_ROW(child)->sibling; + while (GTK_CMCTREE_ROW(child)->children != NULL) { + child = GTK_CMCTREE_ROW(child)->children; + while (GTK_CMCTREE_ROW(child)->sibling != NULL) + child = GTK_CMCTREE_ROW(child)->sibling; } return child; } -gboolean gtkut_ctree_node_is_selected(GtkCTree *ctree, GtkCTreeNode *node) +gboolean gtkut_ctree_node_is_selected(GtkCMCTree *ctree, GtkCMCTreeNode *node) { - GtkCList *clist = GTK_CLIST(ctree); + GtkCMCList *clist = GTK_CMCLIST(ctree); GList *cur; for (cur = clist->selection; cur != NULL; cur = cur->next) { - if (node == GTK_CTREE_NODE(cur->data)) + if (node == GTK_CMCTREE_NODE(cur->data)) return TRUE; } return FALSE; } -GtkCTreeNode *gtkut_ctree_find_collapsed_parent(GtkCTree *ctree, - GtkCTreeNode *node) +GtkCMCTreeNode *gtkut_ctree_find_collapsed_parent(GtkCMCTree *ctree, + GtkCMCTreeNode *node) { if (!node) return NULL; - while ((node = GTK_CTREE_ROW(node)->parent) != NULL) { - if (!GTK_CTREE_ROW(node)->expanded) + while ((node = GTK_CMCTREE_ROW(node)->parent) != NULL) { + if (!GTK_CMCTREE_ROW(node)->expanded) return node; } return NULL; } -void gtkut_ctree_expand_parent_all(GtkCTree *ctree, GtkCTreeNode *node) +void gtkut_ctree_expand_parent_all(GtkCMCTree *ctree, GtkCMCTreeNode *node) { while ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL) - gtk_ctree_expand(ctree, node); + gtk_cmctree_expand(ctree, node); } -gboolean gtkut_ctree_node_is_parent(GtkCTreeNode *parent, GtkCTreeNode *node) +gboolean gtkut_ctree_node_is_parent(GtkCMCTreeNode *parent, GtkCMCTreeNode *node) { - GtkCTreeNode *tmp; + GtkCMCTreeNode *tmp; g_return_val_if_fail(node != NULL, FALSE); g_return_val_if_fail(parent != NULL, FALSE); tmp = node; while (tmp) { - if(GTK_CTREE_ROW(tmp)->parent && GTK_CTREE_ROW(tmp)->parent == parent) + if(GTK_CMCTREE_ROW(tmp)->parent && GTK_CMCTREE_ROW(tmp)->parent == parent) return TRUE; - tmp = GTK_CTREE_ROW(tmp)->parent; + tmp = GTK_CMCTREE_ROW(tmp)->parent; } return FALSE; } -void gtkut_ctree_set_focus_row(GtkCTree *ctree, GtkCTreeNode *node) +void gtkut_ctree_set_focus_row(GtkCMCTree *ctree, GtkCMCTreeNode *node) { if (node == NULL) return; - gtkut_clist_set_focus_row(GTK_CLIST(ctree), + gtkut_clist_set_focus_row(GTK_CMCLIST(ctree), gtkut_ctree_get_nth_from_node(ctree, node)); } -void gtkut_clist_set_focus_row(GtkCList *clist, gint row) +void gtkut_clist_set_focus_row(GtkCMCList *clist, gint row) { clist->focus_row = row; GTKUT_CTREE_REFRESH(clist); @@ -652,7 +647,7 @@ static void gtkut_clist_bindings_add(GtkWidget *clist) GtkBindingSet *binding_set; binding_set = gtk_binding_set_by_class - (GTK_CLIST_GET_CLASS(clist)); + (GTK_CMCLIST_GET_CLASS(clist)); gtk_binding_entry_add_signal(binding_set, GDK_n, GDK_CONTROL_MASK, "scroll_vertical", 2, @@ -668,13 +663,13 @@ void gtkut_widget_init(void) { GtkWidget *clist; - clist = gtk_clist_new(1); + clist = gtk_cmclist_new(1); g_object_ref(GTK_OBJECT(clist)); g_object_ref_sink(GTK_OBJECT(clist)); gtkut_clist_bindings_add(clist); g_object_unref(GTK_OBJECT(clist)); - clist = gtk_ctree_new(1, 0); + clist = gtk_cmctree_new(1, 0); g_object_ref(GTK_OBJECT(clist)); g_object_ref_sink(GTK_OBJECT(clist)); gtkut_clist_bindings_add(clist); diff --git a/src/gtk/gtkutils.h b/src/gtk/gtkutils.h @@ -43,16 +43,7 @@ #include <gtk/gtkmain.h> #endif -typedef struct _ComboButton ComboButton; - -struct _ComboButton -{ - GtkWidget *arrow; - GtkWidget *button; - GtkWidget *menu; - GtkItemFactory *factory; - gpointer data; -}; +#include "gtkcmctree.h" #define GTK_EVENTS_FLUSH() \ { \ @@ -84,14 +75,14 @@ struct _ComboButton #define GTKUT_CTREE_NODE_SET_ROW_DATA(node, d) \ { \ - GTK_CTREE_ROW(node)->row.data = d; \ + GTK_CMCTREE_ROW(node)->row.data = d; \ } #define GTKUT_CTREE_NODE_GET_ROW_DATA(node) \ - (GTK_CTREE_ROW(node)->row.data) + (GTK_CMCTREE_ROW(node)->row.data) #define GTKUT_CTREE_REFRESH(clist) \ - GTK_CLIST_GET_CLASS(clist)->refresh(clist) + GTK_CMCLIST_GET_CLASS(clist)->refresh(clist) gboolean gtkut_get_font_size (GtkWidget *widget, gint *width, @@ -122,28 +113,28 @@ void gtkut_stock_with_text_button_set_create(GtkWidget **bbox, GtkWidget **button3, const gchar *label3, const gchar *text3); void gtkut_ctree_node_move_if_on_the_edge - (GtkCTree *ctree, - GtkCTreeNode *node, + (GtkCMCTree *ctree, + GtkCMCTreeNode *node, gint _row); -gint gtkut_ctree_get_nth_from_node (GtkCTree *ctree, - GtkCTreeNode *node); -GtkCTreeNode *gtkut_ctree_node_next (GtkCTree *ctree, - GtkCTreeNode *node); -GtkCTreeNode *gtkut_ctree_node_prev (GtkCTree *ctree, - GtkCTreeNode *node); -gboolean gtkut_ctree_node_is_selected (GtkCTree *ctree, - GtkCTreeNode *node); -GtkCTreeNode *gtkut_ctree_find_collapsed_parent - (GtkCTree *ctree, - GtkCTreeNode *node); -void gtkut_ctree_expand_parent_all (GtkCTree *ctree, - GtkCTreeNode *node); -gboolean gtkut_ctree_node_is_parent (GtkCTreeNode *parent, - GtkCTreeNode *node); -void gtkut_ctree_set_focus_row (GtkCTree *ctree, - GtkCTreeNode *node); - -void gtkut_clist_set_focus_row (GtkCList *clist, +gint gtkut_ctree_get_nth_from_node (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +GtkCMCTreeNode *gtkut_ctree_node_next (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +GtkCMCTreeNode *gtkut_ctree_node_prev (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +gboolean gtkut_ctree_node_is_selected (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +GtkCMCTreeNode *gtkut_ctree_find_collapsed_parent + (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +void gtkut_ctree_expand_parent_all (GtkCMCTree *ctree, + GtkCMCTreeNode *node); +gboolean gtkut_ctree_node_is_parent (GtkCMCTreeNode *parent, + GtkCMCTreeNode *node); +void gtkut_ctree_set_focus_row (GtkCMCTree *ctree, + GtkCMCTreeNode *node); + +void gtkut_clist_set_focus_row (GtkCMCList *clist, gint row); void gtkut_container_remove (GtkContainer *container, diff --git a/src/gtk/gtkvscrollbutton.c b/src/gtk/gtkvscrollbutton.c @@ -87,24 +87,27 @@ static gint gtk_real_vscrollbutton_timer (GtkVScrollbutton *scrollbutton); static void gtk_vscrollbutton_set_sensitivity (GtkAdjustment *adjustment, GtkVScrollbutton *scrollbutton); -GtkType gtk_vscrollbutton_get_type(void) +GType gtk_vscrollbutton_get_type(void) { - static GtkType vscrollbutton_type = 0; + static GType vscrollbutton_type = 0; if (!vscrollbutton_type) { - static const GtkTypeInfo vscrollbutton_info = { - "GtkVScrollbutton", - sizeof(GtkVScrollbutton), - sizeof(GtkVScrollbuttonClass), - (GtkClassInitFunc) gtk_vscrollbutton_class_init, - (GtkObjectInitFunc) gtk_vscrollbutton_init, - /* reserved_1 */ NULL, - /* reserved_2 */ NULL, - (GtkClassInitFunc) NULL, + static const GTypeInfo vscrollbutton_info = { + sizeof (GtkVScrollbuttonClass), + + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + + (GClassInitFunc) gtk_vscrollbutton_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + + sizeof (GtkVScrollbutton), + 0, /* n_preallocs */ + (GInstanceInitFunc) gtk_vscrollbutton_init, }; - vscrollbutton_type = - gtk_type_unique(GTK_TYPE_VBOX, &vscrollbutton_info); + vscrollbutton_type = g_type_register_static (GTK_TYPE_VBOX, "GtkVScrollbutton", &vscrollbutton_info, (GTypeFlags)0); } return vscrollbutton_type; @@ -206,7 +209,8 @@ static void gtk_vscrollbutton_init(GtkVScrollbutton *scrollbutton) GtkWidget *gtk_vscrollbutton_new(GtkAdjustment *adjustment) { GtkWidget *vscrollbutton; - vscrollbutton = GTK_WIDGET(gtk_type_new(gtk_vscrollbutton_get_type())); + vscrollbutton = g_object_new (gtk_vscrollbutton_get_type(), + NULL); gtk_vscrollbutton_set_adjustment(GTK_VSCROLLBUTTON(vscrollbutton), adjustment); g_signal_connect(G_OBJECT(GTK_VSCROLLBUTTON(vscrollbutton)->adjustment), diff --git a/src/gtk/menu.c b/src/gtk/menu.c @@ -25,6 +25,7 @@ #include <glib/gi18n.h> #include <gtk/gtk.h> +#include "gtkcmoptionmenu.h" #include "menu.h" #include "utils.h" #include "gtkutils.h" @@ -166,7 +167,7 @@ void menu_button_position(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, *y -= mreq.height; } -gint menu_find_option_menu_index(GtkOptionMenu *optmenu, gpointer data, +gint menu_find_option_menu_index(GtkCMOptionMenu *optmenu, gpointer data, GCompareFunc func) { GtkWidget *menu; @@ -175,7 +176,7 @@ gint menu_find_option_menu_index(GtkOptionMenu *optmenu, gpointer data, GList *cur; gint n; - menu = gtk_option_menu_get_menu(optmenu); + menu = gtk_cmoption_menu_get_menu(optmenu); for (cur = GTK_MENU_SHELL(menu)->children, n = 0; cur != NULL; cur = cur->next, n++) { @@ -204,6 +205,7 @@ static void connect_accel_change_signals(GtkWidget* widget, GtkWidget *wid2) void menu_connect_identical_items(void) { +#if 0 /* DEPRECATED */ gint n; GtkWidget *item1; GtkWidget *item2; @@ -273,4 +275,5 @@ void menu_connect_identical_items(void) if (!item2) debug_print(" ** Menu item not found: %s\n",pairs[n].path2); } } +#endif } diff --git a/src/gtk/menu.h b/src/gtk/menu.h @@ -22,6 +22,7 @@ #include <glib.h> #include <gtk/gtk.h> +#include "gtkcmoptionmenu.h" #define MENU_VAL_ID "Claws::Menu::ValueID" #define MENU_VAL_DATA "Claws::Menu::ValueDATA" @@ -91,15 +92,15 @@ void cm_toggle_menu_set_active(gchar *menu, gboolean active); void cm_menu_set_sensitive_full(GtkUIManager *gui_manager, gchar *menu, gboolean sensitive); void cm_toggle_menu_set_active_full(GtkUIManager *gui_manager, gchar *menu, gboolean active); +gint menu_find_option_menu_index(GtkCMOptionMenu *optmenu, gpointer data, + GCompareFunc func); + void menu_button_position (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data); -gint menu_find_option_menu_index(GtkOptionMenu *optmenu, - gpointer data, - GCompareFunc func); void menu_set_sensitive_all(GtkMenuShell *menu_shell, gboolean sensitive); void menu_connect_identical_items(void); diff --git a/src/gtk/quicksearch.c b/src/gtk/quicksearch.c @@ -29,6 +29,7 @@ #include <gtk/gtk.h> #include <gdk/gdkkeysyms.h> +#include "gtkcmoptionmenu.h" #include "utils.h" #include "combobox.h" #include "menu.h" @@ -87,10 +88,10 @@ gboolean quicksearch_is_fast(QuickSearch *quicksearch) static void quicksearch_set_type(QuickSearch *quicksearch, gint type) { gint index; - index = menu_find_option_menu_index(GTK_OPTION_MENU(quicksearch->search_type_opt), + index = menu_find_option_menu_index(GTK_CMOPTION_MENU(quicksearch->search_type_opt), GINT_TO_POINTER(type), NULL); - gtk_option_menu_set_history(GTK_OPTION_MENU(quicksearch->search_type_opt), index); + gtk_cmoption_menu_set_history(GTK_CMOPTION_MENU(quicksearch->search_type_opt), index); } static gchar *quicksearch_get_text(QuickSearch * quicksearch) @@ -557,7 +558,7 @@ QuickSearch *quicksearch_new() /* quick search */ hbox_search = gtk_hbox_new(FALSE, 0); - search_type_opt = gtk_option_menu_new(); + search_type_opt = gtk_cmoption_menu_new(); gtk_widget_show(search_type_opt); gtk_box_pack_start(GTK_BOX(hbox_search), search_type_opt, FALSE, FALSE, 0); @@ -638,7 +639,7 @@ QuickSearch *quicksearch_new() G_CALLBACK(searchtype_autorun_changed), quicksearch); - gtk_option_menu_set_menu(GTK_OPTION_MENU(search_type_opt), search_type); + gtk_cmoption_menu_set_menu(GTK_CMOPTION_MENU(search_type_opt), search_type); quicksearch->search_type_opt = search_type_opt; quicksearch_set_type(quicksearch, prefs_common.summary_quicksearch_type); @@ -800,7 +801,7 @@ void quicksearch_show(QuickSearch *quicksearch) ctree = summary_get_main_widget(mainwin->summaryview); if (ctree && mainwin->summaryview->selected) - gtk_ctree_node_moveto(GTK_CTREE(ctree), + gtk_cmctree_node_moveto(GTK_CMCTREE(ctree), mainwin->summaryview->selected, 0, 0.5, 0); } diff --git a/src/plugins/dillo_viewer/dillo_viewer.c b/src/plugins/dillo_viewer/dillo_viewer.c @@ -197,7 +197,7 @@ static void dillo_destroy_viewer(MimeViewer *_viewer) gtk_widget_destroy(viewer->socket); } - gtk_widget_unref(GTK_WIDGET(viewer->widget)); + g_object_unref(GTK_WIDGET(viewer->widget)); claws_unlink(viewer->filename); g_free(viewer->filename); g_free(viewer); @@ -219,7 +219,7 @@ static MimeViewer *dillo_viewer_create(void) viewer->widget = gtk_event_box_new(); gtk_widget_show(viewer->widget); - gtk_widget_ref(viewer->widget); + g_object_ref(viewer->widget); viewer->filename = NULL; diff --git a/src/plugins/pgpcore/select-keys.c b/src/plugins/pgpcore/select-keys.c @@ -53,7 +53,7 @@ struct select_keys_s { int okay; GtkWidget *window; GtkLabel *toplabel; - GtkCList *clist; + GtkCMCList *clist; const char *pattern; unsigned int num_keys; gpgme_key_t *kset; @@ -65,7 +65,7 @@ struct select_keys_s { }; -static void set_row (GtkCList *clist, gpgme_key_t key, gpgme_protocol_t proto); +static void set_row (GtkCMCList *clist, gpgme_key_t key, gpgme_protocol_t proto); static gpgme_key_t fill_clist (struct select_keys_s *sk, const char *pattern, gpgme_protocol_t proto); static void create_dialog (struct select_keys_s *sk); @@ -126,7 +126,7 @@ gpgmegtk_recipient_selection (GSList *recp_names, SelectionResult *result, do { sk.pattern = recp_names? recp_names->data:NULL; sk.proto = proto; - gtk_clist_clear (sk.clist); + gtk_cmclist_clear (sk.clist); key = fill_clist (&sk, sk.pattern, proto); update_progress (&sk, 0, sk.pattern); if (!key) { @@ -172,7 +172,7 @@ destroy_key (gpointer data) } static void -set_row (GtkCList *clist, gpgme_key_t key, gpgme_protocol_t proto) +set_row (GtkCMCList *clist, gpgme_key_t key, gpgme_protocol_t proto) { const char *s; const char *text[N_COL_TITLES]; @@ -256,16 +256,16 @@ set_row (GtkCList *clist, gpgme_key_t key, gpgme_protocol_t proto) } text[COL_VALIDITY] = s; - row = gtk_clist_append (clist, (gchar**)text); + row = gtk_cmclist_append (clist, (gchar**)text); g_free (algo_buf); - gtk_clist_set_row_data_full (clist, row, key, destroy_key); + gtk_cmclist_set_row_data_full (clist, row, key, destroy_key); } static gpgme_key_t fill_clist (struct select_keys_s *sk, const char *pattern, gpgme_protocol_t proto) { - GtkCList *clist; + GtkCMCList *clist; gpgme_ctx_t ctx; gpgme_error_t err; gpgme_key_t key; @@ -279,7 +279,7 @@ fill_clist (struct select_keys_s *sk, const char *pattern, gpgme_protocol_t prot debug_print ("select_keys:fill_clist: pattern '%s' proto %d\n", pattern, proto); - /*gtk_clist_freeze (select_keys.clist);*/ + /*gtk_cmclist_freeze (select_keys.clist);*/ err = gpgme_new (&ctx); g_assert (!err); @@ -343,7 +343,7 @@ fill_clist (struct select_keys_s *sk, const char *pattern, gpgme_protocol_t prot sk->select_ctx = NULL; gpgme_release (ctx); } - /*gtk_clist_thaw (select_keys.clist);*/ + /*gtk_cmclist_thaw (select_keys.clist);*/ return (exact_match == TRUE && num_results == 1 ? last_key:NULL); } @@ -396,18 +396,18 @@ create_dialog (struct select_keys_s *sk) titles[COL_EMAIL] = _("Address"); titles[COL_VALIDITY] = _("Val"); - clist = gtk_clist_new_with_titles (N_COL_TITLES, (char**)titles); + clist = gtk_cmclist_new_with_titles (N_COL_TITLES, (char**)titles); gtk_container_add (GTK_CONTAINER (scrolledwin), clist); - gtk_clist_set_column_width (GTK_CLIST(clist), COL_ALGO, 72); - gtk_clist_set_column_width (GTK_CLIST(clist), COL_KEYID, 76); - gtk_clist_set_column_width (GTK_CLIST(clist), COL_NAME, 130); - gtk_clist_set_column_width (GTK_CLIST(clist), COL_EMAIL, 130); - gtk_clist_set_column_width (GTK_CLIST(clist), COL_VALIDITY, 20); - gtk_clist_set_selection_mode (GTK_CLIST(clist), GTK_SELECTION_BROWSE); - g_signal_connect (G_OBJECT(GTK_CLIST(clist)->column[COL_NAME].button), + gtk_cmclist_set_column_width (GTK_CMCLIST(clist), COL_ALGO, 72); + gtk_cmclist_set_column_width (GTK_CMCLIST(clist), COL_KEYID, 76); + gtk_cmclist_set_column_width (GTK_CMCLIST(clist), COL_NAME, 130); + gtk_cmclist_set_column_width (GTK_CMCLIST(clist), COL_EMAIL, 130); + gtk_cmclist_set_column_width (GTK_CMCLIST(clist), COL_VALIDITY, 20); + gtk_cmclist_set_selection_mode (GTK_CMCLIST(clist), GTK_SELECTION_BROWSE); + g_signal_connect (G_OBJECT(GTK_CMCLIST(clist)->column[COL_NAME].button), "clicked", G_CALLBACK(sort_keys_name), sk); - g_signal_connect (G_OBJECT(GTK_CLIST(clist)->column[COL_EMAIL].button), + g_signal_connect (G_OBJECT(GTK_CMCLIST(clist)->column[COL_EMAIL].button), "clicked", G_CALLBACK(sort_keys_email), sk); @@ -440,7 +440,7 @@ create_dialog (struct select_keys_s *sk) sk->window = window; sk->toplabel = GTK_LABEL (label); - sk->clist = GTK_CLIST (clist); + sk->clist = GTK_CMCLIST (clist); } @@ -505,7 +505,7 @@ select_btn_cb (GtkWidget *widget, gpointer data) return; } row = GPOINTER_TO_INT(sk->clist->selection->data); - key = gtk_clist_get_row_data(sk->clist, row); + key = gtk_cmclist_get_row_data(sk->clist, row); if (key) { if ( key->uids->validity < GPGME_VALIDITY_FULL ) { use_key = use_untrusted(key, sk->proto); @@ -599,10 +599,10 @@ use_untrusted (gpgme_key_t key, gpgme_protocol_t proto) static gint -cmp_name (GtkCList *clist, gconstpointer pa, gconstpointer pb) +cmp_name (GtkCMCList *clist, gconstpointer pa, gconstpointer pb) { - gpgme_key_t a = ((GtkCListRow *)pa)->data; - gpgme_key_t b = ((GtkCListRow *)pb)->data; + gpgme_key_t a = ((GtkCMCListRow *)pa)->data; + gpgme_key_t b = ((GtkCMCListRow *)pb)->data; const char *sa, *sb; sa = a? a->uids->name : NULL; @@ -615,10 +615,10 @@ cmp_name (GtkCList *clist, gconstpointer pa, gconstpointer pb) } static gint -cmp_email (GtkCList *clist, gconstpointer pa, gconstpointer pb) +cmp_email (GtkCMCList *clist, gconstpointer pa, gconstpointer pb) { - gpgme_key_t a = ((GtkCListRow *)pa)->data; - gpgme_key_t b = ((GtkCListRow *)pb)->data; + gpgme_key_t a = ((GtkCMCListRow *)pa)->data; + gpgme_key_t b = ((GtkCMCListRow *)pb)->data; const char *sa, *sb; sa = a? a->uids->email : NULL; @@ -633,14 +633,14 @@ cmp_email (GtkCList *clist, gconstpointer pa, gconstpointer pb) static void sort_keys ( struct select_keys_s *sk, enum col_titles column) { - GtkCList *clist = sk->clist; + GtkCMCList *clist = sk->clist; switch (column) { case COL_NAME: - gtk_clist_set_compare_func (clist, cmp_name); + gtk_cmclist_set_compare_func (clist, cmp_name); break; case COL_EMAIL: - gtk_clist_set_compare_func (clist, cmp_email); + gtk_cmclist_set_compare_func (clist, cmp_email); break; default: return; @@ -655,8 +655,8 @@ sort_keys ( struct select_keys_s *sk, enum col_titles column) sk->sort_type = GTK_SORT_ASCENDING; sk->sort_column = column; - gtk_clist_set_sort_type (clist, sk->sort_type); - gtk_clist_sort (clist); + gtk_cmclist_set_sort_type (clist, sk->sort_type); + gtk_cmclist_sort (clist); } static void diff --git a/src/prefs_account.c b/src/prefs_account.c @@ -35,7 +35,7 @@ #include <string.h> #include <stdlib.h> #include <ctype.h> - +#include "gtkcmoptionmenu.h" #include "main.h" #include "prefs_gtk.h" #include "prefs_account.h" @@ -2601,12 +2601,12 @@ static void advanced_create_widget_func(PrefsPage * _page, G_CALLBACK (crosspost_color_toggled), NULL); - colormenu_crosspost = gtk_option_menu_new(); + colormenu_crosspost = gtk_cmoption_menu_new(); gtk_widget_show (colormenu_crosspost); gtk_box_pack_start (GTK_BOX (hbox1), colormenu_crosspost, FALSE, FALSE, 0); menu = colorlabel_create_color_menu(); - gtk_option_menu_set_menu (GTK_OPTION_MENU(colormenu_crosspost), menu); + gtk_cmoption_menu_set_menu (GTK_CMOPTION_MENU(colormenu_crosspost), menu); SET_TOGGLE_SENSITIVITY(checkbtn_crosspost, colormenu_crosspost); PACK_HBOX (hbox1); @@ -3591,7 +3591,7 @@ static void prefs_account_crosspost_set_data_from_colormenu(PrefParam *pparam) GtkWidget *menu; GtkWidget *menuitem; - menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(advanced_page.crosspost_colormenu)); + menu = gtk_cmoption_menu_get_menu(GTK_CMOPTION_MENU(advanced_page.crosspost_colormenu)); menuitem = gtk_menu_get_active(GTK_MENU(menu)); *((gint *)pparam->data) = GPOINTER_TO_INT (g_object_get_data(G_OBJECT(menuitem), "color")); @@ -3600,12 +3600,12 @@ static void prefs_account_crosspost_set_data_from_colormenu(PrefParam *pparam) static void prefs_account_crosspost_set_colormenu(PrefParam *pparam) { gint colorlabel = *((gint *)pparam->data); - GtkOptionMenu *colormenu = GTK_OPTION_MENU(*pparam->widget); + GtkCMOptionMenu *colormenu = GTK_CMOPTION_MENU(*pparam->widget); GtkWidget *menu; GtkWidget *menuitem; - gtk_option_menu_set_history(colormenu, colorlabel); - menu = gtk_option_menu_get_menu(colormenu); + gtk_cmoption_menu_set_history(colormenu, colorlabel); + menu = gtk_cmoption_menu_get_menu(colormenu); menuitem = gtk_menu_get_active(GTK_MENU(menu)); gtk_menu_item_activate(GTK_MENU_ITEM(menuitem)); } diff --git a/src/prefs_filtering_action.c b/src/prefs_filtering_action.c @@ -33,6 +33,7 @@ #include <string.h> #include <errno.h> +#include "gtkcmoptionmenu.h" #include "main.h" #include "prefs_gtk.h" #include "prefs_filtering_action.h" @@ -271,7 +272,7 @@ void prefs_filtering_action_open(GSList *action_list, prefs_filtering_action_create(); } else { /* update color label menu */ - gtk_option_menu_set_menu(GTK_OPTION_MENU(filtering_action.color_optmenu), + gtk_cmoption_menu_set_menu(GTK_CMOPTION_MENU(filtering_action.color_optmenu), colorlabel_create_color_menu()); } @@ -503,9 +504,9 @@ static void prefs_filtering_action_create(void) score_entry = gtk_spin_button_new_with_range(-1000, 1000, 1); gtk_box_pack_start(GTK_BOX(hbox1), score_entry, FALSE, FALSE, 0); - color_optmenu = gtk_option_menu_new(); + color_optmenu = gtk_cmoption_menu_new(); gtk_size_group_add_widget(size_action, color_optmenu); - gtk_option_menu_set_menu(GTK_OPTION_MENU(color_optmenu), + gtk_cmoption_menu_set_menu(GTK_CMOPTION_MENU(color_optmenu), colorlabel_create_color_menu()); prefs_filtering_action_check_widget_width(color_optmenu); gtk_box_pack_start(GTK_BOX(hbox1), color_optmenu, FALSE, FALSE, 0); @@ -904,7 +905,7 @@ static FilteringAction * prefs_filtering_action_dialog_to_action(gboolean alert) break; case ACTION_COLOR: labelcolor = colorlabel_get_color_menu_active_item( - gtk_option_menu_get_menu(GTK_OPTION_MENU(filtering_action.color_optmenu))); + gtk_cmoption_menu_get_menu(GTK_CMOPTION_MENU(filtering_action.color_optmenu))); destination = NULL; break; case ACTION_CHANGE_SCORE: @@ -1273,8 +1274,8 @@ static void prefs_filtering_action_enable_widget(GtkWidget* widget, const gboole gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), 0); else if(GTK_IS_ENTRY(widget)) { gtk_entry_set_text(GTK_ENTRY(widget), ""); - } else if(GTK_IS_OPTION_MENU(widget)) - gtk_option_menu_set_history(GTK_OPTION_MENU(widget), 0); + } else if(GTK_IS_CMOPTION_MENU(widget)) + gtk_cmoption_menu_set_history(GTK_CMOPTION_MENU(widget), 0); gtk_widget_set_sensitive(widget, TRUE); gtk_widget_show(widget); @@ -1572,7 +1573,7 @@ static gboolean prefs_filtering_actions_selected case MATCHACTION_COLOR: combobox_select_by_data(GTK_COMBO_BOX(filtering_action.action_combo), ACTION_COLOR); - gtk_option_menu_set_history(GTK_OPTION_MENU(filtering_action.color_optmenu), + gtk_cmoption_menu_set_history(GTK_CMOPTION_MENU(filtering_action.color_optmenu), action->labelcolor); break; case MATCHACTION_CHANGE_SCORE: diff --git a/src/prefs_matcher.c b/src/prefs_matcher.c @@ -33,6 +33,7 @@ #include <string.h> #include <errno.h> +#include "gtkcmoptionmenu.h" #include "main.h" #include "prefs_gtk.h" #include "prefs_matcher.h" @@ -422,7 +423,7 @@ void prefs_matcher_open(MatcherList *matchers, PrefsMatcherSignal *cb) prefs_matcher_create(); } else { /* update color label menu */ - gtk_option_menu_set_menu(GTK_OPTION_MENU(matcher.color_optmenu), + gtk_cmoption_menu_set_menu(GTK_CMOPTION_MENU(matcher.color_optmenu), colorlabel_create_color_menu()); } @@ -656,8 +657,8 @@ static void prefs_matcher_create(void) gtk_box_pack_start(GTK_BOX(match_hbox), match_combo, TRUE, TRUE, 0); /* color labels combo */ - color_optmenu = gtk_option_menu_new(); - gtk_option_menu_set_menu(GTK_OPTION_MENU(color_optmenu), + color_optmenu = gtk_cmoption_menu_new(); + gtk_cmoption_menu_set_menu(GTK_CMOPTION_MENU(color_optmenu), colorlabel_create_color_menu()); gtk_box_pack_start(GTK_BOX(match_hbox), color_optmenu, FALSE, FALSE, 0); @@ -868,7 +869,7 @@ static void prefs_matcher_reset_condition(void) gtk_combo_box_set_active(GTK_COMBO_BOX(matcher.criteria_combo2), 0); gtk_combo_box_set_active(GTK_COMBO_BOX(matcher.match_combo), 0); gtk_combo_box_set_active(GTK_COMBO_BOX(matcher.match_combo2), 0); - gtk_option_menu_set_history(GTK_OPTION_MENU(matcher.color_optmenu), 0); + gtk_cmoption_menu_set_history(GTK_CMOPTION_MENU(matcher.color_optmenu), 0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(matcher.numeric_entry), 0); gtk_entry_set_text(GTK_ENTRY(matcher.header_entry), ""); gtk_entry_set_text(GTK_ENTRY(matcher.header_addr_entry), ""); @@ -1440,7 +1441,7 @@ static MatcherProp *prefs_matcher_dialog_to_matcher(void) case CRITERIA_COLORLABEL: value = colorlabel_get_color_menu_active_item - (gtk_option_menu_get_menu(GTK_OPTION_MENU + (gtk_cmoption_menu_get_menu(GTK_CMOPTION_MENU (matcher.color_optmenu))); break; @@ -1836,7 +1837,7 @@ static void prefs_matcher_criteria_select(GtkWidget *widget, gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.case_checkbtn), FALSE); break; case MATCH_LABEL: - gtk_option_menu_set_history(GTK_OPTION_MENU(matcher.color_optmenu), 0); + gtk_cmoption_menu_set_history(GTK_CMOPTION_MENU(matcher.color_optmenu), 0); prefs_matcher_set_model(matcher.match_combo2, matcher.model_set); gtk_label_set_text(GTK_LABEL(matcher.match_label), _("Label")); gtk_label_set_text(GTK_LABEL(matcher.match_label2), _("is")); @@ -2394,9 +2395,9 @@ static gboolean prefs_matcher_selected(GtkTreeSelection *selector, case MATCHCRITERIA_NOT_COLORLABEL: case MATCHCRITERIA_COLORLABEL: - gtk_option_menu_set_history(GTK_OPTION_MENU(matcher.color_optmenu), + gtk_cmoption_menu_set_history(GTK_CMOPTION_MENU(matcher.color_optmenu), prop->value); - menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(matcher.color_optmenu)); + menu = gtk_cmoption_menu_get_menu(GTK_CMOPTION_MENU(matcher.color_optmenu)); g_signal_emit_by_name(G_OBJECT(menu), "selection-done", menu); break;