comparison console/libgnt/gnttree.c @ 13850:0e1e59770cb0

[gaim-migrate @ 16308] This is my first commit here. So don't yell at me if things get borked. Also, I haven't looked at the auto-thingies yet. So don't puke at the Makefiles. Files in console/libgnt/ are for the 'Gaim/GObjectified Ncurses Toolkit' library. Files in console/ uses libgaim and libgnt. Currently, only the buddylist-ui is 'functional', ie. the buddy-list updates when someone logs on or logs off. It still needs a lot of work. committer: Tailor Script <tailor@pidgin.im>
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Thu, 22 Jun 2006 08:33:54 +0000
parents
children 41753203a94d
comparison
equal deleted inserted replaced
13849:8d1c55309e3c 13850:0e1e59770cb0
1 #include "gnttree.h"
2
3 enum
4 {
5 SIGS = 1,
6 };
7
8 /* XXX: Make this one into a GObject?
9 * ... Probably not */
10 struct _GnTreeRow
11 {
12 void *key;
13 char *text;
14 void *data; /* XXX: unused */
15
16 GntTreeRow *parent;
17 GntTreeRow *child;
18 GntTreeRow *next;
19 };
20
21 static GntWidgetClass *parent_class = NULL;
22 static guint signals[SIGS] = { 0 };
23
24 /* XXX: This is ugly, but what can you do ... */
25 static void
26 gnt_tree_refresh(GntTree *tree)
27 {
28 GntWidget *widget = GNT_WIDGET(tree);
29 int pos;
30
31 if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER))
32 pos = 0;
33 else
34 pos = 1;
35
36 copywin(tree->scroll, widget->window, tree->top, 0,
37 pos, pos, widget->priv.height - pos - 1, widget->priv.width - pos - 1, FALSE);
38 wrefresh(widget->window);
39 }
40
41 static void
42 redraw_tree(GntTree *tree)
43 {
44 int start;
45 GntWidget *widget = GNT_WIDGET(tree);
46 GList *iter;
47
48 wbkgd(tree->scroll, COLOR_PAIR(GNT_COLOR_NORMAL));
49
50 /* XXX: Add the rows */
51 for (start = tree->top, iter = g_list_nth(tree->list, tree->top);
52 iter && start < tree->bottom; start++, iter = iter->next)
53 {
54 char str[2096]; /* XXX: This should be safe for any terminal */
55 GntTreeRow *row = g_hash_table_lookup(tree->hash, iter->data);
56
57 snprintf(str, widget->priv.width - 2, "%s\n", row->text);
58
59 if (start == tree->current)
60 {
61 wbkgdset(tree->scroll, '\0' | COLOR_PAIR(GNT_COLOR_HIGHLIGHT));
62 mvwprintw(tree->scroll, start, 0, str);
63 wbkgdset(tree->scroll, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL));
64 }
65 else
66 mvwprintw(tree->scroll, start, 0, str);
67 }
68
69 while (start < tree->bottom)
70 {
71 wmove(tree->scroll, start, 0);
72 wclrtoeol(tree->scroll);
73 start++;
74 }
75
76 gnt_tree_refresh(tree);
77 }
78
79 static void
80 gnt_tree_draw(GntWidget *widget)
81 {
82 GntTree *tree = GNT_TREE(widget);
83
84 /* For the Tree (or anything that scrolls), we will create a 'hidden' window
85 * of 'large enough' size. We never wrefresh that hidden-window, instead we
86 * just 'scroll' it, and wrefresh the subwindow */
87
88 if (tree->scroll == NULL)
89 {
90 tree->scroll = newwin(SCROLL_HEIGHT, widget->priv.width, widget->priv.y, widget->priv.x);
91 scrollok(tree->scroll, TRUE);
92 wsetscrreg(tree->scroll, 0, SCROLL_HEIGHT - 1);
93
94 tree->top = 0;
95 tree->bottom = widget->priv.height -
96 (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER) ? 0 : 2);
97 }
98
99 redraw_tree(tree);
100
101 DEBUG;
102 }
103
104 static void
105 gnt_tree_size_request(GntWidget *widget)
106 {
107 if (widget->priv.height == 0)
108 widget->priv.height = 10; /* XXX: Why?! */
109 if (widget->priv.width == 0)
110 widget->priv.width = 20; /* YYY: 'cuz ... */
111 }
112
113 static void
114 gnt_tree_map(GntWidget *widget)
115 {
116 if (widget->priv.width == 0 || widget->priv.height == 0)
117 gnt_widget_size_request(widget);
118 DEBUG;
119 }
120
121 static gboolean
122 gnt_tree_key_pressed(GntWidget *widget, const char *text)
123 {
124 GntTree *tree = GNT_TREE(widget);
125 if (text[0] == 27)
126 {
127 if (strcmp(text+1, GNT_KEY_DOWN) == 0 && tree->current < g_list_length(tree->list) - 1)
128 {
129 tree->current++;
130 if (tree->current >= tree->bottom)
131 gnt_tree_scroll(tree, 1 + tree->current - tree->bottom);
132 redraw_tree(tree);
133 }
134 else if (strcmp(text+1, GNT_KEY_UP) == 0 && tree->current > 0)
135 {
136 tree->current--;
137 if (tree->current < tree->top)
138 gnt_tree_scroll(tree, tree->current - tree->top);
139 redraw_tree(tree);
140 }
141 }
142 else if (text[0] == '\r')
143 {
144 gnt_widget_activate(widget);
145 }
146
147 return FALSE;
148 }
149
150 static void
151 gnt_tree_destroy(GntWidget *widget)
152 {
153 GntTree *tree = GNT_TREE(widget);
154
155 g_hash_table_destroy(tree->hash);
156 g_list_free(tree->list);
157 }
158
159 static void
160 gnt_tree_class_init(GntWidgetClass *klass)
161 {
162 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
163
164 parent_class = GNT_WIDGET_CLASS(klass);
165 parent_class->destroy = gnt_tree_destroy;
166 parent_class->draw = gnt_tree_draw;
167 parent_class->map = gnt_tree_map;
168 parent_class->size_request = gnt_tree_size_request;
169 parent_class->key_pressed = gnt_tree_key_pressed;
170
171 DEBUG;
172 }
173
174 static void
175 gnt_tree_init(GTypeInstance *instance, gpointer class)
176 {
177 DEBUG;
178 }
179
180 /******************************************************************************
181 * GntTree API
182 *****************************************************************************/
183 GType
184 gnt_tree_get_gtype(void)
185 {
186 static GType type = 0;
187
188 if(type == 0)
189 {
190 static const GTypeInfo info = {
191 sizeof(GntTreeClass),
192 NULL, /* base_init */
193 NULL, /* base_finalize */
194 (GClassInitFunc)gnt_tree_class_init,
195 NULL, /* class_finalize */
196 NULL, /* class_data */
197 sizeof(GntTree),
198 0, /* n_preallocs */
199 gnt_tree_init, /* instance_init */
200 };
201
202 type = g_type_register_static(GNT_TYPE_WIDGET,
203 "GntTree",
204 &info, 0);
205 }
206
207 return type;
208 }
209
210 GntWidget *gnt_tree_new()
211 {
212 GntWidget *widget = g_object_new(GNT_TYPE_TREE, NULL);
213 GntTree *tree = GNT_TREE(widget);
214
215 tree->hash = g_hash_table_new(g_direct_hash, g_direct_equal);
216
217 return widget;
218 }
219
220 void gnt_tree_set_visible_rows(GntTree *tree, int rows)
221 {
222 GntWidget *widget = GNT_WIDGET(tree);
223 widget->priv.height = rows;
224 if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER))
225 widget->priv.height += 2;
226 }
227
228 int gnt_tree_get_visible_rows(GntTree *tree)
229 {
230 GntWidget *widget = GNT_WIDGET(tree);
231 int ret = widget->priv.height;
232 if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER))
233 widget->priv.height -= 2;
234 }
235
236 void gnt_tree_scroll(GntTree *tree, int count)
237 {
238 if (tree->top == 0 && count < 0)
239 return;
240
241 if (count > 0 && tree->bottom + count >= g_list_length(tree->list))
242 count = g_list_length(tree->list) - tree->bottom;
243 else if (count < 0 && tree->top + count < 0)
244 count = -tree->top;
245
246 tree->top += count;
247 tree->bottom += count;
248
249 /*wscrl(tree->scroll, count);*/
250 gnt_tree_refresh(tree);
251 }
252
253 void gnt_tree_add_row_after(GntTree *tree, void *key, const char *text, void *parent, void *bigbro)
254 {
255 GntTreeRow *row = g_new0(GntTreeRow, 1), *pr = NULL;
256
257 row->key = key;
258 row->text = g_strdup(text);
259 row->data = NULL;
260
261 g_hash_table_insert(tree->hash, key, row);
262
263 if (tree->root == NULL)
264 {
265 tree->root = row;
266 tree->list = g_list_prepend(tree->list, key);
267 }
268 else
269 {
270 int position;
271
272 if (bigbro)
273 {
274 pr = g_hash_table_lookup(tree->hash, bigbro);
275 if (pr)
276 {
277 row->next = pr->next;
278 pr->next = row;
279 row->parent = pr->parent;
280
281 position = g_list_index(tree->list, bigbro);
282 }
283 }
284
285 if (pr == NULL && parent)
286 {
287 pr = g_hash_table_lookup(tree->hash, parent);
288 if (pr)
289 {
290 row->next = pr->child;
291 pr->child = row;
292 row->parent = pr;
293
294 position = g_list_index(tree->list, parent);
295 }
296 }
297
298 if (pr == NULL)
299 {
300 row->next = tree->root;
301 tree->root = row;
302
303 tree->list = g_list_prepend(tree->list, key);
304 }
305 else
306 {
307 tree->list = g_list_insert(tree->list, key, position + 1);
308 }
309 }
310
311 if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_MAPPED))
312 redraw_tree(tree);
313 }
314
315 gpointer gnt_tree_get_selection_data(GntTree *tree)
316 {
317 return g_list_nth(tree->list, tree->current);
318 }
319
320 int gnt_tree_get_selection_index(GntTree *tree)
321 {
322 return tree->current;
323 }
324
325 void gnt_tree_remove(GntTree *tree, gpointer key)
326 {
327 GntTreeRow *row = g_hash_table_lookup(tree->hash, key);
328 if (row)
329 {
330 int len, pos;
331
332 g_free(row->text);
333 g_free(row);
334
335 pos = g_list_index(tree->list, key);
336
337 g_hash_table_remove(tree->hash, key);
338 tree->list = g_list_remove(tree->list, key);
339
340 if (pos >= tree->top && pos < tree->bottom)
341 {
342 redraw_tree(tree);
343 }
344 }
345 }
346