mirror of https://github.com/fltk/fltk
Add support for dragging to reorder in Fl_Tree, STR #2828 (I)
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10275 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
parent
d67f2e8e3e
commit
d1d203ca57
|
@ -317,7 +317,8 @@ enum Fl_Tree_Reason {
|
|||
FL_TREE_REASON_RESELECTED, ///< an item was re-selected (e.g. double-clicked)
|
||||
#endif /*FLTK_ABI_VERSION*/
|
||||
FL_TREE_REASON_OPENED, ///< an item was opened
|
||||
FL_TREE_REASON_CLOSED ///< an item was closed
|
||||
FL_TREE_REASON_CLOSED, ///< an item was closed
|
||||
FL_TREE_REASON_DRAGGED ///< an item was dragged into a new place
|
||||
};
|
||||
|
||||
class FL_EXPORT Fl_Tree : public Fl_Group {
|
||||
|
|
|
@ -67,8 +67,10 @@ enum Fl_Tree_Connector {
|
|||
enum Fl_Tree_Select {
|
||||
FL_TREE_SELECT_NONE=0, ///< Nothing selected when items are clicked
|
||||
FL_TREE_SELECT_SINGLE=1, ///< Single item selected when item is clicked (default)
|
||||
FL_TREE_SELECT_MULTI=2 ///< Multiple items can be selected by clicking
|
||||
FL_TREE_SELECT_MULTI=2, ///< Multiple items can be selected by clicking
|
||||
///< with SHIFT, CTRL or mouse drags.
|
||||
FL_TREE_SELECT_SINGLE_DRAGGABLE=3, ///< Single items may be selected, and they may be
|
||||
///< reordered by mouse drag.
|
||||
};
|
||||
|
||||
#if FLTK_ABI_VERSION >= 10301
|
||||
|
|
109
src/Fl_Tree.cxx
109
src/Fl_Tree.cxx
|
@ -328,6 +328,7 @@ int Fl_Tree::handle(int e) {
|
|||
case FL_TREE_SELECT_NONE:
|
||||
break; // ignore, let group have shot at event
|
||||
case FL_TREE_SELECT_SINGLE:
|
||||
case FL_TREE_SELECT_SINGLE_DRAGGABLE:
|
||||
if ( is_ctrl ) { // CTRL-SPACE: (single mode) toggle
|
||||
if ( ! _item_focus->is_selected() ) {
|
||||
select_only(_item_focus, when());
|
||||
|
@ -389,6 +390,7 @@ int Fl_Tree::handle(int e) {
|
|||
switch ( _prefs.selectmode() ) {
|
||||
case FL_TREE_SELECT_NONE:
|
||||
case FL_TREE_SELECT_SINGLE:
|
||||
case FL_TREE_SELECT_SINGLE_DRAGGABLE:
|
||||
break;
|
||||
case FL_TREE_SELECT_MULTI:
|
||||
// Do a 'select all'
|
||||
|
@ -432,6 +434,7 @@ int Fl_Tree::handle(int e) {
|
|||
case FL_TREE_SELECT_NONE:
|
||||
break;
|
||||
case FL_TREE_SELECT_SINGLE:
|
||||
case FL_TREE_SELECT_SINGLE_DRAGGABLE:
|
||||
case FL_TREE_SELECT_MULTI:
|
||||
deselect_all();
|
||||
break;
|
||||
|
@ -449,6 +452,7 @@ int Fl_Tree::handle(int e) {
|
|||
case FL_TREE_SELECT_NONE:
|
||||
break;
|
||||
case FL_TREE_SELECT_SINGLE:
|
||||
case FL_TREE_SELECT_SINGLE_DRAGGABLE:
|
||||
select_only(item, when()); // select only this item (handles redraw)
|
||||
_lastselect = item;
|
||||
break;
|
||||
|
@ -511,7 +515,8 @@ int Fl_Tree::handle(int e) {
|
|||
#endif
|
||||
if ( !item ) break; // not near item? ignore drag event
|
||||
ret |= 1; // acknowledge event
|
||||
set_item_focus(item); // becomes new focus item
|
||||
if (_prefs.selectmode() != FL_TREE_SELECT_SINGLE_DRAGGABLE)
|
||||
set_item_focus(item); // becomes new focus item
|
||||
if (item==_lastselect) break; // same item as before? avoid reselect
|
||||
|
||||
// Handle selection behavior
|
||||
|
@ -522,6 +527,11 @@ int Fl_Tree::handle(int e) {
|
|||
select_only(item, when()); // select only this item (handles redraw)
|
||||
break;
|
||||
}
|
||||
case FL_TREE_SELECT_SINGLE_DRAGGABLE: {
|
||||
item = _lastselect; // Keep the source intact
|
||||
redraw();
|
||||
break;
|
||||
}
|
||||
case FL_TREE_SELECT_MULTI: {
|
||||
Fl_Tree_Item *from = next_visible_item(_lastselect, dir); // avoid reselecting item
|
||||
Fl_Tree_Item *to = item;
|
||||
|
@ -535,6 +545,57 @@ int Fl_Tree::handle(int e) {
|
|||
break;
|
||||
}
|
||||
case FL_RELEASE:
|
||||
if (_prefs.selectmode() == FL_TREE_SELECT_SINGLE_DRAGGABLE &&
|
||||
Fl::event_button() == FL_LEFT_MOUSE) {
|
||||
#if FLTK_ABI_VERSION >= 10303
|
||||
Fl_Tree_Item *item = _root->find_clicked(_prefs, 1); // item we're on, vertically
|
||||
#else
|
||||
Fl_Tree_Item *item = _root->find_clicked(_prefs); // item we're on, vertically
|
||||
#endif
|
||||
|
||||
if (item && _lastselect && item != _lastselect &&
|
||||
Fl::event_x() >= item->label_x()) {
|
||||
//printf("Would drag '%s' to '%s'\n", _lastselect->label(), item->label());
|
||||
// Are we dropping above or below the target item?
|
||||
const int h = Fl::event_y() - item->y();
|
||||
const int mid = item->h() / 2;
|
||||
const bool before = h < mid;
|
||||
//printf("Dropping %s it\n", before ? "before" : "after");
|
||||
|
||||
// Do nothing if it would be a no-op
|
||||
if ((before && prev(item) != _lastselect) ||
|
||||
(!before && next(item) != _lastselect)) {
|
||||
Fl_Tree_Item *parent = item->parent();
|
||||
|
||||
if (parent) {
|
||||
int pos = parent->find_child(item);
|
||||
if (!before)
|
||||
pos++;
|
||||
|
||||
// Special case: trying to drop right before a folder
|
||||
if (item->children() && item->is_open() && !before) {
|
||||
parent = item;
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
// If we're moving inside the same parent, use the below/above methods
|
||||
if (_lastselect->parent() == parent) {
|
||||
if (before) {
|
||||
_lastselect->move_above(item);
|
||||
} else {
|
||||
_lastselect->move_below(item);
|
||||
}
|
||||
} else {
|
||||
_lastselect->move_into(parent, pos);
|
||||
}
|
||||
|
||||
redraw();
|
||||
do_callback_for_item(_lastselect, FL_TREE_REASON_DRAGGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
redraw();
|
||||
} // End single-drag check
|
||||
ret |= 1;
|
||||
break;
|
||||
}
|
||||
|
@ -750,6 +811,29 @@ void Fl_Tree::draw() {
|
|||
_vscroll->w(),
|
||||
_hscroll->h());
|
||||
}
|
||||
|
||||
// Draw dragging line
|
||||
if (_prefs.selectmode() == FL_TREE_SELECT_SINGLE_DRAGGABLE &&
|
||||
Fl::pushed() == this) {
|
||||
|
||||
Fl_Tree_Item *item = _root->find_clicked(_prefs, 1); // item we're on, vertically
|
||||
if (item && item != _item_focus) {
|
||||
// Are we dropping above or before the target item?
|
||||
const int h = Fl::event_y() - item->y();
|
||||
const int mid = item->h() / 2;
|
||||
const bool before = h < mid;
|
||||
|
||||
fl_color(FL_BLACK);
|
||||
|
||||
int tgt;
|
||||
if (before) {
|
||||
tgt = item->y();
|
||||
} else {
|
||||
tgt = item->y() + item->h();
|
||||
}
|
||||
fl_line(item->x(), tgt, item->x() + item->w(), tgt);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
/// Standard FLTK draw() method, handles drawing the tree widget.
|
||||
|
@ -775,6 +859,29 @@ void Fl_Tree::draw() {
|
|||
}
|
||||
Fl::add_timeout(.10, redraw_soon, (void*)this); // use timer to trigger redraw; we can't
|
||||
}
|
||||
|
||||
// Draw dragging line
|
||||
if (_prefs.selectmode() == FL_TREE_SELECT_SINGLE_DRAGGABLE &&
|
||||
Fl::pushed() == this) {
|
||||
|
||||
Fl_Tree_Item *item = _root->find_clicked(_prefs); // item we're on, vertically
|
||||
if (item && item != _item_focus) {
|
||||
// Are we dropping above or before the target item?
|
||||
const int h = Fl::event_y() - item->y();
|
||||
const int mid = item->h() / 2;
|
||||
const bool before = h < mid;
|
||||
|
||||
fl_color(FL_BLACK);
|
||||
|
||||
int tgt;
|
||||
if (before) {
|
||||
tgt = item->y();
|
||||
} else {
|
||||
tgt = item->y() + item->h();
|
||||
}
|
||||
fl_line(item->x(), tgt, item->x() + item->w(), tgt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method is undocumented, and has been removed in ABI 1.3.3
|
||||
|
|
15
test/tree.fl
15
test/tree.fl
|
@ -51,6 +51,7 @@ Function {reason_as_name(Fl_Tree_Reason reason)} {
|
|||
case FL_TREE_REASON_DESELECTED: return("deselected");
|
||||
case FL_TREE_REASON_OPENED: return("opened");
|
||||
case FL_TREE_REASON_CLOSED: return("closed");
|
||||
case FL_TREE_REASON_DRAGGED: return("dragged");
|
||||
\#if FLTK_ABI_VERSION >= 10301
|
||||
case FL_TREE_REASON_RESELECTED: return("reselected");
|
||||
\#endif
|
||||
|
@ -345,7 +346,7 @@ Function {} {open
|
|||
} {
|
||||
Fl_Window window {
|
||||
label tree open
|
||||
xywh {0 234 1045 580} type Double visible
|
||||
xywh {1 234 1045 580} type Double visible
|
||||
} {
|
||||
Fl_Group tree {
|
||||
label Tree
|
||||
|
@ -637,8 +638,9 @@ switch ( selectmode_chooser->value() ) {
|
|||
case 0: tree->selectmode(FL_TREE_SELECT_NONE); break; // None
|
||||
case 1: tree->selectmode(FL_TREE_SELECT_SINGLE); break; // Single
|
||||
case 2: tree->selectmode(FL_TREE_SELECT_MULTI); break; // Multi
|
||||
case 3: tree->selectmode(FL_TREE_SELECT_SINGLE_DRAGGABLE); break; // Single draggable
|
||||
default: tree->selectmode(FL_TREE_SELECT_SINGLE); break; // Single
|
||||
}}
|
||||
}} open selected
|
||||
tooltip {Tests Fl_Tree::selectmode()
|
||||
Sets how Fl_Tree handles mouse selection of tree items.
|
||||
NONE -- Not selectable by keyboard/mouse
|
||||
|
@ -659,6 +661,10 @@ Sets how Fl_Tree handles mouse selection of tree items.
|
|||
label Multi
|
||||
xywh {60 60 36 21} labelsize 12
|
||||
}
|
||||
MenuItem {} {
|
||||
label {Single + drag}
|
||||
xywh {70 70 36 21} labelsize 12
|
||||
}
|
||||
}
|
||||
Fl_Choice reselectmode_chooser {
|
||||
label {Item Reselect Mode}
|
||||
|
@ -1393,7 +1399,7 @@ if ( !item) {
|
|||
}
|
||||
int onoff = rootselect2_toggle->value();
|
||||
if ( onoff ) tree->select_all(item); // select /ROOT and its children
|
||||
else tree->deselect_all(item); // deselect /ROOT and its children} selected
|
||||
else tree->deselect_all(item); // deselect /ROOT and its children}
|
||||
tooltip {Toggle selection of the ROOT item and all children} xywh {914 219 95 16} selection_color 1 labelsize 9
|
||||
}
|
||||
Fl_Box {} {
|
||||
|
@ -1728,8 +1734,7 @@ helpwin->show();}
|
|||
callback {tree->scrollbar_size((int)tree_scrollbar_size_slider->value());
|
||||
tree->redraw();}
|
||||
tooltip {Tests Fl_Tree::scrollbar_size() effects on tree clipping.
|
||||
The value is normally 0, which causes Fl_Tree to use the global Fl::scrollbar_size() instead.
|
||||
} xywh {835 499 180 16} type Horizontal color 46 selection_color 1 labelsize 11 align 4 textsize 9
|
||||
The value is normally 0, which causes Fl_Tree to use the global Fl::scrollbar_size() instead.} xywh {835 499 180 16} type Horizontal color 46 selection_color 1 labelsize 11 align 4 textsize 9
|
||||
code0 {o->value(tree->scrollbar_size());}
|
||||
code1 {o->range(0.0, 30.0);}
|
||||
code2 {o->step(1.0);}
|
||||
|
|
Loading…
Reference in New Issue