remove dbus
[rofl0r-ixchat.git] / src / fe-gtk / chanview-tree.c
blob88d1662b41a83778612cc71d65e5d47a02ea2dba
1 /* file included in chanview.c */
3 typedef struct
5 GtkTreeView *tree;
6 GtkWidget *scrollw; /* scrolledWindow */
7 } treeview;
9 #include "../common/xchat.h"
10 #include "../common/xchatc.h"
11 #include "fe-gtk.h"
12 #include "maingui.h"
14 #include <gdk/gdk.h>
15 #include <gtk/gtktreeview.h>
17 static void /* row-activated, when a row is double clicked */
18 cv_tree_activated_cb (GtkTreeView *view, GtkTreePath *path,
19 GtkTreeViewColumn *column, gpointer data)
21 if (gtk_tree_view_row_expanded (view, path))
22 gtk_tree_view_collapse_row (view, path);
23 else
24 gtk_tree_view_expand_row (view, path, FALSE);
27 static void /* row selected callback */
28 cv_tree_sel_cb (GtkTreeSelection *sel, chanview *cv)
30 GtkTreeModel *model;
31 GtkTreeIter iter;
32 chan *ch;
34 if (gtk_tree_selection_get_selected (sel, &model, &iter))
36 gtk_tree_model_get (model, &iter, COL_CHAN, &ch, -1);
38 cv->focused = ch;
39 cv->cb_focus (cv, ch, ch->tag, ch->userdata);
43 static gboolean
44 cv_tree_click_cb (GtkTreeView *tree, GdkEventButton *event, chanview *cv)
46 chan *ch;
47 GtkTreeSelection *sel;
48 GtkTreePath *path;
49 GtkTreeIter iter;
50 int ret = FALSE;
52 if (event->button != 3 && event->state == 0)
53 return FALSE;
55 sel = gtk_tree_view_get_selection (tree);
56 if (gtk_tree_view_get_path_at_pos (tree, event->x, event->y, &path, 0, 0, 0))
58 if (event->button == 2)
60 gtk_tree_selection_unselect_all (sel);
61 gtk_tree_selection_select_path (sel, path);
63 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (cv->store), &iter, path))
65 gtk_tree_model_get (GTK_TREE_MODEL (cv->store), &iter, COL_CHAN, &ch, -1);
66 ret = cv->cb_contextmenu (cv, ch, ch->tag, ch->userdata, event);
68 gtk_tree_path_free (path);
70 return ret;
73 static void
74 cv_tree_init (chanview *cv)
76 GtkWidget *view, *win;
77 GtkCellRenderer *renderer;
78 static const GtkTargetEntry dnd_src_target[] =
80 {"XCHAT_CHANVIEW", GTK_TARGET_SAME_APP, 75 }
82 static const GtkTargetEntry dnd_dest_target[] =
84 {"XCHAT_USERLIST", GTK_TARGET_SAME_APP, 75 }
87 win = gtk_scrolled_window_new (0, 0);
88 /*gtk_container_set_border_width (GTK_CONTAINER (win), 1);*/
89 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (win),
90 GTK_SHADOW_IN);
91 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (win),
92 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
93 gtk_container_add (GTK_CONTAINER (cv->box), win);
94 gtk_widget_show (win);
96 view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (cv->store));
97 gtk_widget_set_name (view, "xchat-tree");
98 if (cv->style)
99 gtk_widget_set_style (view, cv->style);
100 /*gtk_widget_modify_base (view, GTK_STATE_NORMAL, &colors[COL_BG]);*/
101 GTK_WIDGET_UNSET_FLAGS (view, GTK_CAN_FOCUS);
102 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE);
104 if (!(prefs.gui_tweaks & 8))
105 gtk_tree_view_set_enable_tree_lines (GTK_TREE_VIEW (view), TRUE);
107 gtk_container_add (GTK_CONTAINER (win), view);
109 /* icon column */
110 if (cv->use_icons)
112 renderer = gtk_cell_renderer_pixbuf_new ();
113 if (prefs.gui_tweaks & 32)
114 g_object_set (G_OBJECT (renderer), "ypad", 0, NULL);
115 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
116 -1, NULL, renderer,
117 "pixbuf", COL_PIXBUF, NULL);
120 /* main column */
121 renderer = gtk_cell_renderer_text_new ();
122 if (prefs.gui_tweaks & 32)
123 g_object_set (G_OBJECT (renderer), "ypad", 0, NULL);
124 gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1);
125 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
126 -1, NULL, renderer,
127 "text", COL_NAME, "attributes", COL_ATTR, NULL);
129 g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (view))),
130 "changed", G_CALLBACK (cv_tree_sel_cb), cv);
131 g_signal_connect (G_OBJECT (view), "button-press-event",
132 G_CALLBACK (cv_tree_click_cb), cv);
133 g_signal_connect (G_OBJECT (view), "row-activated",
134 G_CALLBACK (cv_tree_activated_cb), NULL);
136 gtk_drag_dest_set (view, GTK_DEST_DEFAULT_ALL, dnd_dest_target, 1,
137 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
138 gtk_drag_source_set (view, GDK_BUTTON1_MASK, dnd_src_target, 1, GDK_ACTION_COPY);
140 #ifndef WIN32
141 g_signal_connect (G_OBJECT (view), "drag_begin",
142 G_CALLBACK (mg_drag_begin_cb), NULL);
143 g_signal_connect (G_OBJECT (view), "drag_drop",
144 G_CALLBACK (mg_drag_drop_cb), NULL);
145 g_signal_connect (G_OBJECT (view), "drag_motion",
146 G_CALLBACK (mg_drag_motion_cb), NULL);
147 g_signal_connect (G_OBJECT (view), "drag_end",
148 G_CALLBACK (mg_drag_end_cb), NULL);
149 #endif
151 ((treeview *)cv)->tree = GTK_TREE_VIEW (view);
152 ((treeview *)cv)->scrollw = win;
153 gtk_widget_show (view);
156 static void
157 cv_tree_postinit (chanview *cv)
159 gtk_tree_view_expand_all (((treeview *)cv)->tree);
162 static void *
163 cv_tree_add (chanview *cv, chan *ch, char *name, GtkTreeIter *parent)
165 GtkTreePath *path;
167 if (parent)
169 /* expand the parent node */
170 path = gtk_tree_model_get_path (GTK_TREE_MODEL (cv->store), parent);
171 if (path)
173 gtk_tree_view_expand_row (((treeview *)cv)->tree, path, FALSE);
174 gtk_tree_path_free (path);
178 return NULL;
181 static void
182 cv_tree_change_orientation (chanview *cv)
186 static void
187 cv_tree_focus (chan *ch)
189 GtkTreeView *tree = ((treeview *)ch->cv)->tree;
190 GtkTreeModel *model = gtk_tree_view_get_model (tree);
191 GtkTreePath *path;
192 GtkTreeIter parent;
193 GdkRectangle cell_rect;
194 GdkRectangle vis_rect;
195 gint dest_y;
197 /* expand the parent node */
198 if (gtk_tree_model_iter_parent (model, &parent, &ch->iter))
200 path = gtk_tree_model_get_path (model, &parent);
201 if (path)
203 /*if (!gtk_tree_view_row_expanded (tree, path))
205 gtk_tree_path_free (path);
206 return;
208 gtk_tree_view_expand_row (tree, path, FALSE);
209 gtk_tree_path_free (path);
213 path = gtk_tree_model_get_path (model, &ch->iter);
214 if (path)
216 /* This full section does what
217 * gtk_tree_view_scroll_to_cell (tree, path, NULL, TRUE, 0.5, 0.5);
218 * does, except it only scrolls the window if the provided cell is
219 * not visible. Basic algorithm taken from gtktreeview.c */
221 /* obtain information to see if the cell is visible */
222 gtk_tree_view_get_background_area (tree, path, NULL, &cell_rect);
223 gtk_tree_view_get_visible_rect (tree, &vis_rect);
225 /* The cordinates aren't offset correctly */
226 gtk_tree_view_widget_to_tree_coords( tree, cell_rect.x, cell_rect.y, NULL, &cell_rect.y );
228 /* only need to scroll if out of bounds */
229 if (cell_rect.y < vis_rect.y ||
230 cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
232 dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * 0.5);
233 if (dest_y < 0)
234 dest_y = 0;
235 gtk_tree_view_scroll_to_point (tree, -1, dest_y);
237 /* theft done, now make it focused like */
238 gtk_tree_view_set_cursor (tree, path, NULL, FALSE);
239 gtk_tree_path_free (path);
243 static void
244 cv_tree_move_focus (chanview *cv, gboolean relative, int num)
246 chan *ch;
248 if (relative)
250 num += cv_find_number_of_chan (cv, cv->focused);
251 num %= cv->size;
252 /* make it wrap around at both ends */
253 if (num < 0)
254 num = cv->size - 1;
257 ch = cv_find_chan_by_number (cv, num);
258 if (ch)
259 cv_tree_focus (ch);
262 static void
263 cv_tree_remove (chan *ch)
267 static void
268 move_row (chan *ch, int delta, GtkTreeIter *parent)
270 GtkTreeStore *store = ch->cv->store;
271 GtkTreeIter *src = &ch->iter;
272 GtkTreeIter dest = ch->iter;
273 GtkTreePath *dest_path;
275 if (delta < 0) /* down */
277 if (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &dest))
278 gtk_tree_store_swap (store, src, &dest);
279 else /* move to top */
280 gtk_tree_store_move_after (store, src, NULL);
282 } else
284 dest_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &dest);
285 if (gtk_tree_path_prev (dest_path))
287 gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &dest, dest_path);
288 gtk_tree_store_swap (store, src, &dest);
289 } else
290 { /* move to bottom */
291 gtk_tree_store_move_before (store, src, NULL);
294 gtk_tree_path_free (dest_path);
298 static void
299 cv_tree_move (chan *ch, int delta)
301 GtkTreeIter parent;
303 /* do nothing if this is a server row */
304 if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (ch->cv->store), &parent, &ch->iter))
305 move_row (ch, delta, &parent);
308 static void
309 cv_tree_move_family (chan *ch, int delta)
311 move_row (ch, delta, NULL);
314 static void
315 cv_tree_cleanup (chanview *cv)
317 if (cv->box)
318 /* kill the scrolled window */
319 gtk_widget_destroy (((treeview *)cv)->scrollw);
322 static void
323 cv_tree_set_color (chan *ch, PangoAttrList *list)
325 /* nothing to do, it's already set in the store */
328 static void
329 cv_tree_rename (chan *ch, char *name)
331 /* nothing to do, it's already renamed in the store */
334 static chan *
335 cv_tree_get_parent (chan *ch)
337 chan *parent_ch = NULL;
338 GtkTreeIter parent;
340 if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (ch->cv->store), &parent, &ch->iter))
342 gtk_tree_model_get (GTK_TREE_MODEL (ch->cv->store), &parent, COL_CHAN, &parent_ch, -1);
345 return parent_ch;
348 static gboolean
349 cv_tree_is_collapsed (chan *ch)
351 chan *parent = cv_tree_get_parent (ch);
352 GtkTreePath *path = NULL;
353 gboolean ret;
355 if (parent == NULL)
356 return FALSE;
358 path = gtk_tree_model_get_path (GTK_TREE_MODEL (parent->cv->store),
359 &parent->iter);
360 ret = !gtk_tree_view_row_expanded (((treeview *)parent->cv)->tree, path);
361 gtk_tree_path_free (path);
363 return ret;