summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FL/Fl_Tree.H3
-rw-r--r--FL/Fl_Tree_Prefs.H4
-rw-r--r--src/Fl_Tree.cxx109
-rw-r--r--test/tree.fl15
4 files changed, 123 insertions, 8 deletions
diff --git a/FL/Fl_Tree.H b/FL/Fl_Tree.H
index 99a1e5e2d..826973593 100644
--- a/FL/Fl_Tree.H
+++ b/FL/Fl_Tree.H
@@ -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 {
diff --git a/FL/Fl_Tree_Prefs.H b/FL/Fl_Tree_Prefs.H
index 1b1a7b139..1ef56ca52 100644
--- a/FL/Fl_Tree_Prefs.H
+++ b/FL/Fl_Tree_Prefs.H
@@ -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
diff --git a/src/Fl_Tree.cxx b/src/Fl_Tree.cxx
index c5cb0817e..75befe164 100644
--- a/src/Fl_Tree.cxx
+++ b/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
diff --git a/test/tree.fl b/test/tree.fl
index 0b92231ab..7d1779fa0 100644
--- a/test/tree.fl
+++ b/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);}