summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Fl_Tree.cxx71
-rw-r--r--src/Fl_Tree_Item.cxx36
2 files changed, 69 insertions, 38 deletions
diff --git a/src/Fl_Tree.cxx b/src/Fl_Tree.cxx
index 95247e354..1f91a00e9 100644
--- a/src/Fl_Tree.cxx
+++ b/src/Fl_Tree.cxx
@@ -195,21 +195,24 @@ int Fl_Tree::handle(int e) {
// Do shortcuts first or scrollbar will get them...
if ( (Fl::focus() == this) && // tree has focus?
_prefs.selectmode() > FL_TREE_SELECT_NONE ) { // select mode that supports kb events?
- if ( !_item_focus ) {
- set_item_focus(first());
+ if ( !_item_focus ) { // no current focus item?
+ set_item_focus(first_visible()); // use first vis item
+ if ( Fl::event_key() == FL_Up || // Up or down?
+ Fl::event_key() == FL_Down ) // ..if so, already did 'motion'
+ return(1); // ..so just return.
}
if ( _item_focus ) {
int ekey = Fl::event_key();
switch (ekey) {
case FL_Enter: // ENTER: toggle open/close
case FL_KP_Enter: {
- open_toggle(_item_focus, when());
- break;
+ open_toggle(_item_focus, when()); // toggle item in focus
+ return(1); // done, we handled key
}
case ' ': // SPACE: change selection state
switch ( _prefs.selectmode() ) {
case FL_TREE_SELECT_NONE:
- break;
+ break; // ignore, let group have shot at event
case FL_TREE_SELECT_SINGLE:
if ( is_ctrl ) { // CTRL-SPACE: (single mode) toggle
if ( ! _item_focus->is_selected() ) {
@@ -221,7 +224,7 @@ int Fl_Tree::handle(int e) {
select_only(_item_focus, when()); // SPACE: (single mode) select only
}
_lastselect = _item_focus;
- return(1);
+ return(1); // done, we handled key
case FL_TREE_SELECT_MULTI:
if ( is_ctrl ) {
select_toggle(_item_focus, when()); // CTRL-SPACE: (multi mode) toggle selection
@@ -229,7 +232,7 @@ int Fl_Tree::handle(int e) {
select(_item_focus, when()); // SPACE: (multi-mode) select
}
_lastselect = _item_focus;
- return(1);
+ return(1); // done, we handled key
}
break;
case FL_Right: // RIGHT: open children (if any)
@@ -280,7 +283,7 @@ int Fl_Tree::handle(int e) {
case FL_TREE_SELECT_MULTI:
// Do a 'select all'
select_all();
- _lastselect = first();
+ _lastselect = first_visible();
take_focus();
return(1);
}
@@ -588,13 +591,16 @@ Fl_Tree_Item* Fl_Tree::insert(Fl_Tree_Item *item, const char *name, int pos) {
/// Remove the specified \p item from the tree.
/// \p item may not be NULL.
/// If it has children, all those are removed too.
+/// If item being removed has focus, no item will have focus.
/// \returns 0 if done, -1 if 'item' not found.
///
int Fl_Tree::remove(Fl_Tree_Item *item) {
+ // Item being removed is focus item? zero focus
+ if ( item == _item_focus ) _item_focus = 0;
if ( item == _root ) {
clear();
} else {
- Fl_Tree_Item *parent = item->parent(); // find item's parent
+ Fl_Tree_Item *parent = item->parent(); // find item's parent
if ( ! parent ) return(-1);
parent->remove_child(item); // remove child + children
}
@@ -755,7 +761,8 @@ Fl_Tree_Item* Fl_Tree::item_clicked() {
///
Fl_Tree_Item *Fl_Tree::next_visible_item(Fl_Tree_Item *item, int dir) {
if ( ! item ) { // no start item?
- item = ( dir == FL_Up ) ? last() : first(); // start at top or bottom
+ item = ( dir == FL_Up ) ? last_visible() : // wrap to bottom
+ first_visible(); // wrap to top
if ( ! item ) return(0);
if ( item->visible_r() ) return(item); // return first/last visible item
}
@@ -782,6 +789,19 @@ Fl_Tree_Item* Fl_Tree::first() {
return(_root); // first item always root
}
+/// Returns the first visible item in the tree.
+/// \returns first visible item in tree, or 0 if none.
+/// \see first_visible(), last_visible()
+///
+Fl_Tree_Item* Fl_Tree::first_visible() {
+ Fl_Tree_Item *i = showroot() ? first() : next(first());
+ while ( i ) {
+ if ( i->visible() ) return(i);
+ i = next(i);
+ }
+ return(0);
+}
+
/// Return the next item after \p item, or 0 if no more items.
///
/// Use this code to walk the entire tree:
@@ -844,6 +864,26 @@ Fl_Tree_Item* Fl_Tree::last() {
return(item);
}
+/// Returns the last visible item in the tree.
+/// \returns last visible item in the tree, or 0 if none.
+///
+/// \see first_visible(), last_visible()
+///
+Fl_Tree_Item* Fl_Tree::last_visible() {
+ Fl_Tree_Item *item = last();
+ while ( item ) {
+ if ( item->visible() ) {
+ if ( item == _root && !showroot() ) {
+ return(0);
+ } else {
+ return(item);
+ }
+ }
+ item = prev(item);
+ }
+ return(item);
+}
+
/// Returns the first selected item in the tree.
///
/// Use this to walk the tree looking for all the selected items, eg:
@@ -1334,6 +1374,11 @@ int Fl_Tree::select_all(Fl_Tree_Item *item, int docallback) {
return(count);
}
+/// Get the item that currently has keyboard focus.
+Fl_Tree_Item* Fl_Tree::get_item_focus() const {
+ return(_item_focus);
+}
+
/// Set the item that currently should have keyboard focus.
/// Handles calling redraw() to update the focus box (if it is visible).
///
@@ -1899,6 +1944,12 @@ void Fl_Tree::scrollbar_size(int size) {
}
}
+/// See if the vertical scrollbar is currently visible.
+/// \returns 1 if scrollbar visible, 0 if not.
+int Fl_Tree::is_vscroll_visible() const {
+ return(_vscroll->visible() ? 1 : 0);
+}
+
/// Do the callback for the item, setting the item and reason
void Fl_Tree::do_callback_for_item(Fl_Tree_Item* item, Fl_Tree_Reason reason) {
callback_reason(reason);
diff --git a/src/Fl_Tree_Item.cxx b/src/Fl_Tree_Item.cxx
index d20437b9e..31080b40c 100644
--- a/src/Fl_Tree_Item.cxx
+++ b/src/Fl_Tree_Item.cxx
@@ -1023,34 +1023,13 @@ void Fl_Tree_Item::update_prev_next(int index) {
/// \returns the next visible item below us, or 0 if there's no more items.
///
Fl_Tree_Item *Fl_Tree_Item::next_displayed(Fl_Tree_Prefs &prefs) {
- Fl_Tree_Item *c = this;
- while ( c ) {
- if ( c->is_root() && !prefs.showroot() ) { // on root and can't show it?
- c = c->next(); // skip ahead, try again
- continue;
- }
- if ( c->has_children() && c->is_close() ) { // item has children and: invisible or closed?
- // Skip children, take next sibling. If none, try parent's sibling, repeat
- while ( c ) {
- Fl_Tree_Item *sib = c->next_sibling(); // get sibling
- if ( sib ) { c = sib; break; } // Found? let outer loop test it
- c = c->parent(); // No sibling? move up tree, try parent's sibling
- }
- } else { // has children and isn't closed, or no children
- c = c->next(); // use normal 'next'
- }
- if ( !c ) return(0); // no more? done
- // Check all parents to be sure none are closed.
- // If closed, move up to that level and repeat until sure none are closed.
- Fl_Tree_Item *p = c->parent();
- while (1) {
- if ( !p || p->is_root() ) return(c); // hit top? then we're displayed, return c
- if ( p->is_close() ) c = p; // found closed parent? make it current
- p = p->parent(); // continue up tree
- }
- if ( c && c->visible() ) return(c); // item visible? return it
+ Fl_Tree_Item *item = this;
+ while ( 1 ) {
+ item = item->next();
+ if ( !item ) return 0;
+ if ( item->is_root() && !prefs.showroot() ) continue;
+ if ( item->visible_r() ) return(item);
}
- return(0); // hit end: no more items
}
/// Return the previous visible item. (If this item above us has children and is closed, its children are skipped)
@@ -1087,7 +1066,8 @@ Fl_Tree_Item *Fl_Tree_Item::prev_displayed(Fl_Tree_Prefs &prefs) {
/// 0 -- item (or parents) invisible or close()ed.
///
int Fl_Tree_Item::visible_r() const {
- for (const Fl_Tree_Item *p=this; p; p=p->parent()) // move up through parents
+ if ( !visible() ) return(0);
+ for (const Fl_Tree_Item *p=parent(); p; p=p->parent())// move up through parents
if (!p->visible() || p->is_close()) return(0); // any parent not visible or closed?
return(1);
}