Mercurial > pidgin
comparison console/libgnt/gnttree.c @ 13964:0a0d2a1fd2bc
[gaim-migrate @ 16520]
Add multi-column support for GntTree. Use it for email-notifications.
Restore colors before exiting.
committer: Tailor Script <tailor@pidgin.im>
author | Sadrul Habib Chowdhury <imadil@gmail.com> |
---|---|
date | Wed, 19 Jul 2006 07:12:59 +0000 |
parents | 841a5ffbfee4 |
children | df8183b7fa2c |
comparison
equal
deleted
inserted
replaced
13963:f7cfaee79982 | 13964:0a0d2a1fd2bc |
---|---|
16 /* XXX: Make this one into a GObject? | 16 /* XXX: Make this one into a GObject? |
17 * ... Probably not */ | 17 * ... Probably not */ |
18 struct _GnTreeRow | 18 struct _GnTreeRow |
19 { | 19 { |
20 void *key; | 20 void *key; |
21 char *text; | |
22 void *data; /* XXX: unused */ | 21 void *data; /* XXX: unused */ |
23 | 22 |
24 gboolean collapsed; | 23 gboolean collapsed; |
25 gboolean choice; /* Is this a choice-box? | 24 gboolean choice; /* Is this a choice-box? |
26 If choice is true, then child will be NULL */ | 25 If choice is true, then child will be NULL */ |
29 | 28 |
30 GntTreeRow *parent; | 29 GntTreeRow *parent; |
31 GntTreeRow *child; | 30 GntTreeRow *child; |
32 GntTreeRow *next; | 31 GntTreeRow *next; |
33 GntTreeRow *prev; | 32 GntTreeRow *prev; |
33 | |
34 GList *columns; | |
35 }; | |
36 | |
37 struct _GnTreeCol | |
38 { | |
39 char *text; | |
40 int span; /* How many columns does it span? */ | |
34 }; | 41 }; |
35 | 42 |
36 static GntWidgetClass *parent_class = NULL; | 43 static GntWidgetClass *parent_class = NULL; |
37 static guint signals[SIGS] = { 0 }; | 44 static guint signals[SIGS] = { 0 }; |
38 | 45 |
149 int hb = get_root_distance(b); | 156 int hb = get_root_distance(b); |
150 | 157 |
151 return (hb - ha); | 158 return (hb - ha); |
152 } | 159 } |
153 | 160 |
161 static int | |
162 find_depth(GntTreeRow *row) | |
163 { | |
164 int dep = -1; | |
165 | |
166 while (row) | |
167 { | |
168 dep++; | |
169 row = row->parent; | |
170 } | |
171 | |
172 return dep; | |
173 } | |
174 | |
175 static char * | |
176 update_row_text(GntTree *tree, GntTreeRow *row) | |
177 { | |
178 GString *string = g_string_new(NULL); | |
179 GList *iter; | |
180 int i; | |
181 | |
182 for (i = 0, iter = row->columns; i < tree->ncol && iter; i++, iter = iter->next) | |
183 { | |
184 GntTreeCol *col = iter->data; | |
185 char *text; | |
186 int len = g_utf8_strlen(col->text, -1); | |
187 int fl = 0; | |
188 gboolean ell = FALSE; | |
189 | |
190 if (i == 0) | |
191 { | |
192 if (row->choice) | |
193 { | |
194 g_string_append_printf(string, "[%c] ", | |
195 row->isselected ? 'X' : ' '); | |
196 fl = 4; | |
197 } | |
198 else if (row->parent == NULL && row->child) | |
199 { | |
200 if (row->collapsed) | |
201 { | |
202 string = g_string_append(string, "+ "); | |
203 } | |
204 else | |
205 { | |
206 string = g_string_append(string, "- "); | |
207 } | |
208 fl = 2; | |
209 } | |
210 else | |
211 { | |
212 fl = TAB_SIZE * find_depth(row); | |
213 g_string_append_printf(string, "%*s", fl, ""); | |
214 } | |
215 len += fl; | |
216 } | |
217 else | |
218 g_string_append_c(string, '|'); | |
219 | |
220 if (len > tree->columns[i].width) | |
221 { | |
222 len = tree->columns[i].width; | |
223 ell = TRUE; | |
224 } | |
225 | |
226 text = g_utf8_offset_to_pointer(col->text, len - fl - ell); | |
227 string = g_string_append_len(string, col->text, text - col->text); | |
228 if (len < tree->columns[i].width) | |
229 g_string_append_printf(string, "%*s", tree->columns[i].width - len, ""); | |
230 else if (ell) | |
231 { | |
232 g_string_append_unichar(string, (gunichar)2026); | |
233 } | |
234 } | |
235 return g_string_free(string, FALSE); | |
236 } | |
237 | |
154 static void | 238 static void |
155 redraw_tree(GntTree *tree) | 239 redraw_tree(GntTree *tree) |
156 { | 240 { |
157 int start; | 241 int start; |
158 GntWidget *widget = GNT_WIDGET(tree); | 242 GntWidget *widget = GNT_WIDGET(tree); |
159 GntTreeRow *row; | 243 GntTreeRow *row; |
160 int pos; | 244 int pos; |
161 gboolean deep; | |
162 | 245 |
163 if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) | 246 if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) |
164 pos = 0; | 247 pos = 0; |
165 else | 248 else |
166 pos = 1; | 249 pos = 1; |
170 if (tree->current == NULL) | 253 if (tree->current == NULL) |
171 tree->current = tree->root; | 254 tree->current = tree->root; |
172 | 255 |
173 wbkgd(widget->window, COLOR_PAIR(GNT_COLOR_NORMAL)); | 256 wbkgd(widget->window, COLOR_PAIR(GNT_COLOR_NORMAL)); |
174 | 257 |
175 deep = TRUE; | |
176 row = tree->top; | 258 row = tree->top; |
177 for (start = pos; row && start < widget->priv.height - pos; | 259 for (start = pos; row && start < widget->priv.height - pos; |
178 start++, row = get_next(row)) | 260 start++, row = get_next(row)) |
179 { | 261 { |
180 char str[2048]; | 262 char *str; |
181 int wr; | 263 int wr; |
182 char format[16] = ""; | |
183 | 264 |
184 GntTextFormatFlags flags = row->flags; | 265 GntTextFormatFlags flags = row->flags; |
185 int attr = 0; | 266 int attr = 0; |
186 | 267 |
187 deep = TRUE; | 268 str = update_row_text(tree, row); |
188 | |
189 if (row->parent == NULL && row->child) | |
190 { | |
191 if (row->collapsed) | |
192 { | |
193 strcpy(format, "+ "); | |
194 deep = FALSE; | |
195 } | |
196 else | |
197 strcpy(format, "- "); | |
198 } | |
199 else if (row->choice) | |
200 { | |
201 g_snprintf(format, sizeof(format) - 1, "[%c] ", row->isselected ? 'X' : ' '); | |
202 } | |
203 | |
204 g_snprintf(str, sizeof(str) - 1, "%s%s", format, row->text); | |
205 | 269 |
206 if ((wr = g_utf8_strlen(str, -1)) >= widget->priv.width - 1 - pos) | 270 if ((wr = g_utf8_strlen(str, -1)) >= widget->priv.width - 1 - pos) |
207 { | 271 { |
208 /* XXX: ellipsize */ | 272 /* XXX: ellipsize */ |
209 char *s = g_utf8_offset_to_pointer(str, widget->priv.width - 1 - pos); | 273 char *s = g_utf8_offset_to_pointer(str, widget->priv.width - 1 - pos); |
236 | 300 |
237 wbkgdset(widget->window, '\0' | attr); | 301 wbkgdset(widget->window, '\0' | attr); |
238 mvwprintw(widget->window, start, pos, str); | 302 mvwprintw(widget->window, start, pos, str); |
239 whline(widget->window, ' ', widget->priv.width - pos * 2 - g_utf8_strlen(str, -1)); | 303 whline(widget->window, ' ', widget->priv.width - pos * 2 - g_utf8_strlen(str, -1)); |
240 tree->bottom = row; | 304 tree->bottom = row; |
305 g_free(str); | |
241 } | 306 } |
242 | 307 |
243 wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); | 308 wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL)); |
244 while (start < widget->priv.height - pos) | 309 while (start < widget->priv.height - pos) |
245 { | 310 { |
265 gnt_tree_size_request(GntWidget *widget) | 330 gnt_tree_size_request(GntWidget *widget) |
266 { | 331 { |
267 if (widget->priv.height == 0) | 332 if (widget->priv.height == 0) |
268 widget->priv.height = 10; /* XXX: Why?! */ | 333 widget->priv.height = 10; /* XXX: Why?! */ |
269 if (widget->priv.width == 0) | 334 if (widget->priv.width == 0) |
270 widget->priv.width = 20; /* YYY: 'cuz ... */ | 335 { |
336 GntTree *tree = GNT_TREE(widget); | |
337 int i, width = 0; | |
338 for (i = 0; i < tree->ncol; i++) | |
339 width += tree->columns[i].width; | |
340 widget->priv.width = width + i; | |
341 } | |
271 } | 342 } |
272 | 343 |
273 static void | 344 static void |
274 gnt_tree_map(GntWidget *widget) | 345 gnt_tree_map(GntWidget *widget) |
275 { | 346 { |
435 | 506 |
436 return type; | 507 return type; |
437 } | 508 } |
438 | 509 |
439 static void | 510 static void |
511 free_tree_col(gpointer data) | |
512 { | |
513 GntTreeCol *col = data; | |
514 | |
515 g_free(col->text); | |
516 g_free(col); | |
517 } | |
518 | |
519 static void | |
440 free_tree_row(gpointer data) | 520 free_tree_row(gpointer data) |
441 { | 521 { |
442 GntTreeRow *row = data; | 522 GntTreeRow *row = data; |
443 | 523 |
444 if (!row) | 524 if (!row) |
445 return; | 525 return; |
446 | 526 |
447 g_free(row->text); | 527 g_list_foreach(row->columns, (GFunc)free_tree_col, NULL); |
528 g_list_free(row->columns); | |
448 g_free(row); | 529 g_free(row); |
449 } | 530 } |
450 | 531 |
451 GntWidget *gnt_tree_new() | 532 GntWidget *gnt_tree_new() |
452 { | 533 { |
453 GntWidget *widget = g_object_new(GNT_TYPE_TREE, NULL); | 534 return gnt_tree_new_with_columns(1); |
454 GntTree *tree = GNT_TREE(widget); | |
455 | |
456 tree->hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free_tree_row); | |
457 GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_SHADOW); | |
458 gnt_widget_set_take_focus(widget, TRUE); | |
459 | |
460 return widget; | |
461 } | 535 } |
462 | 536 |
463 void gnt_tree_set_visible_rows(GntTree *tree, int rows) | 537 void gnt_tree_set_visible_rows(GntTree *tree, int rows) |
464 { | 538 { |
465 GntWidget *widget = GNT_WIDGET(tree); | 539 GntWidget *widget = GNT_WIDGET(tree); |
498 | 572 |
499 redraw_tree(tree); | 573 redraw_tree(tree); |
500 g_signal_emit(tree, signals[SIG_SCROLLED], 0, count); | 574 g_signal_emit(tree, signals[SIG_SCROLLED], 0, count); |
501 } | 575 } |
502 | 576 |
503 static int | 577 GntTreeRow *gnt_tree_add_row_after(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro) |
504 find_depth(GntTreeRow *row) | 578 { |
505 { | 579 GntTreeRow *pr = NULL; |
506 int dep = -1; | |
507 | |
508 while (row) | |
509 { | |
510 dep++; | |
511 row = row->parent; | |
512 } | |
513 | |
514 return dep; | |
515 } | |
516 | |
517 GntTreeRow *gnt_tree_add_row_after(GntTree *tree, void *key, const char *text, void *parent, void *bigbro) | |
518 { | |
519 GntTreeRow *row = g_new0(GntTreeRow, 1), *pr = NULL; | |
520 | 580 |
521 g_hash_table_replace(tree->hash, key, row); | 581 g_hash_table_replace(tree->hash, key, row); |
522 | 582 |
523 if (tree->root == NULL) | 583 if (tree->root == NULL) |
524 { | 584 { |
573 tree->list = g_list_insert(tree->list, key, position + 1); | 633 tree->list = g_list_insert(tree->list, key, position + 1); |
574 } | 634 } |
575 } | 635 } |
576 | 636 |
577 row->key = key; | 637 row->key = key; |
578 row->text = g_strdup_printf("%*s%s", TAB_SIZE * find_depth(row), "", text); | |
579 row->data = NULL; | 638 row->data = NULL; |
580 | 639 |
581 if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_MAPPED)) | 640 if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_MAPPED)) |
582 redraw_tree(tree); | 641 redraw_tree(tree); |
583 | 642 |
589 if (tree->current) | 648 if (tree->current) |
590 return tree->current->key; /* XXX: perhaps we should just get rid of 'data' */ | 649 return tree->current->key; /* XXX: perhaps we should just get rid of 'data' */ |
591 return NULL; | 650 return NULL; |
592 } | 651 } |
593 | 652 |
594 const char *gnt_tree_get_selection_text(GntTree *tree) | 653 char *gnt_tree_get_selection_text(GntTree *tree) |
595 { | 654 { |
596 if (tree->current) | 655 if (tree->current) |
597 return tree->current->text; | 656 update_row_text(tree, tree->current); |
598 return NULL; | 657 return NULL; |
599 } | 658 } |
600 | 659 |
601 /* XXX: Should this also remove all the children of the row being removed? */ | 660 /* XXX: Should this also remove all the children of the row being removed? */ |
602 void gnt_tree_remove(GntTree *tree, gpointer key) | 661 void gnt_tree_remove(GntTree *tree, gpointer key) |
655 { | 714 { |
656 return get_distance(tree->top, tree->current) + | 715 return get_distance(tree->top, tree->current) + |
657 !!(GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_NO_BORDER)); | 716 !!(GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_NO_BORDER)); |
658 } | 717 } |
659 | 718 |
660 void gnt_tree_change_text(GntTree *tree, gpointer key, const char *text) | 719 void gnt_tree_change_text(GntTree *tree, gpointer key, int colno, const char *text) |
661 { | 720 { |
662 GntTreeRow *row = g_hash_table_lookup(tree->hash, key); | 721 GntTreeRow *row; |
722 GntTreeCol *col; | |
723 | |
724 g_return_if_fail(colno < tree->ncol); | |
725 | |
726 row = g_hash_table_lookup(tree->hash, key); | |
663 if (row) | 727 if (row) |
664 { | 728 { |
665 g_free(row->text); | 729 col = g_list_nth_data(row->columns, colno); |
666 row->text = g_strdup_printf("%*s%s", TAB_SIZE * find_depth(row), "", text); | 730 g_free(col->text); |
731 col->text = g_strdup(text); | |
667 | 732 |
668 if (get_distance(tree->top, row) >= 0 && get_distance(row, tree->bottom) > 0) | 733 if (get_distance(tree->top, row) >= 0 && get_distance(row, tree->bottom) > 0) |
669 redraw_tree(tree); | 734 redraw_tree(tree); |
670 } | 735 } |
671 } | 736 } |
672 | 737 |
673 GntTreeRow *gnt_tree_add_choice(GntTree *tree, void *key, const char *text, void *parent, void *bigbro) | 738 GntTreeRow *gnt_tree_add_choice(GntTree *tree, void *key, GntTreeRow *row, void *parent, void *bigbro) |
674 { | 739 { |
675 GntTreeRow *row; | 740 GntTreeRow *r; |
676 | 741 r = g_hash_table_lookup(tree->hash, key); |
677 row = g_hash_table_lookup(tree->hash, key); | 742 g_return_val_if_fail(!r || !r->choice, NULL); |
678 g_return_val_if_fail(!row || !row->choice, NULL); | |
679 | 743 |
680 row = gnt_tree_add_row_after(tree, key, text, parent, bigbro); | 744 row = gnt_tree_add_row_after(tree, key, row, parent, bigbro); |
681 row->choice = TRUE; | 745 row->choice = TRUE; |
682 | 746 |
683 return row; | 747 return row; |
684 } | 748 } |
685 | 749 |
735 gnt_tree_scroll(tree, -dist); | 799 gnt_tree_scroll(tree, -dist); |
736 else | 800 else |
737 redraw_tree(tree); | 801 redraw_tree(tree); |
738 } | 802 } |
739 | 803 |
804 GntWidget *gnt_tree_new_with_columns(int col) | |
805 { | |
806 GntWidget *widget = g_object_new(GNT_TYPE_TREE, NULL); | |
807 GntTree *tree = GNT_TREE(widget); | |
808 | |
809 tree->hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free_tree_row); | |
810 tree->ncol = col; | |
811 tree->columns = g_new0(struct _GntTreeColInfo, col); | |
812 while (col--) | |
813 { | |
814 tree->columns[col].width = 15; | |
815 } | |
816 | |
817 GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_SHADOW); | |
818 gnt_widget_set_take_focus(widget, TRUE); | |
819 | |
820 return widget; | |
821 } | |
822 | |
823 GntTreeRow *gnt_tree_create_row(GntTree *tree, ...) | |
824 { | |
825 GntTreeRow *row = g_new0(GntTreeRow, 1); | |
826 int i; | |
827 va_list args; | |
828 | |
829 va_start(args, tree); | |
830 | |
831 for (i = 0; i < tree->ncol; i++) | |
832 { | |
833 GntTreeCol *col = g_new0(GntTreeCol, 1); | |
834 col->span = 1; | |
835 col->text = g_strdup(va_arg(args, const char *)); | |
836 | |
837 row->columns = g_list_append(row->columns, col); | |
838 } | |
839 | |
840 return row; | |
841 } | |
842 | |
843 void gnt_tree_set_col_width(GntTree *tree, int col, int width) | |
844 { | |
845 g_return_if_fail(col < tree->ncol); | |
846 | |
847 tree->columns[col].width = width; | |
848 } | |
849 |