Added to assist cand for his patch to solve RFE STR #2828 option (I).

o Add move() methods to Fl_Tree_Item.
o Add deparent()/reparent() methods
o Supporting methods added to Fl_Tree_Item_Array, and enhancement
  to update_prev_next() to allow -1 option to create an orphan item

Added to Fl_Tree_Item:

    * Fl_Tree_Item* deparent(int pos)
    * int reparent(Fl_Tree_Item *newchild, int pos)

    * int move(int to, int from)
    * int move(Fl_Tree_Item *item, int op, int pos)
    * int move_above(Fl_Tree_Item *item)
    * int move_below(Fl_Tree_Item *item)
    * int move_into(Fl_Tree_Item *item, int pos)

Added to Fl_Tree_Item_Array:

    * int move(int to, int from)
    * int deparent(int pos)
    * int reparent(Fl_Tree_Item *item, Fl_Tree_Item* newparent, int pos)



git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10271 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Greg Ercolano 2014-09-04 18:56:52 +00:00
parent 0ed1e8e0f0
commit 107fc50e48
4 changed files with 226 additions and 1 deletions

View File

@ -271,6 +271,13 @@ public:
#endif
Fl_Tree_Item *insert(const Fl_Tree_Prefs &prefs, const char *new_label, int pos=0);
Fl_Tree_Item *insert_above(const Fl_Tree_Prefs &prefs, const char *new_label);
Fl_Tree_Item* deparent(int index);
int reparent(Fl_Tree_Item *newchild, int index);
int move(int to, int from);
int move(Fl_Tree_Item *item, int op=0, int pos=0);
int move_above(Fl_Tree_Item *item);
int move_below(Fl_Tree_Item *item);
int move_into(Fl_Tree_Item *item, int pos=0);
int depth() const;
Fl_Tree_Item *prev();
Fl_Tree_Item *next();

View File

@ -84,6 +84,9 @@ public:
_items[bx] = asave;
}
#endif /*FLTK_ABI_VERSION*/
int move(int to, int from);
int deparent(int pos);
int reparent(Fl_Tree_Item *item, Fl_Tree_Item *newparent, int pos);
void clear();
void add(Fl_Tree_Item *val);
void insert(int pos, Fl_Tree_Item *new_item);

View File

@ -453,6 +453,142 @@ Fl_Tree_Item *Fl_Tree_Item::insert_above(const Fl_Tree_Prefs &prefs, const char
return(0);
}
/// Deparent child at index position \p 'pos'.
/// This creates an "orphaned" item that is still allocated,
/// but has no parent or siblings. Normally the caller would
/// want to immediately reparent the orphan elsewhere.
///
/// A successfully orphaned item will have its parent()
/// and prev_sibling()/next_sibling() set to NULL.
///
/// \returns
/// - pointer to orphaned item on success
/// - NULL on error (could not deparent the item)
///
Fl_Tree_Item* Fl_Tree_Item::deparent(int pos) {
Fl_Tree_Item *orphan = _children[pos];
if ( _children.deparent(pos) < 0 ) return NULL;
return orphan;
}
/// Reparent specified item as a child of ourself at position \p 'pos'.
/// Typically 'newchild' was recently orphaned with deparent().
///
/// \returns
/// - 0: on success
/// - -1: on error (e.g. if \p 'pos' out of range)
///
int Fl_Tree_Item::reparent(Fl_Tree_Item *newchild, int pos) {
int ret;
if ( (ret = _children.reparent(newchild, this, pos)) < 0 ) return ret;
newchild->parent(this); // take custody
return 0;
}
/// Move the item 'to' to sibling position of 'from'.
///
/// \returns
/// - 0: Success
/// - -1: range error (e.g. if \p 'to' or \p 'from' out of range).
/// - (Other return values reserved for future use)
///
int Fl_Tree_Item::move(int to, int from) {
return _children.move(to, from);
}
/// Move the current item above/below/into the specified 'item',
/// where \p 'op' determines the type of move:
///
/// - 0: move above \p 'item' (\p 'pos' ignored)
/// - 1: move below \p 'item' (\p 'pos' ignored)
/// - 2: move into \p 'item' as a child (at optional position \p 'pos')
///
/// \returns 0 on success. a negative number on error:
/// - -1: one of the items has no parent
/// - -2: item's index could not be determined
/// - -3: bad 'op'
/// - -4: index range error
/// - -5: could not deparent
/// - -6: could not reparent at \p 'pos'
/// - (Other return values reserved for future use.)
///
int Fl_Tree_Item::move(Fl_Tree_Item *item, int op, int pos) {
Fl_Tree_Item *from_parent, *to_parent;
int from, to;
switch (op) {
case 0: // "above"
from_parent = this->parent();
to_parent = item->parent();
from = from_parent->find_child(this);
to = to_parent->find_child(item);
break;
case 1: // "below"
from_parent = this->parent();
to_parent = item->parent();
from = from_parent->find_child(this);
to = to_parent->find_child(item);
break;
case 2: // "into"
from_parent = this->parent();
to_parent = item;
from = from_parent->find_child(this);
to = pos;
break;
default:
return -3;
}
if ( !from_parent || !to_parent ) return -1;
if ( from < 0 || to < 0 ) return -2;
if ( op == 1 ) to++; // 'below'? apply +1 offset for 'to'
if ( from_parent == to_parent ) { // same parent?
if ( from_parent->move(to, from) < 0 ) // simple move among siblings
return -4;
} else { // different parent?
if ( to > to_parent->children() ) // try to prevent a reparent() error
return -4;
if ( from_parent->deparent(from) < 0 ) // deparent self from current parent
return -5;
if ( to_parent->reparent(this, to) < 0 ) { // reparent self to new parent at position 'to'
to_parent->reparent(this, 0); // failed? shouldn't happen, reparent at 0
return -6;
}
}
return 0;
}
/// Move the current item above the specified 'item'.
/// This is the equivalent of calling move(item,0,0).
///
/// \returns 0 on success.<br>
/// On error returns a negative value;
/// see move(Fl_Tree_Item*,int,int) for possible error codes.
///
int Fl_Tree_Item::move_above(Fl_Tree_Item *item) {
return move(item, 0, 0);
}
/// Move the current item below the specified 'item'.
/// This is the equivalent of calling move(item,1,0).
///
/// \returns 0 on success.<br>
/// On error returns a negative value;
/// see move(Fl_Tree_Item*,int,int) for possible error codes.
///
int Fl_Tree_Item::move_below(Fl_Tree_Item *item) {
return move(item, 1, 0);
}
/// Parent the current item as a child of the specified \p 'item'.
/// This is the equivalent of calling move(item,2,pos).
///
/// \returns 0 on success.<br>
/// On error returns a negative value;
/// see move(Fl_Tree_Item*,int,int) for possible error codes.
///
int Fl_Tree_Item::move_into(Fl_Tree_Item *item, int pos) {
return move(item, 2, pos);
}
#if FLTK_ABI_VERSION >= 10303
/// Return the parent tree's prefs.
/// \returns a reference to the parent tree's Fl_Tree_Prefs
@ -1519,11 +1655,18 @@ Fl_Tree_Item *Fl_Tree_Item::prev_sibling() {
/// Update our _prev_sibling and _next_sibling pointers to point to neighbors
/// given \p index as being our current position in the parent's item array.
/// Call this whenever items in the array are added/removed/moved/swapped/etc.
/// \param[in] index Our index# in the parent
/// \param[in] index Our index# in the parent.<br>
/// Special case if index=-1: become an orphan; null out all parent/sibling associations.
///
void Fl_Tree_Item::update_prev_next(int index) {
#if FLTK_ABI_VERSION >= 10301
// NEW
if ( index == -1 ) { // special case: become an orphan
_parent = 0;
_prev_sibling = 0;
_next_sibling = 0;
return;
}
int pchildren = parent() ? parent()->children() : 0;
int index_prev = index-1;
int index_next = index+1;

View File

@ -233,6 +233,78 @@ void Fl_Tree_Item_Array::swap(int ax, int bx) {
}
#endif /* FLTK_ABI_VERSION */
/// Move item at 'from' to new position 'to' in the array.
///
/// \returns 0 on success, -1 on range error (e.g. if \p 'to' or \p 'from' out of range)
///
int Fl_Tree_Item_Array::move(int to, int from) {
if ( from == to ) return 0; // nop
if ( to<0 || to>=_total || from<0 || from>=_total ) return -1;
Fl_Tree_Item *item = _items[from];
Fl_Tree_Item *prev = item->prev_sibling();
Fl_Tree_Item *next = item->next_sibling();
// Remove item..
if ( from < to )
for ( int t=from; t<to && t<_total; t++ )
_items[t] = _items[t+1];
else
for ( int t=from; t>to; t-- )
_items[t] = _items[t-1];
// Move to new position
_items[to] = item;
// Adjust for new siblings
_items[to]->update_prev_next(to);
_items[from]->update_prev_next(from);
// Adjust old siblings
if ( prev ) prev->update_prev_next(from-1);
if ( next ) next->update_prev_next(from);
return 0;
}
/// Deparent item at \p 'pos' from our list of children.
/// Similar to a remove() without the destruction of the item.
/// This creates an orphaned item (still allocated, has no parent)
/// which soon after is typically reparented elsewhere.
///
/// \returns 0 on success, -1 on error (e.g. if \p 'pos' out of range)
///
int Fl_Tree_Item_Array::deparent(int pos) {
if ( pos>=_total || pos<0 ) return -1;
// Save item being deparented, and its two nearest siblings
Fl_Tree_Item *item = _items[pos];
Fl_Tree_Item *prev = item->prev_sibling();
Fl_Tree_Item *next = item->next_sibling();
// Remove from parent's list of children
_total -= 1;
for ( int t=pos; t<_total; t++ )
_items[t] = _items[t+1]; // delete, no destroy
// Now an orphan: remove association with old parent and siblings
item->update_prev_next(-1); // become an orphan
// Adjust bereaved siblings
if ( prev ) prev->update_prev_next(pos-1);
if ( next ) next->update_prev_next(pos);
return 0;
}
/// Reparent specified item as a child of ourself.
/// Typically 'newchild' was recently orphaned with deparent().
///
/// \returns 0 on success, -1 on error (e.g. if \p 'pos' out of range)
///
int Fl_Tree_Item_Array::reparent(Fl_Tree_Item *item, Fl_Tree_Item* newparent, int pos) {
if ( pos<0 || pos>_total ) return -1;
// Add item to new parent
enlarge(1);
_total += 1;
for ( int t=_total-1; t>pos; --t ) // shuffle array to make room for new entry
_items[t] = _items[t-1];
_items[pos] = item; // insert new entry
// Attach to new parent and siblings
_items[pos]->parent(newparent); // reparent (update_prev_next() needs this)
_items[pos]->update_prev_next(pos); // find new siblings
return 0;
}
//
// End of "$Id$".
//