Fl_Tree related mods
* open() / close() now can invoke the callback(). New method callback_reason() lets one determine the cause. (Used FLU's tree for reference on this) * new Fl_Tree methods: > item_pathname() > show_item(), show_top(), show_middle(), show_bottom(). > next_selected_item() -- loop through the selected items. > callback_item() -- the item that caused the callback > callback_reason() -- reason the callback was invoked FL_TREE_REASON_SELECTED -- item was selected FL_TREE_REASON_DESELECTED -- item was de-selected FL_TREE_REASON_OPENED -- item was opened FL_TREE_REASON_CLOSED -- item was closed > position() > display() * new Fl_Tree_Item methods: > find_child_item() -- searches children for a path > find_item() -- searches self and children for a path > next(item) -- loop forward through tree > prev(item) -- loop backward through tree > first_selected_item() > next_selected_item() > x(), y(), w(), h() * deprecated: > item_clicked(). Use callback_item() instead * the 'docallback' optional integer argument for all methods is now back to 0 or 1 only. (Other values became unnecessary when above new callback() behavior was defined) * test/tree has new "Test Callback Flags" button to test the 'docallback' flags for eg. open/close/select/deselect to make sure no bugs creep in. * INTERNAL: added free_path() to free special path array created by parse_path(). * Various docs strengthened: * How to use first()/next() and last()/prev() to walk tree > made sure more method's options use \param[in] > Added more \see references * Moved several implementations from .H -> .cxx * Added autoscroll to keyboard nav and mouse drags * test/unittests: added Fl_Tree to scrollsize test TODO: o Horiz scroll bar (see Johannes Schock's email re. additions he sent) o Need to allow keyboard nav to move focus to child FLTK widgets o Fix fast-selections so that no gaps are left behind. (Select all items from the last selected item to the current) o Investigate non-default values of when() causing odd behavior. (See the tree demo's when() pulldown..) * tree demo modified to include top/mid/bot buttons that test the above. * Keyboard navigation added: Up/Down -- move focus Left/Right -- closes/opens tree item in focus Spacebar -- toggle selection state of item in focus Enter -- selects the item in focus, deselecting all others Tab/Shift-Tab -- change widget focus * All Fl_Tree select() and deselect() methods now return a value that indicates if the item's state was changed. * Fixed focus box drawing (focus box resides more precisely within item's box) git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@7691 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
parent
23303736e3
commit
c7ef0f1d17
563
FL/Fl_Tree.H
563
FL/Fl_Tree.H
@ -84,67 +84,74 @@
|
||||
/// tree.end();
|
||||
/// \endcode
|
||||
///
|
||||
/// Items can be added with Fl_Tree::add(),
|
||||
/// removed with Fl_Tree::remove(),
|
||||
/// inserted with Fl_Tree::insert_above(),
|
||||
/// selected/deselected with Fl_Tree::select() and Fl_Tree::deselect().
|
||||
/// Items can be swapped with Fl_Tree_Item::swap_children(), sorting control via
|
||||
/// Fl_Tree::sortorder().
|
||||
/// Items can be added with add(),
|
||||
/// removed with remove(),
|
||||
/// completely cleared with clear(),
|
||||
/// inserted with insert() and insert_above(),
|
||||
/// selected/deselected with select() and deselect(),
|
||||
/// open/closed with open() and closed().
|
||||
/// Children of an item can be swapped around with Fl_Tree_Item::swap_children(),
|
||||
/// sorting can be controlled when items are add()ed via sortorder().
|
||||
/// You can walk the entire tree with first() and next().
|
||||
/// You can walk selected items with first_selected_item() and
|
||||
/// next_selected_item().
|
||||
/// Items can be found by their pathname using find_item(const char*),
|
||||
/// and an item's pathname can be found with item_pathname().
|
||||
///
|
||||
/// The tree can have different selection behaviors controlled by Fl_Tree::selectmode().
|
||||
/// The tree can have different selection behaviors controlled by selectmode().
|
||||
///
|
||||
/// FLTK and custom FLTK widgets can be assigned to tree items via Fl_Tree_Item::widget().
|
||||
/// FLTK widgets (including custom widgets) can be assigned to tree items via
|
||||
/// Fl_Tree_Item::widget().
|
||||
///
|
||||
/// Parent nodes can be open/closed with open() and close(), icons can be assigned
|
||||
/// or redefined with some or all items via
|
||||
/// Icons for individual items can be changed with
|
||||
/// Fl_Tree_Item::openicon(),
|
||||
/// Fl_Tree_Item::closeicon(),
|
||||
/// Fl_Tree_Item::usericon().
|
||||
///
|
||||
/// Various default preferences can be manipulated via Fl_Tree_Prefs, including
|
||||
/// colors, margins, connection lines.
|
||||
/// Various default preferences can be globally manipulated via Fl_Tree_Prefs,
|
||||
/// including colors, margins, icons, connection lines.
|
||||
///
|
||||
/// The tree's callback() will be invoked when items change state or are open/closed.
|
||||
/// when() controls when mouse/keyboard events invoke the callback.
|
||||
/// callback_item() and callback_reason() can be used to determine the cause of the callback.
|
||||
///
|
||||
/// \image html tree-elements.png
|
||||
///
|
||||
/// \todo Needs handling of callbacks when items are procedurally select()ed
|
||||
|
||||
/// \enum Fl_Tree_Reason
|
||||
/// The reason the callback was invoked.
|
||||
///
|
||||
enum Fl_Tree_Reason {
|
||||
FL_TREE_REASON_NONE=0, ///< unknown reason
|
||||
FL_TREE_REASON_SELECTED, ///< an item was selected
|
||||
FL_TREE_REASON_DESELECTED, ///< an item was de-selected
|
||||
FL_TREE_REASON_OPENED, ///< an item was opened
|
||||
FL_TREE_REASON_CLOSED ///< an item was closed
|
||||
};
|
||||
|
||||
|
||||
class Fl_Tree : public Fl_Group {
|
||||
Fl_Tree_Item *_root; // can be null!
|
||||
Fl_Tree_Item *_item_clicked;
|
||||
Fl_Tree_Item *_item_focus; // item that has focus box
|
||||
Fl_Tree_Item *_callback_item; // item invoked during callback (can be NULL)
|
||||
Fl_Tree_Reason _callback_reason; // reason for the callback
|
||||
Fl_Tree_Prefs _prefs; // all the tree's settings
|
||||
int _scrollbar_size; // size of scrollbar trough
|
||||
|
||||
protected:
|
||||
/// Vertical scrollbar
|
||||
Fl_Scrollbar *_vscroll;
|
||||
|
||||
public:
|
||||
/// Find the item that was clicked.
|
||||
/// You probably want to use item_clicked() instead, which is fast.
|
||||
///
|
||||
/// This method walks the entire tree looking for the first item that is
|
||||
/// under the mouse (ie. at Fl::event_x()/Fl:event_y().
|
||||
///
|
||||
/// Use this method /only/ if you've subclassed Fl_Tree, and are receiving
|
||||
/// events before Fl_Tree has been able to process and update item_clicked().
|
||||
///
|
||||
/// \returns the item clicked, or 0 if no item was under the current event.
|
||||
///
|
||||
const Fl_Tree_Item *find_clicked() const {
|
||||
if ( ! _root ) return(0);
|
||||
return(_root->find_clicked(_prefs));
|
||||
}
|
||||
protected:
|
||||
/// Set the item that was last clicked.
|
||||
/// Should only be used by subclasses needing to change this value.
|
||||
/// Normally Fl_Tree manages this value.
|
||||
///
|
||||
void item_clicked(Fl_Tree_Item* val) {
|
||||
_item_clicked = val;
|
||||
}
|
||||
void do_callback_for_item(Fl_Tree_Item* item) {
|
||||
Fl_Tree_Item *save = _item_clicked; // save previous 'item_clicked'
|
||||
_item_clicked = item; // set item_clicked to this item while we do callback
|
||||
void set_item_focus(Fl_Tree_Item *o);
|
||||
void item_clicked(Fl_Tree_Item* val);
|
||||
/// Do the callback for the item, setting the item and reason
|
||||
void do_callback_for_item(Fl_Tree_Item* item, Fl_Tree_Reason reason) {
|
||||
callback_reason(reason);
|
||||
callback_item(item);
|
||||
do_callback((Fl_Widget*)this, user_data());
|
||||
_item_clicked = save; // restore item_clicked
|
||||
}
|
||||
Fl_Tree_Item *next_visible_item(Fl_Tree_Item *start, int dir);
|
||||
|
||||
public:
|
||||
Fl_Tree(int X, int Y, int W, int H, const char *L=0);
|
||||
@ -213,51 +220,28 @@ public:
|
||||
////////////////////////
|
||||
Fl_Tree_Item *find_item(const char *path);
|
||||
const Fl_Tree_Item *find_item(const char *path) const;
|
||||
int item_pathname(char *pathname, int pathnamelen, const Fl_Tree_Item *item) const;
|
||||
|
||||
const Fl_Tree_Item *find_clicked() const;
|
||||
|
||||
/// Return the item that was last clicked.
|
||||
///
|
||||
/// Valid only from within an Fl_Tree::callback().
|
||||
/// Valid only from within the callback().
|
||||
///
|
||||
/// Deprecated: use callback_item() instead.
|
||||
///
|
||||
/// \returns the item clicked, or 0 if none.
|
||||
/// 0 may also be used to indicate several items were clicked/changed.
|
||||
///
|
||||
Fl_Tree_Item *item_clicked() {
|
||||
return(_item_clicked);
|
||||
}
|
||||
/// Returns the first item in the tree.
|
||||
///
|
||||
/// Use this to walk the tree in the forward direction, eg:
|
||||
/// \code
|
||||
/// for ( Fl_Tree_Item *item = tree->first(); item; item = item->next() ) {
|
||||
/// printf("Item: %s\n", item->label());
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \returns first item in tree, or 0 if none (tree empty).
|
||||
///
|
||||
Fl_Tree_Item *first() {
|
||||
return(_root); // first item always root
|
||||
}
|
||||
/// Returns the last item in the tree.
|
||||
///
|
||||
/// Use this to walk the tree in reverse, eg:
|
||||
///
|
||||
/// \code
|
||||
/// for ( Fl_Tree_Item *item = tree->last(); item; item = item->prev() ) {
|
||||
/// printf("Item: %s\n", item->label());
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \returns last item in the tree, or 0 if none (tree empty).
|
||||
///
|
||||
Fl_Tree_Item *last() {
|
||||
if ( ! _root ) return(0);
|
||||
Fl_Tree_Item *item = _root;
|
||||
while ( item->has_children() ) {
|
||||
item = item->child(item->children()-1);
|
||||
}
|
||||
return(item);
|
||||
return(_callback_item);
|
||||
}
|
||||
Fl_Tree_Item *first();
|
||||
Fl_Tree_Item *next(Fl_Tree_Item *item=0);
|
||||
Fl_Tree_Item *prev(Fl_Tree_Item *item=0);
|
||||
Fl_Tree_Item *last();
|
||||
Fl_Tree_Item *first_selected_item();
|
||||
Fl_Tree_Item *next_selected_item(Fl_Tree_Item *item=0);
|
||||
|
||||
//////////////////////////
|
||||
// Item open/close methods
|
||||
@ -266,59 +250,140 @@ public:
|
||||
/// Open the specified 'item'.
|
||||
/// This causes the item's children (if any) to be shown.
|
||||
/// Handles redrawing if anything was actually changed.
|
||||
/// Invokes the callback depending on the value of optional parameter \p docallback.
|
||||
///
|
||||
void open(Fl_Tree_Item *item) {
|
||||
if ( ! item->is_open() ) {
|
||||
/// The callback can use callback_item() and callback_reason() respectively to determine
|
||||
/// the item changed and the reason the callback was called.
|
||||
///
|
||||
/// \param[in] item -- the item to be opened
|
||||
/// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
|
||||
/// - 0 - callback() is not invoked
|
||||
/// - 1 - callback() is invoked if item changed,
|
||||
/// callback_reason() will be FL_TREE_REASON_OPENED
|
||||
///
|
||||
/// \returns
|
||||
/// - 1 -- item was opened
|
||||
/// - 0 -- item was already open, no change
|
||||
///
|
||||
/// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason()
|
||||
///
|
||||
int open(Fl_Tree_Item *item, int docallback=1) {
|
||||
if ( item->is_open() ) return(0);
|
||||
item->open();
|
||||
redraw();
|
||||
if ( docallback ) {
|
||||
do_callback_for_item(item, FL_TREE_REASON_OPENED);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
/// Opens the item specified by \p path (eg: "Parent/child/item").
|
||||
/// This causes the item's children (if any) to be shown.
|
||||
/// Handles redrawing if anything was actually changed.
|
||||
/// Invokes the callback depending on the value of optional parameter \p docallback.
|
||||
///
|
||||
/// The callback can use callback_item() and callback_reason() respectively to determine
|
||||
/// the item changed and the reason the callback was called.
|
||||
///
|
||||
/// \param[in] path -- the tree item's pathname (eg. "Flintstones/Fred")
|
||||
/// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
|
||||
/// - 0 - callback() is not invoked
|
||||
/// - 1 - callback() is invoked if item changed,
|
||||
/// callback_reason() will be FL_TREE_REASON_OPENED
|
||||
///
|
||||
/// \returns
|
||||
/// - 0 : OK
|
||||
/// - -1 : item was not found
|
||||
/// - 1 -- OK: item opened
|
||||
/// - 0 -- OK: item was already open, no change
|
||||
/// - -1 -- ERROR: item was not found
|
||||
///
|
||||
int open(const char *path) {
|
||||
/// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason()
|
||||
///
|
||||
int open(const char *path, int docallback=1) {
|
||||
Fl_Tree_Item *item = find_item(path);
|
||||
if ( item ) {
|
||||
open(item);
|
||||
return(0);
|
||||
if ( ! item ) return(-1);
|
||||
return(open(item, docallback));
|
||||
}
|
||||
/// Toggle the open state of \p item.
|
||||
/// Handles redrawing if anything was actually changed.
|
||||
/// Invokes the callback depending on the value of optional parameter \p docallback.
|
||||
///
|
||||
/// The callback can use callback_item() and callback_reason() respectively to determine
|
||||
/// the item changed and the reason the callback was called.
|
||||
///
|
||||
/// \param[in] item -- the item to be opened
|
||||
/// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
|
||||
/// - 0 - callback() is not invoked
|
||||
/// - 1 - callback() is invoked, callback_reason() will be either
|
||||
/// FL_TREE_REASON_OPENED or FL_TREE_REASON_CLOSED
|
||||
///
|
||||
/// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason()
|
||||
///
|
||||
void open_toggle(Fl_Tree_Item *item, int docallback=1) {
|
||||
if ( item->is_open() ) {
|
||||
close(item, docallback);
|
||||
} else {
|
||||
open(item, docallback);
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
/// Closes the specified \p item.
|
||||
/// Handles redrawing if anything was actually changed.
|
||||
/// Invokes the callback depending on the value of optional parameter \p docallback.
|
||||
///
|
||||
void close(Fl_Tree_Item *item) {
|
||||
if ( ! item->is_close() ) {
|
||||
item->close();
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
/// Closes the item specified by \p path, eg: "Parent/child/item".
|
||||
/// The callback can use callback_item() and callback_reason() respectively to determine
|
||||
/// the item changed and the reason the callback was called.
|
||||
///
|
||||
/// Handles redrawing if anything was actually changed.
|
||||
/// \param[in] item -- the item to be closed
|
||||
/// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
|
||||
/// - 0 - callback() is not invoked
|
||||
/// - 1 - callback() is invoked if item changed,
|
||||
/// callback_reason() will be FL_TREE_REASON_CLOSED
|
||||
///
|
||||
/// \returns
|
||||
/// - 0 -- OK
|
||||
/// - -1 -- item was not found
|
||||
/// - 1 -- item was closed
|
||||
/// - 0 -- item was already closed, no change
|
||||
///
|
||||
int close(const char *path) {
|
||||
Fl_Tree_Item *item = find_item(path);
|
||||
if ( item ) {
|
||||
close(item);
|
||||
return(0);
|
||||
/// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason()
|
||||
///
|
||||
int close(Fl_Tree_Item *item, int docallback=1) {
|
||||
if ( item->is_close() ) return(0);
|
||||
item->close();
|
||||
redraw();
|
||||
if ( docallback ) {
|
||||
do_callback_for_item(item, FL_TREE_REASON_CLOSED);
|
||||
}
|
||||
return(-1);
|
||||
return(1);
|
||||
}
|
||||
/// Closes the item specified by \p path, eg: "Parent/child/item".
|
||||
/// Handles redrawing if anything was actually changed.
|
||||
/// Invokes the callback depending on the value of optional parameter \p docallback.
|
||||
///
|
||||
/// The callback can use callback_item() and callback_reason() respectively to determine
|
||||
/// the item changed and the reason the callback was called.
|
||||
///
|
||||
/// \param[in] path -- the tree item's pathname (eg. "Flintstones/Fred")
|
||||
/// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
|
||||
/// - 0 - callback() is not invoked
|
||||
/// - 1 - callback() is invoked if item changed,
|
||||
/// callback_reason() will be FL_TREE_REASON_CLOSED
|
||||
///
|
||||
/// \returns
|
||||
/// - 1 -- OK: item closed
|
||||
/// - 0 -- OK: item was already closed, no change
|
||||
/// - -1 -- ERROR: item was not found
|
||||
///
|
||||
/// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason()
|
||||
///
|
||||
int close(const char *path, int docallback=1) {
|
||||
Fl_Tree_Item *item = find_item(path);
|
||||
if ( ! item ) return(-1);
|
||||
return(close(item, docallback));
|
||||
}
|
||||
/// See if \p item is open.
|
||||
///
|
||||
/// Items that are 'open' are themselves not necessarily visible;
|
||||
/// one of the item's parents might be closed.
|
||||
///
|
||||
/// \param[in] item -- the item to be tested
|
||||
///
|
||||
/// \returns
|
||||
/// - 1 : item is open
|
||||
/// - 0 : item is closed
|
||||
@ -331,17 +396,22 @@ public:
|
||||
/// Items that are 'open' are themselves not necessarily visible;
|
||||
/// one of the item's parents might be closed.
|
||||
///
|
||||
/// \param[in] path -- the tree item's pathname (eg. "Flintstones/Fred")
|
||||
///
|
||||
/// \returns
|
||||
/// - 1 : item is open
|
||||
/// - 0 : item is closed
|
||||
/// - -1 : item was not found
|
||||
/// - 1 - OK: item is open
|
||||
/// - 0 - OK: item is closed
|
||||
/// - -1 - ERROR: item was not found
|
||||
///
|
||||
int is_open(const char *path) const {
|
||||
const Fl_Tree_Item *item = find_item(path);
|
||||
if ( item ) return(item->is_open()?1:0);
|
||||
return(-1);
|
||||
if ( ! item ) return(-1);
|
||||
return(item->is_open()?1:0);
|
||||
}
|
||||
/// See if the specified \p item is closed.
|
||||
///
|
||||
/// \param[in] item -- the item to be tested
|
||||
///
|
||||
/// \returns
|
||||
/// - 1 : item is open
|
||||
/// - 0 : item is closed
|
||||
@ -351,111 +421,154 @@ public:
|
||||
}
|
||||
/// See if item specified by \p path (eg: "Parent/child/item") is closed.
|
||||
///
|
||||
/// \param[in] path -- the tree item's pathname (eg. "Flintstones/Fred")
|
||||
///
|
||||
/// \returns
|
||||
/// - 1 : item is closed
|
||||
/// - 0 : item is open
|
||||
/// - -1 : item was not found
|
||||
/// - 1 - OK: item is closed
|
||||
/// - 0 - OK: item is open
|
||||
/// - -1 - ERROR: item was not found
|
||||
///
|
||||
int is_close(const char *path) const {
|
||||
const Fl_Tree_Item *item = find_item(path);
|
||||
if ( item ) return(item->is_close()?1:0);
|
||||
return(-1);
|
||||
if ( ! item ) return(-1);
|
||||
return(item->is_close()?1:0);
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// Item selection methods
|
||||
/////////////////////////
|
||||
|
||||
/// Select the specified \p item. Use 'deselect()' to de-select it.
|
||||
/// Handles redrawing if anything was actually changed.
|
||||
/// Invokes the callback depending on the value of optional parameter \p docallback.
|
||||
///
|
||||
/// \p docallback is an optional paramemter that can either be 0 or 1.
|
||||
/// - 0 - the callback() is not invoked (default)
|
||||
/// - 1 - the callback() is invoked if the item changed state,
|
||||
/// and the callback can use item_clicked() to determine the selected item.
|
||||
/// The callback can use callback_item() and callback_reason() respectively to determine
|
||||
/// the item changed and the reason the callback was called.
|
||||
///
|
||||
void select(Fl_Tree_Item *item, int docallback=0) {
|
||||
/// \param[in] item -- the item to be selected
|
||||
/// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
|
||||
/// - 0 - the callback() is not invoked
|
||||
/// - 1 - the callback() is invoked if item changed state,
|
||||
/// callback_reason() will be FL_TREE_REASON_SELECTED
|
||||
///
|
||||
/// \returns
|
||||
/// - 1 - item's state was changed
|
||||
/// - 0 - item was already selected, no change was made
|
||||
///
|
||||
int select(Fl_Tree_Item *item, int docallback=1) {
|
||||
if ( ! item->is_selected() ) {
|
||||
item->select();
|
||||
if ( docallback == 1 ) do_callback_for_item(item);
|
||||
redraw();
|
||||
set_changed();
|
||||
if ( docallback ) {
|
||||
do_callback_for_item(item, FL_TREE_REASON_SELECTED);
|
||||
}
|
||||
redraw();
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/// Select the item specified by \p path (eg: "Parent/child/item").
|
||||
/// Handles redrawing if anything was actually changed.
|
||||
/// Invokes the callback depending on the value of optional parameter \p docallback.
|
||||
///
|
||||
/// \p docallback is an optional paramemter that can either be 0 or 1.
|
||||
/// - 0 - the callback() is not invoked (default)
|
||||
/// - 1 - the callback() is invoked if the item changed state,
|
||||
/// and the callback can use item_clicked() to determine the selected item.
|
||||
/// The callback can use callback_item() and callback_reason() respectively to determine
|
||||
/// the item changed and the reason the callback was called.
|
||||
///
|
||||
/// \param[in] path -- the tree item's pathname (eg. "Flintstones/Fred")
|
||||
/// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
|
||||
/// - 0 - the callback() is not invoked
|
||||
/// - 1 - the callback() is invoked if item changed state,
|
||||
/// callback_reason() will be FL_TREE_REASON_SELECTED
|
||||
///
|
||||
/// \returns
|
||||
/// - 0 : OK
|
||||
/// - -1 : item was not found
|
||||
/// - 1 : OK: item's state was changed
|
||||
/// - 0 : OK: item was already selected, no change was made
|
||||
/// - -1 : ERROR: item was not found
|
||||
///
|
||||
int select(const char *path, int docallback=0) {
|
||||
int select(const char *path, int docallback=1) {
|
||||
Fl_Tree_Item *item = find_item(path);
|
||||
if ( item ) {
|
||||
select(item);
|
||||
if ( docallback == 1 ) do_callback_for_item(item);
|
||||
return(0);
|
||||
}
|
||||
return(-1);
|
||||
if ( ! item ) return(-1);
|
||||
return(select(item, docallback));
|
||||
}
|
||||
/// Toggle the select state of the specified \p item.
|
||||
/// Handles redrawing.
|
||||
/// Handles redrawing if anything was actually changed.
|
||||
/// Invokes the callback depending on the value of optional parameter \p docallback.
|
||||
///
|
||||
/// \p docallback is an optional paramemter that can either be 0 or 1.
|
||||
/// - 0 - the callback() is not invoked (default)
|
||||
/// - 1 - the callback() is invoked,
|
||||
/// and the callback can use item_clicked() to determine the selected item.
|
||||
/// The callback can use callback_item() and callback_reason() respectively to determine
|
||||
/// the item changed and the reason the callback was called.
|
||||
///
|
||||
void select_toggle(Fl_Tree_Item *item, int docallback=0) {
|
||||
/// \param[in] item -- the item to be selected
|
||||
/// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
|
||||
/// - 0 - the callback() is not invoked
|
||||
/// - 1 - the callback() is invoked, callback_reason() will be
|
||||
/// either FL_TREE_REASON_SELECTED or FL_TREE_REASON_DESELECTED
|
||||
///
|
||||
void select_toggle(Fl_Tree_Item *item, int docallback=1) {
|
||||
item->select_toggle();
|
||||
if ( docallback == 1 ) do_callback_for_item(item);
|
||||
set_changed();
|
||||
if ( docallback ) {
|
||||
do_callback_for_item(item, item->is_selected() ? FL_TREE_REASON_SELECTED
|
||||
: FL_TREE_REASON_DESELECTED);
|
||||
}
|
||||
redraw();
|
||||
}
|
||||
/// De-select the specified \p item.
|
||||
/// Handles redrawing if anything was actually changed.
|
||||
/// Invokes the callback depending on the value of optional parameter \p docallback.
|
||||
///
|
||||
/// \p docallback is an optional paramemter that can either be 0 or 1.
|
||||
/// - 0 - the callback() is not invoked (default)
|
||||
/// - 1 - the callback() is invoked if the item changed state,
|
||||
/// and the callback can use item_clicked() to determine the selected item.
|
||||
/// The callback can use callback_item() and callback_reason() respectively to determine
|
||||
/// the item changed and the reason the callback was called.
|
||||
///
|
||||
void deselect(Fl_Tree_Item *item, int docallback=0) {
|
||||
if ( item->is_selected() ) {
|
||||
item->deselect();
|
||||
if ( docallback == 1 ) do_callback_for_item(item);
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
/// De-select an item specified by \p path (eg: "Parent/child/item").
|
||||
/// Handles redrawing if anything was actually changed.
|
||||
///
|
||||
/// \p docallback is an optional paramemter that can either be 0 or 1.
|
||||
/// - 0 - the callback() is not invoked (default)
|
||||
/// - 1 - the callback() is invoked if the item changed state,
|
||||
/// and the callback can use item_clicked() to determine the selected item.
|
||||
/// \param[in] item -- the item to be selected
|
||||
/// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
|
||||
/// - 0 - the callback() is not invoked
|
||||
/// - 1 - the callback() is invoked if item changed state,
|
||||
/// callback_reason() will be FL_TREE_REASON_DESELECTED
|
||||
///
|
||||
/// \returns
|
||||
/// - 0 : OK
|
||||
/// - -1 : item was not found
|
||||
/// - 0 - item was already deselected, no change was made
|
||||
/// - 1 - item's state was changed
|
||||
///
|
||||
int deselect(const char *path, int docallback=0) {
|
||||
Fl_Tree_Item *item = find_item(path);
|
||||
if ( item ) {
|
||||
deselect(item, docallback);
|
||||
int deselect(Fl_Tree_Item *item, int docallback=1) {
|
||||
if ( item->is_selected() ) {
|
||||
item->deselect();
|
||||
set_changed();
|
||||
if ( docallback ) {
|
||||
do_callback_for_item(item, FL_TREE_REASON_DESELECTED);
|
||||
}
|
||||
redraw();
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
return(-1);
|
||||
/// Deselect an item specified by \p path (eg: "Parent/child/item").
|
||||
/// Handles redrawing if anything was actually changed.
|
||||
/// Invokes the callback depending on the value of optional parameter \p docallback.
|
||||
///
|
||||
/// The callback can use callback_item() and callback_reason() respectively to determine
|
||||
/// the item changed and the reason the callback was called.
|
||||
///
|
||||
/// \param[in] path -- the tree item's pathname (eg. "Flintstones/Fred")
|
||||
/// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
|
||||
/// - 0 - the callback() is not invoked
|
||||
/// - 1 - the callback() is invoked if item changed state,
|
||||
/// callback_reason() will be FL_TREE_REASON_DESELECTED
|
||||
///
|
||||
/// \returns
|
||||
/// - 1 - OK: item's state was changed
|
||||
/// - 0 - OK: item was already deselected, no change was made
|
||||
/// - -1 - ERROR: item was not found
|
||||
///
|
||||
int deselect(const char *path, int docallback=1) {
|
||||
Fl_Tree_Item *item = find_item(path);
|
||||
if ( ! item ) return(-1);
|
||||
return(deselect(item, docallback));
|
||||
}
|
||||
|
||||
int deselect_all(Fl_Tree_Item *item=0, int docallback=0);
|
||||
int select_only(Fl_Tree_Item *selitem, int docallback=0);
|
||||
int select_all(Fl_Tree_Item *item=0, int docallback=0);
|
||||
int deselect_all(Fl_Tree_Item *item=0, int docallback=1);
|
||||
int select_only(Fl_Tree_Item *selitem, int docallback=1);
|
||||
int select_all(Fl_Tree_Item *item=0, int docallback=1);
|
||||
|
||||
/// See if the specified \p item is selected.
|
||||
///
|
||||
/// \param[in] item -- the item to be tested
|
||||
///
|
||||
/// \return
|
||||
/// - 1 : item selected
|
||||
/// - 0 : item deselected
|
||||
@ -465,6 +578,8 @@ public:
|
||||
}
|
||||
/// See if item specified by \p path (eg: "Parent/child/item") is selected.
|
||||
///
|
||||
/// \param[in] path -- the tree item's pathname (eg. "Flintstones/Fred")
|
||||
///
|
||||
/// \returns
|
||||
/// - 1 : item selected
|
||||
/// - 0 : item deselected
|
||||
@ -472,8 +587,8 @@ public:
|
||||
///
|
||||
int is_selected(const char *path) {
|
||||
Fl_Tree_Item *item = find_item(path);
|
||||
if ( item ) return(is_selected(item));
|
||||
return(-1);
|
||||
if ( ! item ) return(-1);
|
||||
return(is_selected(item));
|
||||
}
|
||||
/// Print the tree as 'ascii art' to stdout.
|
||||
/// Used mainly for debugging.
|
||||
@ -688,7 +803,109 @@ public:
|
||||
void selectmode(Fl_Tree_Select val) {
|
||||
_prefs.selectmode(val);
|
||||
}
|
||||
void show_item(Fl_Tree_Item *item, int yoff=0);
|
||||
void show_item_bottom(Fl_Tree_Item *item);
|
||||
void show_item_middle(Fl_Tree_Item *item);
|
||||
void show_item_top(Fl_Tree_Item *item);
|
||||
void display(Fl_Tree_Item *item);
|
||||
int vposition() const;
|
||||
void vposition(int ypos);
|
||||
|
||||
/// See if widget \p w is one of the Fl_Tree widget's scrollbars.
|
||||
/// Use this to skip over the scrollbars when walking the child() array. Example:
|
||||
/// \code
|
||||
/// for ( int i=0; i<tree->children(); i++ ) { // walk children
|
||||
/// Fl_Widget *w= tree->child(i);
|
||||
/// if ( brow->is_scrollbar(w) ) continue; // skip scrollbars
|
||||
/// ..do work here..
|
||||
/// }
|
||||
/// \endcode
|
||||
/// \param[in] w Widget to test
|
||||
/// \returns 1 if \p w is a scrollbar, 0 if not.
|
||||
///
|
||||
int is_scrollbar(Fl_Widget *w) {
|
||||
return( ( w == _vscroll ) ? 1 : 0 );
|
||||
}
|
||||
/// Gets the current size of the scrollbars' troughs, in pixels.
|
||||
///
|
||||
/// If this value is zero (default), this widget will use the global
|
||||
/// Fl::scrollbar_size() value as the scrollbar's width.
|
||||
///
|
||||
/// \returns Scrollbar size in pixels, or 0 if the global Fl::scrollsize() is being used.
|
||||
/// \see Fl::scrollbar_size(int)
|
||||
///
|
||||
int scrollbar_size() const {
|
||||
return(_scrollbar_size);
|
||||
}
|
||||
/// Sets the pixel size of the scrollbars' troughs to the \p size, in pixels.
|
||||
///
|
||||
/// Normally you should not need this method, and should use the global
|
||||
/// Fl::scrollbar_size(int) instead to manage the size of ALL
|
||||
/// your widgets' scrollbars. This ensures your application
|
||||
/// has a consistent UI, is the default behavior, and is normally
|
||||
/// what you want.
|
||||
///
|
||||
/// Only use THIS method if you really need to override the global
|
||||
/// scrollbar size. The need for this should be rare.
|
||||
///
|
||||
/// Setting \p size to the special value of 0 causes the widget to
|
||||
/// track the global Fl::scrollbar_size(), which is the default.
|
||||
///
|
||||
/// \param[in] size Sets the scrollbar size in pixels.\n
|
||||
/// If 0 (default), scrollbar size tracks the global Fl::scrollbar_size()
|
||||
/// \see Fl::scrollbar_size()
|
||||
///
|
||||
void scrollbar_size(int size) {
|
||||
_scrollbar_size = size;
|
||||
int scrollsize = _scrollbar_size ? _scrollbar_size : Fl::scrollbar_size();
|
||||
if ( _vscroll->w() != scrollsize ) {
|
||||
_vscroll->resize(x()+w()-scrollsize, h(), scrollsize, _vscroll->h());
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
// callback related
|
||||
///////////////////////
|
||||
|
||||
/// Sets the item that was changed for this callback.
|
||||
/// Used internally to pass the item that invoked the callback.
|
||||
///
|
||||
void callback_item(Fl_Tree_Item* item) {
|
||||
_callback_item = item;
|
||||
}
|
||||
/// Gets the item that caused the callback.
|
||||
/// The callback() can use this value to see which item changed.
|
||||
///
|
||||
Fl_Tree_Item* callback_item() {
|
||||
return(_callback_item);
|
||||
}
|
||||
/// Sets the reason for this callback.
|
||||
/// Used internally to pass the reason the callback was invoked.
|
||||
///
|
||||
void callback_reason(Fl_Tree_Reason reason) {
|
||||
_callback_reason = reason;
|
||||
}
|
||||
/// Gets the reason for this callback.
|
||||
///
|
||||
/// The callback() can use this value to see why it was called. Example:
|
||||
/// \code
|
||||
/// void MyTreeCallback(Fl_Widget *w, void *userdata) {
|
||||
/// Fl_Tree *tree = (Fl_Tree*)w;
|
||||
/// Fl_Tree_Item *item = tree->callback_item(); // the item changed (can be NULL if more than one item was changed!)
|
||||
/// switch ( tree->callback_reason() ) { // reason callback was invoked
|
||||
/// case FL_TREE_REASON_OPENED: ..item was opened..
|
||||
/// case FL_TREE_REASON_CLOSED: ..item was closed..
|
||||
/// case FL_TREE_REASON_SELECTED: ..item was selected..
|
||||
/// case FL_TREE_REASON_DESELECTED: ..item was deselected..
|
||||
/// }
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
Fl_Tree_Reason callback_reason() const {
|
||||
return(_callback_reason);
|
||||
}
|
||||
|
||||
/// Load FLTK preferences
|
||||
void load(class Fl_Preferences&);
|
||||
};
|
||||
|
||||
|
@ -83,7 +83,11 @@ public:
|
||||
Fl_Tree_Item(const Fl_Tree_Prefs &prefs); // CTOR
|
||||
~Fl_Tree_Item(); // DTOR
|
||||
Fl_Tree_Item(const Fl_Tree_Item *o); // COPY CTOR
|
||||
void draw(int X, int &Y, int W, Fl_Widget *tree, const Fl_Tree_Prefs &prefs, int lastchild=1);
|
||||
int x() const { return(_xywh[0]); }
|
||||
int y() const { return(_xywh[1]); }
|
||||
int w() const { return(_xywh[2]); }
|
||||
int h() const { return(_xywh[3]); }
|
||||
void draw(int X, int &Y, int W, Fl_Widget *tree, Fl_Tree_Item *itemfocus, const Fl_Tree_Prefs &prefs, int lastchild=1);
|
||||
void show_self(const char *indent = "") const;
|
||||
void label(const char *val);
|
||||
const char *label() const;
|
||||
@ -163,8 +167,10 @@ public:
|
||||
void clear_children();
|
||||
void swap_children(int ax, int bx);
|
||||
int swap_children(Fl_Tree_Item *a, Fl_Tree_Item *b);
|
||||
const Fl_Tree_Item *find_item(char **arr) const;
|
||||
Fl_Tree_Item *find_item(char **arr);
|
||||
const Fl_Tree_Item *find_child_item(char **arr) const; // const
|
||||
Fl_Tree_Item *find_child_item(char **arr); // non-const
|
||||
const Fl_Tree_Item *find_item(char **arr) const; // const
|
||||
Fl_Tree_Item *find_item(char **arr); // non-const
|
||||
//////////////////
|
||||
// Adding items
|
||||
//////////////////
|
||||
@ -175,12 +181,16 @@ public:
|
||||
int depth() const;
|
||||
Fl_Tree_Item *prev();
|
||||
Fl_Tree_Item *next();
|
||||
Fl_Tree_Item *next_sibling();
|
||||
Fl_Tree_Item *prev_sibling();
|
||||
Fl_Tree_Item *next_displayed(Fl_Tree_Prefs &prefs);
|
||||
Fl_Tree_Item *prev_displayed(Fl_Tree_Prefs &prefs);
|
||||
|
||||
/// Return the parent for this item.
|
||||
/// Return the parent for this item. Returns NULL if we are the root.
|
||||
Fl_Tree_Item *parent() {
|
||||
return(_parent);
|
||||
}
|
||||
/// Return the const parent for this item.
|
||||
/// Return the const parent for this item. Returns NULL if we are the root.
|
||||
const Fl_Tree_Item *parent() const {
|
||||
return(_parent);
|
||||
}
|
||||
@ -293,6 +303,12 @@ public:
|
||||
char is_active() const {
|
||||
return(_active);
|
||||
}
|
||||
/// See if the item is visible.
|
||||
int visible() const {
|
||||
return(_visible ? 1 : 0);
|
||||
}
|
||||
int visible_r() const;
|
||||
|
||||
/// Set the user icon's image. '0' will disable.
|
||||
void usericon(Fl_Image *val) {
|
||||
_usericon = val;
|
||||
|
@ -69,8 +69,8 @@ enum Fl_Tree_Connector {
|
||||
///
|
||||
enum Fl_Tree_Select {
|
||||
FL_TREE_SELECT_NONE=0, ///< Nothing selected when items are clicked
|
||||
FL_TREE_SELECT_SINGLE, ///< Single item selected when item is clicked (default)
|
||||
FL_TREE_SELECT_MULTI ///< Multiple items can be selected by clicking with
|
||||
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 with
|
||||
///< SHIFT or CTRL or mouse drags.
|
||||
};
|
||||
|
||||
|
702
src/Fl_Tree.cxx
702
src/Fl_Tree.cxx
@ -9,8 +9,6 @@
|
||||
#include <FL/Fl_Tree.H>
|
||||
#include <FL/Fl_Preferences.H>
|
||||
|
||||
#define SCROLL_W 15
|
||||
|
||||
//////////////////////
|
||||
// Fl_Tree.cxx
|
||||
//////////////////////
|
||||
@ -42,7 +40,7 @@ static void scroll_cb(Fl_Widget*,void *data) {
|
||||
// INTERNAL: Parse elements from path into an array of null terminated strings
|
||||
// Path="/aa/bb"
|
||||
// Return: arr[0]="aa", arr[1]="bb", arr[2]=0
|
||||
// Caller must: free(arr[0]); free(arr);
|
||||
// Caller must call free_path(arr).
|
||||
//
|
||||
static char **parse_path(const char *path) {
|
||||
while ( *path == '/' ) path++; // skip leading '/'
|
||||
@ -68,6 +66,14 @@ static char **parse_path(const char *path) {
|
||||
return(arr);
|
||||
}
|
||||
|
||||
// INTERNAL: Free the array returned by parse_path()
|
||||
static void free_path(char **arr) {
|
||||
if ( arr ) {
|
||||
if ( arr[0] ) { free((void*)arr[0]); }
|
||||
free((void*)arr);
|
||||
}
|
||||
}
|
||||
|
||||
// INTERNAL: Recursively descend tree hierarchy, accumulating total child count
|
||||
static int find_total_children(Fl_Tree_Item *item, int count=0) {
|
||||
count++;
|
||||
@ -82,7 +88,10 @@ Fl_Tree::Fl_Tree(int X, int Y, int W, int H, const char *L) : Fl_Group(X,Y,W,H,L
|
||||
_root = new Fl_Tree_Item(_prefs);
|
||||
_root->parent(0); // we are root of tree
|
||||
_root->label("ROOT");
|
||||
_item_clicked = 0;
|
||||
_item_focus = 0;
|
||||
_callback_item = 0;
|
||||
_callback_reason = FL_TREE_REASON_NONE;
|
||||
_scrollbar_size = 0; // 0: uses Fl::scrollbar_size()
|
||||
box(FL_DOWN_BOX);
|
||||
color(FL_WHITE);
|
||||
when(FL_WHEN_CHANGED);
|
||||
@ -112,8 +121,7 @@ Fl_Tree_Item* Fl_Tree::add(const char *path) {
|
||||
}
|
||||
char **arr = parse_path(path);
|
||||
Fl_Tree_Item *item = _root->add(_prefs, arr);
|
||||
free((void*)arr[0]);
|
||||
free((void*)arr);
|
||||
free_path(arr);
|
||||
return(item);
|
||||
}
|
||||
|
||||
@ -125,12 +133,21 @@ Fl_Tree_Item* Fl_Tree::insert_above(Fl_Tree_Item *above, const char *name) {
|
||||
}
|
||||
|
||||
/// Insert a new item into a tree-item's children at a specified position.
|
||||
///
|
||||
/// \param[in] item The existing item to insert new child into
|
||||
/// \param[in] name The label for the new item
|
||||
/// \param[in] pos The position of the new item in the child list
|
||||
///
|
||||
/// \returns the item that was added.
|
||||
Fl_Tree_Item* Fl_Tree::insert(Fl_Tree_Item *item, const char *name, int pos) {
|
||||
return(item->insert(_prefs, name, pos));
|
||||
}
|
||||
|
||||
/// Add a new child to a tree-item.
|
||||
///
|
||||
/// \param[in] item The existing item to add new child to
|
||||
/// \param[in] name The label for the new item
|
||||
///
|
||||
/// \returns the item that was added.
|
||||
Fl_Tree_Item* Fl_Tree::add(Fl_Tree_Item *item, const char *name) {
|
||||
return(item->add(_prefs, name));
|
||||
@ -141,14 +158,17 @@ Fl_Tree_Item* Fl_Tree::add(Fl_Tree_Item *item, const char *name) {
|
||||
/// There is both a const and non-const version of this method.
|
||||
/// Const version allows pure const methods to use this method
|
||||
/// to do lookups without causing compiler errors.
|
||||
///
|
||||
/// \param[in] path -- the tree item's pathname to be found (eg. "Flintstones/Fred")
|
||||
///
|
||||
/// \returns the item, or 0 if not found.
|
||||
/// \see item_pathname()
|
||||
///
|
||||
Fl_Tree_Item *Fl_Tree::find_item(const char *path) {
|
||||
if ( ! _root ) return(0);
|
||||
char **arr = parse_path(path);
|
||||
Fl_Tree_Item *item = _root->find_item(arr);
|
||||
free((void*)arr[0]);
|
||||
free((void*)arr);
|
||||
free_path(arr);
|
||||
return(item);
|
||||
}
|
||||
|
||||
@ -157,18 +177,63 @@ const Fl_Tree_Item *Fl_Tree::find_item(const char *path) const {
|
||||
if ( ! _root ) return(0);
|
||||
char **arr = parse_path(path);
|
||||
const Fl_Tree_Item *item = _root->find_item(arr);
|
||||
free((void*)arr[0]);
|
||||
free((void*)arr);
|
||||
free_path(arr);
|
||||
return(item);
|
||||
}
|
||||
|
||||
// Handle safe 'reverse string concatenation'.
|
||||
// In the following we build the pathname from right-to-left,
|
||||
// since we start at the child and work our way up to the root.
|
||||
//
|
||||
#define SAFE_RCAT(c) { \
|
||||
slen += 1; if ( slen >= pathnamelen ) { pathname[0] = '\0'; return(-2); } \
|
||||
*s-- = c; \
|
||||
}
|
||||
|
||||
/// Find the pathname for the specified \p item.
|
||||
/// If \p item is NULL, root() is used.
|
||||
/// The tree's root will be included in the pathname of showroot() is on.
|
||||
/// \param[in] pathname The string to use to return the pathname
|
||||
/// \param[in] pathnamelen The maximum length of the string (including NULL). Must not be zero.
|
||||
/// \param[in] item The item whose pathname is to be returned.
|
||||
/// \returns
|
||||
/// - 0 : OK (\p pathname returns the item's pathname)
|
||||
/// - -1 : item not found (pathname="")
|
||||
/// - -2 : pathname not large enough (pathname="")
|
||||
/// \see find_item()
|
||||
///
|
||||
int Fl_Tree::item_pathname(char *pathname, int pathnamelen, const Fl_Tree_Item *item) const {
|
||||
pathname[0] = '\0';
|
||||
item = item ? item : _root;
|
||||
if ( !item ) return(-1);
|
||||
// Build pathname starting at end
|
||||
char *s = (pathname+pathnamelen-1);
|
||||
int slen = 0; // length of string compiled so far (including NULL)
|
||||
SAFE_RCAT('\0');
|
||||
while ( item ) {
|
||||
if ( item->is_root() && showroot() == 0 ) break; // don't include root in path if showroot() off
|
||||
// Find name of current item
|
||||
const char *name = item->label() ? item->label() : "???"; // name for this item
|
||||
int len = strlen(name);
|
||||
// Add name to end of pathname[]
|
||||
for ( --len; len>=0; len-- ) { SAFE_RCAT(name[len]); } // rcat name of item
|
||||
SAFE_RCAT('/'); // rcat leading slash
|
||||
item = item->parent(); // move up tree (NULL==root)
|
||||
}
|
||||
if ( *(++s) == '/' ) ++s; // leave off leading slash from pathname
|
||||
if ( s != pathname ) memmove(pathname, s, slen); // Shift down right-aligned string
|
||||
return(0);
|
||||
}
|
||||
|
||||
/// Standard FLTK draw() method, handles draws the tree widget.
|
||||
void Fl_Tree::draw() {
|
||||
// Let group draw box+label but *NOT* children.
|
||||
// We handle drawing children ourselves by calling each item's draw()
|
||||
//
|
||||
// Handle group's bg
|
||||
Fl_Group::draw_box();
|
||||
Fl_Group::draw_label();
|
||||
// Handle tree
|
||||
if ( ! _root ) return;
|
||||
int cx = x() + Fl::box_dx(box());
|
||||
int cy = y() + Fl::box_dy(box());
|
||||
@ -183,7 +248,9 @@ void Fl_Tree::draw() {
|
||||
fl_push_clip(cx,cy,cw,ch);
|
||||
{
|
||||
fl_font(_prefs.labelfont(), _prefs.labelsize());
|
||||
_root->draw(X, Y, W, this, _prefs);
|
||||
_root->draw(X, Y, W, this,
|
||||
(Fl::focus()==this)?_item_focus:0, // show focus item ONLY if Fl_Tree has focus
|
||||
_prefs);
|
||||
}
|
||||
fl_pop_clip();
|
||||
|
||||
@ -197,9 +264,11 @@ void Fl_Tree::draw() {
|
||||
if ( ytoofar > 0 ) ydiff += ytoofar;
|
||||
if ( Ysave<cy || ydiff > ch || int(_vscroll->value()) > 1 ) {
|
||||
_vscroll->visible();
|
||||
int sx = x()+w()-Fl::box_dx(box())-SCROLL_W;
|
||||
|
||||
int scrollsize = _scrollbar_size ? _scrollbar_size : Fl::scrollbar_size();
|
||||
int sx = x()+w()-Fl::box_dx(box())-scrollsize;
|
||||
int sy = y()+Fl::box_dy(box());
|
||||
int sw = SCROLL_W;
|
||||
int sw = scrollsize;
|
||||
int sh = h()-Fl::box_dh(box());
|
||||
_vscroll->show();
|
||||
_vscroll->range(0.0,ydiff-ch);
|
||||
@ -214,219 +283,564 @@ void Fl_Tree::draw() {
|
||||
fl_pop_clip();
|
||||
}
|
||||
|
||||
/// Returns next visible item above (dir==Fl_Up) or below (dir==Fl_Down) the specified \p item.
|
||||
/// If \p item is 0, returns first() if \p dir is Fl_Up, or last() if \p dir is FL_Down.
|
||||
///
|
||||
/// \param[in] item The item above/below which we'll find the next visible item
|
||||
/// \param[in] dir The direction to search. Can be FL_Up or FL_Down.
|
||||
///
|
||||
/// \returns The item found, or 0 if there's no visible items above/below the specified \p item.
|
||||
///
|
||||
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
|
||||
if ( ! item ) return(0);
|
||||
if ( item->visible_r() ) return(item); // return first/last visible item
|
||||
}
|
||||
switch ( dir ) {
|
||||
case FL_Up: return(item->prev_displayed(_prefs));
|
||||
case FL_Down: return(item->next_displayed(_prefs));
|
||||
default: return(item->next_displayed(_prefs));
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the item currently in focus. Handles calling redraw()
|
||||
/// as needed to update the focus box.
|
||||
///
|
||||
void Fl_Tree::set_item_focus(Fl_Tree_Item *item) {
|
||||
if ( _item_focus != item ) { // changed?
|
||||
_item_focus = item; // update
|
||||
if ( visible_focus() ) redraw(); // redraw to update focus box
|
||||
}
|
||||
}
|
||||
|
||||
/// Find the item that was clicked.
|
||||
/// You should use callback_item() instead, which is fast,
|
||||
/// and is meant to be used within a callback to determine the item clicked.
|
||||
///
|
||||
/// This method walks the entire tree looking for the first item that is
|
||||
/// under the mouse (ie. at Fl::event_x()/Fl:event_y().
|
||||
///
|
||||
/// Use this method /only/ if you've subclassed Fl_Tree, and are receiving
|
||||
/// events before Fl_Tree has been able to process and update callback_item().
|
||||
///
|
||||
/// \returns the item clicked, or 0 if no item was under the current event.
|
||||
///
|
||||
const Fl_Tree_Item* Fl_Tree::find_clicked() const {
|
||||
if ( ! _root ) return(0);
|
||||
return(_root->find_clicked(_prefs));
|
||||
}
|
||||
|
||||
/// Set the item that was last clicked.
|
||||
/// Should only be used by subclasses needing to change this value.
|
||||
/// Normally Fl_Tree manages this value.
|
||||
///
|
||||
/// Deprecated: use callback_item() instead.
|
||||
///
|
||||
void Fl_Tree::item_clicked(Fl_Tree_Item* val) {
|
||||
_callback_item = val;
|
||||
}
|
||||
|
||||
/// Returns the first item in the tree.
|
||||
///
|
||||
/// Use this to walk the tree in the forward direction, eg:
|
||||
/// \code
|
||||
/// for ( Fl_Tree_Item *item = tree->first(); item; item = tree->next() ) {
|
||||
/// printf("Item: %s\n", item->label());
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \returns first item in tree, or 0 if none (tree empty).
|
||||
/// \see first(),next(),last(),prev()
|
||||
///
|
||||
Fl_Tree_Item* Fl_Tree::first() {
|
||||
return(_root); // first item always root
|
||||
}
|
||||
|
||||
/// Return the next item after \p item, or 0 if no more items.
|
||||
///
|
||||
/// Use this code to walk the entire tree:
|
||||
/// \code
|
||||
/// for ( Fl_Tree_Item *item = tree->first(); item; item = tree->next(item) ) {
|
||||
/// printf("Item: %s\n", item->label());
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \param[in] item The item to use to find the next item. If NULL, returns NULL
|
||||
///
|
||||
/// \returns Next item in tree, or 0 if at last item.
|
||||
///
|
||||
/// \see first(),next(),last(),prev()
|
||||
///
|
||||
Fl_Tree_Item *Fl_Tree::next(Fl_Tree_Item *item) {
|
||||
if ( ! item ) return(0);
|
||||
return(item->next());
|
||||
}
|
||||
|
||||
/// Return the previous item before \p item, or 0 if no more items.
|
||||
///
|
||||
/// This can be used to walk the tree in reverse, eg:
|
||||
///
|
||||
/// \code
|
||||
/// for ( Fl_Tree_Item *item = tree->first(); item; item = tree->prev(item) ) {
|
||||
/// printf("Item: %s\n", item->label());
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \param[in] item The item to use to find the previous item. If NULL, returns NULL
|
||||
///
|
||||
/// \returns Previous item in tree, or 0 if at first item.
|
||||
///
|
||||
/// \see first(),next(),last(),prev()
|
||||
///
|
||||
Fl_Tree_Item *Fl_Tree::prev(Fl_Tree_Item *item) {
|
||||
if ( ! item ) return(0);
|
||||
return(item->prev());
|
||||
}
|
||||
|
||||
/// Returns the last item in the tree.
|
||||
///
|
||||
/// This can be used to walk the tree in reverse, eg:
|
||||
///
|
||||
/// \code
|
||||
/// for ( Fl_Tree_Item *item = tree->last(); item; item = tree->prev() ) {
|
||||
/// printf("Item: %s\n", item->label());
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \returns last item in the tree, or 0 if none (tree empty).
|
||||
///
|
||||
/// \see first(),next(),last(),prev()
|
||||
///
|
||||
Fl_Tree_Item* Fl_Tree::last() {
|
||||
if ( ! _root ) return(0);
|
||||
Fl_Tree_Item *item = _root;
|
||||
while ( item->has_children() ) {
|
||||
item = item->child(item->children()-1);
|
||||
}
|
||||
return(item);
|
||||
}
|
||||
|
||||
/// Returns the first selected item in the tree.
|
||||
///
|
||||
/// Use this to walk the tree looking for all the selected items, eg:
|
||||
///
|
||||
/// \code
|
||||
/// for ( Fl_Tree_Item *item = tree->first_selected_item(); item; item = tree->next_selected_item(item) ) {
|
||||
/// printf("Item: %s\n", item->label());
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \returns The next selected item, or 0 if there are no more selected items.
|
||||
///
|
||||
Fl_Tree_Item *Fl_Tree::first_selected_item() {
|
||||
return(next_selected_item(0));
|
||||
}
|
||||
|
||||
/// Returns the next selected item after \p item.
|
||||
/// If \p item is 0, search starts at the first item (root).
|
||||
///
|
||||
/// Use this to walk the tree looking for all the selected items, eg:
|
||||
/// \code
|
||||
/// for ( Fl_Tree_Item *item = tree->first_selected_item(); item; item = tree->next_selected_item(item) ) {
|
||||
/// printf("Item: %s\n", item->label());
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \param[in] item The item to use to find the next selected item. If NULL, first() is used.
|
||||
///
|
||||
/// \returns The next selected item, or 0 if there are no more selected items.
|
||||
///
|
||||
Fl_Tree_Item *Fl_Tree::next_selected_item(Fl_Tree_Item *item) {
|
||||
if ( ! item ) {
|
||||
if ( ! (item = first()) ) return(0);
|
||||
if ( item->is_selected() ) return(item);
|
||||
}
|
||||
while ( (item = item->next()) )
|
||||
if ( item->is_selected() )
|
||||
return(item);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/// Standard FLTK event handler for this widget.
|
||||
int Fl_Tree::handle(int e) {
|
||||
int ret = 0;
|
||||
// Developer note: Fl_Browser_::handle() used for reference here..
|
||||
// #include <FL/names.h> // for event debugging
|
||||
// fprintf(stderr, "DEBUG: %s (%d)\n", fl_eventnames[e], e);
|
||||
if (e == FL_ENTER || e == FL_LEAVE) return(1);
|
||||
switch (e) {
|
||||
case FL_FOCUS: {
|
||||
// FLTK tests if we want focus.
|
||||
// If a nav key was used to give us focus, and we've got no saved
|
||||
// focus widget, determine which item gets focus depending on nav key.
|
||||
//
|
||||
if ( ! _item_focus ) { // no focus established yet?
|
||||
switch (Fl::event_key()) { // determine if focus was navigated..
|
||||
case FL_Tab: { // received focus via TAB?
|
||||
if ( Fl::event_state(FL_SHIFT) ) { // SHIFT-TAB similar to FL_Up
|
||||
set_item_focus(next_visible_item(0, FL_Up));
|
||||
} else { // TAB similar to FL_Down
|
||||
set_item_focus(next_visible_item(0, FL_Down));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FL_Left: // received focus via LEFT or UP?
|
||||
case FL_Up:
|
||||
case 0xfe20: { // XK_ISO_Left_Tab
|
||||
set_item_focus(next_visible_item(0, FL_Up));
|
||||
break;
|
||||
}
|
||||
case FL_Right: // received focus via RIGHT or DOWN?
|
||||
case FL_Down:
|
||||
default: {
|
||||
set_item_focus(next_visible_item(0, FL_Down));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( visible_focus() ) redraw(); // draw focus change
|
||||
return(1);
|
||||
}
|
||||
case FL_UNFOCUS: { // FLTK telling us some other widget took focus.
|
||||
if ( visible_focus() ) redraw(); // draw focus change
|
||||
return(1);
|
||||
}
|
||||
case FL_KEYBOARD: { // keyboard shortcut
|
||||
// Do shortcuts first or scrollbar will get them...
|
||||
if (_prefs.selectmode() > FL_TREE_SELECT_NONE ) {
|
||||
if ( !_item_focus ) {
|
||||
set_item_focus(first());
|
||||
}
|
||||
if ( _item_focus ) {
|
||||
int ekey = Fl::event_key();
|
||||
switch (ekey) {
|
||||
case FL_Enter: // ENTER: selects current item only
|
||||
case FL_KP_Enter:
|
||||
if ( when() & ~FL_WHEN_ENTER_KEY) {
|
||||
select_only(_item_focus);
|
||||
return(1);
|
||||
}
|
||||
break;
|
||||
case ' ': // toggle selection state
|
||||
switch ( _prefs.selectmode() ) {
|
||||
case FL_TREE_SELECT_NONE:
|
||||
break;
|
||||
case FL_TREE_SELECT_SINGLE:
|
||||
if ( ! _item_focus->is_selected() ) // not selected?
|
||||
select_only(_item_focus); // select only this
|
||||
else
|
||||
deselect_all(); // select nothing
|
||||
break;
|
||||
case FL_TREE_SELECT_MULTI:
|
||||
select_toggle(_item_focus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FL_Right: // open children (if any)
|
||||
case FL_Left: { // close children (if any)
|
||||
if ( _item_focus ) {
|
||||
if ( ekey == FL_Right && _item_focus->is_close() ) {
|
||||
// Open closed item
|
||||
open(_item_focus);
|
||||
redraw();
|
||||
ret = 1;
|
||||
} else if ( ekey == FL_Left && _item_focus->is_open() ) {
|
||||
// Close open item
|
||||
close(_item_focus);
|
||||
redraw();
|
||||
ret = 1;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FL_Up: // next item up
|
||||
case FL_Down: { // next item down
|
||||
set_item_focus(next_visible_item(_item_focus, ekey)); // next item up|dn
|
||||
if ( _item_focus ) { // item in focus?
|
||||
// Autoscroll
|
||||
int itemtop = _item_focus->y();
|
||||
int itembot = _item_focus->y()+_item_focus->h();
|
||||
if ( itemtop < y() ) { show_item_top(_item_focus); }
|
||||
if ( itembot > y()+h() ) { show_item_bottom(_item_focus); }
|
||||
// Extend selection
|
||||
if ( _prefs.selectmode() == FL_TREE_SELECT_MULTI && // multiselect on?
|
||||
(Fl::event_state() & FL_SHIFT) && // shift key?
|
||||
! _item_focus->is_selected() ) { // not already selected?
|
||||
select(_item_focus); // extend selection..
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Let Fl_Group take a shot at handling the event
|
||||
if (Fl_Group::handle(e)) {
|
||||
return(1); // handled? don't continue below
|
||||
}
|
||||
|
||||
// Handle events the child FLTK widgets didn't need
|
||||
|
||||
static Fl_Tree_Item *lastselect = 0;
|
||||
int changed = 0;
|
||||
int ret = Fl_Group::handle(e);
|
||||
// fprintf(stderr, "ERCODEBUG: Fl_Tree::handle(): Event was %s (%d)\n", fl_eventnames[e], e); // DEBUGGING
|
||||
if ( ! _root ) return(ret);
|
||||
switch ( e ) {
|
||||
case FL_PUSH: {
|
||||
case FL_PUSH: { // clicked on a tree item?
|
||||
if (Fl::visible_focus() && handle(FL_FOCUS)) {
|
||||
Fl::focus(this);
|
||||
}
|
||||
lastselect = 0;
|
||||
item_clicked(0); // assume no item was clicked
|
||||
Fl_Tree_Item *o = _root->find_clicked(_prefs);
|
||||
if ( o ) {
|
||||
if ( ! o ) break;
|
||||
set_item_focus(o); // becomes new focus widget
|
||||
redraw();
|
||||
ret |= 1; // handled
|
||||
if ( Fl::event_button() == FL_LEFT_MOUSE ) {
|
||||
// Was collapse icon clicked?
|
||||
if ( o->event_on_collapse_icon(_prefs) ) {
|
||||
o->open_toggle();
|
||||
redraw();
|
||||
}
|
||||
// Item's label clicked?
|
||||
else if ( o->event_on_label(_prefs) &&
|
||||
(!o->widget() || !Fl::event_inside(o->widget())) &&
|
||||
callback() &&
|
||||
(!_vscroll->visible() || !Fl::event_inside(_vscroll)) ) {
|
||||
item_clicked(o); // save item clicked
|
||||
|
||||
// Handle selection behavior
|
||||
if ( o->event_on_collapse_icon(_prefs) ) { // collapse icon clicked?
|
||||
open_toggle(o);
|
||||
} else if ( o->event_on_label(_prefs) && // label clicked?
|
||||
(!o->widget() || !Fl::event_inside(o->widget())) && // not inside widget
|
||||
(!_vscroll->visible() || !Fl::event_inside(_vscroll)) ) { // not on scroller
|
||||
switch ( _prefs.selectmode() ) {
|
||||
case FL_TREE_SELECT_NONE: { // no selection changes
|
||||
case FL_TREE_SELECT_NONE:
|
||||
break;
|
||||
}
|
||||
case FL_TREE_SELECT_SINGLE: {
|
||||
changed = select_only(o);
|
||||
case FL_TREE_SELECT_SINGLE:
|
||||
select_only(o);
|
||||
break;
|
||||
}
|
||||
case FL_TREE_SELECT_MULTI: {
|
||||
int state = Fl::event_state();
|
||||
if ( state & FL_SHIFT ) {
|
||||
if ( ! o->is_selected() ) {
|
||||
o->select(); // add to selection
|
||||
changed = 1; // changed
|
||||
}
|
||||
} else if ( state & FL_CTRL ) {
|
||||
changed = 1; // changed
|
||||
o->select_toggle(); // toggle selection state
|
||||
lastselect = o; // save we toggled it (prevents oscillation)
|
||||
if ( Fl::event_state() & FL_SHIFT ) { // SHIFT+PUSH?
|
||||
select(o); // add to selection
|
||||
} else if ( Fl::event_state() & FL_CTRL ) { // CTRL+PUSH?
|
||||
select_toggle(o); // toggle selection state
|
||||
lastselect = o; // save toggled item (prevent oscillation)
|
||||
} else {
|
||||
changed = select_only(o);
|
||||
select_only(o);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( changed ) {
|
||||
redraw(); // make change(s) visible
|
||||
if ( when() & FL_WHEN_CHANGED ) {
|
||||
set_changed();
|
||||
do_callback((Fl_Widget*)this, user_data()); // item callback
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FL_DRAG: {
|
||||
// do the scrolling first:
|
||||
int my = Fl::event_y();
|
||||
if ( my < y() ) { // above top?
|
||||
int p = vposition()-(y()-my);
|
||||
if ( p < 0 ) p = 0;
|
||||
vposition(p);
|
||||
} else if ( my > (y()+h()) ) { // below bottom?
|
||||
int p = vposition()+(my-y()-h());
|
||||
if ( p > (int)_vscroll->maximum() ) p = (int)_vscroll->maximum();
|
||||
vposition(p);
|
||||
}
|
||||
if ( Fl::event_button() != FL_LEFT_MOUSE ) break;
|
||||
Fl_Tree_Item *o = _root->find_clicked(_prefs);
|
||||
if ( o ) {
|
||||
ret |= 1; // handled
|
||||
if ( ! o ) break;
|
||||
set_item_focus(o); // becomes new focus widget
|
||||
redraw();
|
||||
ret |= 1;
|
||||
// Item's label clicked?
|
||||
if ( o->event_on_label(_prefs) &&
|
||||
(!o->widget() || !Fl::event_inside(o->widget())) &&
|
||||
callback() &&
|
||||
(!_vscroll->visible() || !Fl::event_inside(_vscroll)) ) {
|
||||
item_clicked(o); // save item clicked
|
||||
// Handle selection behavior
|
||||
switch ( _prefs.selectmode() ) {
|
||||
case FL_TREE_SELECT_NONE: { // no selection changes
|
||||
case FL_TREE_SELECT_NONE: break; // no selection changes
|
||||
case FL_TREE_SELECT_SINGLE:
|
||||
select_only(o);
|
||||
break;
|
||||
}
|
||||
case FL_TREE_SELECT_SINGLE: {
|
||||
changed = select_only(o);
|
||||
break;
|
||||
}
|
||||
case FL_TREE_SELECT_MULTI: {
|
||||
int state = Fl::event_state();
|
||||
if ( state & FL_CTRL ) {
|
||||
if ( lastselect != o ) {// not already toggled from last microdrag?
|
||||
changed = 1; // changed
|
||||
o->select_toggle(); // toggle selection
|
||||
case FL_TREE_SELECT_MULTI:
|
||||
if ( Fl::event_state() & FL_CTRL && // CTRL-DRAG: toggle?
|
||||
lastselect != o ) { // not already toggled from last microdrag?
|
||||
select_toggle(o); // toggle selection
|
||||
lastselect = o; // save we toggled it (prevents oscillation)
|
||||
}
|
||||
} else {
|
||||
if ( ! o->is_selected() ) {
|
||||
changed = 1; // changed
|
||||
o->select(); // select this
|
||||
}
|
||||
select(o); // select this
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( changed ) {
|
||||
redraw(); // make change(s) visible
|
||||
if ( when() & FL_WHEN_CHANGED ) {
|
||||
set_changed();
|
||||
do_callback((Fl_Widget*)this, user_data()); // item callback
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FL_RELEASE: {
|
||||
if ( Fl::event_button() == FL_LEFT_MOUSE ) {
|
||||
ret |= 1;
|
||||
if ( when() & FL_WHEN_RELEASE || ( this->changed() && (when() & FL_WHEN_CHANGED)) ) {
|
||||
do_callback((Fl_Widget*)this, user_data()); // item callback
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/// Deselect item and all its children.
|
||||
/// If item is NULL, root() is used.
|
||||
/// Deselect \p item and all its children.
|
||||
/// If item is NULL, first() is used.
|
||||
/// Handles calling redraw() if anything was changed.
|
||||
/// Returns count of how many items were in the 'selected' state,
|
||||
/// ie. how many items were "changed".
|
||||
/// Invokes the callback depending on the value of optional parameter \p docallback.
|
||||
///
|
||||
/// \p docallback is an optional paramemter that can either be 0 or 1:
|
||||
/// The callback can use callback_item() and callback_reason() respectively to determine
|
||||
/// the item changed and the reason the callback was called.
|
||||
///
|
||||
/// - 0 - the callback() is not invoked (default)
|
||||
/// - 1 - the callback() is invoked once if \b any items changed state,
|
||||
/// and item_clicked() will be NULL (since many items could have been changed).
|
||||
//
|
||||
/// \todo deselect_all()'s docallback should support '2' (invoke callback for each item changed)
|
||||
/// \param[in] item The item that will be deselected (along with all its children)
|
||||
/// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
|
||||
/// - 0 - the callback() is not invoked
|
||||
/// - 1 - the callback() is invoked for each item that changed state,
|
||||
/// callback_reason() will be FL_TREE_REASON_DESELECTED
|
||||
///
|
||||
/// \returns count of how many items were actually changed to the deselected state.
|
||||
///
|
||||
int Fl_Tree::deselect_all(Fl_Tree_Item *item, int docallback) {
|
||||
item = item ? item : root(); // NULL? use root()
|
||||
int count = item->deselect_all();
|
||||
if ( count ) {
|
||||
redraw(); // anything changed? cause redraw
|
||||
if ( docallback == 1 )
|
||||
do_callback_for_item(0);
|
||||
item = item ? item : first(); // NULL? use first()
|
||||
if ( ! item ) return(0);
|
||||
int count = 0;
|
||||
for ( ; item; item = next(item) ) {
|
||||
if ( item->is_selected() )
|
||||
if ( deselect(item, docallback) )
|
||||
++count;
|
||||
}
|
||||
return(count);
|
||||
}
|
||||
|
||||
/// Select item and all its children.
|
||||
/// If item is NULL, root() is used.
|
||||
/// Select \p item and all its children.
|
||||
/// If item is NULL, first() is used.
|
||||
/// Handles calling redraw() if anything was changed.
|
||||
/// Returns count of how many items were in the 'deselected' state,
|
||||
/// ie. how many items were "changed".
|
||||
/// Invokes the callback depending on the value of optional parameter \p docallback.
|
||||
///
|
||||
/// \p docallback is an optional paramemter that can either be 0 or 1:
|
||||
/// The callback can use callback_item() and callback_reason() respectively to determine
|
||||
/// the item changed and the reason the callback was called.
|
||||
///
|
||||
/// - 0 - the callback() is not invoked (default)
|
||||
/// - 1 - the callback() is invoked once if \b any items changed state,
|
||||
/// and item_clicked() will be NULL (since many items could have been changed).
|
||||
/// \param[in] item The item that will be selected (along with all its children).
|
||||
/// If NULL, first() is assumed.
|
||||
/// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
|
||||
/// - 0 - the callback() is not invoked
|
||||
/// - 1 - the callback() is invoked for each item that changed state,
|
||||
/// callback_reason() will be FL_TREE_REASON_SELECTED
|
||||
///
|
||||
/// \todo select_all()'s docallback should support '2' (invoke callback for each item changed)
|
||||
/// \returns count of how many items were actually changed to the selected state.
|
||||
///
|
||||
int Fl_Tree::select_all(Fl_Tree_Item *item, int docallback) {
|
||||
item = item ? item : root(); // NULL? use root()
|
||||
int count = item->select_all();
|
||||
if ( count ) {
|
||||
redraw(); // anything changed? cause redraw
|
||||
if (docallback == 1)
|
||||
do_callback_for_item(0);
|
||||
item = item ? item : first(); // NULL? use first()
|
||||
if ( ! item ) return(0);
|
||||
int count = 0;
|
||||
for ( ; item; item = next(item) ) {
|
||||
if ( !item->is_selected() )
|
||||
if ( select(item, docallback) )
|
||||
++count;
|
||||
}
|
||||
return(count);
|
||||
}
|
||||
|
||||
/// Select only this item.
|
||||
/// If item is NULL, root() is used.
|
||||
/// Select only the specified \p item, deselecting all others that might be selected.
|
||||
/// If item is 0, first() is used.
|
||||
/// Handles calling redraw() if anything was changed.
|
||||
/// Returns how many items were changed, if any.
|
||||
/// Invokes the callback depending on the value of optional parameter \p docallback.
|
||||
///
|
||||
/// \p docallback is an optional paramemter that can either be 0, 1 or 2:
|
||||
/// The callback can use callback_item() and callback_reason() respectively to determine
|
||||
/// the item changed and the reason the callback was called.
|
||||
///
|
||||
/// - 0 - the callback() is not invoked (default)
|
||||
/// - 1 - the callback() is invoked once if \b any items changed state,
|
||||
/// and item_clicked() will be NULL (since many items could have been changed).
|
||||
/// - 2 - the callback() is invoked once for \b each item that changed state,
|
||||
/// and the callback() can use item_clicked() to determine the item changed.
|
||||
/// \param[in] selitem The item to be selected. If NULL, first() is used.
|
||||
/// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
|
||||
/// - 0 - the callback() is not invoked
|
||||
/// - 1 - the callback() is invoked for each item that changed state,
|
||||
/// callback_reason() will be either FL_TREE_REASON_SELECTED or
|
||||
/// FL_TREE_REASON_DESELECTED
|
||||
///
|
||||
/// \returns the number of items whose selection states were changed, if any.
|
||||
///
|
||||
int Fl_Tree::select_only(Fl_Tree_Item *selitem, int docallback) {
|
||||
selitem = selitem ? selitem : root(); // NULL? use root()
|
||||
selitem = selitem ? selitem : first(); // NULL? use first()
|
||||
if ( ! selitem ) return(0);
|
||||
int changed = 0;
|
||||
for ( Fl_Tree_Item *item = first(); item; item = item->next() ) {
|
||||
if ( item == selitem ) {
|
||||
if ( item->is_selected() ) continue; // don't count if already selected
|
||||
item->select();
|
||||
select(item, docallback);
|
||||
++changed;
|
||||
if ( docallback == 2 ) do_callback_for_item(item);
|
||||
} else {
|
||||
if ( item->is_selected() ) {
|
||||
item->deselect();
|
||||
deselect(item, docallback);
|
||||
++changed;
|
||||
if ( docallback == 2 ) do_callback_for_item(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( changed ) {
|
||||
redraw(); // anything changed? redraw
|
||||
if ( docallback == 1 ) do_callback_for_item(0);
|
||||
}
|
||||
return(changed);
|
||||
}
|
||||
|
||||
/// Adjust the vertical scroll bar so that \p item is visible
|
||||
/// \p yoff pixels from the top of the Fl_Tree widget's display.
|
||||
///
|
||||
/// For instance, yoff=0 will position the item at the top.
|
||||
///
|
||||
/// If yoff is larger than the vertical scrollbar's limit,
|
||||
/// the value will be clipped. So if yoff=100, but scrollbar's max
|
||||
/// is 50, then 50 will be used.
|
||||
///
|
||||
/// \see show_item_top(), show_item_middle(), show_item_bottom()
|
||||
///
|
||||
void Fl_Tree::show_item(Fl_Tree_Item *item, int yoff) {
|
||||
if ( ! item ) return;
|
||||
int newval = item->y() - y() - yoff + (int)_vscroll->value();
|
||||
if ( newval < _vscroll->minimum() ) newval = (int)_vscroll->minimum();
|
||||
if ( newval > _vscroll->maximum() ) newval = (int)_vscroll->maximum();
|
||||
_vscroll->value(newval);
|
||||
redraw();
|
||||
}
|
||||
|
||||
/// Adjust the vertical scrollbar so that \p item is at the top of the display.
|
||||
void Fl_Tree::show_item_top(Fl_Tree_Item *item) {
|
||||
item = item ? item : first();
|
||||
if ( ! item ) return;
|
||||
show_item(item, 0);
|
||||
}
|
||||
|
||||
/// Adjust the vertical scrollbar so that \p item is in the middle of the display.
|
||||
void Fl_Tree::show_item_middle(Fl_Tree_Item *item) {
|
||||
item = item ? item : first();
|
||||
if ( ! item ) return;
|
||||
show_item(item, h()/2 - item->h()/2);
|
||||
}
|
||||
|
||||
/// Adjust the vertical scrollbar so that \p item is at the bottom of the display.
|
||||
void Fl_Tree::show_item_bottom(Fl_Tree_Item *item) {
|
||||
item = item ? item : first();
|
||||
if ( ! item ) return;
|
||||
show_item(item, h() - item->h());
|
||||
}
|
||||
|
||||
/// Returns the vertical scroll position as a pixel offset.
|
||||
/// The position returned is how many pixels of the tree are scrolled off the top edge
|
||||
/// of the screen. Example: A position of '3' indicates the top 3 pixels of
|
||||
/// the tree are scrolled off the top edge of the screen.
|
||||
/// \see vposition(), hposition()
|
||||
///
|
||||
int Fl_Tree::vposition() const {
|
||||
return((int)_vscroll->value());
|
||||
}
|
||||
|
||||
/// Sets the vertical scroll offset to position \p pos.
|
||||
/// The position is how many pixels of the tree are scrolled off the top edge
|
||||
/// of the screen. Example: A position of '3' scrolls the top three pixels of
|
||||
/// the tree off the top edge of the screen.
|
||||
/// \param[in] pos The vertical position (in pixels) to scroll the browser to.
|
||||
///
|
||||
void Fl_Tree::vposition(int pos) {
|
||||
if (pos < 0) pos = 0;
|
||||
if (pos > _vscroll->maximum()) pos = (int)_vscroll->maximum();
|
||||
if (pos == _vscroll->value()) return;
|
||||
_vscroll->value(pos);
|
||||
redraw();
|
||||
}
|
||||
|
||||
/// Displays \p item, scrolling the tree as necessary.
|
||||
/// \param[in] item The item to be displayed.
|
||||
///
|
||||
void Fl_Tree::display(Fl_Tree_Item *item) {
|
||||
if ( ! item ) return;
|
||||
show_item_middle(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a preferences database into the tree widget.
|
||||
* A preferences database is a hierarchical collection of data which can be
|
||||
|
@ -165,12 +165,12 @@ int Fl_Tree_Item::find_child(const char *name) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/// Find item by descending array of names.
|
||||
/// Find child item by descending array of names. Does not include self in search.
|
||||
/// Only Fl_Tree should need this method.
|
||||
///
|
||||
/// \returns item, or 0 if not found
|
||||
///
|
||||
const Fl_Tree_Item *Fl_Tree_Item::find_item(char **arr) const {
|
||||
const Fl_Tree_Item *Fl_Tree_Item::find_child_item(char **arr) const {
|
||||
for ( int t=0; t<children(); t++ ) {
|
||||
if ( child(t)->label() ) {
|
||||
if ( strcmp(child(t)->label(), *arr) == 0 ) { // match?
|
||||
@ -185,12 +185,12 @@ const Fl_Tree_Item *Fl_Tree_Item::find_item(char **arr) const {
|
||||
return(0);
|
||||
}
|
||||
|
||||
/// Find item by by descending array of names.
|
||||
/// Only Fl_Tree should need this method.
|
||||
/// Find child item by descending array of names. Does not include self in search.
|
||||
/// Only Fl_Tree should need this method. Use Fl_Tree::find_item() instead.
|
||||
///
|
||||
/// \returns item, or 0 if not found
|
||||
///
|
||||
Fl_Tree_Item *Fl_Tree_Item::find_item(char **arr) {
|
||||
Fl_Tree_Item *Fl_Tree_Item::find_child_item(char **arr) {
|
||||
for ( int t=0; t<children(); t++ ) {
|
||||
if ( child(t)->label() ) {
|
||||
if ( strcmp(child(t)->label(), *arr) == 0 ) { // match?
|
||||
@ -205,6 +205,40 @@ Fl_Tree_Item *Fl_Tree_Item::find_item(char **arr) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
/// Find item by descending array of \p names. Includes self in search.
|
||||
/// Only Fl_Tree should need this method. Use Fl_Tree::find_item() instead.
|
||||
///
|
||||
/// \returns item, or 0 if not found
|
||||
///
|
||||
const Fl_Tree_Item *Fl_Tree_Item::find_item(char **names) const {
|
||||
if ( label() && strcmp(label(), *names) == 0 ) { // match self?
|
||||
if ( *(names+1) == 0 ) { // end of names,
|
||||
return(this); // found ourself.
|
||||
}
|
||||
}
|
||||
if ( children() ) { // check children..
|
||||
return(find_child_item(names));
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/// Find item by descending array of \p names. Includes self in search.
|
||||
/// Only Fl_Tree should need this method.
|
||||
///
|
||||
/// \returns item, or 0 if not found
|
||||
///
|
||||
Fl_Tree_Item *Fl_Tree_Item::find_item(char **names) {
|
||||
if ( label() && strcmp(label(), *names) == 0 ) { // match self?
|
||||
if ( *(names+1) == 0 ) { // end of names,
|
||||
return(this); // found ourself.
|
||||
}
|
||||
}
|
||||
if ( children() ) { // check children..
|
||||
return(find_child_item(names));
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/// Find the index number for the specified 'item'
|
||||
/// in the current item's list of children.
|
||||
///
|
||||
@ -473,8 +507,49 @@ Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void draw_item_focus(Fl_Boxtype B, Fl_Color C, int X, int Y, int W, int H) {
|
||||
if (!Fl::visible_focus()) return;
|
||||
switch (B) {
|
||||
case FL_DOWN_BOX:
|
||||
case FL_DOWN_FRAME:
|
||||
case FL_THIN_DOWN_BOX:
|
||||
case FL_THIN_DOWN_FRAME:
|
||||
X ++;
|
||||
Y ++;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fl_color(fl_contrast(FL_BLACK, C));
|
||||
|
||||
#if defined(USE_X11) || defined(__APPLE_QUARTZ__)
|
||||
fl_line_style(FL_DOT);
|
||||
fl_rect(X + Fl::box_dx(B), Y + Fl::box_dy(B),
|
||||
W - Fl::box_dw(B) - 1, H - Fl::box_dh(B) - 1);
|
||||
fl_line_style(FL_SOLID);
|
||||
#else
|
||||
// Some platforms don't implement dotted line style, so draw
|
||||
// every other pixel around the focus area...
|
||||
//
|
||||
// Also, QuickDraw (MacOS) does not support line styles specifically,
|
||||
// and the hack we use in fl_line_style() will not draw horizontal lines
|
||||
// on odd-numbered rows...
|
||||
int i, xx, yy;
|
||||
|
||||
X += Fl::box_dx(B);
|
||||
Y += Fl::box_dy(B);
|
||||
W -= Fl::box_dw(B) + 2;
|
||||
H -= Fl::box_dh(B) + 2;
|
||||
|
||||
for (xx = 0, i = 1; xx < W; xx ++, i ++) if (i & 1) fl_point(X + xx, Y);
|
||||
for (yy = 0; yy < H; yy ++, i ++) if (i & 1) fl_point(X + W, Y + yy);
|
||||
for (xx = W; xx > 0; xx --, i ++) if (i & 1) fl_point(X + xx, Y + H);
|
||||
for (yy = H; yy > 0; yy --, i ++) if (i & 1) fl_point(X, Y + yy);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Draw this item and its children.
|
||||
void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Widget *tree,
|
||||
Fl_Tree_Item *itemfocus,
|
||||
const Fl_Tree_Prefs &prefs, int lastchild) {
|
||||
if ( ! _visible ) return;
|
||||
fl_font(_labelfont, _labelsize);
|
||||
@ -598,6 +673,10 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Widget *tree,
|
||||
fl_draw(_label, X+useroff, Y+H-fl_descent()-1);
|
||||
}
|
||||
}
|
||||
if ( this == itemfocus && Fl::visible_focus() && Fl::focus() == tree) {
|
||||
// Draw focus box around this item
|
||||
draw_item_focus(FL_NO_BOX,bg,bx+1,by+1,bw-1,bh-1);
|
||||
}
|
||||
Y += H;
|
||||
} // end drawthis
|
||||
// Draw children
|
||||
@ -608,7 +687,7 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Widget *tree,
|
||||
int child_y_start = Y;
|
||||
for ( int t=0; t<children(); t++ ) {
|
||||
int lastchild = ((t+1)==children()) ? 1 : 0;
|
||||
_children[t]->draw(child_x, Y, child_w, tree, prefs, lastchild);
|
||||
_children[t]->draw(child_x, Y, child_w, tree, itemfocus, prefs, lastchild);
|
||||
}
|
||||
if ( has_children() && is_open() ) {
|
||||
Y += prefs.openchild_marginbottom(); // offset below open child tree
|
||||
@ -736,6 +815,115 @@ Fl_Tree_Item *Fl_Tree_Item::prev() {
|
||||
return(p);
|
||||
}
|
||||
|
||||
/// Return this item's next sibling.
|
||||
///
|
||||
/// Moves to the next item below us at the same level (sibling).
|
||||
/// Use this to move down the tree without moving deeper into the tree,
|
||||
/// effectively skipping over this item's children/descendents.
|
||||
///
|
||||
/// \returns item's next sibling, or 0 if none.
|
||||
///
|
||||
Fl_Tree_Item *Fl_Tree_Item::next_sibling() {
|
||||
if ( !parent() ) return(0); // No parent (root)? We have no siblings
|
||||
int index = parent()->find_child(this); // find our position in parent's child() array
|
||||
if ( index == -1 ) return(0); // parent doesn't know us? weird
|
||||
if ( (index+1) < parent()->children() ) // is there a next child?
|
||||
return(parent()->child(index+1)); // return next child if there's one below us
|
||||
return(0); // no siblings below us
|
||||
}
|
||||
|
||||
/// Return this item's previous sibling.
|
||||
///
|
||||
/// Moves to the previous item above us at the same level (sibling).
|
||||
/// Use this to move up the tree without moving deeper into the tree.
|
||||
///
|
||||
/// \returns This item's previous sibling, or 0 if none.
|
||||
///
|
||||
Fl_Tree_Item *Fl_Tree_Item::prev_sibling() {
|
||||
if ( !parent() ) return(0); // No parent (root)? We have no siblings
|
||||
int index = parent()->find_child(this); // find next position up in parent's child() array
|
||||
if ( index == -1 ) return(0); // parent doesn't know us? weird
|
||||
if ( index > 0 ) return(parent()->child(index-1)); // return previous child if there's one above us
|
||||
return(0); // no siblings above us
|
||||
}
|
||||
|
||||
/// Return the next visible item. (If this item has children and is closed, children are skipped)
|
||||
///
|
||||
/// This method can be used to walk the tree forward, skipping items
|
||||
/// that are not currently visible to the user.
|
||||
///
|
||||
/// \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
|
||||
}
|
||||
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)
|
||||
///
|
||||
/// This method can be used to walk the tree backward,
|
||||
/// skipping items that are not currently visible to the user.
|
||||
///
|
||||
/// \returns the previous visible item above us, or 0 if there's no more items.
|
||||
///
|
||||
Fl_Tree_Item *Fl_Tree_Item::prev_displayed(Fl_Tree_Prefs &prefs) {
|
||||
Fl_Tree_Item *c = this;
|
||||
while ( c ) {
|
||||
c = c->prev(); // previous item
|
||||
if ( !c ) break; // no more items? done
|
||||
if ( c->is_root() ) // root
|
||||
return((prefs.showroot()&&c->visible()) ? c : 0); // return root if visible
|
||||
if ( !c->visible() ) continue; // item not visible? skip
|
||||
// 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
|
||||
}
|
||||
}
|
||||
return(0); // hit end: no more items
|
||||
}
|
||||
|
||||
/// Returns if item and all its parents are visible.
|
||||
/// Also takes into consideration if any parent is close()ed.
|
||||
/// \returns
|
||||
/// 1 -- item and its parents are visible/open()
|
||||
/// 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 (!p->visible() || p->is_close()) return(0); // any parent not visible or closed?
|
||||
return(1);
|
||||
}
|
||||
|
||||
//
|
||||
// End of "$Id$".
|
||||
//
|
||||
|
351
test/tree.fl
351
test/tree.fl
@ -20,19 +20,37 @@ decl {\#include <FL/Fl_Tree.H>} {public global
|
||||
decl {\#include <FL/fl_ask.H>} {public global
|
||||
}
|
||||
|
||||
decl {\#include <FL/Fl_File_Chooser.H>} {selected public global
|
||||
decl {\#include <FL/fl_message.H>} {public global
|
||||
}
|
||||
|
||||
decl {\#include <FL/Fl_File_Chooser.H>} {public global
|
||||
}
|
||||
|
||||
decl {\#include <FL/Fl_Preferences.H>} {public global
|
||||
}
|
||||
|
||||
decl {int G_cb_counter = 0;} {
|
||||
comment {// Global callback event counter} private local
|
||||
}
|
||||
|
||||
Function {reason_as_name(Fl_Tree_Reason reason)} {open return_type {const char*}
|
||||
} {
|
||||
code {switch ( reason ) {
|
||||
case FL_TREE_REASON_NONE: return("none");
|
||||
case FL_TREE_REASON_SELECTED: return("selected");
|
||||
case FL_TREE_REASON_DESELECTED: return("deselected");
|
||||
case FL_TREE_REASON_OPENED: return("opened");
|
||||
case FL_TREE_REASON_CLOSED: return("closed");
|
||||
default: return("???");
|
||||
}} {}
|
||||
}
|
||||
|
||||
Function {Button_CB(Fl_Widget*w, void*data)} {return_type void
|
||||
} {
|
||||
code {fprintf(stderr, "'%s' button pushed\\n", w->label());} {}
|
||||
}
|
||||
|
||||
Function {RebuildTree()} {open
|
||||
} {
|
||||
Function {RebuildTree()} {} {
|
||||
code {// REBUILD THE TREE TO MAKE CURRENT "DEFAULT" PREFS TAKE EFFECT
|
||||
tree->clear();
|
||||
tree->add("Aaa");
|
||||
@ -108,6 +126,15 @@ tree->add("Descending/Bbb");
|
||||
tree->add("Descending/Yyy");
|
||||
tree->add("Descending/Ccc");
|
||||
|
||||
// Add 500 items in numerical order
|
||||
tree->sortorder(FL_TREE_SORT_NONE);
|
||||
for ( int t=0; t<500; t++ ) {
|
||||
static char s[80];
|
||||
sprintf(s, "500 Items/item %04d", t);
|
||||
tree->add(s);
|
||||
}
|
||||
tree->close("500 Items"); // close the 500 items by default
|
||||
|
||||
tree->redraw();} {}
|
||||
}
|
||||
|
||||
@ -119,13 +146,17 @@ Function {} {open
|
||||
} {
|
||||
Fl_Group tree {
|
||||
user_data 1234
|
||||
callback {Fl_Tree_Item *item = tree->item_clicked();
|
||||
callback {G_cb_counter++; // Increment callback counter whenever tree callback is invoked
|
||||
|
||||
Fl_Tree_Item *item = tree->callback_item();
|
||||
if ( item ) {
|
||||
fprintf(stderr, "TREE CALLBACK: label='%s' userdata=%ld\\n",
|
||||
fprintf(stderr, "TREE CALLBACK: label='%s' userdata=%ld reason=%s\\n",
|
||||
item->label(),
|
||||
(long)tree->user_data());
|
||||
(long)tree->user_data(),
|
||||
reason_as_name(tree->callback_reason()));
|
||||
} else {
|
||||
fprintf(stderr, "TREE CALLBACK: no item (probably multiple items were changed at once)\\n");
|
||||
fprintf(stderr, "TREE CALLBACK: reason=%s item=(no item -- probably multiple items were changed at once)\\n",
|
||||
reason_as_name(tree->callback_reason()));
|
||||
}} open
|
||||
xywh {15 15 550 390} box DOWN_BOX color 55
|
||||
class Fl_Tree
|
||||
@ -136,7 +167,7 @@ if ( item ) {
|
||||
callback {int val = (int)margintop_slider->value();
|
||||
tree->margintop(val);
|
||||
tree->redraw();}
|
||||
tooltip {Changes the top margin for the tree widget} xywh {190 414 240 16} type Horizontal labelsize 12 align 4 textsize 12
|
||||
tooltip {Changes the top margin for the tree widget} xywh {190 414 240 16} type Horizontal labelsize 12 align 4 step 0.01 textsize 12
|
||||
code0 {o->value(tree->margintop());}
|
||||
code1 {o->range(0.0, 100.0);}
|
||||
code2 {o->step(1.0);}
|
||||
@ -148,7 +179,7 @@ tree->redraw();}
|
||||
callback {int val = (int)marginleft_slider->value();
|
||||
tree->marginleft(val);
|
||||
tree->redraw();}
|
||||
tooltip {Changes the left margin for the tree widget} xywh {190 434 240 16} type Horizontal labelsize 12 align 4 textsize 12
|
||||
tooltip {Changes the left margin for the tree widget} xywh {190 434 240 16} type Horizontal labelsize 12 align 4 step 0.01 textsize 12
|
||||
code0 {o->value(tree->marginleft());}
|
||||
code1 {o->range(0.0, 100.0);}
|
||||
code2 {o->step(1.0);}
|
||||
@ -160,7 +191,7 @@ tree->redraw();}
|
||||
callback {int val = (int)openchild_marginbottom_slider->value();
|
||||
tree->openchild_marginbottom(val);
|
||||
tree->redraw();}
|
||||
tooltip {Changes the vertical space below an open child tree} xywh {190 454 240 16} type Horizontal labelsize 12 align 4 textsize 12
|
||||
tooltip {Changes the vertical space below an open child tree} xywh {190 454 240 16} type Horizontal labelsize 12 align 4 step 0.01 textsize 12
|
||||
code0 {o->value(tree->openchild_marginbottom());}
|
||||
code1 {o->range(0.0, 100.0);}
|
||||
code2 {o->step(1.0);}
|
||||
@ -173,7 +204,7 @@ tree->redraw();}
|
||||
|
||||
// DO SELECTED ITEMS
|
||||
int count = 0;
|
||||
for ( Fl_Tree_Item *item=tree->first(); item; item = item->next() ) {
|
||||
for ( Fl_Tree_Item *item=tree->first(); item; item = tree->next(item) ) {
|
||||
if ( item->is_selected() ) {
|
||||
item->labelsize(size);
|
||||
count++;
|
||||
@ -182,14 +213,14 @@ for ( Fl_Tree_Item *item=tree->first(); item; item = item->next() ) {
|
||||
|
||||
// NO ITEMS SELECTED? DO ALL
|
||||
if ( ! count ) {
|
||||
for ( Fl_Tree_Item *item=tree->first(); item; item = item->next() ) {
|
||||
for ( Fl_Tree_Item *item=tree->first(); item; item = tree->next(item) ) {
|
||||
item->labelsize(size);
|
||||
}
|
||||
}
|
||||
|
||||
tree->redraw();}
|
||||
tooltip {Changes the font size of the selected items
|
||||
If none selected, all are changed} xywh {190 474 240 16} type Horizontal labelsize 12 align 4 textsize 12
|
||||
If none selected, all are changed} xywh {190 474 240 16} type Horizontal labelsize 12 align 4 step 0.01 textsize 12
|
||||
code0 {o->value(tree->labelsize());}
|
||||
code1 {o->range(5.0, 200.0);}
|
||||
code2 {o->step(1.0);}
|
||||
@ -199,7 +230,7 @@ If none selected, all are changed} xywh {190 474 240 16} type Horizontal labelsi
|
||||
label {Connector width}
|
||||
user_data tree
|
||||
callback {tree->connectorwidth((int)connectorwidth_slider->value());}
|
||||
tooltip {Tests Fl_Tree::connectorwidth()} xywh {190 494 240 16} type Horizontal labelsize 12 align 4 textsize 12
|
||||
tooltip {Tests Fl_Tree::connectorwidth()} xywh {190 494 240 16} type Horizontal labelsize 12 align 4 step 0.01 textsize 12
|
||||
code0 {o->value(tree->connectorwidth());}
|
||||
code1 {o->range(1.0, 100.0);}
|
||||
code2 {o->step(1.0);}
|
||||
@ -256,16 +287,25 @@ if ( usericon_radio->value() ) {
|
||||
if ( ( i = tree->find_item("Bbb/bgb/222") ) != NULL ) i->usericon(0);
|
||||
if ( ( i = tree->find_item("Bbb/bgb/333") ) != NULL ) i->usericon(0);
|
||||
}}
|
||||
tooltip {Tests Fl_Tree_Item::usericon()} xywh {145 525 130 16} down_box DOWN_BOX labelsize 11
|
||||
tooltip {Tests Fl_Tree_Item::usericon()} xywh {90 525 130 16} down_box DOWN_BOX labelsize 11
|
||||
}
|
||||
Fl_Check_Button showroot_radio {
|
||||
label {Show root?}
|
||||
user_data tree
|
||||
callback {int onoff = showroot_radio->value();
|
||||
tree->showroot(onoff);}
|
||||
tooltip {Tests Fl_Tree_Item::usericon()} xywh {145 544 130 16} down_box DOWN_BOX labelsize 11
|
||||
tooltip {Tests Fl_Tree_Item::usericon()} xywh {90 542 130 16} down_box DOWN_BOX labelsize 11
|
||||
code0 {int onoff = tree->showroot(); showroot_radio->value(onoff);}
|
||||
}
|
||||
Fl_Check_Button visiblefocus_checkbox {
|
||||
label {Visible focus?}
|
||||
user_data tree
|
||||
callback {int onoff = visiblefocus_checkbox->value();
|
||||
tree->visible_focus(onoff);}
|
||||
tooltip {Toggles the tree's visible_focus()
|
||||
This toggles the visible 'focus box'} xywh {90 559 130 16} down_box DOWN_BOX labelsize 11
|
||||
code0 {int onoff = tree->visible_focus(); visiblefocus_checkbox->value(onoff);}
|
||||
}
|
||||
Fl_Choice collapseicons_chooser {
|
||||
label {Collapse icons}
|
||||
callback {static const char *L_open_xpm[] = {
|
||||
@ -355,7 +395,7 @@ switch ( collapseicons_chooser->value() ) {
|
||||
tree->showcollapse(0);
|
||||
break;
|
||||
}} open
|
||||
tooltip {Tests Fl_Tree::openicon() and Fl_Tree::closeicon()} xywh {145 572 110 16} down_box BORDER_BOX labelsize 11 textsize 11
|
||||
tooltip {Tests Fl_Tree::openicon() and Fl_Tree::closeicon()} xywh {115 589 110 16} down_box BORDER_BOX labelsize 11 textsize 11
|
||||
} {
|
||||
MenuItem {} {
|
||||
label Normal
|
||||
@ -378,7 +418,7 @@ switch ( connectorstyle_chooser->value() ) {
|
||||
case 1: tree->connectorstyle(FL_TREE_CONNECTOR_DOTTED); break;
|
||||
case 2: tree->connectorstyle(FL_TREE_CONNECTOR_SOLID); break;
|
||||
}} open
|
||||
tooltip {Tests connectorstyle() bit flags} xywh {145 592 110 16} down_box BORDER_BOX labelsize 11 textsize 11
|
||||
tooltip {Tests connectorstyle() bit flags} xywh {115 609 110 16} down_box BORDER_BOX labelsize 11 textsize 11
|
||||
code0 {switch (tree->connectorstyle()) { case FL_TREE_CONNECTOR_NONE: connectorstyle_chooser->value(0); break; case FL_TREE_CONNECTOR_DOTTED: connectorstyle_chooser->value(1); break; case FL_TREE_CONNECTOR_SOLID: connectorstyle_chooser->value(2); break; }}
|
||||
} {
|
||||
MenuItem {} {
|
||||
@ -408,7 +448,7 @@ switch ( labelcolor_chooser->value() ) {
|
||||
|
||||
// DO SELECTED ITEMS
|
||||
int count = 0;
|
||||
for ( Fl_Tree_Item *item=tree->first(); item; item = item->next() ) {
|
||||
for ( Fl_Tree_Item *item=tree->first(); item; item = tree->next(item) ) {
|
||||
if ( item->is_selected() ) {
|
||||
item->labelcolor(c);
|
||||
count++;
|
||||
@ -417,14 +457,14 @@ for ( Fl_Tree_Item *item=tree->first(); item; item = item->next() ) {
|
||||
|
||||
// NO ITEMS SELECTED? DO ALL
|
||||
if ( ! count ) {
|
||||
for ( Fl_Tree_Item *item=tree->first(); item; item = item->next() ) {
|
||||
for ( Fl_Tree_Item *item=tree->first(); item; item = tree->next(item) ) {
|
||||
item->labelcolor(c);
|
||||
}
|
||||
}
|
||||
|
||||
tree->redraw();} open
|
||||
tooltip {Changes the label color for the selected items
|
||||
If no items selected, all are changed} xywh {145 612 110 16} down_box BORDER_BOX labelsize 11 textsize 11
|
||||
If no items selected, all are changed} xywh {115 629 110 16} down_box BORDER_BOX labelsize 11 textsize 11
|
||||
} {
|
||||
MenuItem {} {
|
||||
label Black
|
||||
@ -452,7 +492,7 @@ switch ( selectmode_chooser->value() ) {
|
||||
case 2: tree->selectmode(FL_TREE_SELECT_MULTI); break; // Multi
|
||||
default: tree->selectmode(FL_TREE_SELECT_SINGLE); break; // Single
|
||||
}}
|
||||
tooltip {Sets how Fl_Tree handles mouse selection of tree items} xywh {145 632 110 16} down_box BORDER_BOX labelsize 11 textsize 11
|
||||
tooltip {Sets how Fl_Tree handles mouse selection of tree items} xywh {115 649 110 16} down_box BORDER_BOX labelsize 11 textsize 11
|
||||
code0 {selectmode_chooser->value(1);}
|
||||
code1 {cb_selectmode_chooser(selectmode_chooser, (void*)0);}
|
||||
} {
|
||||
@ -477,8 +517,8 @@ switch ( whenmode_chooser->value() ) {
|
||||
case 1: tree->when(FL_WHEN_CHANGED); break;
|
||||
case 2: tree->when(FL_WHEN_NEVER); break;
|
||||
default: tree->when(FL_WHEN_RELEASE); break;
|
||||
}}
|
||||
tooltip {Sets when() the tree's callback is invoked} xywh {145 652 110 16} down_box BORDER_BOX labelsize 11 textsize 11
|
||||
}} open
|
||||
tooltip {Sets when() the tree's callback is invoked} xywh {115 669 110 16} down_box BORDER_BOX labelsize 11 textsize 11
|
||||
code0 {whenmode_chooser->value(1);}
|
||||
code1 {cb_whenmode_chooser(whenmode_chooser, (void*)0);}
|
||||
} {
|
||||
@ -495,68 +535,96 @@ switch ( whenmode_chooser->value() ) {
|
||||
xywh {60 60 36 21} labelsize 11
|
||||
}
|
||||
}
|
||||
Fl_Box docallback_box {
|
||||
xywh {280 521 285 81} box GTK_DOWN_BOX color 47
|
||||
Fl_Box showitem_box {
|
||||
label {show_item()
|
||||
}
|
||||
xywh {468 423 60 77} box GTK_DOWN_BOX color 47 labelsize 11 align 1
|
||||
}
|
||||
Fl_Check_Button docallback_radio {
|
||||
label {Invoke callback on select changes?} user_data_type {void*}
|
||||
tooltip {Invokes the callback when one or more item's state changes.} xywh {310 529 230 16} down_box DOWN_BOX labelsize 11
|
||||
Fl_Button {} {
|
||||
label Top
|
||||
callback {Fl_Tree_Item *item = tree->next_selected_item();
|
||||
tree->show_item_top(item);}
|
||||
tooltip {Scrolls selected item to the top of the display
|
||||
(only works if scrollbar showing)
|
||||
To use:
|
||||
1) open '500 items'
|
||||
2) select item 0010
|
||||
3) Hit Top/Mid/Bot} xywh {478 433 40 16} labelsize 11
|
||||
}
|
||||
Fl_Button {} {
|
||||
label Mid
|
||||
callback {Fl_Tree_Item *item = tree->next_selected_item();
|
||||
tree->show_item_middle(item);}
|
||||
tooltip {Scrolls the selected item to the middle of the display
|
||||
To use:
|
||||
1) open '500 items'
|
||||
2) select 'item 0010'
|
||||
3) Hit Top/Mid/Bot} xywh {478 453 40 16} labelsize 11
|
||||
}
|
||||
Fl_Button {} {
|
||||
label Bot
|
||||
callback {Fl_Tree_Item *item = tree->next_selected_item();
|
||||
tree->show_item_bottom(item);}
|
||||
tooltip {Scrolls the selected item to the bottom of the display
|
||||
To use:
|
||||
1) open '500 items'
|
||||
2) select 'item 0010'
|
||||
3) Hit Top/Mid/Bot} xywh {478 473 40 16} labelsize 11
|
||||
}
|
||||
Fl_Box docallback_box {
|
||||
label {Selection State Changes}
|
||||
xywh {245 527 320 77} box GTK_DOWN_BOX color 47 labelsize 12 align 1
|
||||
}
|
||||
Fl_Button selectall_button {
|
||||
label {Select All}
|
||||
callback {int docallbacks = docallback_radio->value() ? 1 : 0;
|
||||
tree->select_all(0,docallbacks);
|
||||
callback {tree->select_all(0);
|
||||
tree->redraw();}
|
||||
tooltip {Selects all items in the tree} xywh {305 551 105 16} labelsize 11
|
||||
tooltip {Selects all items in the tree} xywh {260 539 75 16} labelsize 9
|
||||
}
|
||||
Fl_Button deselectall_button {
|
||||
label {Deselect All}
|
||||
callback {int docallbacks = docallback_radio->value() ? 1 : 0;
|
||||
tree->deselect_all(0,docallbacks);
|
||||
callback {tree->deselect_all(0);
|
||||
tree->redraw();}
|
||||
tooltip {Deselects all items in the tree} xywh {305 571 105 16} labelsize 11
|
||||
tooltip {Deselects all items in the tree} xywh {260 559 75 16} labelsize 9
|
||||
}
|
||||
Fl_Light_Button bbbselect_toggle {
|
||||
label { Select Bbb}
|
||||
Fl_Light_Button bbbselect2_toggle {
|
||||
label { Select Bbb+}
|
||||
callback {// Toggle select of just the Bbb item and its immediate children
|
||||
int docallback = docallback_radio->value() ? 1 : 0;
|
||||
Fl_Tree_Item *bbb = tree->find_item("/Bbb");
|
||||
if ( !bbb) {
|
||||
fl_alert("FAIL: Couldn't find item '/Bbb'???");
|
||||
return;
|
||||
}
|
||||
int onoff = bbbselect_toggle->value();
|
||||
if ( onoff ) tree->select_all(bbb, docallback); // select /Bbb and its children
|
||||
else tree->deselect_all(bbb, docallback); // deselect /Bbb and its children
|
||||
|
||||
tree->redraw();
|
||||
|
||||
// Toggle select of just the Bbb item and its immediate children
|
||||
//int docallback = docallback_radio->value() ? 1 : 0;
|
||||
//int onoff = bbbselect_toggle->value();
|
||||
//
|
||||
//if ( onoff ) tree->select("/Bbb", docallback);
|
||||
//else tree->deselect("/Bbb", docallback);
|
||||
//
|
||||
//tree->redraw();}
|
||||
tooltip {Toggle selection of the /Bbb item and its children} xywh {430 552 115 15} labelsize 11
|
||||
int onoff = bbbselect2_toggle->value();
|
||||
if ( onoff ) tree->select_all(bbb); // select /Bbb and its children
|
||||
else tree->deselect_all(bbb); // deselect /Bbb and its children}
|
||||
tooltip {Toggle selection of the /Bbb item and its children} xywh {350 560 95 15} selection_color 1 labelsize 9
|
||||
}
|
||||
Fl_Light_Button bbbchild02select_toggle {
|
||||
label { Toggle child-02}
|
||||
callback {// Toggle select of just the /Bbb/child-02 item
|
||||
int docallback = docallback_radio->value() ? 1 : 0;
|
||||
int onoff = bbbchild02select_toggle->value();
|
||||
if ( onoff ) tree->select("/Bbb/child-02", docallback);
|
||||
else tree->deselect("/Bbb/child-02", docallback);
|
||||
tree->redraw();}
|
||||
tooltip {Toggle the single item /Bbb/child-02} xywh {430 571 115 16} labelsize 11
|
||||
if ( onoff ) tree->select("/Bbb/child-02");
|
||||
else tree->deselect("/Bbb/child-02");}
|
||||
tooltip {Toggle the single item /Bbb/child-02} xywh {350 579 95 16} selection_color 1 labelsize 9
|
||||
}
|
||||
Fl_Button loaddb_button {
|
||||
label {Load Database...}
|
||||
callback {const char *filename = fl_file_chooser("Select a Preferences style Database", "Preferences(*.prefs)", 0L);
|
||||
if (filename) {
|
||||
tree->clear();
|
||||
Fl_Preferences prefs(filename, 0L, 0L);
|
||||
tree->load(prefs);
|
||||
tree->redraw();
|
||||
}}
|
||||
tooltip {Load the contents of an Fl_Preferences database into the tree view} xywh {380 614 90 16} labelsize 9
|
||||
}
|
||||
Fl_Light_Button deactivate_toggle {
|
||||
label { Deactivate}
|
||||
callback {int onoff = deactivate_toggle->value() ? 0 : 1;
|
||||
|
||||
int count = 0;
|
||||
for (Fl_Tree_Item *item=tree->first(); item; item = item->next()) {
|
||||
for ( Fl_Tree_Item *item=tree->first(); item; item = tree->next(item) ) {
|
||||
if ( item->is_selected() ) {
|
||||
item->activate(onoff);
|
||||
++count;
|
||||
@ -564,14 +632,14 @@ for (Fl_Tree_Item *item=tree->first(); item; item = item->next()) {
|
||||
}
|
||||
|
||||
if ( count == 0 ) {
|
||||
for (Fl_Tree_Item *item=tree->first(); item; item = item->next()) {
|
||||
for ( Fl_Tree_Item *item=tree->first(); item; item = tree->next(item) ) {
|
||||
item->activate(onoff);
|
||||
}
|
||||
}
|
||||
|
||||
tree->redraw();}
|
||||
tooltip {Toggle the deactivation state of the selected items.
|
||||
If none are selected, all are set.} xywh {280 633 90 16} labelsize 11
|
||||
If none are selected, all are set.} xywh {280 634 90 16} selection_color 1 labelsize 9
|
||||
}
|
||||
Fl_Light_Button bold_toggle {
|
||||
label { Bold Font}
|
||||
@ -579,7 +647,7 @@ If none are selected, all are set.} xywh {280 633 90 16} labelsize 11
|
||||
|
||||
// DO SELECTED ITEMS
|
||||
int count = 0;
|
||||
for ( Fl_Tree_Item *item=tree->first(); item; item = item->next() ) {
|
||||
for ( Fl_Tree_Item *item=tree->first(); item; item = tree->next(item) ) {
|
||||
if ( item->is_selected() ) {
|
||||
item->labelfont(face);
|
||||
count++;
|
||||
@ -588,14 +656,14 @@ for ( Fl_Tree_Item *item=tree->first(); item; item = item->next() ) {
|
||||
|
||||
// NO ITEMS SELECTED? DO ALL
|
||||
if ( ! count ) {
|
||||
for ( Fl_Tree_Item *item=tree->first(); item; item = item->next() ) {
|
||||
for ( Fl_Tree_Item *item=tree->first(); item; item = tree->next(item) ) {
|
||||
item->labelfont(face);
|
||||
}
|
||||
}
|
||||
|
||||
tree->redraw();}
|
||||
tooltip {Toggles bold font for selected items
|
||||
If nothing selected, all are changed} xywh {280 652 90 16} labelsize 11
|
||||
If nothing selected, all are changed} xywh {280 654 90 16} selection_color 1 labelsize 9
|
||||
}
|
||||
Fl_Button insertabove_button {
|
||||
label {Insert Above}
|
||||
@ -610,15 +678,38 @@ while (item) {
|
||||
}
|
||||
|
||||
tree->redraw();}
|
||||
tooltip {Inserts three items above the selected items} xywh {380 632 90 16} labelsize 11
|
||||
tooltip {Inserts three items above the selected items} xywh {380 634 90 16} labelsize 9
|
||||
}
|
||||
Fl_Button rebuildtree_button {
|
||||
label {Rebuild Tree}
|
||||
callback {RebuildTree();}
|
||||
tooltip {Rebuilds the tree with defaults} xywh {380 652 90 16} labelsize 11
|
||||
tooltip {Rebuilds the tree with defaults} xywh {380 654 90 16} labelsize 9
|
||||
}
|
||||
Fl_Button showpathname_button {
|
||||
label {Show Pathname}
|
||||
callback {Fl_Tree_Item *item = tree->first_selected_item();
|
||||
if ( !item ) { fl_message("No item was selected"); return; }
|
||||
|
||||
char pathname[256];
|
||||
switch ( tree->item_pathname(pathname, sizeof(pathname), item) ) {
|
||||
case 0: fl_message("Pathname for '%s' is: \\"%s\\"", (item->label() ? item->label() : "???"), pathname); break;
|
||||
case -1: fl_message("item_pathname() returned -1 (NOT FOUND)"); break;
|
||||
case -2: fl_message("item_pathname() returned -2 (STRING TOO LONG)"); break;
|
||||
}} selected
|
||||
tooltip {Show the pathname for the selected item. Tests the Fl_Tree::item_pathname() method.} xywh {380 674 90 16} labelsize 8
|
||||
}
|
||||
Fl_Button showselected_button {
|
||||
label {Show Selected}
|
||||
callback {fprintf(stderr, "--- SELECTED ITEMS\\n");
|
||||
for ( Fl_Tree_Item *item = tree->first_selected_item();
|
||||
item;
|
||||
item = tree->next_selected_item(item) ) {
|
||||
fprintf(stderr, "\\t%s\\n", item->label() ? item->label() : "???");
|
||||
}}
|
||||
tooltip {Clears the selected items} xywh {475 614 90 16} labelsize 9
|
||||
}
|
||||
Fl_Button clearselected_button {
|
||||
label {Clear Selected}
|
||||
label {Remove Selected}
|
||||
callback {Fl_Tree_Item *item=tree->first();
|
||||
while (item) {
|
||||
if ( item->is_selected() ) {
|
||||
@ -630,34 +721,130 @@ while (item) {
|
||||
}
|
||||
|
||||
tree->redraw();}
|
||||
tooltip {Clears the selected items} xywh {475 632 90 16} labelsize 11
|
||||
tooltip {Removes the selected items} xywh {475 634 90 16} labelsize 9
|
||||
}
|
||||
Fl_Button clearall_button {
|
||||
label {Clear All}
|
||||
callback {tree->clear();
|
||||
tree->redraw();}
|
||||
tooltip {Clears all items
|
||||
Tests Fl_Tree::clear()} xywh {475 652 90 16} labelsize 11
|
||||
Tests Fl_Tree::clear()} xywh {475 654 90 16} labelsize 9
|
||||
}
|
||||
Fl_Button loaddb_button {
|
||||
label {Load Database...}
|
||||
callback {const char *filename = fl_file_chooser("Select a Preferences style Database", "Preferences(*.prefs)", 0L);
|
||||
if (filename) {
|
||||
tree->clear();
|
||||
Fl_Preferences prefs(filename, 0L, 0L);
|
||||
tree->load(prefs);
|
||||
tree->redraw();
|
||||
}}
|
||||
tooltip {Load the contents of an Fl_Preferences database into the tree view} xywh {380 612 90 16} labelsize 11
|
||||
Fl_Button testcallbackflag_button {
|
||||
label {Test Callback Flag}
|
||||
callback {Fl_Tree_Item *root = tree->root();
|
||||
fprintf(stderr, "--- Checking docallback off\\n");
|
||||
|
||||
//// "OFF" TEST
|
||||
|
||||
// open/close: Make sure these methods don't trigger cb
|
||||
G_cb_counter = 0; tree->close(root, 0); if ( G_cb_counter ) fl_alert("FAILED 'OFF' TEST\\n close(item) triggered cb!");
|
||||
G_cb_counter = 0; tree->open(root, 0); if ( G_cb_counter ) fl_alert("FAILED 'OFF' TEST\\n open(item) triggered cb!");
|
||||
G_cb_counter = 0; tree->open_toggle(root, 0); if ( G_cb_counter ) fl_alert("FAILED 'OFF' TEST\\n open_toggle(item) triggered cb!");
|
||||
G_cb_counter = 0; tree->open("ROOT", 0); if ( G_cb_counter ) fl_alert("FAILED 'OFF' TEST\\n open(path) triggered cb!");
|
||||
G_cb_counter = 0; tree->close("ROOT", 0); if ( G_cb_counter ) fl_alert("FAILED 'OFF' TEST\\n close(path) triggered cb!");
|
||||
tree->open(root,0); // leave root open
|
||||
|
||||
// select/deselect: Make sure these methods don't trigger cb
|
||||
G_cb_counter = 0; tree->select(root, 0); if ( G_cb_counter ) fl_alert("FAILED 'OFF' TEST\\n select(item) triggered cb!");
|
||||
G_cb_counter = 0; tree->deselect(root, 0); if ( G_cb_counter ) fl_alert("FAILED 'OFF' TEST\\n deselect(item) triggered cb!");
|
||||
G_cb_counter = 0; tree->select_toggle(root, 0); if ( G_cb_counter ) fl_alert("FAILED 'OFF' TEST\\n select_toggle(item) triggered cb!");
|
||||
G_cb_counter = 0; tree->deselect("ROOT", 0); if ( G_cb_counter ) fl_alert("FAILED 'OFF' TEST\\n deselect(path) triggered cb!");
|
||||
G_cb_counter = 0; tree->select("ROOT", 0); if ( G_cb_counter ) fl_alert("FAILED 'OFF' TEST\\n select(path) triggered cb!");
|
||||
tree->deselect("ROOT"); // leave deselected
|
||||
|
||||
//// "ON" TEST
|
||||
|
||||
// open/close: Make sure these methods don't trigger cb
|
||||
G_cb_counter = 0; tree->close(root, 1); if ( !G_cb_counter ) fl_alert("FAILED 'ON' TEST\\n close(item) cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->open(root, 1); if ( !G_cb_counter ) fl_alert("FAILED 'ON' TEST\\n open(item) cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->open_toggle(root, 1); if ( !G_cb_counter ) fl_alert("FAILED 'ON' TEST\\n open_toggle(item) cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->open(root, 1); if ( !G_cb_counter ) fl_alert("FAILED 'ON' TEST\\n open(item)[2] cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->close(root, 1); if ( !G_cb_counter ) fl_alert("FAILED 'ON' TEST\\n close(item)[2] cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->open("ROOT", 1); if ( !G_cb_counter ) fl_alert("FAILED 'ON' TEST\\n open(path) cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->close("ROOT", 1); if ( !G_cb_counter ) fl_alert("FAILED 'ON' TEST\\n close(path) cb wasn't triggered!");
|
||||
tree->open(root,0); // leave root open
|
||||
|
||||
// select/deselect: Make sure these methods don't trigger cb
|
||||
G_cb_counter = 0; tree->select(root, 1); if ( !G_cb_counter ) fl_alert("FAILED 'ON' TEST\\n select(item) cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->deselect(root, 1); if ( !G_cb_counter ) fl_alert("FAILED 'ON' TEST\\n deselect(item) cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->select_toggle(root, 1); if ( !G_cb_counter ) fl_alert("FAILED 'ON' TEST\\n select_toggle(item) cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->deselect("ROOT", 1); if ( !G_cb_counter ) fl_alert("FAILED 'ON' TEST\\n deselect(path) cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->select("ROOT", 1); if ( !G_cb_counter ) fl_alert("FAILED 'ON' TEST\\n select(path) cb wasn't triggered!");
|
||||
tree->deselect("ROOT"); // leave deselected
|
||||
|
||||
//// "default" TEST (should be same as 'on'
|
||||
|
||||
// open/close: Make sure these methods don't trigger cb
|
||||
G_cb_counter = 0; tree->close(root); if ( !G_cb_counter ) fl_alert("FAILED 'DEFAULT' TEST: close(item) cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->open(root); if ( !G_cb_counter ) fl_alert("FAILED 'DEFAULT' TEST: open(item) cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->open_toggle(root); if ( !G_cb_counter ) fl_alert("FAILED 'DEFAULT' TEST: open_toggle(item) cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->open("ROOT"); if ( !G_cb_counter ) fl_alert("FAILED 'DEFAULT' TEST: open(path) cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->close("ROOT"); if ( !G_cb_counter ) fl_alert("FAILED 'DEFAULT' TEST: close(path) cb wasn't triggered!");
|
||||
tree->open(root,0); // leave root open
|
||||
|
||||
// select/deselect: Make sure these methods don't trigger cb
|
||||
G_cb_counter = 0; tree->select(root); if ( !G_cb_counter ) fl_alert("FAILED 'DEFAULT' TEST\\n select(item) cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->deselect(root); if ( !G_cb_counter ) fl_alert("FAILED 'DEFAULT' TEST\\n deselect(item) cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->select_toggle(root); if ( !G_cb_counter ) fl_alert("FAILED 'DEFAULT' TEST\\n select_toggle(item) cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->deselect("ROOT"); if ( !G_cb_counter ) fl_alert("FAILED 'DEFAULT' TEST\\n deselect(path) cb wasn't triggered!");
|
||||
G_cb_counter = 0; tree->select("ROOT"); if ( !G_cb_counter ) fl_alert("FAILED 'DEFAULT' TEST\\n select(path) cb wasn't triggered!");
|
||||
tree->deselect("ROOT"); // leave deselected
|
||||
|
||||
fl_alert("TEST COMPLETED\\n If you didn't see any error dialogs, test PASSED.");}
|
||||
tooltip {Test the 'docallback' argument can disable callbacks.} xywh {475 674 90 16} labelsize 8
|
||||
}
|
||||
Fl_Light_Button rootselect_toggle {
|
||||
label {Select ROOT}
|
||||
callback {// Toggle select of ROOT item and its children
|
||||
Fl_Tree_Item *item = tree->find_item("/ROOT");
|
||||
if ( !item) {
|
||||
fl_alert("FAIL: Couldn't find item '/ROOT'???");
|
||||
return;
|
||||
}
|
||||
int onoff = rootselect_toggle->value();
|
||||
if ( onoff ) tree->select(item); // select /ROOT and its children
|
||||
else tree->deselect(item); // deselect /ROOT and its children}
|
||||
tooltip {Toggle selection of the ROOT item} xywh {460 540 90 15} selection_color 1 labelsize 9
|
||||
}
|
||||
Fl_Light_Button bbbselect_toggle {
|
||||
label { Select Bbb}
|
||||
callback {// Toggle select of just the Bbb item (not children)
|
||||
Fl_Tree_Item *bbb = tree->find_item("/Bbb");
|
||||
if ( !bbb) {
|
||||
fl_alert("FAIL: Couldn't find item '/Bbb'???");
|
||||
return;
|
||||
}
|
||||
int onoff = bbbselect_toggle->value();
|
||||
if ( onoff ) tree->select(bbb); // select /Bbb
|
||||
else tree->deselect(bbb); // deselect /Bbb}
|
||||
tooltip {Toggle selection of just the /Bbb item
|
||||
(Not children)} xywh {350 540 95 15} selection_color 1 labelsize 9
|
||||
}
|
||||
Fl_Light_Button rootselect2_toggle {
|
||||
label {Select ROOT+}
|
||||
callback {// Toggle select of ROOT item and its children
|
||||
Fl_Tree_Item *item = tree->find_item("/ROOT");
|
||||
if ( !item) {
|
||||
fl_alert("FAIL: Couldn't find item '/ROOT'???");
|
||||
return;
|
||||
}
|
||||
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}
|
||||
tooltip {Toggle selection of the ROOT item and all children} xywh {460 560 90 15} selection_color 1 labelsize 9
|
||||
}
|
||||
}
|
||||
code {// Initialize Tree
|
||||
tree->root_label("ROOT");
|
||||
docallback_radio->value(1); // enable docallbacks radio button
|
||||
RebuildTree();
|
||||
tree->show_self();} {}
|
||||
/*tree->show_self();*/} {}
|
||||
code {// FLTK stuff
|
||||
Fl::scheme("gtk+");
|
||||
window->resizable(window);
|
||||
window->size_range(window->w(), window->h(), 0, 0);} {}
|
||||
window->size_range(window->w(), window->h(), 0, 0);
|
||||
|
||||
if ( tree->when() == FL_WHEN_CHANGED ) whenmode_chooser->value(0);
|
||||
else if ( tree->when() == FL_WHEN_RELEASE ) whenmode_chooser->value(1);
|
||||
else if ( tree->when() == FL_WHEN_NEVER ) whenmode_chooser->value(2);} {}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include <FL/Fl_Group.H>
|
||||
#include <FL/Fl_Browser.H>
|
||||
#include <FL/Fl_Tree.H>
|
||||
#include <FL/Fl_Value_Slider.H>
|
||||
|
||||
//
|
||||
@ -34,10 +35,12 @@
|
||||
//
|
||||
class ScrollBarSizeTest : public Fl_Group {
|
||||
Fl_Browser *brow_a, *brow_b, *brow_c;
|
||||
Fl_Tree *tree_a, *tree_b, *tree_c;
|
||||
|
||||
Fl_Browser *makebrowser(int X,int Y,int W,int H,const char*L=0) {
|
||||
Fl_Browser *b = new Fl_Browser(X,Y,W,H,L);
|
||||
b->type(FL_MULTI_BROWSER);
|
||||
b->align(FL_ALIGN_TOP);
|
||||
b->add("Papa"); b->add("Delta"); b->add("Hotel");
|
||||
b->add("Long entry will show h-bar");
|
||||
b->add("Charlie"); b->add("Echo"); b->add("Foxtrot");
|
||||
@ -59,12 +62,29 @@ class ScrollBarSizeTest : public Fl_Group {
|
||||
b->add("Whisky"); b->add("Zulu");
|
||||
return(b);
|
||||
}
|
||||
Fl_Tree *maketree(int X,int Y,int W,int H,const char*L=0) {
|
||||
Fl_Tree *b = new Fl_Tree(X,Y,W,H,L);
|
||||
b->type(FL_TREE_SELECT_MULTI);
|
||||
b->align(FL_ALIGN_TOP);
|
||||
b->add("Papa"); b->add("Delta"); b->add("Hotel");
|
||||
b->add("Long entry will show h-bar");
|
||||
b->add("Charlie"); b->add("Echo"); b->add("Foxtrot");
|
||||
b->add("Golf"); b->add("Lima"); b->add("Victor");
|
||||
b->add("Alpha"); b->add("Xray"); b->add("Yankee");
|
||||
b->add("Oscar"); b->add("India"); b->add("Juliet");
|
||||
b->add("Kilo"); b->add("Mike"); b->add("Sierra");
|
||||
b->add("November"); b->add("Tango"); b->add("Quebec");
|
||||
b->add("Bravo"); b->add("Romeo"); b->add("Uniform");
|
||||
b->add("Whisky"); b->add("Zulu");
|
||||
return(b);
|
||||
}
|
||||
void slide_cb2(Fl_Value_Slider *in) {
|
||||
const char *label = in->label();
|
||||
int val = in->value();
|
||||
//fprintf(stderr, "VAL='%d'\n",val);
|
||||
if ( strcmp(label,"A: Scroll Size") == 0 ) {
|
||||
brow_a->scrollbar_size(val);
|
||||
tree_a->scrollbar_size(val);
|
||||
} else {
|
||||
Fl::scrollbar_size(val);
|
||||
}
|
||||
@ -82,10 +102,36 @@ public:
|
||||
// CTOR
|
||||
ScrollBarSizeTest(int X, int Y, int W, int H) : Fl_Group(X,Y,W,H) {
|
||||
begin();
|
||||
brow_a = makebrowser(X+ 10,Y+40,100,H-170,"Browser A");
|
||||
brow_b = makebrowser(X+120,Y+40,100,H-170,"Browser B");
|
||||
brow_c = makebrowser(X+240,Y+40,100,H-170,"Browser C");
|
||||
Fl_Value_Slider *slide_glob = new Fl_Value_Slider(X+100,Y+10,100,18,"Global Scroll Size");
|
||||
// _____________ _______________
|
||||
// |_____________| |_______________|
|
||||
// --- ----- <-- tgrpy
|
||||
// brow_a brow_b brow_c | 14 |
|
||||
// ---------- ---------- ---------- --- | <-- browy
|
||||
// | | | | | | | |
|
||||
// | | | | | | |browh |
|
||||
// | | | | | | | |
|
||||
// ---------- ---------- ---------- --- tgrph
|
||||
// | |
|
||||
// tree_a tree_b tree_c | 20 |
|
||||
// ---------- ---------- ---------- --- | <-- treey
|
||||
// | | | | | | | |
|
||||
// | | | | | | |treeh |
|
||||
// | | | | | | | |
|
||||
// ---------- ---------- ---------- --- ------
|
||||
//
|
||||
int tgrpy = Y+30;
|
||||
int tgrph = H-130;
|
||||
int browy = tgrpy+14;
|
||||
int browh = tgrph/2 - 20;
|
||||
int treey = browy + browh + 20;
|
||||
int treeh = browh;
|
||||
brow_a = makebrowser(X+ 10,browy,100,browh,"Browser A");
|
||||
brow_b = makebrowser(X+120,browy,100,browh,"Browser B");
|
||||
brow_c = makebrowser(X+240,browy,100,browh,"Browser C");
|
||||
tree_a = maketree(X+ 10,treey,100,treeh,"Tree A");
|
||||
tree_b = maketree(X+120,treey,100,treeh,"Tree B");
|
||||
tree_c = maketree(X+240,treey,100,treeh,"Tree C");
|
||||
Fl_Value_Slider *slide_glob = new Fl_Value_Slider(X+100,Y,100,18,"Global Scroll Size");
|
||||
slide_glob->value(16);
|
||||
slide_glob->type(FL_HORIZONTAL);
|
||||
slide_glob->align(FL_ALIGN_LEFT);
|
||||
@ -93,7 +139,7 @@ public:
|
||||
slide_glob->step(1.0);
|
||||
slide_glob->callback(slide_cb, (void*)this);
|
||||
slide_glob->labelsize(12);
|
||||
Fl_Value_Slider *slide_browa = new Fl_Value_Slider(X+350,Y+10,100,18,"A: Scroll Size");
|
||||
Fl_Value_Slider *slide_browa = new Fl_Value_Slider(X+350,Y,100,18,"A: Scroll Size");
|
||||
slide_browa->value(16);
|
||||
slide_browa->type(FL_HORIZONTAL);
|
||||
slide_browa->align(FL_ALIGN_LEFT);
|
||||
|
Loading…
Reference in New Issue
Block a user