2 * GNT - The GLib Ncurses Toolkit
4 * GNT is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
8 * This library is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
23 #include "gntmarshal.h"
31 #define SEARCH_TIMEOUT 4000 /* 4 secs */
32 #define SEARCHING(tree) (tree->priv->search && tree->priv->search->len > 0)
34 #define COLUMN_INVISIBLE(tree, index) (tree->columns[index].flags & GNT_TREE_COLUMN_INVISIBLE)
35 #define BINARY_DATA(tree, index) (tree->columns[index].flags & GNT_TREE_COLUMN_BINARY_DATA)
36 #define RIGHT_ALIGNED(tree, index) (tree->columns[index].flags & GNT_TREE_COLUMN_RIGHT_ALIGNED)
46 SIG_SELECTION_CHANGED
,
58 gboolean (*search_func
)(GntTree
*tree
, gpointer key
, const char *search
, const char *current
);
66 /* XXX: Make this one into a GObject?
71 void *data
; /* XXX: unused */
74 gboolean choice
; /* Is this a choice-box?
75 If choice is true, then child will be NULL */
77 GntTextFormatFlags flags
;
92 int span
; /* How many columns does it span? */
95 static void tree_selection_changed(GntTree
*, GntTreeRow
*, GntTreeRow
*);
96 static void _gnt_tree_init_internals(GntTree
*tree
, int col
);
98 static GntWidgetClass
*parent_class
= NULL
;
99 static guint signals
[SIGS
] = { 0 };
102 readjust_columns(GntTree
*tree
)
106 #define WIDTH(i) (tree->columns[i].width_ratio ? tree->columns[i].width_ratio : tree->columns[i].width)
107 gnt_widget_get_size(GNT_WIDGET(tree
), &width
, NULL
);
108 if (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree
), GNT_WIDGET_NO_BORDER
))
110 for (i
= 0, total
= 0; i
< tree
->ncol
; i
++) {
111 if (tree
->columns
[i
].flags
& GNT_TREE_COLUMN_INVISIBLE
)
113 if (tree
->columns
[i
].flags
& GNT_TREE_COLUMN_FIXED_SIZE
)
114 width
-= WIDTH(i
) + 1;
116 total
+= WIDTH(i
) + 1;
122 for (i
= 0; i
< tree
->ncol
; i
++) {
123 if (tree
->columns
[i
].flags
& GNT_TREE_COLUMN_INVISIBLE
)
125 if (tree
->columns
[i
].flags
& GNT_TREE_COLUMN_FIXED_SIZE
)
128 col
= (WIDTH(i
) * width
) / total
;
129 gnt_tree_set_col_width(GNT_TREE(tree
), i
, col
);
133 /* Move the item at position old to position new */
135 g_list_reposition_child(GList
*list
, int old
, int new)
137 gpointer item
= g_list_nth_data(list
, old
);
138 list
= g_list_remove(list
, item
);
140 new--; /* because the positions would have shifted after removing the item */
141 list
= g_list_insert(list
, item
, new);
146 _get_next(GntTreeRow
*row
, gboolean godeep
)
150 if (godeep
&& row
->child
)
154 return _get_next(row
->parent
, FALSE
);
158 row_matches_search(GntTreeRow
*row
)
160 GntTree
*t
= row
->tree
;
161 if (t
->priv
->search
&& t
->priv
->search
->len
> 0) {
162 GntTreeCol
*col
= (col
= g_list_nth_data(row
->columns
, t
->priv
->search_column
)) ? col
: row
->columns
->data
;
164 if (t
->priv
->search_func
)
165 return t
->priv
->search_func(t
, row
->key
, t
->priv
->search
->str
, col
->text
);
166 one
= g_utf8_casefold(col
->text
, -1);
167 two
= g_utf8_casefold(t
->priv
->search
->str
, -1);
168 z
= strstr(one
, two
);
178 get_next(GntTreeRow
*row
)
182 while ((row
= _get_next(row
, !row
->collapsed
)) != NULL
) {
183 if (row_matches_search(row
))
189 /* Returns the n-th next row. If it doesn't exist, returns NULL */
191 get_next_n(GntTreeRow
*row
, int n
)
198 /* Returns the n-th next row. If it doesn't exist, then the last non-NULL node */
200 get_next_n_opt(GntTreeRow
*row
, int n
, int *pos
)
202 GntTreeRow
*next
= row
;
225 get_last_child(GntTreeRow
*row
)
229 if (!row
->collapsed
&& row
->child
)
236 return get_last_child(row
);
240 get_prev(GntTreeRow
*row
)
246 row
= get_last_child(row
->prev
);
249 if (!row
|| row_matches_search(row
))
256 get_prev_n(GntTreeRow
*row
, int n
)
263 /* Distance of row from the root */
264 /* XXX: This is uber-inefficient */
266 get_root_distance(GntTreeRow
*row
)
270 return get_root_distance(get_prev(row
)) + 1;
273 /* Returns the distance between a and b.
274 * If a is 'above' b, then the distance is positive */
276 get_distance(GntTreeRow
*a
, GntTreeRow
*b
)
278 /* First get the distance from a to the root.
279 * Then the distance from b to the root.
281 * It's not that good, but it works. */
282 int ha
= get_root_distance(a
);
283 int hb
= get_root_distance(b
);
289 find_depth(GntTreeRow
*row
)
303 update_row_text(GntTree
*tree
, GntTreeRow
*row
)
305 GString
*string
= g_string_new(NULL
);
308 gboolean notfirst
= FALSE
;
310 for (i
= 0, iter
= row
->columns
; i
< tree
->ncol
&& iter
; i
++, iter
= iter
->next
)
312 GntTreeCol
*col
= iter
->data
;
316 gboolean cut
= FALSE
;
320 if (COLUMN_INVISIBLE(tree
, i
))
323 if (BINARY_DATA(tree
, i
))
328 len
= gnt_util_onscreen_width(display
, NULL
);
330 width
= tree
->columns
[i
].width
;
336 g_string_append_printf(string
, "[%c] ",
337 row
->isselected
? 'X' : ' ');
340 else if (row
->parent
== NULL
&& row
->child
)
344 string
= g_string_append(string
, "+ ");
348 string
= g_string_append(string
, "- ");
354 fl
= TAB_SIZE
* find_depth(row
);
355 g_string_append_printf(string
, "%*s", fl
, "");
358 } else if (notfirst
&& tree
->show_separator
)
359 g_string_append_c(string
, '|');
361 g_string_append_c(string
, ' ');
366 len
= MAX(1, width
- 1);
370 if (RIGHT_ALIGNED(tree
, i
) && len
< tree
->columns
[i
].width
) {
371 g_string_append_printf(string
, "%*s", width
- len
- cut
, "");
374 text
= gnt_util_onscreen_width_to_pointer(display
, len
- fl
, NULL
);
375 string
= g_string_append_len(string
, display
, text
- display
);
376 if (cut
&& width
> 1) { /* ellipsis */
377 if (gnt_ascii_only())
378 g_string_append_c(string
, '~');
380 string
= g_string_append(string
, "\342\200\246");
384 if (!RIGHT_ALIGNED(tree
, i
) && len
< tree
->columns
[i
].width
&& iter
->next
)
385 g_string_append_printf(string
, "%*s", width
- len
, "");
387 return g_string_free(string
, FALSE
);
390 #define NEXT_X x += tree->columns[i].width + (i > 0 ? 1 : 0)
393 tree_mark_columns(GntTree
*tree
, int pos
, int y
, chtype type
)
395 GntWidget
*widget
= GNT_WIDGET(tree
);
398 gboolean notfirst
= FALSE
;
400 for (i
= 0; i
< tree
->ncol
- 1; i
++)
402 if (!COLUMN_INVISIBLE(tree
, i
)) {
406 if (!COLUMN_INVISIBLE(tree
, i
+1) && notfirst
)
407 mvwaddch(widget
->window
, y
, x
, type
);
412 redraw_tree(GntTree
*tree
)
415 GntWidget
*widget
= GNT_WIDGET(tree
);
417 int pos
, up
, down
= 0;
420 if (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree
), GNT_WIDGET_MAPPED
))
423 if (GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_NO_BORDER
))
428 if (tree
->top
== NULL
)
429 tree
->top
= tree
->root
;
430 if (tree
->current
== NULL
) {
431 tree
->current
= tree
->root
;
432 tree_selection_changed(tree
, NULL
, tree
->current
);
435 wbkgd(widget
->window
, gnt_color_pair(GNT_COLOR_NORMAL
));
438 if (tree
->show_title
)
443 mvwhline(widget
->window
, pos
+ 1, pos
, ACS_HLINE
| gnt_color_pair(GNT_COLOR_NORMAL
),
444 widget
->priv
.width
- pos
- 1);
445 mvwhline(widget
->window
, pos
, pos
, ' ' | gnt_color_pair(GNT_COLOR_NORMAL
),
446 widget
->priv
.width
- pos
- 1);
448 for (i
= 0; i
< tree
->ncol
; i
++)
450 if (COLUMN_INVISIBLE(tree
, i
)) {
453 mvwaddnstr(widget
->window
, pos
, x
+ (x
!= pos
), tree
->columns
[i
].title
, tree
->columns
[i
].width
);
458 tree_mark_columns(tree
, pos
, 0,
459 (tree
->show_separator
? ACS_TTEE
: ACS_HLINE
) | gnt_color_pair(GNT_COLOR_NORMAL
));
460 tree_mark_columns(tree
, pos
, widget
->priv
.height
- pos
,
461 (tree
->show_separator
? ACS_BTEE
: ACS_HLINE
) | gnt_color_pair(GNT_COLOR_NORMAL
));
463 tree_mark_columns(tree
, pos
, pos
+ 1,
464 (tree
->show_separator
? ACS_PLUS
: ACS_HLINE
) | gnt_color_pair(GNT_COLOR_NORMAL
));
465 tree_mark_columns(tree
, pos
, pos
,
466 (tree
->show_separator
? ACS_VLINE
: ' ') | gnt_color_pair(GNT_COLOR_NORMAL
));
470 rows
= widget
->priv
.height
- pos
* 2 - start
- 1;
471 tree
->bottom
= get_next_n_opt(tree
->top
, rows
, &down
);
474 tree
->top
= get_prev_n(tree
->bottom
, rows
);
475 if (tree
->top
== NULL
)
476 tree
->top
= tree
->root
;
479 up
= get_distance(tree
->top
, tree
->current
);
481 tree
->top
= tree
->current
;
482 else if (up
>= widget
->priv
.height
- pos
)
483 tree
->top
= get_prev_n(tree
->current
, rows
);
485 if (tree
->top
&& !row_matches_search(tree
->top
))
486 tree
->top
= get_next(tree
->top
);
488 scrcol
= widget
->priv
.width
- 1 - 2 * pos
; /* exclude the borders and the scrollbar */
489 for (i
= start
+ pos
; row
&& i
< widget
->priv
.height
- pos
;
490 i
++, row
= get_next(row
))
495 GntTextFormatFlags flags
= row
->flags
;
498 if (!row_matches_search(row
))
500 str
= update_row_text(tree
, row
);
502 if ((wr
= gnt_util_onscreen_width(str
, NULL
)) > scrcol
)
504 char *s
= (char*)gnt_util_onscreen_width_to_pointer(str
, scrcol
, &wr
);
508 if (flags
& GNT_TEXT_FLAG_BOLD
)
510 if (flags
& GNT_TEXT_FLAG_UNDERLINE
)
512 if (flags
& GNT_TEXT_FLAG_BLINK
)
515 if (row
== tree
->current
)
517 if (gnt_widget_has_focus(widget
))
518 attr
|= gnt_color_pair(GNT_COLOR_HIGHLIGHT
);
520 attr
|= gnt_color_pair(GNT_COLOR_HIGHLIGHT_D
);
524 if (flags
& GNT_TEXT_FLAG_DIM
)
525 attr
|= (A_DIM
| gnt_color_pair(GNT_COLOR_DISABLED
));
526 else if (flags
& GNT_TEXT_FLAG_HIGHLIGHT
)
527 attr
|= (A_DIM
| gnt_color_pair(GNT_COLOR_HIGHLIGHT
));
529 attr
|= gnt_color_pair(GNT_COLOR_NORMAL
);
532 wbkgdset(widget
->window
, '\0' | attr
);
533 mvwaddstr(widget
->window
, i
, pos
, str
);
534 whline(widget
->window
, ' ', scrcol
- wr
);
537 tree_mark_columns(tree
, pos
, i
,
538 (tree
->show_separator
? ACS_VLINE
: ' ') | attr
);
541 wbkgdset(widget
->window
, '\0' | gnt_color_pair(GNT_COLOR_NORMAL
));
542 while (i
< widget
->priv
.height
- pos
)
544 mvwhline(widget
->window
, i
, pos
, ' ',
545 widget
->priv
.width
- pos
* 2 - 1);
546 tree_mark_columns(tree
, pos
, i
,
547 (tree
->show_separator
? ACS_VLINE
: ' '));
551 scrcol
= widget
->priv
.width
- pos
- 1; /* position of the scrollbar */
556 int showing
, position
;
558 get_next_n_opt(tree
->root
, g_list_length(tree
->list
), &total
);
559 showing
= rows
* rows
/ MAX(total
, 1) + 1;
560 showing
= MIN(rows
, showing
);
563 up
= get_distance(tree
->root
, tree
->top
);
566 position
= (rows
- showing
) * up
/ MAX(1, up
+ down
);
567 position
= MAX((tree
->top
!= tree
->root
), position
);
569 if (showing
+ position
> rows
)
570 position
= rows
- showing
;
572 if (showing
+ position
== rows
&& row
)
573 position
= MAX(0, rows
- 1 - showing
);
574 else if (showing
+ position
< rows
&& !row
)
575 position
= rows
- showing
;
577 position
+= pos
+ start
+ 1;
579 mvwvline(widget
->window
, pos
+ start
+ 1, scrcol
,
580 ' ' | gnt_color_pair(GNT_COLOR_NORMAL
), rows
);
581 mvwvline(widget
->window
, position
, scrcol
,
582 ACS_CKBOARD
| gnt_color_pair(GNT_COLOR_HIGHLIGHT_D
), showing
);
585 mvwaddch(widget
->window
, start
+ pos
, scrcol
,
586 ((tree
->top
!= tree
->root
) ? ACS_UARROW
: ' ') |
587 gnt_color_pair(GNT_COLOR_HIGHLIGHT_D
));
589 mvwaddch(widget
->window
, widget
->priv
.height
- pos
- 1, scrcol
,
590 (row
? ACS_DARROW
: ' ') | gnt_color_pair(GNT_COLOR_HIGHLIGHT_D
));
592 /* If there's a search-text, show it in the bottom of the tree */
593 if (tree
->priv
->search
&& tree
->priv
->search
->len
> 0) {
594 const char *str
= gnt_util_onscreen_width_to_pointer(tree
->priv
->search
->str
, scrcol
- 1, NULL
);
595 wbkgdset(widget
->window
, '\0' | gnt_color_pair(GNT_COLOR_HIGHLIGHT_D
));
596 mvwaddnstr(widget
->window
, widget
->priv
.height
- pos
- 1, pos
,
597 tree
->priv
->search
->str
, str
- tree
->priv
->search
->str
);
600 gnt_widget_queue_update(widget
);
604 gnt_tree_draw(GntWidget
*widget
)
606 GntTree
*tree
= GNT_TREE(widget
);
614 gnt_tree_size_request(GntWidget
*widget
)
616 if (widget
->priv
.height
== 0)
617 widget
->priv
.height
= 10; /* XXX: Why?! */
618 if (widget
->priv
.width
== 0)
620 GntTree
*tree
= GNT_TREE(widget
);
622 width
= 1 + 2 * (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree
), GNT_WIDGET_NO_BORDER
));
623 for (i
= 0; i
< tree
->ncol
; i
++)
624 if (!COLUMN_INVISIBLE(tree
, i
)) {
625 width
= width
+ tree
->columns
[i
].width
;
626 if (tree
->priv
->lastvisible
!= i
)
629 widget
->priv
.width
= width
;
634 gnt_tree_map(GntWidget
*widget
)
636 GntTree
*tree
= GNT_TREE(widget
);
637 if (widget
->priv
.width
== 0 || widget
->priv
.height
== 0)
639 gnt_widget_size_request(widget
);
641 tree
->top
= tree
->root
;
642 tree
->current
= tree
->root
;
647 tree_selection_changed(GntTree
*tree
, GntTreeRow
*old
, GntTreeRow
*current
)
649 g_signal_emit(tree
, signals
[SIG_SELECTION_CHANGED
], 0, old
? old
->key
: NULL
,
650 current
? current
->key
: NULL
);
654 action_down(GntBindable
*bind
, GList
*null
)
657 GntTree
*tree
= GNT_TREE(bind
);
658 GntTreeRow
*old
= tree
->current
;
659 GntTreeRow
*row
= get_next(tree
->current
);
663 if ((dist
= get_distance(tree
->current
, tree
->bottom
)) < 0)
664 gnt_tree_scroll(tree
, -dist
);
667 if (old
!= tree
->current
)
668 tree_selection_changed(tree
, old
, tree
->current
);
673 action_move_parent(GntBindable
*bind
, GList
*null
)
675 GntTree
*tree
= GNT_TREE(bind
);
676 GntTreeRow
*row
= tree
->current
;
679 if (!row
->parent
|| SEARCHING(tree
))
682 tree
->current
= row
->parent
;
683 if ((dist
= get_distance(tree
->current
, tree
->top
)) > 0)
684 gnt_tree_scroll(tree
, -dist
);
687 tree_selection_changed(tree
, row
, tree
->current
);
692 action_up(GntBindable
*bind
, GList
*list
)
695 GntTree
*tree
= GNT_TREE(bind
);
696 GntTreeRow
*old
= tree
->current
;
697 GntTreeRow
*row
= get_prev(tree
->current
);
701 if ((dist
= get_distance(tree
->current
, tree
->top
)) > 0)
702 gnt_tree_scroll(tree
, -dist
);
705 if (old
!= tree
->current
)
706 tree_selection_changed(tree
, old
, tree
->current
);
712 action_page_down(GntBindable
*bind
, GList
*null
)
714 GntTree
*tree
= GNT_TREE(bind
);
715 GntTreeRow
*old
= tree
->current
;
716 GntTreeRow
*row
= get_next(tree
->bottom
);
719 int dist
= get_distance(tree
->top
, tree
->current
);
720 tree
->top
= tree
->bottom
;
721 tree
->current
= get_next_n_opt(tree
->top
, dist
, NULL
);
724 else if (tree
->current
!= tree
->bottom
)
726 tree
->current
= tree
->bottom
;
730 if (old
!= tree
->current
)
731 tree_selection_changed(tree
, old
, tree
->current
);
736 action_page_up(GntBindable
*bind
, GList
*null
)
738 GntWidget
*widget
= GNT_WIDGET(bind
);
739 GntTree
*tree
= GNT_TREE(bind
);
741 GntTreeRow
*old
= tree
->current
;
743 if (tree
->top
!= tree
->root
)
745 int dist
= get_distance(tree
->top
, tree
->current
);
746 row
= get_prev_n(tree
->top
, widget
->priv
.height
- 1 -
747 tree
->show_title
* 2 - 2 * (GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_NO_BORDER
) == 0));
751 tree
->current
= get_next_n_opt(tree
->top
, dist
, NULL
);
754 else if (tree
->current
!= tree
->top
)
756 tree
->current
= tree
->top
;
759 if (old
!= tree
->current
)
760 tree_selection_changed(tree
, old
, tree
->current
);
765 end_search(GntTree
*tree
)
767 if (tree
->priv
->search
) {
768 g_source_remove(tree
->priv
->search_timeout
);
769 g_string_free(tree
->priv
->search
, TRUE
);
770 tree
->priv
->search
= NULL
;
771 tree
->priv
->search_timeout
= 0;
772 GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(tree
), GNT_WIDGET_DISABLE_ACTIONS
);
777 search_timeout(gpointer data
)
779 GntTree
*tree
= data
;
788 gnt_tree_key_pressed(GntWidget
*widget
, const char *text
)
790 GntTree
*tree
= GNT_TREE(widget
);
791 GntTreeRow
*old
= tree
->current
;
793 if (text
[0] == '\r') {
795 gnt_widget_activate(widget
);
796 } else if (tree
->priv
->search
) {
797 gboolean changed
= TRUE
;
798 if (isalnum(*text
)) {
799 tree
->priv
->search
= g_string_append_c(tree
->priv
->search
, *text
);
800 } else if (g_utf8_collate(text
, GNT_KEY_BACKSPACE
) == 0) {
801 if (tree
->priv
->search
->len
)
802 tree
->priv
->search
->str
[--tree
->priv
->search
->len
] = '\0';
807 g_source_remove(tree
->priv
->search_timeout
);
808 tree
->priv
->search_timeout
= g_timeout_add(SEARCH_TIMEOUT
, search_timeout
, tree
);
810 gnt_bindable_perform_action_key(GNT_BINDABLE(tree
), text
);
813 } else if (text
[0] == ' ' && text
[1] == 0) {
815 GntTreeRow
*row
= tree
->current
;
816 if (row
&& row
->child
)
818 row
->collapsed
= !row
->collapsed
;
820 g_signal_emit(tree
, signals
[SIG_COLLAPSED
], 0, row
->key
, row
->collapsed
);
822 else if (row
&& row
->choice
)
824 row
->isselected
= !row
->isselected
;
825 g_signal_emit(tree
, signals
[SIG_TOGGLED
], 0, row
->key
);
832 if (old
!= tree
->current
)
834 tree_selection_changed(tree
, old
, tree
->current
);
841 gnt_tree_free_columns(GntTree
*tree
)
844 for (i
= 0; i
< tree
->ncol
; i
++) {
845 g_free(tree
->columns
[i
].title
);
847 g_free(tree
->columns
);
851 gnt_tree_destroy(GntWidget
*widget
)
853 GntTree
*tree
= GNT_TREE(widget
);
857 g_hash_table_destroy(tree
->hash
);
858 g_list_free(tree
->list
);
859 gnt_tree_free_columns(tree
);
864 gnt_tree_clicked(GntWidget
*widget
, GntMouseEvent event
, int x
, int y
)
866 GntTree
*tree
= GNT_TREE(widget
);
867 GntTreeRow
*old
= tree
->current
;
868 if (event
== GNT_MOUSE_SCROLL_UP
) {
869 action_up(GNT_BINDABLE(widget
), NULL
);
870 } else if (event
== GNT_MOUSE_SCROLL_DOWN
) {
871 action_down(GNT_BINDABLE(widget
), NULL
);
872 } else if (event
== GNT_LEFT_MOUSE_DOWN
) {
874 GntTree
*tree
= GNT_TREE(widget
);
876 if (GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_NO_BORDER
))
878 if (tree
->show_title
)
880 pos
= y
- widget
->priv
.y
- pos
;
881 row
= get_next_n(tree
->top
, pos
);
882 if (row
&& tree
->current
!= row
) {
883 GntTreeRow
*old
= tree
->current
;
886 tree_selection_changed(tree
, old
, tree
->current
);
887 } else if (row
&& row
== tree
->current
) {
889 row
->isselected
= !row
->isselected
;
890 g_signal_emit(tree
, signals
[SIG_TOGGLED
], 0, row
->key
);
893 gnt_widget_activate(widget
);
899 if (old
!= tree
->current
) {
900 tree_selection_changed(tree
, old
, tree
->current
);
906 gnt_tree_size_changed(GntWidget
*widget
, int w
, int h
)
908 GntTree
*tree
= GNT_TREE(widget
);
909 if (widget
->priv
.width
<= 0)
912 readjust_columns(tree
);
916 start_search(GntBindable
*bindable
, GList
*list
)
918 GntTree
*tree
= GNT_TREE(bindable
);
919 if (tree
->priv
->search
)
921 GNT_WIDGET_SET_FLAGS(GNT_WIDGET(tree
), GNT_WIDGET_DISABLE_ACTIONS
);
922 tree
->priv
->search
= g_string_new(NULL
);
923 tree
->priv
->search_timeout
= g_timeout_add(SEARCH_TIMEOUT
, search_timeout
, tree
);
928 end_search_action(GntBindable
*bindable
, GList
*list
)
930 GntTree
*tree
= GNT_TREE(bindable
);
931 if (tree
->priv
->search
== NULL
)
933 GNT_WIDGET_UNSET_FLAGS(GNT_WIDGET(tree
), GNT_WIDGET_DISABLE_ACTIONS
);
940 gnt_tree_set_property(GObject
*obj
, guint prop_id
, const GValue
*value
,
943 GntTree
*tree
= GNT_TREE(obj
);
946 _gnt_tree_init_internals(tree
, g_value_get_int(value
));
954 gnt_tree_get_property(GObject
*obj
, guint prop_id
, GValue
*value
,
957 GntTree
*tree
= GNT_TREE(obj
);
960 g_value_set_int(value
, tree
->ncol
);
968 gnt_tree_class_init(GntTreeClass
*klass
)
970 GntBindableClass
*bindable
= GNT_BINDABLE_CLASS(klass
);
971 GObjectClass
*gclass
= G_OBJECT_CLASS(klass
);
973 parent_class
= GNT_WIDGET_CLASS(klass
);
974 parent_class
->destroy
= gnt_tree_destroy
;
975 parent_class
->draw
= gnt_tree_draw
;
976 parent_class
->map
= gnt_tree_map
;
977 parent_class
->size_request
= gnt_tree_size_request
;
978 parent_class
->key_pressed
= gnt_tree_key_pressed
;
979 parent_class
->clicked
= gnt_tree_clicked
;
980 parent_class
->size_changed
= gnt_tree_size_changed
;
982 gclass
->set_property
= gnt_tree_set_property
;
983 gclass
->get_property
= gnt_tree_get_property
;
984 g_object_class_install_property(gclass
,
986 g_param_spec_int("columns", "Columns",
987 "Number of columns in the tree.",
989 G_PARAM_READWRITE
|G_PARAM_STATIC_NAME
|G_PARAM_STATIC_NICK
|G_PARAM_STATIC_BLURB
993 signals
[SIG_SELECTION_CHANGED
] =
994 g_signal_new("selection-changed",
995 G_TYPE_FROM_CLASS(klass
),
997 G_STRUCT_OFFSET(GntTreeClass
, selection_changed
),
999 gnt_closure_marshal_VOID__POINTER_POINTER
,
1000 G_TYPE_NONE
, 2, G_TYPE_POINTER
, G_TYPE_POINTER
);
1001 signals
[SIG_SCROLLED
] =
1002 g_signal_new("scrolled",
1003 G_TYPE_FROM_CLASS(klass
),
1007 g_cclosure_marshal_VOID__INT
,
1008 G_TYPE_NONE
, 1, G_TYPE_INT
);
1009 signals
[SIG_TOGGLED
] =
1010 g_signal_new("toggled",
1011 G_TYPE_FROM_CLASS(klass
),
1013 G_STRUCT_OFFSET(GntTreeClass
, toggled
),
1015 g_cclosure_marshal_VOID__POINTER
,
1016 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1017 signals
[SIG_COLLAPSED
] =
1018 g_signal_new("collapse-toggled",
1019 G_TYPE_FROM_CLASS(klass
),
1023 gnt_closure_marshal_VOID__POINTER_BOOLEAN
,
1024 G_TYPE_NONE
, 2, G_TYPE_POINTER
, G_TYPE_BOOLEAN
);
1026 gnt_bindable_class_register_action(bindable
, "move-up", action_up
,
1028 gnt_bindable_register_binding(bindable
, "move-up", GNT_KEY_CTRL_P
, NULL
);
1029 gnt_bindable_class_register_action(bindable
, "move-down", action_down
,
1030 GNT_KEY_DOWN
, NULL
);
1031 gnt_bindable_register_binding(bindable
, "move-down", GNT_KEY_CTRL_N
, NULL
);
1032 gnt_bindable_class_register_action(bindable
, "move-parent", action_move_parent
,
1033 GNT_KEY_BACKSPACE
, NULL
);
1034 gnt_bindable_class_register_action(bindable
, "page-up", action_page_up
,
1035 GNT_KEY_PGUP
, NULL
);
1036 gnt_bindable_class_register_action(bindable
, "page-down", action_page_down
,
1037 GNT_KEY_PGDOWN
, NULL
);
1038 gnt_bindable_class_register_action(bindable
, "start-search", start_search
,
1040 gnt_bindable_class_register_action(bindable
, "end-search", end_search_action
,
1043 gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass
), bindable
);
1048 gnt_tree_init(GTypeInstance
*instance
, gpointer
class)
1050 GntWidget
*widget
= GNT_WIDGET(instance
);
1051 GntTree
*tree
= GNT_TREE(widget
);
1052 tree
->show_separator
= TRUE
;
1053 tree
->priv
= g_new0(GntTreePriv
, 1);
1054 GNT_WIDGET_SET_FLAGS(widget
, GNT_WIDGET_GROW_X
| GNT_WIDGET_GROW_Y
|
1055 GNT_WIDGET_CAN_TAKE_FOCUS
| GNT_WIDGET_NO_SHADOW
);
1056 gnt_widget_set_take_focus(widget
, TRUE
);
1057 widget
->priv
.minw
= 4;
1058 widget
->priv
.minh
= 1;
1062 /******************************************************************************
1064 *****************************************************************************/
1066 gnt_tree_get_gtype(void)
1068 static GType type
= 0;
1072 static const GTypeInfo info
= {
1073 sizeof(GntTreeClass
),
1074 NULL
, /* base_init */
1075 NULL
, /* base_finalize */
1076 (GClassInitFunc
)gnt_tree_class_init
,
1077 NULL
, /* class_finalize */
1078 NULL
, /* class_data */
1080 0, /* n_preallocs */
1081 gnt_tree_init
, /* instance_init */
1082 NULL
/* value_table */
1085 type
= g_type_register_static(GNT_TYPE_WIDGET
,
1094 free_tree_col(gpointer data
)
1096 GntTreeCol
*col
= data
;
1103 free_tree_row(gpointer data
)
1105 GntTreeRow
*row
= data
;
1110 g_list_foreach(row
->columns
, (GFunc
)free_tree_col
, NULL
);
1111 g_list_free(row
->columns
);
1115 GntWidget
*gnt_tree_new()
1117 return gnt_tree_new_with_columns(1);
1120 void gnt_tree_set_visible_rows(GntTree
*tree
, int rows
)
1122 GntWidget
*widget
= GNT_WIDGET(tree
);
1123 widget
->priv
.height
= rows
;
1124 if (!GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_NO_BORDER
))
1125 widget
->priv
.height
+= 2;
1128 int gnt_tree_get_visible_rows(GntTree
*tree
)
1130 GntWidget
*widget
= GNT_WIDGET(tree
);
1131 int ret
= widget
->priv
.height
;
1132 if (!GNT_WIDGET_IS_FLAG_SET(widget
, GNT_WIDGET_NO_BORDER
))
1137 GList
*gnt_tree_get_rows(GntTree
*tree
)
1142 void gnt_tree_scroll(GntTree
*tree
, int count
)
1148 if (get_root_distance(tree
->top
) == 0)
1150 row
= get_prev_n(tree
->top
, -count
);
1157 get_next_n_opt(tree
->bottom
, count
, &count
);
1158 tree
->top
= get_next_n(tree
->top
, count
);
1162 g_signal_emit(tree
, signals
[SIG_SCROLLED
], 0, count
);
1166 find_position(GntTree
*tree
, gpointer key
, gpointer parent
)
1170 if (tree
->priv
->compare
== NULL
)
1176 row
= g_hash_table_lookup(tree
->hash
, parent
);
1186 if (tree
->priv
->compare(key
, row
->key
) < 0)
1187 return (row
->prev
? row
->prev
->key
: NULL
);
1196 void gnt_tree_sort_row(GntTree
*tree
, gpointer key
)
1198 GntTreeRow
*row
, *q
, *s
;
1201 if (!tree
->priv
->compare
)
1204 row
= g_hash_table_lookup(tree
->hash
, key
);
1205 g_return_if_fail(row
!= NULL
);
1207 current
= g_list_index(tree
->list
, key
);
1210 s
= row
->parent
->child
;
1216 if (tree
->priv
->compare(row
->key
, s
->key
) < 0)
1222 /* Move row between q and s */
1223 if (row
== q
|| row
== s
)
1227 /* row becomes the first child of its parent */
1228 row
->prev
->next
= row
->next
; /* row->prev cannot be NULL at this point */
1230 row
->next
->prev
= row
->prev
;
1232 row
->parent
->child
= row
;
1236 s
->prev
= row
; /* s cannot be NULL */
1238 newp
= g_list_index(tree
->list
, s
) - 1;
1241 row
->prev
->next
= row
->next
;
1243 /* row was the first child of its parent */
1245 row
->parent
->child
= row
->next
;
1247 tree
->top
= row
->next
;
1251 row
->next
->prev
= row
->prev
;
1258 newp
= g_list_index(tree
->list
, q
) + 1;
1260 tree
->list
= g_list_reposition_child(tree
->list
, current
, newp
);
1265 GntTreeRow
*gnt_tree_add_row_after(GntTree
*tree
, void *key
, GntTreeRow
*row
, void *parent
, void *bigbro
)
1267 GntTreeRow
*pr
= NULL
;
1272 g_hash_table_replace(tree
->hash
, key
, row
);
1274 if (bigbro
== NULL
&& tree
->priv
->compare
)
1276 bigbro
= find_position(tree
, key
, parent
);
1279 if (tree
->root
== NULL
)
1282 tree
->list
= g_list_prepend(tree
->list
, key
);
1290 pr
= g_hash_table_lookup(tree
->hash
, bigbro
);
1293 if (pr
->next
) pr
->next
->prev
= row
;
1294 row
->next
= pr
->next
;
1297 row
->parent
= pr
->parent
;
1299 position
= g_list_index(tree
->list
, bigbro
);
1303 if (pr
== NULL
&& parent
)
1305 pr
= g_hash_table_lookup(tree
->hash
, parent
);
1308 if (pr
->child
) pr
->child
->prev
= row
;
1309 row
->next
= pr
->child
;
1313 position
= g_list_index(tree
->list
, parent
);
1319 GntTreeRow
*r
= tree
->root
;
1321 if (r
) r
->prev
= row
;
1322 if (tree
->current
== tree
->root
)
1323 tree
->current
= row
;
1325 tree
->list
= g_list_prepend(tree
->list
, key
);
1329 tree
->list
= g_list_insert(tree
->list
, key
, position
+ 1);
1337 GntTreeRow
*gnt_tree_add_row_last(GntTree
*tree
, void *key
, GntTreeRow
*row
, void *parent
)
1339 GntTreeRow
*pr
= NULL
, *br
= NULL
;
1342 pr
= g_hash_table_lookup(tree
->hash
, parent
);
1355 return gnt_tree_add_row_after(tree
, key
, row
, parent
, br
? br
->key
: NULL
);
1358 gpointer
gnt_tree_get_selection_data(GntTree
*tree
)
1361 return tree
->current
->key
; /* XXX: perhaps we should just get rid of 'data' */
1365 char *gnt_tree_get_selection_text(GntTree
*tree
)
1368 return update_row_text(tree
, tree
->current
);
1372 GList
*gnt_tree_get_row_text_list(GntTree
*tree
, gpointer key
)
1374 GList
*list
= NULL
, *iter
;
1375 GntTreeRow
*row
= key
? g_hash_table_lookup(tree
->hash
, key
) : tree
->current
;
1381 for (i
= 0, iter
= row
->columns
; i
< tree
->ncol
&& iter
;
1382 i
++, iter
= iter
->next
)
1384 GntTreeCol
*col
= iter
->data
;
1385 list
= g_list_append(list
, BINARY_DATA(tree
, i
) ? col
->text
: g_strdup(col
->text
));
1391 GList
*gnt_tree_get_selection_text_list(GntTree
*tree
)
1393 return gnt_tree_get_row_text_list(tree
, NULL
);
1396 void gnt_tree_remove(GntTree
*tree
, gpointer key
)
1398 GntTreeRow
*row
= g_hash_table_lookup(tree
->hash
, key
);
1399 static int depth
= 0; /* Only redraw after all child nodes are removed */
1402 gboolean redraw
= FALSE
;
1406 while (row
->child
) {
1407 gnt_tree_remove(tree
, row
->child
->key
);
1412 if (get_distance(tree
->top
, row
) >= 0 && get_distance(row
, tree
->bottom
) >= 0)
1415 /* Update root/top/current/bottom if necessary */
1416 if (tree
->root
== row
)
1417 tree
->root
= get_next(row
);
1418 if (tree
->top
== row
)
1420 if (tree
->top
!= tree
->root
)
1421 tree
->top
= get_prev(row
);
1423 tree
->top
= get_next(row
);
1425 if (tree
->current
== row
)
1427 if (tree
->current
!= tree
->root
)
1428 tree
->current
= get_prev(row
);
1430 tree
->current
= get_next(row
);
1431 tree_selection_changed(tree
, row
, tree
->current
);
1433 if (tree
->bottom
== row
)
1435 tree
->bottom
= get_prev(row
);
1440 row
->next
->prev
= row
->prev
;
1441 if (row
->parent
&& row
->parent
->child
== row
)
1442 row
->parent
->child
= row
->next
;
1444 row
->prev
->next
= row
->next
;
1446 g_hash_table_remove(tree
->hash
, key
);
1447 tree
->list
= g_list_remove(tree
->list
, key
);
1449 if (redraw
&& depth
== 0)
1457 return_true(gpointer key
, gpointer data
, gpointer null
)
1462 void gnt_tree_remove_all(GntTree
*tree
)
1465 g_hash_table_foreach_remove(tree
->hash
, (GHRFunc
)return_true
, tree
);
1466 g_list_free(tree
->list
);
1468 tree
->current
= tree
->top
= tree
->bottom
= NULL
;
1471 int gnt_tree_get_selection_visible_line(GntTree
*tree
)
1473 return get_distance(tree
->top
, tree
->current
) +
1474 !!(GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree
), GNT_WIDGET_NO_BORDER
));
1477 void gnt_tree_change_text(GntTree
*tree
, gpointer key
, int colno
, const char *text
)
1482 g_return_if_fail(colno
< tree
->ncol
);
1484 row
= g_hash_table_lookup(tree
->hash
, key
);
1487 col
= g_list_nth_data(row
->columns
, colno
);
1488 if (BINARY_DATA(tree
, colno
)) {
1489 col
->text
= (gpointer
)text
;
1492 col
->text
= g_strdup(text
? text
: "");
1495 if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree
), GNT_WIDGET_MAPPED
) &&
1496 get_distance(tree
->top
, row
) >= 0 && get_distance(row
, tree
->bottom
) >= 0)
1501 GntTreeRow
*gnt_tree_add_choice(GntTree
*tree
, void *key
, GntTreeRow
*row
, void *parent
, void *bigbro
)
1504 r
= g_hash_table_lookup(tree
->hash
, key
);
1505 g_return_val_if_fail(!r
|| !r
->choice
, NULL
);
1507 if (bigbro
== NULL
) {
1508 if (tree
->priv
->compare
)
1509 bigbro
= find_position(tree
, key
, parent
);
1511 r
= g_hash_table_lookup(tree
->hash
, parent
);
1523 row
= gnt_tree_add_row_after(tree
, key
, row
, parent
, bigbro
);
1529 void gnt_tree_set_choice(GntTree
*tree
, void *key
, gboolean set
)
1531 GntTreeRow
*row
= g_hash_table_lookup(tree
->hash
, key
);
1535 g_return_if_fail(row
->choice
);
1537 row
->isselected
= set
;
1541 gboolean
gnt_tree_get_choice(GntTree
*tree
, void *key
)
1543 GntTreeRow
*row
= g_hash_table_lookup(tree
->hash
, key
);
1547 g_return_val_if_fail(row
->choice
, FALSE
);
1549 return row
->isselected
;
1552 void gnt_tree_set_row_flags(GntTree
*tree
, void *key
, GntTextFormatFlags flags
)
1554 GntTreeRow
*row
= g_hash_table_lookup(tree
->hash
, key
);
1555 if (!row
|| row
->flags
== flags
)
1559 redraw_tree(tree
); /* XXX: It shouldn't be necessary to redraw the whole darned tree */
1562 void gnt_tree_set_selected(GntTree
*tree
, void *key
)
1565 GntTreeRow
*row
= g_hash_table_lookup(tree
->hash
, key
);
1566 if (!row
|| row
== tree
->current
)
1569 if (tree
->top
== NULL
)
1571 if (tree
->bottom
== NULL
)
1574 tree
->current
= row
;
1575 if ((dist
= get_distance(tree
->current
, tree
->bottom
)) < 0)
1576 gnt_tree_scroll(tree
, -dist
);
1577 else if ((dist
= get_distance(tree
->current
, tree
->top
)) > 0)
1578 gnt_tree_scroll(tree
, -dist
);
1581 tree_selection_changed(tree
, row
, tree
->current
);
1584 static void _gnt_tree_init_internals(GntTree
*tree
, int col
)
1586 gnt_tree_free_columns(tree
);
1589 tree
->hash
= g_hash_table_new_full(g_direct_hash
, g_direct_equal
, NULL
, free_tree_row
);
1590 tree
->columns
= g_new0(struct _GntTreeColInfo
, col
);
1591 tree
->priv
->lastvisible
= col
- 1;
1594 tree
->columns
[col
].width
= 15;
1597 tree
->show_title
= FALSE
;
1598 g_object_notify(G_OBJECT(tree
), "columns");
1601 GntWidget
*gnt_tree_new_with_columns(int col
)
1603 GntWidget
*widget
= g_object_new(GNT_TYPE_TREE
,
1610 GntTreeRow
*gnt_tree_create_row_from_list(GntTree
*tree
, GList
*list
)
1614 GntTreeRow
*row
= g_new0(GntTreeRow
, 1);
1616 for (i
= 0, iter
= list
; i
< tree
->ncol
&& iter
; iter
= iter
->next
, i
++)
1618 GntTreeCol
*col
= g_new0(GntTreeCol
, 1);
1620 if (BINARY_DATA(tree
, i
)) {
1621 col
->text
= iter
->data
;
1622 col
->isbinary
= TRUE
;
1624 col
->text
= g_strdup(iter
->data
? iter
->data
: "");
1625 col
->isbinary
= FALSE
;
1628 row
->columns
= g_list_append(row
->columns
, col
);
1634 GntTreeRow
*gnt_tree_create_row(GntTree
*tree
, ...)
1641 va_start(args
, tree
);
1642 for (i
= 0; i
< tree
->ncol
; i
++)
1644 list
= g_list_append(list
, va_arg(args
, char *));
1648 row
= gnt_tree_create_row_from_list(tree
, list
);
1654 void gnt_tree_set_col_width(GntTree
*tree
, int col
, int width
)
1656 g_return_if_fail(col
< tree
->ncol
);
1658 tree
->columns
[col
].width
= width
;
1659 if (tree
->columns
[col
].width_ratio
== 0)
1660 tree
->columns
[col
].width_ratio
= width
;
1663 void gnt_tree_set_column_title(GntTree
*tree
, int index
, const char *title
)
1665 g_free(tree
->columns
[index
].title
);
1666 tree
->columns
[index
].title
= g_strdup(title
);
1669 void gnt_tree_set_column_titles(GntTree
*tree
, ...)
1674 va_start(args
, tree
);
1675 for (i
= 0; i
< tree
->ncol
; i
++)
1677 const char *title
= va_arg(args
, const char *);
1678 tree
->columns
[i
].title
= g_strdup(title
);
1683 void gnt_tree_set_show_title(GntTree
*tree
, gboolean set
)
1685 tree
->show_title
= set
;
1686 GNT_WIDGET(tree
)->priv
.minh
= (set
? 6 : 4);
1689 void gnt_tree_set_compare_func(GntTree
*tree
, GCompareFunc func
)
1691 tree
->priv
->compare
= func
;
1694 void gnt_tree_set_expanded(GntTree
*tree
, void *key
, gboolean expanded
)
1696 GntTreeRow
*row
= g_hash_table_lookup(tree
->hash
, key
);
1698 row
->collapsed
= !expanded
;
1699 if (GNT_WIDGET(tree
)->window
)
1700 gnt_widget_draw(GNT_WIDGET(tree
));
1701 g_signal_emit(tree
, signals
[SIG_COLLAPSED
], 0, key
, row
->collapsed
);
1705 void gnt_tree_set_show_separator(GntTree
*tree
, gboolean set
)
1707 tree
->show_separator
= set
;
1710 void gnt_tree_adjust_columns(GntTree
*tree
)
1712 GntTreeRow
*row
= tree
->root
;
1713 int *widths
, i
, twidth
;
1715 widths
= g_new0(int, tree
->ncol
);
1718 for (i
= 0, iter
= row
->columns
; iter
; iter
= iter
->next
, i
++) {
1719 GntTreeCol
*col
= iter
->data
;
1720 int w
= gnt_util_onscreen_width(col
->text
, NULL
);
1721 if (i
== 0 && row
->choice
)
1724 w
+= find_depth(row
) * TAB_SIZE
;
1729 row
= get_next(row
);
1732 twidth
= 1 + 2 * (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree
), GNT_WIDGET_NO_BORDER
));
1733 for (i
= 0; i
< tree
->ncol
; i
++) {
1734 if (tree
->columns
[i
].flags
& GNT_TREE_COLUMN_FIXED_SIZE
)
1735 widths
[i
] = tree
->columns
[i
].width
;
1736 gnt_tree_set_col_width(tree
, i
, widths
[i
]);
1737 if (!COLUMN_INVISIBLE(tree
, i
)) {
1738 twidth
= twidth
+ widths
[i
];
1739 if (tree
->priv
->lastvisible
!= i
)
1745 gnt_widget_set_size(GNT_WIDGET(tree
), twidth
, -1);
1748 void gnt_tree_set_hash_fns(GntTree
*tree
, gpointer hash
, gpointer eq
, gpointer kd
)
1750 g_hash_table_foreach_remove(tree
->hash
, return_true
, NULL
);
1751 g_hash_table_destroy(tree
->hash
);
1752 tree
->hash
= g_hash_table_new_full(hash
, eq
, kd
, free_tree_row
);
1756 set_column_flag(GntTree
*tree
, int col
, GntTreeColumnFlag flag
, gboolean set
)
1759 tree
->columns
[col
].flags
|= flag
;
1761 tree
->columns
[col
].flags
&= ~flag
;
1764 void gnt_tree_set_column_visible(GntTree
*tree
, int col
, gboolean vis
)
1766 g_return_if_fail(col
< tree
->ncol
);
1767 set_column_flag(tree
, col
, GNT_TREE_COLUMN_INVISIBLE
, !vis
);
1769 /* the column is visible */
1770 if (tree
->priv
->lastvisible
< col
)
1771 tree
->priv
->lastvisible
= col
;
1773 if (tree
->priv
->lastvisible
== col
)
1774 while (tree
->priv
->lastvisible
) {
1775 tree
->priv
->lastvisible
--;
1776 if (!COLUMN_INVISIBLE(tree
, tree
->priv
->lastvisible
))
1780 if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree
), GNT_WIDGET_MAPPED
))
1781 readjust_columns(tree
);
1784 void gnt_tree_set_column_resizable(GntTree
*tree
, int col
, gboolean res
)
1786 g_return_if_fail(col
< tree
->ncol
);
1787 set_column_flag(tree
, col
, GNT_TREE_COLUMN_FIXED_SIZE
, !res
);
1790 void gnt_tree_set_column_is_binary(GntTree
*tree
, int col
, gboolean bin
)
1792 g_return_if_fail(col
< tree
->ncol
);
1793 set_column_flag(tree
, col
, GNT_TREE_COLUMN_FIXED_SIZE
, bin
);
1796 void gnt_tree_set_column_is_right_aligned(GntTree
*tree
, int col
, gboolean right
)
1798 g_return_if_fail(col
< tree
->ncol
);
1799 set_column_flag(tree
, col
, GNT_TREE_COLUMN_RIGHT_ALIGNED
, right
);
1802 void gnt_tree_set_column_width_ratio(GntTree
*tree
, int cols
[])
1805 for (i
= 0; i
< tree
->ncol
&& cols
[i
]; i
++) {
1806 tree
->columns
[i
].width_ratio
= cols
[i
];
1810 void gnt_tree_set_search_column(GntTree
*tree
, int col
)
1812 g_return_if_fail(col
< tree
->ncol
);
1813 g_return_if_fail(!BINARY_DATA(tree
, col
));
1814 tree
->priv
->search_column
= col
;
1817 gboolean
gnt_tree_is_searching(GntTree
*tree
)
1819 return (tree
->priv
->search
!= NULL
);
1822 void gnt_tree_set_search_function(GntTree
*tree
,
1823 gboolean (*func
)(GntTree
*tree
, gpointer key
, const char *search
, const char *current
))
1825 tree
->priv
->search_func
= func
;