Solves STR #3127.
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:
parent
0ed1e8e0f0
commit
107fc50e48
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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$".
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user