diff options
author | berkeviktor@aol.com <berkeviktor@aol.com> | 2011-02-24 04:14:30 +0100 |
---|---|---|
committer | berkeviktor@aol.com <berkeviktor@aol.com> | 2011-02-24 04:14:30 +0100 |
commit | 4a6ceffb98a0b785494f680d3776c4bfc4052f9e (patch) | |
tree | 850703c1c841ccd99f58d0b06084615aaebe782c /src/fe-gtk/chanview-tree.c | |
parent | f16af8be941b596dedac3bf4e371ee2d21f4b598 (diff) |
add xchat r1489
Diffstat (limited to 'src/fe-gtk/chanview-tree.c')
-rw-r--r-- | src/fe-gtk/chanview-tree.c | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/src/fe-gtk/chanview-tree.c b/src/fe-gtk/chanview-tree.c new file mode 100644 index 00000000..5373f21b --- /dev/null +++ b/src/fe-gtk/chanview-tree.c @@ -0,0 +1,364 @@ +/* file included in chanview.c */ + +typedef struct +{ + GtkTreeView *tree; + GtkWidget *scrollw; /* scrolledWindow */ +} treeview; + +#include "../common/xchat.h" +#include "../common/xchatc.h" +#include "fe-gtk.h" +#include "maingui.h" + +#include <gdk/gdk.h> +#include <gtk/gtktreeview.h> + +static void /* row-activated, when a row is double clicked */ +cv_tree_activated_cb (GtkTreeView *view, GtkTreePath *path, + GtkTreeViewColumn *column, gpointer data) +{ + if (gtk_tree_view_row_expanded (view, path)) + gtk_tree_view_collapse_row (view, path); + else + gtk_tree_view_expand_row (view, path, FALSE); +} + +static void /* row selected callback */ +cv_tree_sel_cb (GtkTreeSelection *sel, chanview *cv) +{ + GtkTreeModel *model; + GtkTreeIter iter; + chan *ch; + + if (gtk_tree_selection_get_selected (sel, &model, &iter)) + { + gtk_tree_model_get (model, &iter, COL_CHAN, &ch, -1); + + cv->focused = ch; + cv->cb_focus (cv, ch, ch->tag, ch->userdata); + } +} + +static gboolean +cv_tree_click_cb (GtkTreeView *tree, GdkEventButton *event, chanview *cv) +{ + chan *ch; + GtkTreeSelection *sel; + GtkTreePath *path; + GtkTreeIter iter; + int ret = FALSE; + + if (event->button != 3 && event->state == 0) + return FALSE; + + sel = gtk_tree_view_get_selection (tree); + if (gtk_tree_view_get_path_at_pos (tree, event->x, event->y, &path, 0, 0, 0)) + { + if (event->button == 2) + { + gtk_tree_selection_unselect_all (sel); + gtk_tree_selection_select_path (sel, path); + } + if (gtk_tree_model_get_iter (GTK_TREE_MODEL (cv->store), &iter, path)) + { + gtk_tree_model_get (GTK_TREE_MODEL (cv->store), &iter, COL_CHAN, &ch, -1); + ret = cv->cb_contextmenu (cv, ch, ch->tag, ch->userdata, event); + } + gtk_tree_path_free (path); + } + return ret; +} + +static void +cv_tree_init (chanview *cv) +{ + GtkWidget *view, *win; + GtkCellRenderer *renderer; + static const GtkTargetEntry dnd_src_target[] = + { + {"XCHAT_CHANVIEW", GTK_TARGET_SAME_APP, 75 } + }; + static const GtkTargetEntry dnd_dest_target[] = + { + {"XCHAT_USERLIST", GTK_TARGET_SAME_APP, 75 } + }; + + win = gtk_scrolled_window_new (0, 0); + /*gtk_container_set_border_width (GTK_CONTAINER (win), 1);*/ + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (win), + GTK_SHADOW_IN); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (win), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_container_add (GTK_CONTAINER (cv->box), win); + gtk_widget_show (win); + + view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (cv->store)); + gtk_widget_set_name (view, "xchat-tree"); + if (cv->style) + gtk_widget_set_style (view, cv->style); + /*gtk_widget_modify_base (view, GTK_STATE_NORMAL, &colors[COL_BG]);*/ + GTK_WIDGET_UNSET_FLAGS (view, GTK_CAN_FOCUS); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE); +#if GTK_CHECK_VERSION(2,10,0) + if (!(prefs.gui_tweaks & 8)) + gtk_tree_view_set_enable_tree_lines (GTK_TREE_VIEW (view), TRUE); +#endif + gtk_container_add (GTK_CONTAINER (win), view); + + /* icon column */ + if (cv->use_icons) + { + renderer = gtk_cell_renderer_pixbuf_new (); + if (prefs.gui_tweaks & 32) + g_object_set (G_OBJECT (renderer), "ypad", 0, NULL); + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view), + -1, NULL, renderer, + "pixbuf", COL_PIXBUF, NULL); + } + + /* main column */ + renderer = gtk_cell_renderer_text_new (); + if (prefs.gui_tweaks & 32) + g_object_set (G_OBJECT (renderer), "ypad", 0, NULL); + gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1); + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view), + -1, NULL, renderer, + "text", COL_NAME, "attributes", COL_ATTR, NULL); + + g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (view))), + "changed", G_CALLBACK (cv_tree_sel_cb), cv); + g_signal_connect (G_OBJECT (view), "button-press-event", + G_CALLBACK (cv_tree_click_cb), cv); + g_signal_connect (G_OBJECT (view), "row-activated", + G_CALLBACK (cv_tree_activated_cb), NULL); + + gtk_drag_dest_set (view, GTK_DEST_DEFAULT_ALL, dnd_dest_target, 1, + GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK); + gtk_drag_source_set (view, GDK_BUTTON1_MASK, dnd_src_target, 1, GDK_ACTION_COPY); + +#ifndef WIN32 + g_signal_connect (G_OBJECT (view), "drag_begin", + G_CALLBACK (mg_drag_begin_cb), NULL); + g_signal_connect (G_OBJECT (view), "drag_drop", + G_CALLBACK (mg_drag_drop_cb), NULL); + g_signal_connect (G_OBJECT (view), "drag_motion", + G_CALLBACK (mg_drag_motion_cb), NULL); + g_signal_connect (G_OBJECT (view), "drag_end", + G_CALLBACK (mg_drag_end_cb), NULL); +#endif + + ((treeview *)cv)->tree = GTK_TREE_VIEW (view); + ((treeview *)cv)->scrollw = win; + gtk_widget_show (view); +} + +static void +cv_tree_postinit (chanview *cv) +{ + gtk_tree_view_expand_all (((treeview *)cv)->tree); +} + +static void * +cv_tree_add (chanview *cv, chan *ch, char *name, GtkTreeIter *parent) +{ + GtkTreePath *path; + + if (parent) + { + /* expand the parent node */ + path = gtk_tree_model_get_path (GTK_TREE_MODEL (cv->store), parent); + if (path) + { + gtk_tree_view_expand_row (((treeview *)cv)->tree, path, FALSE); + gtk_tree_path_free (path); + } + } + + return NULL; +} + +static void +cv_tree_change_orientation (chanview *cv) +{ +} + +static void +cv_tree_focus (chan *ch) +{ + GtkTreeView *tree = ((treeview *)ch->cv)->tree; + GtkTreeModel *model = gtk_tree_view_get_model (tree); + GtkTreePath *path; + GtkTreeIter parent; + GdkRectangle cell_rect; + GdkRectangle vis_rect; + gint dest_y; + + /* expand the parent node */ + if (gtk_tree_model_iter_parent (model, &parent, &ch->iter)) + { + path = gtk_tree_model_get_path (model, &parent); + if (path) + { + /*if (!gtk_tree_view_row_expanded (tree, path)) + { + gtk_tree_path_free (path); + return; + }*/ + gtk_tree_view_expand_row (tree, path, FALSE); + gtk_tree_path_free (path); + } + } + + path = gtk_tree_model_get_path (model, &ch->iter); + if (path) + { + /* This full section does what + * gtk_tree_view_scroll_to_cell (tree, path, NULL, TRUE, 0.5, 0.5); + * does, except it only scrolls the window if the provided cell is + * not visible. Basic algorithm taken from gtktreeview.c */ + + /* obtain information to see if the cell is visible */ + gtk_tree_view_get_background_area (tree, path, NULL, &cell_rect); + gtk_tree_view_get_visible_rect (tree, &vis_rect); + + /* The cordinates aren't offset correctly */ + gtk_tree_view_widget_to_tree_coords( tree, cell_rect.x, cell_rect.y, NULL, &cell_rect.y ); + + /* only need to scroll if out of bounds */ + if (cell_rect.y < vis_rect.y || + cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height) + { + dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * 0.5); + if (dest_y < 0) + dest_y = 0; + gtk_tree_view_scroll_to_point (tree, -1, dest_y); + } + /* theft done, now make it focused like */ + gtk_tree_view_set_cursor (tree, path, NULL, FALSE); + gtk_tree_path_free (path); + } +} + +static void +cv_tree_move_focus (chanview *cv, gboolean relative, int num) +{ + chan *ch; + + if (relative) + { + num += cv_find_number_of_chan (cv, cv->focused); + num %= cv->size; + /* make it wrap around at both ends */ + if (num < 0) + num = cv->size - 1; + } + + ch = cv_find_chan_by_number (cv, num); + if (ch) + cv_tree_focus (ch); +} + +static void +cv_tree_remove (chan *ch) +{ +} + +static void +move_row (chan *ch, int delta, GtkTreeIter *parent) +{ + GtkTreeStore *store = ch->cv->store; + GtkTreeIter *src = &ch->iter; + GtkTreeIter dest = ch->iter; + GtkTreePath *dest_path; + + if (delta < 0) /* down */ + { + if (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &dest)) + gtk_tree_store_swap (store, src, &dest); + else /* move to top */ + gtk_tree_store_move_after (store, src, NULL); + + } else + { + dest_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &dest); + if (gtk_tree_path_prev (dest_path)) + { + gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &dest, dest_path); + gtk_tree_store_swap (store, src, &dest); + } else + { /* move to bottom */ + gtk_tree_store_move_before (store, src, NULL); + } + + gtk_tree_path_free (dest_path); + } +} + +static void +cv_tree_move (chan *ch, int delta) +{ + GtkTreeIter parent; + + /* do nothing if this is a server row */ + if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (ch->cv->store), &parent, &ch->iter)) + move_row (ch, delta, &parent); +} + +static void +cv_tree_move_family (chan *ch, int delta) +{ + move_row (ch, delta, NULL); +} + +static void +cv_tree_cleanup (chanview *cv) +{ + if (cv->box) + /* kill the scrolled window */ + gtk_widget_destroy (((treeview *)cv)->scrollw); +} + +static void +cv_tree_set_color (chan *ch, PangoAttrList *list) +{ + /* nothing to do, it's already set in the store */ +} + +static void +cv_tree_rename (chan *ch, char *name) +{ + /* nothing to do, it's already renamed in the store */ +} + +static chan * +cv_tree_get_parent (chan *ch) +{ + chan *parent_ch = NULL; + GtkTreeIter parent; + + if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (ch->cv->store), &parent, &ch->iter)) + { + gtk_tree_model_get (GTK_TREE_MODEL (ch->cv->store), &parent, COL_CHAN, &parent_ch, -1); + } + + return parent_ch; +} + +static gboolean +cv_tree_is_collapsed (chan *ch) +{ + chan *parent = cv_tree_get_parent (ch); + GtkTreePath *path = NULL; + gboolean ret; + + if (parent == NULL) + return FALSE; + + path = gtk_tree_model_get_path (GTK_TREE_MODEL (parent->cv->store), + &parent->iter); + ret = !gtk_tree_view_row_expanded (((treeview *)parent->cv)->tree, path); + gtk_tree_path_free (path); + + return ret; +} |