summaryrefslogtreecommitdiff
path: root/FL
diff options
context:
space:
mode:
authorMatthias Melcher <fltk@matthiasm.com>2009-11-14 15:49:12 +0000
committerMatthias Melcher <fltk@matthiasm.com>2009-11-14 15:49:12 +0000
commit07a18370ad2aa1f2253afbf45565d55605a88b47 (patch)
treef2619866e648a105259b24c8265ec08a11bf1971 /FL
parent69601a6d5827539394b9468176727ec651c1ebbc (diff)
Added Fl_Tree source code, demo files, and documentation. Thanks, Greg!
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@6934 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'FL')
-rw-r--r--FL/Fl_Table.H398
-rw-r--r--FL/Fl_Table_Row.H18
-rw-r--r--FL/Fl_Tree.H647
-rw-r--r--FL/Fl_Tree_Item.H291
-rw-r--r--FL/Fl_Tree_Item_Array.H80
-rw-r--r--FL/Fl_Tree_Prefs.H353
6 files changed, 1579 insertions, 208 deletions
diff --git a/FL/Fl_Table.H b/FL/Fl_Table.H
index 5d0d2cf28..47e394176 100644
--- a/FL/Fl_Table.H
+++ b/FL/Fl_Table.H
@@ -52,24 +52,24 @@
Normally applications use widgets derived from this widget, and do not use this
widget directly; this widget is usually too low level to be used directly by
applications.
-
+
This widget does \em not handle the data in the table. The draw_cell()
method must be overridden by a subclass to manage drawing the contents of
the cells.
-
+
This widget can be used in several ways:
- - As a custom widget; see test/testtablerow.cxx. Very optimal for even
- extremely large tables.
- - As a table made up of a single FLTK widget instanced all over the table;
- see test/singleinput.cxx. Very optimal for even extremely large tables;
- - As a regular container of FLTK widgets, one widget per cell.
- See test/widgettable.cxx. \em Not recommended for large tables.
-
+ - As a custom widget; see test/testtablerow.cxx. Very optimal for even
+ extremely large tables.
+ - As a table made up of a single FLTK widget instanced all over the table;
+ see test/singleinput.cxx. Very optimal for even extremely large tables;
+ - As a regular container of FLTK widgets, one widget per cell.
+ See test/widgettable.cxx. \em Not recommended for large tables.
+
When acting as part of a custom widget, events on the cells and/or headings
generate callbacks when they are clicked by the user. You control when events
are generated based on the setting for Fl_Table::when().
-
+
When acting as a container for FLTK widgets, the FLTK widgets maintain
themselves. Although the draw_cell() method must be overridden, its contents
can be very simple. See the draw_cell() code in test/widgettable.cxx.
@@ -77,7 +77,7 @@
The following variables are available to classes deriving from Fl_Table:
\image html table-dimensions.gif
-
+
<table border=0>
<tr><td>x()/y()/w()/h()</td>
<td>Fl_Table widget's outer dimension. The outer edge of the border of the
@@ -178,21 +178,21 @@ public:
CONTEXT_TABLE = 0x20, // in the table
CONTEXT_RC_RESIZE = 0x40 // column or row being resized
};
-
+
private:
int _rows, _cols; // total rows/cols
int _row_header_w; // width of row header
int _col_header_h; // height of column header
int _row_position; // last row_position set (not necessarily == toprow!)
int _col_position; // last col_position set (not necessarily == leftcol!)
-
+
char _row_header; // row header enabled?
char _col_header; // col header enabled?
char _row_resize; // row resizing enabled?
char _col_resize; // col resizing enabled?
int _row_resize_min; // row minimum resizing height (default=1)
int _col_resize_min; // col minimum resizing width (default=1)
-
+
// OPTIMIZATION: partial row/column redraw variables
int _redraw_toprow;
int _redraw_botrow;
@@ -200,10 +200,10 @@ private:
int _redraw_rightcol;
Fl_Color _row_header_color;
Fl_Color _col_header_color;
-
+
int _auto_drag;
int _selecting;
-
+
// An STL-ish vector without templates
class IntVector {
int *arr;
@@ -231,23 +231,23 @@ private:
void size(unsigned int count) {
if ( count != _size ) {
arr = (int*)realloc(arr, count * sizeof(int));
- _size = count;
+ _size = count;
}
}
int pop_back() { int tmp = arr[_size-1]; _size--; return(tmp); }
void push_back(int val) { unsigned int x = _size; size(_size+1); arr[x] = val; }
int back() { return(arr[_size-1]); }
};
-
+
IntVector _colwidths; // column widths in pixels
IntVector _rowheights; // row heights in pixels
-
+
Fl_Cursor _last_cursor; // last mouse cursor before changed to 'resize' cursor
-
+
// EVENT CALLBACK DATA
TableContext _callback_context; // event context
int _callback_row, _callback_col; // event row/col
-
+
// handle() state variables.
// Put here instead of local statics in handle(), so more
// than one Fl_Table can exist without crosstalk between them.
@@ -257,15 +257,15 @@ private:
int _dragging_x; // starting x position for horiz drag
int _dragging_y; // starting y position for vert drag
int _last_row; // last row we FL_PUSH'ed
-
+
// Redraw single cell
void _redraw_cell(TableContext context, int R, int C);
-
+
void _start_auto_drag();
void _stop_auto_drag();
void _auto_drag_cb();
static void _auto_drag_cb2(void *d);
-
+
protected:
enum ResizeFlag {
RESIZE_NONE = 0,
@@ -274,51 +274,51 @@ protected:
RESIZE_ROW_ABOVE = 3,
RESIZE_ROW_BELOW = 4
};
-
+
int table_w, table_h; // table's virtual size (in pixels)
int toprow, botrow, leftcol, rightcol; // four corners of viewable table
-
+
// selection
int current_row, current_col;
int select_row, select_col;
-
+
// OPTIMIZATION: Precomputed scroll positions for the toprow/leftcol
int toprow_scrollpos;
int leftcol_scrollpos;
-
+
// Dimensions
int tix, tiy, tiw, tih; // data table inner dimension xywh
int tox, toy, tow, toh; // data table outer dimension xywh
int wix, wiy, wiw, wih; // widget inner dimension xywh
-
+
Fl_Scroll *table; // container for child fltk widgets (if any)
Fl_Scrollbar *vscrollbar; // vertical scrollbar
Fl_Scrollbar *hscrollbar; // horizontal scrollbar
-
+
// Fltk
int handle(int e); // fltk handle() override
-
+
// Class maintenance
void recalc_dimensions();
void table_resized(); // table resized; recalc
void table_scrolled(); // table scrolled; recalc
void get_bounds(TableContext context, // return x/y/w/h bounds for context
- int &X, int &Y, int &W, int &H);
+ int &X, int &Y, int &W, int &H);
void change_cursor(Fl_Cursor newcursor); // change mouse cursor to some other shape
TableContext cursor2rowcol(int &R, int &C, ResizeFlag &resizeflag);
- // find r/c given current x/y event
+ // find r/c given current x/y event
int find_cell(TableContext context, // find cell's x/y/w/h given r/c
- int R, int C, int &X, int &Y, int &W, int &H);
+ int R, int C, int &X, int &Y, int &W, int &H);
int row_col_clamp(TableContext context, int &R, int &C);
- // clamp r/c to known universe
-
+ // clamp r/c to known universe
+
/**
Subclass should override this method to handle drawing the cells.
This method will be called whenever the table is redrawn, once per cell.
-
+
Only cells that are completely (or partially) visible will be told to draw.
-
+
\p context will be one of the following:
<table border=1>
@@ -371,65 +371,65 @@ protected:
// This is called whenever Fl_Table wants you to draw a cell
void MyTable::draw_cell(TableContext context, int R=0, int C=0, int X=0, int Y=0, int W=0, int H=0)
{
- static char s[40];
- sprintf(s, "%d/%d", R, C); // text for each cell
- switch ( context )
- {
- case CONTEXT_STARTPAGE: // Fl_Table telling us its starting to draw page
- fl_font(FL_HELVETICA, 16);
- return;
-
- case CONTEXT_ROW_HEADER: // Fl_Table telling us it's draw row/col headers
- case CONTEXT_COL_HEADER:
- fl_push_clip(X, Y, W, H);
- {
- fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, color());
- fl_color(FL_BLACK);
- fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
- }
- fl_pop_clip();
- return;
-
- case CONTEXT_CELL: // Fl_Table telling us to draw cells
- fl_push_clip(X, Y, W, H);
- {
- // BG COLOR
- fl_color( row_selected(R) ? selection_color() : FL_WHITE);
- fl_rectf(X, Y, W, H);
-
- // TEXT
- fl_color(FL_BLACK);
- fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
-
- // BORDER
- fl_color(FL_LIGHT2);
- fl_rect(X, Y, W, H);
- }
- fl_pop_clip();
- return;
-
- default:
- return;
- }
- //NOTREACHED
+ static char s[40];
+ sprintf(s, "%d/%d", R, C); // text for each cell
+ switch ( context )
+ {
+ case CONTEXT_STARTPAGE: // Fl_Table telling us its starting to draw page
+ fl_font(FL_HELVETICA, 16);
+ return;
+
+ case CONTEXT_ROW_HEADER: // Fl_Table telling us it's draw row/col headers
+ case CONTEXT_COL_HEADER:
+ fl_push_clip(X, Y, W, H);
+ {
+ fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, color());
+ fl_color(FL_BLACK);
+ fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
+ }
+ fl_pop_clip();
+ return;
+
+ case CONTEXT_CELL: // Fl_Table telling us to draw cells
+ fl_push_clip(X, Y, W, H);
+ {
+ // BG COLOR
+ fl_color( row_selected(R) ? selection_color() : FL_WHITE);
+ fl_rectf(X, Y, W, H);
+
+ // TEXT
+ fl_color(FL_BLACK);
+ fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
+
+ // BORDER
+ fl_color(FL_LIGHT2);
+ fl_rect(X, Y, W, H);
+ }
+ fl_pop_clip();
+ return;
+
+ default:
+ return;
+ }
+ //NOTREACHED
}
\endcode
*/
virtual void draw_cell(TableContext context, int R=0, int C=0,
- int X=0, int Y=0, int W=0, int H=0)
- { } // overridden by deriving class
-
+ int X=0, int Y=0, int W=0, int H=0)
+ { } // overridden by deriving class
+
long row_scroll_position(int row); // find scroll position of row (in pixels)
long col_scroll_position(int col); // find scroll position of col (in pixels)
-
+
int is_fltk_container() { // does table contain fltk widgets?
return( Fl_Group::children() > 3 ); // (ie. more than box and 2 scrollbars?)
}
-
+
static void scroll_cb(Fl_Widget*,void*); // h/v scrollbar callback
-
+
void damage_zone(int r1, int c1, int r2, int c2, int r3 = 0, int c3 = 0);
-
+
void redraw_range(int toprow, int botrow, int leftcol, int rightcol) {
if ( _redraw_toprow == -1 ) {
// Initialize redraw range
@@ -444,11 +444,11 @@ protected:
if ( leftcol < _redraw_leftcol ) _redraw_leftcol = leftcol;
if ( rightcol > _redraw_rightcol ) _redraw_rightcol = rightcol;
}
-
+
// Indicate partial redraw needed of some cells
damage(FL_DAMAGE_CHILD);
}
-
+
public:
/**
The constructor for the Fl_Table.
@@ -456,24 +456,24 @@ public:
with headers and row/column resize behavior disabled.
*/
Fl_Table(int X, int Y, int W, int H, const char *l=0);
-
+
/**
The destructor for the Fl_Table.
Destroys the table and its associated widgets.
*/
~Fl_Table();
-
+
/**
Clears the table to zero rows, zero columns.
Same as rows(0); cols(0);
\see rows(int), cols(int)
*/
virtual void clear() { rows(0); cols(0); }
-
+
// topline()
// middleline()
// bottomline()
-
+
/**
Sets the kind of box drawn around the data table,
the default being FL_NO_BOX. Changing this value will cause the table
@@ -518,30 +518,30 @@ public:
/**
Returns the range of row and column numbers for all the
visible (and partially visible) cells in the table.
-
+
These values can be used e.g. by your draw_cell() routine during
CONTEXT_STARTPAGE to figure out what cells are about to be redrawn,
for the purposes of locking the data from a database before it's drawn.
\code
- leftcol rightcol
- : :
+ leftcol rightcol
+ : :
toprow .. .-------------------.
- | |
- | V I S I B L E |
- | |
- | T A B L E |
- | |
+ | |
+ | V I S I B L E |
+ | |
+ | T A B L E |
+ | |
botrow .. '-------------------`
\endcode
e.g. in a table where the visible rows are 5-20, and the
visible columns are 100-120, then those variables would be:
- - toprow = 5
- - botrow = 20
- - leftcol = 100
- - rightcol = 120
+ - toprow = 5
+ - botrow = 20
+ - leftcol = 100
+ - rightcol = 120
*/
inline void visible_cells(int& r1, int& r2, int& c1, int& c2) {
r1 = toprow;
@@ -733,7 +733,7 @@ public:
inline int row_height(int row) {
return((row<0 || row>=(int)_rowheights.size()) ? 0 : _rowheights[row]);
}
-
+
/**
Sets the width of the specified column in pixels, and the table is redrawn.
callback() will be invoked with CONTEXT_RC_RESIZE
@@ -812,24 +812,24 @@ public:
void get_selection(int& s_top, int& s_left, int& s_bottom, int& s_right);
void set_selection(int s_top, int s_left, int s_bottom, int s_right);
int move_cursor(int R, int C);
-
+
/**
Changes the size of the Fl_Table, causing it to redraw.
*/
void resize(int X, int Y, int W, int H); // fltk resize() override
void draw(void); // fltk draw() override
-
-// This crashes sortapp() during init.
-// void box(Fl_Boxtype val) {
-// Fl_Group::box(val);
-// if ( table ) {
-// resize(x(), y(), w(), h());
-// }
-// }
-// Fl_Boxtype box(void) const {
-// return(Fl_Group::box());
-// }
-
+
+ // This crashes sortapp() during init.
+ // void box(Fl_Boxtype val) {
+ // Fl_Group::box(val);
+ // if ( table ) {
+ // resize(x(), y(), w(), h());
+ // }
+ // }
+ // Fl_Boxtype box(void) const {
+ // return(Fl_Group::box());
+ // }
+
// Child group
void init_sizes() {
table->init_sizes();
@@ -879,8 +879,8 @@ public:
\code
for ( int i=0; i<children(); i++ )
{
- Fl_Widget *w = child(i);
- [..]
+ Fl_Widget *w = child(i);
+ [..]
}
\endcode
*/
@@ -975,85 +975,85 @@ public:
#if DOXYGEN
/**
- Callbacks will be called depending on the setting of Fl_Widget::when().
-
- Callback functions should use the following functions to determine the
- context/row/column:
-
- * Fl_Table::callback_row() returns current row
- * Fl_Table::callback_col() returns current column
- * Fl_Table::callback_context() returns current table context
-
- callback_row() and callback_col() will be set to the row and column number the
- event occurred on. If someone clicked on a row header, \p col will be \a 0.
- If someone clicked on a column header, \p row will be \a 0.
-
- callback_context() will return one of the following:
-
- <table border=1>
- <tr><td><tt>Fl_Table::CONTEXT_ROW_HEADER</tt></td>
- <td>Someone clicked on a row header. Excludes resizing.</td>
- </tr><tr>
- <td><tt>Fl_Table::CONTEXT_COL_HEADER</tt></td>
- <td>Someone clicked on a column header. Excludes resizing.</td>
- </tr><tr>
- <td><tt>Fl_Table::CONTEXT_CELL</tt></td>
- <td>
- Someone clicked on a cell.
-
- To receive callbacks for FL_RELEASE events, you must set
- when(FL_WHEN_RELEASE).
- </td>
- </tr><tr>
- <td><tt>Fl_Table::CONTEXT_RC_RESIZE</tt></td>
- <td>
- Someone is resizing rows/columns either interactively,
- or via the col_width() or row_height() API.
-
- Use is_interactive_resize()
- to determine interactive resizing.
-
- If resizing a column, R=0 and C=column being resized.
-
- If resizing a row, C=0 and R=row being resized.
-
- NOTE: To receive resize events, you must set when(FL_WHEN_CHANGED).
- </td>
- </tr>
- </table>
-
- \code
- class MyTable
- {
- [..]
- private:
- // Handle events that happen on the table
- void event_callback2()
- {
- int R = callback_row(), // row where event occurred
- C = callback_col(); // column where event occurred
- TableContext context = callback_context(); // which part of table
- fprintf(stderr, "callback: Row=%d Col=%d Context=%d Event=%d\n",
- R, C, (int)context, (int)Fl::event());
- }
-
- // Actual static callback
- static void event_callback(Fl_Widget*, void* data)
- {
- MyTable *o = (MyTable*)data;
- o-&gt;event_callback2();
- }
-
- public:
- MyTable() // Constructor
- {
- [..]
- table.callback(&event_callback, (void*)this); // setup callback
- table.when(FL_WHEN_CHANGED|FL_WHEN_RELEASE); // when to call it
- }
- };
- \endcode
- */
+ Callbacks will be called depending on the setting of Fl_Widget::when().
+
+ Callback functions should use the following functions to determine the
+ context/row/column:
+
+ * Fl_Table::callback_row() returns current row
+ * Fl_Table::callback_col() returns current column
+ * Fl_Table::callback_context() returns current table context
+
+ callback_row() and callback_col() will be set to the row and column number the
+ event occurred on. If someone clicked on a row header, \p col will be \a 0.
+ If someone clicked on a column header, \p row will be \a 0.
+
+ callback_context() will return one of the following:
+
+ <table border=1>
+ <tr><td><tt>Fl_Table::CONTEXT_ROW_HEADER</tt></td>
+ <td>Someone clicked on a row header. Excludes resizing.</td>
+ </tr><tr>
+ <td><tt>Fl_Table::CONTEXT_COL_HEADER</tt></td>
+ <td>Someone clicked on a column header. Excludes resizing.</td>
+ </tr><tr>
+ <td><tt>Fl_Table::CONTEXT_CELL</tt></td>
+ <td>
+ Someone clicked on a cell.
+
+ To receive callbacks for FL_RELEASE events, you must set
+ when(FL_WHEN_RELEASE).
+ </td>
+ </tr><tr>
+ <td><tt>Fl_Table::CONTEXT_RC_RESIZE</tt></td>
+ <td>
+ Someone is resizing rows/columns either interactively,
+ or via the col_width() or row_height() API.
+
+ Use is_interactive_resize()
+ to determine interactive resizing.
+
+ If resizing a column, R=0 and C=column being resized.
+
+ If resizing a row, C=0 and R=row being resized.
+
+ NOTE: To receive resize events, you must set when(FL_WHEN_CHANGED).
+ </td>
+ </tr>
+ </table>
+
+ \code
+ class MyTable
+ {
+ [..]
+ private:
+ // Handle events that happen on the table
+ void event_callback2()
+ {
+ int R = callback_row(), // row where event occurred
+ C = callback_col(); // column where event occurred
+ TableContext context = callback_context(); // which part of table
+ fprintf(stderr, "callback: Row=%d Col=%d Context=%d Event=%d\n",
+ R, C, (int)context, (int)Fl::event());
+ }
+
+ // Actual static callback
+ static void event_callback(Fl_Widget*, void* data)
+ {
+ MyTable *o = (MyTable*)data;
+ o-&gt;event_callback2();
+ }
+
+ public:
+ MyTable() // Constructor
+ {
+ [..]
+ table.callback(&event_callback, (void*)this); // setup callback
+ table.when(FL_WHEN_CHANGED|FL_WHEN_RELEASE); // when to call it
+ }
+ };
+ \endcode
+ */
void callback(Fl_Widget*, void*);
#endif
};
diff --git a/FL/Fl_Table_Row.H b/FL/Fl_Table_Row.H
index 593cf0b58..137993c94 100644
--- a/FL/Fl_Table_Row.H
+++ b/FL/Fl_Table_Row.H
@@ -98,7 +98,7 @@ private:
void size(int count) {
if ( count != _size ) {
arr = (char*)realloc(arr, count * sizeof(char));
- _size = count;
+ _size = count;
}
}
char pop_back() {
@@ -116,7 +116,7 @@ private:
}
};
CharVector _rowselect; // selection flag for each row
-
+
// handle() state variables.
// Put here instead of local statics in handle(), so more
// than one instance can exist without crosstalk between.
@@ -126,22 +126,22 @@ private:
int _last_y; // last event's Y position
int _last_push_x; // last PUSH event's X position
int _last_push_y; // last PUSH event's Y position
-
+
TableRowSelectMode _selectmode;
-
+
protected:
int handle(int event);
int find_cell(TableContext context, // find cell's x/y/w/h given r/c
- int R, int C, int &X, int &Y, int &W, int &H) {
+ int R, int C, int &X, int &Y, int &W, int &H) {
return(Fl_Table::find_cell(context, R, C, X, Y, W, H));
}
-
+
public:
/**
The constructor for the Fl_Table_Row.
This creates an empty table with no rows or columns,
with headers and row/column resize behavior disabled.
- */
+ */
Fl_Table_Row(int X, int Y, int W, int H, const char *l=0) : Fl_Table(X,Y,W,H,l) {
_dragging_select = 0;
_last_row = -1;
@@ -168,7 +168,7 @@ public:
- \p Fl_Table_Row::SELECT_NONE - No selection allowed
- \p Fl_Table_Row::SELECT_SINGLE - Only single rows can be selected
- \p Fl_Table_Row::SELECT_MULTI - Multiple rows can be selected
- */
+ */
void type(TableRowSelectMode val); // set selection mode
TableRowSelectMode type() const { // get selection mode
@@ -187,7 +187,7 @@ public:
of 'flag'. 0=deselected, 1=select, 2=toggle existing state.
*/
int select_row(int row, int flag=1); // select state for row: flag:0=off, 1=on, 2=toggle
- // returns: 0=no change, 1=changed, -1=range err
+ // returns: 0=no change, 1=changed, -1=range err
/**
This convenience function changes the selection state
diff --git a/FL/Fl_Tree.H b/FL/Fl_Tree.H
new file mode 100644
index 000000000..edef13b00
--- /dev/null
+++ b/FL/Fl_Tree.H
@@ -0,0 +1,647 @@
+#ifndef FL_TREE_H
+#define FL_TREE_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Group.H>
+#include <FL/Fl_Scrollbar.H>
+#include <FL/fl_draw.H>
+
+#include <FL/Fl_Tree_Item.H>
+#include <FL/Fl_Tree_Prefs.H>
+
+//////////////////////
+// FL/Fl_Tree.H
+//////////////////////
+//
+// Fl_Tree -- This file is part of the Fl_Tree widget for FLTK
+// Copyright (C) 2009 by Greg Ercolano.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+
+///
+/// \file
+/// \brief This file contains the definitions of the Fl_Tree class
+///
+
+/// \class Fl_Tree
+///
+/// \brief Tree widget.
+///
+/// \code
+/// Fl_Tree // Top level widget
+/// |--- Fl_Tree_Item // Items in the tree
+/// |--- Fl_Tree_Prefs // Preferences for the tree
+/// |--- Fl_Tree_Connector (enum) // Connection modes
+/// |--- Fl_Tree_Select (enum) // Selection modes
+/// |--- Fl_Tree_Sort (enum) // Sort behavior
+/// \endcode
+///
+/// An expandable tree widget.
+///
+/// Similar to Fl_Browser, Fl_Tree is browser of Fl_Tree_Item's, which can be
+/// in a parented hierarchy. Subtrees can be expanded or closed. Items can be
+/// added, deleted, inserted, sorted and re-ordered.
+///
+/// The tree items may also contain other FLTK widgets, like buttons, input fields,
+/// or even "custom" widgets.
+///
+/// The simple way to define a tree:
+/// \code
+/// Fl_Tree tree(X,Y,W,H);
+/// tree.begin();
+/// tree.add("Flintstones/Fred");
+/// tree.add("Flintstones/Wilma");
+/// tree.add("Flintstones/Pebbles");
+/// tree.add("Simpsons/Homer");
+/// tree.add("Simpsons/Marge");
+/// tree.add("Simpsons/Bart");
+/// tree.add("Simpsons/Lisa");
+/// 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().
+///
+/// The tree can have different selection behaviors controlled by Fl_Tree::selectmode().
+///
+/// FLTK and custom FLTK 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
+/// Fl_Tree_Item::openicon(),
+/// Fl_Tree_Item::closeicon(),
+/// Fl_Tree_Item::usericon().
+///
+/// Various default preferences can be manipulated vi Fl_Tree_Prefs, including
+/// colors, margins, connection lines.
+///
+/// \image html tree-elements.png
+///
+
+class Fl_Tree : public Fl_Group {
+ Fl_Tree_Item *_root; // can be null!
+ Fl_Tree_Item *_item_clicked;
+ Fl_Tree_Prefs _prefs; // all the tree's settings
+ Fl_Scrollbar *_vscroll;
+
+protected:
+ /// 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));
+ }
+ /// 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;
+ }
+
+public:
+ Fl_Tree(int X, int Y, int W, int H, const char *L=0);
+ ~Fl_Tree();
+ int handle(int e);
+ void draw();
+
+ ///////////////////////
+ // root methods
+ ///////////////////////
+
+ /// Set the label for the root item.
+ ///
+ /// Makes an internally managed copy of 'new_label'.
+ ///
+ void root_label(const char *new_label) {
+ if ( ! _root ) return;
+ _root->label(new_label);
+ }
+ /// Returns the root item.
+ Fl_Tree_Item* root() {
+ return(_root);
+ }
+
+ ////////////////////////////////
+ // Item creation/removal methods
+ ////////////////////////////////
+ Fl_Tree_Item *add(const char *path);
+ Fl_Tree_Item *insert_above(Fl_Tree_Item *above, const char *name);
+
+ /// Remove the specified 'item' from the tree.
+ /// If it has children, all those are removed too.
+ /// \returns 0 if done, -1 if 'item' not found.
+ ///
+ int remove(Fl_Tree_Item *item) {
+ if ( !item ) return(0);
+ if ( item == _root ) {
+ clear();
+ } else {
+ Fl_Tree_Item *parent = item->parent(); // find item's parent
+ if ( ! parent ) return(-1);
+ parent->remove_child(item); // remove child + children
+ }
+ return(0);
+ }
+ /// Clear all children from the tree.
+ /// The tree will be left completely empty.
+ ///
+ void clear() {
+ if ( ! _root ) return;
+ _root->clear_children();
+ delete _root; _root = 0;
+ }
+ /// Clear all the children of a particular node in the tree.
+ void clear_children(Fl_Tree_Item *item) {
+ if ( item->has_children() ) {
+ item->clear_children();
+ redraw(); // redraw only if there were children to clear
+ }
+ }
+
+ ////////////////////////
+ // Item lookup methods
+ ////////////////////////
+ Fl_Tree_Item *find_item(const char *path);
+ const Fl_Tree_Item *find_item(const char *path) const;
+
+ /// Return the parent for specified 'item'.
+ ///
+ /// \returns item's parent, or 0 if none (root).
+ ///
+ Fl_Tree_Item *parent(Fl_Tree_Item *item) {
+ return(item->parent());
+ }
+ /// Return the item that was last clicked.
+ ///
+ /// Valid only from within an Fl_Tree::callback().
+ ///
+ /// \returns the item clicked, or 0 if none.
+ ///
+ 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);
+ }
+
+ //////////////////////////
+ // Item open/close methods
+ //////////////////////////
+
+ /// Open the specified 'item'.
+ /// This causes the item's children (if any) to be shown.
+ /// Handles redrawing if anything was actually changed.
+ ///
+ void open(Fl_Tree_Item *item) {
+ if ( ! item->is_open() ) {
+ item->open();
+ redraw();
+ }
+ }
+ /// Opens the item specified by a 'menu item' style pathname (eg: "Parent/child/item").
+ /// This causes the item's children (if any) to be shown.
+ /// Handles redrawing if anything was actually changed.
+ ///
+ /// \returns
+ /// - 0 : OK
+ /// - -1 : item was not found
+ ///
+ int open(const char *path) {
+ Fl_Tree_Item *item = find_item(path);
+ if ( item ) {
+ open(item);
+ return(0);
+ }
+ return(-1);
+ }
+ /// Closes the 'item'.
+ /// Handles redrawing if anything was actually changed.
+ ///
+ void close(Fl_Tree_Item *item) {
+ if ( ! item->is_close() ) {
+ item->close();
+ redraw();
+ }
+ }
+ /// Closes the item specified by 'path', eg: "Parent/child/item".
+ ///
+ /// Handles redrawing if anything was actually changed.
+ ///
+ /// \returns
+ /// - 0 -- OK
+ /// - -1 -- item was not found
+ ///
+ int close(const char *path) {
+ Fl_Tree_Item *item = find_item(path);
+ if ( item ) {
+ close(item);
+ return(0);
+ }
+ return(-1);
+ }
+ /// See if item is open.
+ ///
+ /// Items that are 'open' are themselves not necessarily visible;
+ /// one of the item's parents might be closed.
+ ///
+ /// \returns
+ /// - 1 : item is open
+ /// - 0 : item is closed
+ ///
+ int is_open(Fl_Tree_Item *item) const {
+ return(item->is_open()?1:0);
+ }
+ /// See if item specified by 'path' (eg: "Parent/child/item") is open.
+ ///
+ /// Items that are 'open' are themselves not necessarily visible;
+ /// one of the item's parents might be closed.
+ ///
+ /// \returns
+ /// - 1 : item is open
+ /// - 0 : item is closed
+ /// - -1 : 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);
+ }
+ /// See if item is closed.
+ /// \returns
+ /// - 1 : item is open
+ /// - 0 : item is closed
+ ///
+ int is_close(Fl_Tree_Item *item) const {
+ return(item->is_close());
+ }
+ /// See if item specified by 'path' (eg: "Parent/child/item") is closed.
+ ///
+ /// \returns
+ /// - 1 : item is closed
+ /// - 0 : item is open
+ /// - -1 : 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);
+ }
+
+ /////////////////////////
+ // Item selection methods
+ /////////////////////////
+
+ /// Select the specified item. Use 'deselect()' to de-select it.
+ /// Handles redrawing if anything was actually changed.
+ ///
+ void select(Fl_Tree_Item *item) {
+ if ( ! item->is_selected() ) {
+ item->select();
+ redraw();
+ }
+ }
+ /// Select an item specified by 'path' (eg: "Parent/child/item").
+ /// Handles redrawing if anything was actually changed.
+ ///
+ /// \returns
+ /// - 0 : OK
+ /// - -1 : item was not found
+ ///
+ int select(const char *path) {
+ Fl_Tree_Item *item = find_item(path);
+ if ( item ) {
+ select(item);
+ return(0);
+ }
+ return(-1);
+ }
+ /// Toggle item's select state.
+ /// Handles redrawing.
+ ///
+ void select_toggle(Fl_Tree_Item *item) {
+ item->select_toggle();
+ redraw();
+ }
+ /// De-select the specified item.
+ /// Handles redrawing if anything was actually changed.
+ ///
+ void deselect(Fl_Tree_Item *item) {
+ if ( item->is_selected() ) {
+ item->deselect();
+ redraw();
+ }
+ }
+ /// De-select an item specified by 'path' (eg: "Parent/child/item").
+ /// Handles redrawing if anything was actually changed.
+ ///
+ /// \returns
+ /// - 0 : OK
+ /// - -1 : item was not found
+ ///
+ int deselect(const char *path) {
+ Fl_Tree_Item *item = find_item(path);
+ if ( item ) {
+ deselect(item);
+ return(0);
+ }
+ return(-1);
+ }
+
+ int deselect_all(Fl_Tree_Item *item=0);
+ int select_only(Fl_Tree_Item *selitem);
+
+ /// See if the specified item is selected.
+ /// \return
+ /// - 1 : item selected
+ /// - 0 : item deselected
+ ///
+ int is_selected(Fl_Tree_Item *item) const {
+ return(item->is_selected()?1:0);
+ }
+ /// See if item specified by 'path' (eg: "Parent/child/item") is selected.
+ ///
+ /// \returns
+ /// - 1 : item selected
+ /// - 0 : item deselected
+ /// - -1 : item was not found
+ ///
+ int is_selected(const char *path) {
+ Fl_Tree_Item *item = find_item(path);
+ if ( item ) return(is_selected(item));
+ return(-1);
+ }
+ /// Print the tree as 'ascii art' to stdout.
+ /// Used mainly for debugging.
+ ///
+ void show_self() {
+ if ( ! _root ) return;
+ _root->show_self();
+ }
+
+ /////////////////////////////////
+ // Item attribute related methods
+ /////////////////////////////////
+
+ /// Get the default label fontsize used for creating new items.
+ int labelsize() const {
+ return(_prefs.labelsize());
+ }
+ /// Set the default label font size used for creating new items.
+ /// To change the font size on a per-item basis, use Fl_Tree_Item::labelsize(int)
+ ///
+ void labelsize(int val) {
+ _prefs.labelsize(val);
+ }
+
+ /// Get the default font face used for item's labels when new items are created.
+ ///
+ /// Don't use this if you want to change an existing label() size; use
+ /// item->labelfont() instead.
+ ///
+ int labelfont() const {
+ return(_prefs.labelfont());
+ }
+ /// Set the default font face used for item's labels when new items are created.
+ ///
+ /// Don't use this if you want to change an existing label() size; use
+ /// item->labelfont(int) instead.
+ ///
+ void labelfont(int val) {
+ _prefs.labelfont(val);
+ }
+ /// Get the amount of white space (in pixels) that should appear
+ /// between the widget's left border and the tree's contents.
+ ///
+ int marginleft() const {
+ return(_prefs.marginleft());
+ }
+ /// Set the amount of white space (in pixels) that should appear
+ /// between the widget's left border and the left side of the tree's contents.
+ ///
+ void marginleft(int val) {
+ _prefs.marginleft(val);
+ redraw();
+ }
+ /// Get the amount of white space (in pixels) that should appear
+ /// between the widget's top border and the top of the tree's contents.
+ ///
+ int margintop() const {
+ return(_prefs.margintop());
+ }
+ /// Sets the amount of white space (in pixels) that should appear
+ /// between the widget's top border and the top of the tree's contents.
+ ///
+ void margintop(int val) {
+ _prefs.margintop(val);
+ redraw();
+ }
+ /// Get the amount of white space (in pixels) that should appear
+ /// below an open child tree's contents.
+ ///
+ int openchild_marginbottom() const {
+ return(_prefs.openchild_marginbottom());
+ }
+ /// Set the amount of white space (in pixels) that should appear
+ /// below an open child tree's contents.
+ ///
+ void openchild_marginbottom(int val) {
+ _prefs.openchild_marginbottom(val);
+ redraw();
+ }
+ /// Gets the width of the horizontal connection lines (in pixels)
+ /// that appear to the left of each tree item's label.
+ ///
+ int connectorwidth() const {
+ return(_prefs.connectorwidth());
+ }
+ /// Sets the width of the horizontal connection lines (in pixels)
+ /// that appear to the left of each tree item's label.
+ ///
+ void connectorwidth(int val) {
+ _prefs.connectorwidth(val);
+ redraw();
+ }
+ /// Returns the Fl_Pixmap being used as the default user icon for newly created items.
+ /// Returns zero if no icon has been set, which is the default.
+ ///
+ Fl_Pixmap *usericon() const {
+ return(_prefs.usericon());
+ }
+ /// Sets the Fl_Pixmap to be used as the default user icon for all
+ /// newly created items.
+ ///
+ /// If you want to specify user icons on a per-item basis,
+ /// use Fl_Tree_Item::usericon() instead.
+ ///
+ /// \param[in] val -- The new pixmap to be used, or
+ /// zero to disable user icons.
+ ///
+ void usericon(Fl_Pixmap *val) {
+ _prefs.usericon(val);
+ redraw();
+ }
+ /// Returns the icon to be used as the 'open' icon.
+ /// If none was set, the internal default is returned,
+ /// a simple '[+]' icon.
+ ///
+ Fl_Pixmap *openicon() const {
+ return(_prefs.openicon());
+ }
+ /// Sets the icon to be used as the 'open' icon.
+ /// This overrides the built in default '[+]' icon.
+ ///
+ /// \param[in] val -- The new pixmap, or zero to use the default [+] icon.
+ ///
+ void openicon(Fl_Pixmap *val) {
+ _prefs.openicon(val);
+ redraw();
+ }
+ /// Returns the icon to be used as the 'close' icon.
+ /// If none was set, the internal default is returned,
+ /// a simple '[-]' icon.
+ ///
+ Fl_Pixmap *closeicon() const {
+ return(_prefs.closeicon());
+ }
+ /// Sets the icon to be used as the 'close' icon.
+ /// This overrides the built in default '[-]' icon.
+ ///
+ /// \param[in] val -- The new pixmap, or zero to use the default [-] icon.
+ ///
+ void closeicon(Fl_Pixmap *val) {
+ _prefs.closeicon(val);
+ redraw();
+ }
+ /// Returns 1 if the collapse icon is enabled, 0 if not.
+ int showcollapse() const {
+ return(_prefs.showcollapse());
+ }
+ /// Set if we should show the collapse icon or not.
+ /// If collapse icons are disabled, the user will not be able
+ /// to interactively collapse items in the tree, unless the application
+ /// provides some other means via open() and close().
+ ///
+ /// \param[in] val 1: shows collapse icons (default),\n
+ /// 0: hides collapse icons.
+ ///
+ void showcollapse(int val) {
+ _prefs.showcollapse(val);
+ redraw();
+ }
+ /// Returns 1 if the root item is to be shown, or 0 if not.
+ int showroot() const {
+ return(_prefs.showroot());
+ }
+ /// Set if the root item should be shown or not.
+ /// \param[in] val 1 -- show the root item (default)\n
+ /// 0 -- hide the root item.
+ ///
+ void showroot(int val) {
+ _prefs.showroot(val);
+ redraw();
+ }
+ /// Returns the line drawing style for inter-connecting items.
+ Fl_Tree_Connector connectorstyle() const {
+ return(_prefs.connectorstyle());
+ }
+ /// Sets the line drawing style for inter-connecting items.
+ void connectorstyle(Fl_Tree_Connector val) {
+ _prefs.connectorstyle(val);
+ redraw();
+ }
+ /// Set the default sort order used when items are added to the tree.
+ /// See Fl_Tree_Sort for possible values.
+ ///
+ Fl_Tree_Sort sortorder() const {
+ return(_prefs.sortorder());
+ }
+ /// Gets the sort order used to add items to the tree.
+ void sortorder(Fl_Tree_Sort val) {
+ _prefs.sortorder(val);
+ // no redraw().. only affects new add()itions
+ }
+ /// Sets the style of box used to draw selected items.
+ /// This is an fltk Fl_Boxtype.
+ /// The default is influenced by FLTK's current Fl::scheme()
+ ///
+ Fl_Boxtype selectbox() const {
+ return(_prefs.selectbox());
+ }
+ /// Gets the style of box used to draw selected items.
+ /// This is an fltk Fl_Boxtype.
+ /// The default is influenced by FLTK's current Fl::scheme()
+ ///
+ void selectbox(Fl_Boxtype val) {
+ _prefs.selectbox(val);
+ redraw();
+ }
+ /// Gets the tree's current selection mode.
+ Fl_Tree_Select selectmode() const {
+ return(_prefs.selectmode());
+ }
+ /// Sets the tree's selection mode.
+ void selectmode(Fl_Tree_Select val) {
+ _prefs.selectmode(val);
+ }
+};
+
+#endif /*FL_TREE_H*/
diff --git a/FL/Fl_Tree_Item.H b/FL/Fl_Tree_Item.H
new file mode 100644
index 000000000..388dce790
--- /dev/null
+++ b/FL/Fl_Tree_Item.H
@@ -0,0 +1,291 @@
+#ifndef FL_TREE_ITEM_H
+#define FL_TREE_ITEM_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Widget.H>
+#include <FL/Fl_Pixmap.H>
+#include <FL/fl_draw.H>
+
+#include <FL/Fl_Tree_Item_Array.H>
+#include <FL/Fl_Tree_Prefs.H>
+
+//////////////////////
+// FL/Fl_Tree_Item.H
+//////////////////////
+//
+// Fl_Tree -- This file is part of the Fl_Tree widget for FLTK
+// Copyright (C) 2009 by Greg Ercolano.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+
+///
+/// \file
+/// \brief This file contains the definitions for Fl_Tree_Item
+///
+
+/// \brief Tree item
+///
+/// This class is a single tree item, and manages all of the item's attributes.
+/// Fl_Tree_Item is used by Fl_Tree, which is comprised of many instances of Fl_Tree_Item.
+///
+/// Fl_Tree_Item is hierarchical; it dynamically manages an Fl_Tree_Item_Array of children
+/// that are themselves instances of Fl_Tree_Item. Each item can have zero or more children.
+/// When an item has children, close() and open() can be used to hide or show them.
+///
+/// Items have their own attributes; font size, face, color.
+/// Items maintain their own hierarchy of children.
+///
+/// When you make changes to items, you'll need to tell the tree to redraw()
+/// for the changes to show up.
+///
+class Fl_Tree_Item {
+ const char *_label; // label (memory managed)
+ int _labelfont; // label's font face
+ int _labelsize; // label's font size
+ Fl_Color _labelfgcolor; // label's fg color
+ Fl_Color _labelbgcolor; // label's bg color
+ char _open; // item is open?
+ char _visible; // item is visible?
+ char _active; // item activated?
+ char _selected; // item selected?
+ int _xywh[4]; // xywh of this widget (if visible)
+ int _collapse_xywh[4]; // xywh of collapse icon (if any)
+ int _label_xywh[4]; // xywh of label
+ Fl_Widget *_widget; // item's label widget (optional)
+ Fl_Pixmap *_usericon; // item's user-specific icon (optional)
+ Fl_Tree_Item_Array _children; // array of child items
+ Fl_Tree_Item *_parent; // parent item (=0 if root)
+protected:
+ void show_widgets();
+ void hide_widgets();
+ void draw_vertical_connector(int x, int y1, int y2, const Fl_Tree_Prefs &prefs);
+ void draw_horizontal_connector(int x1, int x2, int y, const Fl_Tree_Prefs &prefs);
+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);
+ void show_self(const char *indent = "") const;
+ void label(const char *val);
+ const char *label() const;
+
+ /// Set item's label font face.
+ void labelfont(int val) {
+ _labelfont = val;
+ }
+ /// Get item's label font face.
+ int labelfont() const {
+ return(_labelfont);
+ }
+ /// Set item's label font size.
+ void labelsize(int val) {
+ _labelsize = val;
+ }
+ /// Get item's label font size.
+ int labelsize() const {
+ return(_labelsize);
+ }
+ /// Set item's label foreground text color.
+ void labelfgcolor(Fl_Color val) {
+ _labelfgcolor = val;
+ }
+ /// Set item's label text color.
+ void labelcolor(Fl_Color val) {
+ _labelfgcolor = val;
+ }
+ /// Return item's label text color.
+ Fl_Color labelcolor() const {
+ return(_labelfgcolor);
+ }
+ /// Return item's label foreground text color.
+ Fl_Color labelfgcolor() const {
+ return(_labelfgcolor);
+ }
+ /// Set item's label background color.
+ void labelbgcolor(Fl_Color val) {
+ _labelbgcolor = val;
+ }
+ /// Return item's background text color.
+ Fl_Color labelbgcolor() const {
+ return(_labelbgcolor);
+ }
+ /// Assign an FLTK widget to this item.
+ void widget(Fl_Widget *val) {
+ _widget = val;
+ }
+ /// Return FLTK widget assigned to this item.
+ Fl_Widget *widget() const {
+ return(_widget);
+ }
+ /// Return the number of children this item has.
+ int children() const {
+ return(_children.total());
+ }
+ /// Return the child item for the given 'index'.
+ Fl_Tree_Item *child(int index) {
+ return(_children[index]);
+ }
+ /// Return the const child item for the given 'index'.
+ const Fl_Tree_Item *child(int t) const;
+ /// See if this item has children.
+ int has_children() const {
+ return(children());
+ }
+ int find_child(const char *name);
+ int find_child(Fl_Tree_Item *item);
+ int remove_child(Fl_Tree_Item *item);
+ int remove_child(const char *new_label);
+ 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);
+ //////////////////
+ // Adding items
+ //////////////////
+ Fl_Tree_Item *add(const Fl_Tree_Prefs &prefs, const char *new_label);
+ Fl_Tree_Item *add(const Fl_Tree_Prefs &prefs, char **arr);
+ Fl_Tree_Item *insert(const Fl_Tree_Prefs &prefs, const char *new_label, int pos=0);
+ Fl_Tree_Item *insert_above(const Fl_Tree_Prefs &prefs, const char *new_label);
+ int depth() const;
+ Fl_Tree_Item *prev();
+ Fl_Tree_Item *next();
+
+ /// Return the parent for this item.
+ Fl_Tree_Item *parent() {
+ return(_parent);
+ }
+ /// Return the const parent for this item.
+ const Fl_Tree_Item *parent() const {
+ return(_parent);
+ }
+ /// Set the parent for this item.
+ /// Should only be used by Fl_Tree's internals.
+ ///
+ void parent(Fl_Tree_Item *val) {
+ _parent = val;
+ }
+ //////////////////
+ // State
+ //////////////////
+ void open();
+ void close();
+ /// See if the item is 'open'.
+ int is_open() const {
+ return(_open?1:0);
+ }
+ /// See if the item is 'closed'.
+ int is_close() const {
+ return(_open?0:1);
+ }
+ /// Toggle the item's open/closed state.
+ void open_toggle() {
+ _open?close():open();
+ }
+ /// Change the item's selection state to the optionally specified 'val'.
+ /// If 'val' is not specified, the item will be selected.
+ ///
+ void select(int val=1) {
+ _selected = val;
+ }
+ /// Toggle the item's selection state.
+ void select_toggle() {
+ if ( is_selected() ) {
+ deselect(); // deselect if selected
+ } else {
+ select(); // select if deselected
+ }
+ }
+ /// Disable the item's selection state.
+ void deselect() {
+ _selected = 0;
+ }
+ /// Deselect self and all children
+ /// Returns count of how many items were in the 'selected' state,
+ /// ie. how many items were "changed".
+ ///
+ int deselect_all() {
+ int count = 0;
+ if ( is_selected() ) {
+ deselect();
+ ++count;
+ }
+ for ( int t=0; t<children(); t++ ) {
+ count += child(t)->deselect_all();
+ }
+ return(count);
+ }
+ /// See if the item is selected.
+ char is_selected() const {
+ return(_selected);
+ }
+ /// Change the item's activation state to the optionally specified 'val'.
+ ///
+ /// When deactivated, the item will be 'grayed out'; the callback()
+ /// won't be invoked if the user clicks on the label. If the item
+ /// has a widget() associated with the item, its activation state
+ /// will be changed as well.
+ ///
+ /// If 'val' is not specified, the item will be activated.
+ ///
+ void activate(int val=1) {
+ _active = val;
+ if ( _widget && val != (int)_widget->active() ) {
+ if ( val ) {
+ _widget->activate();
+ } else {
+ _widget->deactivate();
+ }
+ _widget->redraw();
+ }
+ }
+ /// Deactivate the item; the callback() won't be invoked when clicked.
+ /// Same as activate(0)
+ ///
+ void deactivate() {
+ activate(0);
+ }
+ /// See if the item is activated.
+ char is_activated() const {
+ return(_active);
+ }
+ /// See if the item is activated.
+ char is_active() const {
+ return(_active);
+ }
+ /// Set the user icon's pixmap. '0' will disable.
+ void usericon(Fl_Pixmap *val) {
+ _usericon = val;
+ }
+ /// Get the user icon. Returns '0' if disabled.
+ Fl_Pixmap *usericon() const {
+ return(_usericon);
+ }
+ //////////////////
+ // Events
+ //////////////////
+ const Fl_Tree_Item *find_clicked(const Fl_Tree_Prefs &prefs) const;
+ Fl_Tree_Item *find_clicked(const Fl_Tree_Prefs &prefs);
+ int event_on_collapse_icon(const Fl_Tree_Prefs &prefs) const;
+ int event_on_label(const Fl_Tree_Prefs &prefs) const;
+ /// Is this item the root of the tree?
+ int is_root() const {
+ return(_parent==0?1:0);
+ }
+};
+
+#endif /*FL_TREE_ITEM_H*/
diff --git a/FL/Fl_Tree_Item_Array.H b/FL/Fl_Tree_Item_Array.H
new file mode 100644
index 000000000..7e31862eb
--- /dev/null
+++ b/FL/Fl_Tree_Item_Array.H
@@ -0,0 +1,80 @@
+#ifndef _FL_TREE_ITEM_ARRAY_H
+#define _FL_TREE_ITEM_ARRAY_H
+
+class Fl_Tree_Item; // forward decl must *precede* first doxygen comment block
+// or doxygen will not document our class..
+
+//////////////////////
+// FL/Fl_Tree_Item_Array.H
+//////////////////////
+//
+// Fl_Tree -- This file is part of the Fl_Tree widget for FLTK
+// Copyright (C) 2009 by Greg Ercolano.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+
+///
+/// \file
+/// \brief This file defines a class that manages an array of Fl_Tree_Item pointers.
+///
+
+/// \brief Manages an array of Fl_Tree_Item pointers.
+///
+/// Because FLTK 1.x.x. has mandated that templates and STL not be used,
+/// we use this class to dynamically manage the arrays.
+///
+/// None of the methods do range checking on index values; the caller
+/// must be sure that index values are within the range 0<index<total()
+/// (unless otherwise noted).
+///
+
+class Fl_Tree_Item_Array {
+ Fl_Tree_Item **_items; // items array
+ int _total; // #items in array
+ int _size; // #items *allocated* for array
+ int _chunksize; // #items to enlarge mem allocation
+ void enlarge(int count);
+public:
+ Fl_Tree_Item_Array(int new_chunksize = 10); // CTOR
+ ~Fl_Tree_Item_Array(); // DTOR
+ Fl_Tree_Item_Array(const Fl_Tree_Item_Array *o); // COPY CTOR
+ /// Return the item and index \p i.
+ Fl_Tree_Item *operator[](int i) {
+ return(_items[i]);
+ }
+ /// Const version of operator[](int i)
+ const Fl_Tree_Item *operator[](int i) const {
+ return(_items[i]);
+ }
+ /// Return the total items in the array, or 0 if empty.
+ int total() const {
+ return(_total);
+ }
+ /// Swap the two items at index positions \p ax and \p bx.
+ void swap(int ax, int bx) {
+ Fl_Tree_Item *asave = _items[ax];
+ _items[ax] = _items[bx];
+ _items[bx] = asave;
+ }
+ void clear();
+ void add(Fl_Tree_Item *val);
+ void insert(int pos, Fl_Tree_Item *new_item);
+ void remove(int index);
+ int remove(Fl_Tree_Item *item);
+};
+
+#endif /*_FL_TREE_ITEM_ARRAY_H*/
diff --git a/FL/Fl_Tree_Prefs.H b/FL/Fl_Tree_Prefs.H
new file mode 100644
index 000000000..36cecefa5
--- /dev/null
+++ b/FL/Fl_Tree_Prefs.H
@@ -0,0 +1,353 @@
+#ifndef FL_TREE_PREFS_H
+#define FL_TREE_PREFS_H
+
+//////////////////////
+// FL/Fl_Tree_Prefs.H
+//////////////////////
+//
+// Fl_Tree -- This file is part of the Fl_Tree widget for FLTK
+// Copyright (C) 2009 by Greg Ercolano.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+
+///
+/// \file
+/// \brief This file contains the definitions for Fl_Tree's preferences.
+///
+/// \code
+/// Fl_Tree_Prefs
+/// :
+/// .....:.......
+/// : :
+/// Fl_Tree :
+/// |_____ Fl_Tree_Item
+///
+/// \endcode
+///
+
+/// \class Fl_Tree_Prefs
+/// \brief Tree widget's preferences.
+
+/// \enum Fl_Tree_Sort
+/// Sort order options for items added to the tree
+///
+enum Fl_Tree_Sort {
+ FL_TREE_SORT_NONE=0, ///< No sorting; items are added in the order defined (default).
+ FL_TREE_SORT_ASCENDING=1, ///< Add items in ascending sort order.
+ FL_TREE_SORT_DESCENDING=2 ///< Add items in descending sort order.
+};
+
+/// \enum Fl_Tree_Connector
+/// Defines the style of connection lines between items.
+///
+enum Fl_Tree_Connector {
+ FL_TREE_CONNECTOR_NONE=0, ///< Use no lines connecting items
+ FL_TREE_CONNECTOR_DOTTED=1, ///< Use dotted lines connecting items (default)
+ FL_TREE_CONNECTOR_SOLID=2 ///< Use solid lines connecting items
+};
+
+/// \enum Fl_Tree_Select
+/// Tree selection style.
+///
+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
+ ///< SHIFT or CTRL or mouse drags.
+};
+
+/// \class Fl_Tree_Prefs
+///
+/// \brief Fl_Tree's Preferences class.
+///
+/// This class manages the Fl_Tree's defaults.
+/// You should probably be using the methods in Fl_Tree
+/// instead of trying to accessing tree's preferences settings directly.
+///
+class Fl_Tree_Prefs {
+ int _labelfont; // label's font face
+ int _labelsize; // label's font size
+ int _margintop; // --
+ int _marginleft; // |- tree's margins
+ //int _marginright; // |
+ //int _marginbottom; // --
+ int _openchild_marginbottom; // extra space below an open child tree
+ int _usericonmarginleft; // space to left of user icon (if any)
+ int _labelmarginleft; // space to left of label
+ int _connectorwidth; // connector width (right of open/close icon)
+ int _linespacing; // vertical space between lines
+ // Colors
+ Fl_Color _fgcolor; // label's foreground color
+ Fl_Color _bgcolor; // background color
+ Fl_Color _selectcolor; // selection color
+ Fl_Color _inactivecolor; // inactive color
+ Fl_Color _connectorcolor; // connector dotted line color
+ Fl_Tree_Connector _connectorstyle; // connector line style
+ Fl_Pixmap *_openpixmap; // the 'open' icon [+]
+ Fl_Pixmap *_closepixmap; // the 'close' icon [-]
+ Fl_Pixmap *_userpixmap; // user's own icon
+ char _showcollapse; // 1=show collapse icons, 0=don't
+ char _showroot; // show the root item as part of the tree
+ Fl_Tree_Sort _sortorder; // none, ascening, descending, etc.
+ Fl_Boxtype _selectbox; // selection box type
+ Fl_Tree_Select _selectmode; // selection mode
+public:
+ Fl_Tree_Prefs();
+
+ ////////////////////////////
+ // Labels
+ ////////////////////////////
+ /// Return the label's font.
+ inline int labelfont() const {
+ return(_labelfont);
+ }
+ /// Set the label's font to \p val.
+ inline void labelfont(int val) {
+ _labelfont = val;
+ }
+ /// Return the label's size in pixels.
+ inline int labelsize() const {
+ return(_labelsize);
+ }
+ /// Set the label's size in pixels to \p val.
+ inline void labelsize(int val) {
+ _labelsize = val;
+ }
+
+ ////////////////////////////
+ // Margins
+ ////////////////////////////
+ /// Get the left margin's value in pixels
+ inline int marginleft() const {
+ return(_marginleft);
+ }
+ /// Set the left margin's value in pixels
+ inline void marginleft(int val) {
+ _marginleft = val;
+ }
+ /// Get the top margin's value in pixels
+ inline int margintop() const {
+ return(_margintop);
+ }
+ /// Set the top margin's value in pixels
+ inline void margintop(int val) {
+ _margintop = val;
+ }
+ /// Get the margin below an open child in pixels
+ inline int openchild_marginbottom() const {
+ return(_openchild_marginbottom);
+ }
+ /// Set the margin below an open child in pixels
+ inline void openchild_marginbottom(int val) {
+ _openchild_marginbottom = val;
+ }
+
+ /****** NOT IMPLEMENTED
+ inline int marginright() const {
+ return(_marginright);
+ }
+ inline void marginright(int val) {
+ _marginright = val;
+ }
+ inline int marginbottom() const {
+ return(_marginbottom);
+ }
+ inline void marginbottom(int val) {
+ _marginbottom = val;
+ }
+ *******/
+
+ /// Get the user icon's left margin value in pixels
+ inline int usericonmarginleft() const {
+ return(_usericonmarginleft);
+ }
+ /// Set the user icon's left margin value in pixels
+ inline void usericonmarginleft(int val) {
+ _usericonmarginleft = val;
+ }
+ /// Get the label's left margin value in pixels
+ inline int labelmarginleft() const {
+ return(_labelmarginleft);
+ }
+ /// Set the label's left margin value in pixels
+ inline void labelmarginleft(int val) {
+ _labelmarginleft = val;
+ }
+ /// Get the line spacing value in pixels
+ inline int linespacing() const {
+ return(_linespacing);
+ }
+ /// Set the line spacing value in pixels
+ inline void linespacing(int val) {
+ _linespacing = val;
+ }
+
+ ////////////////////////////
+ // Colors and Styles
+ ////////////////////////////
+ /// Get the default label foreground color
+ inline Fl_Color fgcolor() const {
+ return(_fgcolor);
+ }
+ /// Set the default label foreground color
+ inline void fgcolor(Fl_Color val) {
+ _fgcolor = val;
+ }
+ /// Get the default label background color
+ inline Fl_Color bgcolor() const {
+ return(_bgcolor);
+ }
+ /// Set the default label background color
+ inline void bgcolor(Fl_Color val) {
+ _bgcolor = val;
+ }
+ /// Get the default selection color
+ inline Fl_Color selectcolor() const {
+ return(_selectcolor);
+ }
+ /// Set the default selection color
+ inline void selectcolor(Fl_Color val) {
+ _selectcolor = val;
+ }
+ /// Get the default inactive color
+ inline Fl_Color inactivecolor() const {
+ return(_inactivecolor);
+ }
+ /// Set the default inactive color
+ inline void inactivecolor(Fl_Color val) {
+ _inactivecolor = val;
+ }
+ /// Get the connector color; the color used for tree connection lines
+ inline Fl_Color connectorcolor() const {
+ return(_connectorcolor);
+ }
+ /// Set the connector color; the color used for tree connection lines
+ inline void connectorcolor(Fl_Color val) {
+ _connectorcolor = val;
+ }
+ /// Get the connector style
+ inline Fl_Tree_Connector connectorstyle() const {
+ return(_connectorstyle);
+ }
+ /// Set the connector style
+ inline void connectorstyle(Fl_Tree_Connector val) {
+ _connectorstyle = val;
+ }
+ /// Set the connector style [integer].
+ inline void connectorstyle(int val) {
+ _connectorstyle = Fl_Tree_Connector(val);
+ }
+ /// Get the tree connection line's width
+ inline int connectorwidth() const {
+ return(_connectorwidth);
+ }
+ /// Set the tree connection line's width
+ inline void connectorwidth(int val) {
+ _connectorwidth = val;
+ }
+
+ ////////////////////////////
+ // Icons
+ ////////////////////////////
+ /// Get the current default 'open' icon.
+ /// Returns the Fl_Pixmap* of the icon, or 0 if none.
+ ///
+ inline Fl_Pixmap *openicon() const {
+ return(_openpixmap);
+ }
+ void openicon(Fl_Pixmap *val);
+ /// Gets the default 'close' icon
+ /// Returns the Fl_Pixmap* of the icon, or 0 if none.
+ ///
+ inline Fl_Pixmap *closeicon() const {
+ return(_closepixmap);
+ }
+ void closeicon(Fl_Pixmap *val);
+ /// Gets the default 'user icon' (default is 0)
+ inline Fl_Pixmap *usericon() const {
+ return(_userpixmap);
+ }
+ /// Sets the default 'user icon'
+ /// Returns the Fl_Pixmap* of the icon, or 0 if none (default).
+ ///
+ inline void usericon(Fl_Pixmap *val) {
+ _userpixmap = val;
+ }
+
+ ////////////////////////////
+ // Options
+ ////////////////////////////
+ /// Returns 1 if the collapse icon is enabled, 0 if not.
+ inline char showcollapse() const {
+ return(_showcollapse);
+ }
+ /// Set if we should show the collapse icon or not.
+ /// If collapse icons are disabled, the user will not be able
+ /// to interactively collapse items in the tree, unless the application
+ /// provides some other means via open() and close().
+ ///
+ /// \param[in] val 1: shows collapse icons (default),\n
+ /// 0: hides collapse icons.
+ ///
+ inline void showcollapse(int val) {
+ _showcollapse = val;
+ }
+ /// Get the default sort order value
+ inline Fl_Tree_Sort sortorder() const {
+ return(_sortorder);
+ }
+ /// Set the default sort order value.
+ /// Defines the order new items appear when add()ed to the tree.
+ /// See Fl_Tree_Sort for possible values.
+ ///
+ inline void sortorder(Fl_Tree_Sort val) {
+ _sortorder = val;
+ }
+ /// Get the default selection box's box drawing style as an Fl_Boxtype.
+ inline Fl_Boxtype selectbox() const {
+ return(_selectbox);
+ }
+ /// Set the default selection box's box drawing style to \p val.
+ inline void selectbox(Fl_Boxtype val) {
+ _selectbox = val;
+ }
+ /// Returns 1 if the root item is to be shown, or 0 if not.
+ inline int showroot() const {
+ return(int(_showroot));
+ }
+ /// Set if the root item should be shown or not.
+ /// \param[in] val 1 -- show the root item (default)\n
+ /// 0 -- hide the root item.
+ ///
+ inline void showroot(int val) {
+ _showroot = char(val);
+ }
+ /// Get the selection mode used for the tree
+ inline Fl_Tree_Select selectmode() const {
+ return(_selectmode);
+ }
+ /// Set the selection mode used for the tree to \p val.
+ /// This affects how items in the tree are selected
+ /// when clicked on and dragged over by the mouse.
+ /// See Fl_Tree_Select for possible values.
+ ///
+ inline void selectmode(Fl_Tree_Select val) {
+ _selectmode = val;
+ }
+};
+
+#endif /*FL_TREE_PREFS_H*/