diff --git a/FL/Fl_Table.H b/FL/Fl_Table.H index bce52bb3e..8c8dabe97 100644 --- a/FL/Fl_Table.H +++ b/FL/Fl_Table.H @@ -35,145 +35,95 @@ #include /** - A table of widgets or other content. + A table of widgets or other content. - This is the base class for table widgets. + This is the base class for table widgets. - To be useful it must be subclassed and several virtual functions defined. - 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. + To be useful it must be subclassed and several virtual functions defined. + 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 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: + This widget can be used in several ways: - - As a custom widget; see examples/table-simple.cxx and test/table.cxx. - Very optimal for even extremely large tables. - - As a table made up of a single FLTK widget instanced all over the table, - simulating a numeric spreadsheet. See examples/table-spreadsheet.cxx and - examples/table-spreadsheet-with-keyboard-nav.cxx. Optimal for large tables. - - As a regular container of FLTK widgets, one widget per cell. - See examples/table-as-container.cxx. \em Not recommended for large tables. + - As a custom widget; see examples/table-simple.cxx and test/table.cxx. + Very optimal for even extremely large tables. + - As a table made up of a single FLTK widget instanced all over the table, + simulating a numeric spreadsheet. See examples/table-spreadsheet.cxx and + examples/table-spreadsheet-with-keyboard-nav.cxx. Optimal for large tables. + - As a regular container of FLTK widgets, one widget per cell. + See examples/table-as-container.cxx. \em Not recommended for large tables. - \image html table-simple.png - \image latex table-simple.png "table-simple example" width=6cm + \image html table-simple.png + \image latex table-simple.png "table-simple example" width=6cm - \image html table-as-container.png - \image latex table-as-container.png "table-as-container example" width=6cm + \image html table-as-container.png + \image latex table-as-container.png "table-as-container example" width=6cm - 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 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 examples/table-simple.cxx. + 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 examples/table-simple.cxx. - The following variables are available to classes deriving from Fl_Table: + The following variables are available to classes deriving from Fl_Table: - \image html table-dimensions.png - \image latex table-dimensions.png "Fl_Table Dimensions" width=6cm + \image html table-dimensions.png + \image latex table-dimensions.png "Fl_Table Dimensions" width=6cm - - - +
x()/y()/w()/h()Fl_Table widget's outer dimension. The outer edge of the border of the - Fl_Table. (Red in the diagram above)
+ + - - + + - - + + - -
x()/y()/w()/h()Fl_Table widget's outer dimension. The outer edge of the border of the + Fl_Table. (Red in the diagram above)
wix/wiy/wiw/wihFl_Table widget's inner dimension. The inner edge of the border of the - Fl_Table. eg. if the Fl_Table's box() is FL_NO_BOX, these values are the same - as x()/y()/w()/h(). (Yellow in the diagram above)
wix/wiy/wiw/wihFl_Table widget's inner dimension. The inner edge of the border of the + Fl_Table. eg. if the Fl_Table's box() is FL_NO_BOX, these values are the same + as x()/y()/w()/h(). (Yellow in the diagram above)
tox/toy/tow/tohThe table's outer dimension. The outer edge of the border around the cells, - but inside the row/col headings and scrollbars. (Green in the diagram above) -
tox/toy/tow/tohThe table's outer dimension. The outer edge of the border around the cells, + but inside the row/col headings and scrollbars. (Green in the diagram above) +
tix/tiy/tiw/tihThe table's inner dimension. The inner edge of the border around the cells, - but inside the row/col headings and scrollbars. AKA the table's clip region. - eg. if the table_box() is FL_NO_BOX, these values are the same as - tox/toy/tow/toh. (Blue in the diagram above) -
+ tix/tiy/tiw/tih + The table's inner dimension. The inner edge of the border around the cells, + but inside the row/col headings and scrollbars. AKA the table's clip region. + eg. if the table_box() is FL_NO_BOX, these values are the same as + tox/toy/tow/toh. (Blue in the diagram above) + - CORE DEVELOPERS + CORE DEVELOPERS - - Greg Ercolano : 12/16/2002 - initial implementation 12/16/02. Fl_Table, Fl_Table_Row, docs. - - Jean-Marc Lienher : 02/22/2004 - added keyboard nav + mouse selection, and ported Fl_Table into fltk-utf8-1.1.4 + - Greg Ercolano : 12/16/2002 - initial implementation 12/16/02. Fl_Table, Fl_Table_Row, docs. + - Jean-Marc Lienher : 02/22/2004 - added keyboard nav + mouse selection, and ported Fl_Table into fltk-utf8-1.1.4 - OTHER CONTRIBUTORS + OTHER CONTRIBUTORS - - Inspired by the Feb 2000 version of FLVW's Flvw_Table widget. Mucho thanks to those folks. - - Mister Satan : 04/07/2003 - MinGW porting mods, and singleinput.cxx; a cool Fl_Input oriented spreadsheet example - - Marek Paliwoda : 01/08/2003 - Porting mods for Borland - - Ori Berger : 03/16/2006 - Optimizations for >500k rows/cols + - Inspired by the Feb 2000 version of FLVW's Flvw_Table widget. Mucho thanks to those folks. + - Mister Satan : 04/07/2003 - MinGW porting mods, and singleinput.cxx; a cool Fl_Input oriented spreadsheet example + - Marek Paliwoda : 01/08/2003 - Porting mods for Borland + - Ori Berger : 03/16/2006 - Optimizations for >500k rows/cols - LICENSE + LICENSE - Greg added the following license to the original distribution of Fl_Table. He - kindly gave his permission to integrate Fl_Table and Fl_Table_Row into FLTK, - allowing FLTK license to apply while his widgets are part of the library. - - If used on its own, this is the license that applies: - - \verbatim - Fl_Table License - December 16, 2002 - - The Fl_Table library and included programs are provided under the terms - of the GNU Library General Public License (LGPL) with the following - exceptions: - - 1. Modifications to the Fl_Table configure script, config - header file, and makefiles by themselves to support - a specific platform do not constitute a modified or - derivative work. - - The authors do request that such modifications be - contributed to the Fl_Table project - send all - contributions to "erco at seriss dot com". - - 2. Widgets that are subclassed from Fl_Table widgets do not - constitute a derivative work. - - 3. Static linking of applications and widgets to the - Fl_Table library does not constitute a derivative work - and does not require the author to provide source - code for the application or widget, use the shared - Fl_Table libraries, or link their applications or - widgets against a user-supplied version of Fl_Table. - - If you link the application or widget to a modified - version of Fl_Table, then the changes to Fl_Table must be - provided under the terms of the LGPL in sections - 1, 2, and 4. - - 4. You do not have to provide a copy of the Fl_Table license - with programs that are linked to the Fl_Table library, nor - do you have to identify the Fl_Table license in your - program or documentation as required by section 6 - of the LGPL. - - However, programs must still identify their use of Fl_Table. - The following example statement can be included in user - documentation to satisfy this requirement: - - [program/widget] is based in part on the work of - the Fl_Table project http://seriss.com/people/erco/fltk/Fl_Table/ - \endverbatim - - - */ + Greg kindly gave his permission to integrate Fl_Table and Fl_Table_Row + into FLTK, allowing FLTK license to apply while his widgets are part + of the library. [updated by Greg, 04/26/17] +*/ class FL_EXPORT Fl_Table : public Fl_Group { public: /** - The context bit flags for Fl_Table related callbacks. + The context bit flags for Fl_Table related callbacks. - Used in draw_cell(), callback(), etc. - */ + Used in draw_cell(), callback(), etc. + */ enum TableContext { CONTEXT_NONE = 0, ///< no known context CONTEXT_STARTPAGE = 0x01, ///< before a page is redrawn @@ -317,117 +267,116 @@ protected: 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 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 row_col_clamp(TableContext context, int &R, int &C); // clamp r/c to known universe /** - Subclass should override this method to handle drawing the cells. + Subclass should override this method to handle drawing the cells. - This method will be called whenever the table is redrawn, once per cell. + 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. + Only cells that are completely (or partially) visible will be told to draw. - \p context will be one of the following: + \p context will be one of the following: - - - - - - - - - - - - - - - - - - - - -
\p Fl_Table::CONTEXT_STARTPAGEWhen table, or parts of the table, are about to be redrawn.
- Use to initialize static data, such as font selections.

- R/C will be zero,
- X/Y/W/H will be the dimensions of the table's entire data area.
- (Useful for locking a database before accessing; see - also visible_cells())

\p Fl_Table::CONTEXT_ENDPAGEWhen table has completed being redrawn.
- R/C will be zero, X/Y/W/H dimensions of table's data area.
- (Useful for unlocking a database after accessing)
\p Fl_Table::CONTEXT_ROW_HEADERWhenever a row header cell needs to be drawn.
- R will be the row number of the header being redrawn,
- C will be zero,
- X/Y/W/H will be the fltk drawing area of the row header in the window
\p Fl_Table::CONTEXT_COL_HEADERWhenever a column header cell needs to be drawn.
- R will be zero,
- C will be the column number of the header being redrawn,
- X/Y/W/H will be the fltk drawing area of the column header in the window
\p Fl_Table::CONTEXT_CELLWhenever a data cell in the table needs to be drawn.
- R/C will be the row/column of the cell to be drawn,
- X/Y/W/H will be the fltk drawing area of the cell in the window
\p Fl_Table::CONTEXT_RC_RESIZEWhenever table or row/column is resized or scrolled, - either interactively or via col_width() or row_height().
- R/C/X/Y/W/H will all be zero. -

- Useful for fltk containers that need to resize or move - the child fltk widgets.

+ + + + + + + + + + + + + + + + + + + + +
\p Fl_Table::CONTEXT_STARTPAGEWhen table, or parts of the table, are about to be redrawn.
+ Use to initialize static data, such as font selections.

+ R/C will be zero,
+ X/Y/W/H will be the dimensions of the table's entire data area.
+ (Useful for locking a database before accessing; see + also visible_cells())

\p Fl_Table::CONTEXT_ENDPAGEWhen table has completed being redrawn.
+ R/C will be zero, X/Y/W/H dimensions of table's data area.
+ (Useful for unlocking a database after accessing)
\p Fl_Table::CONTEXT_ROW_HEADERWhenever a row header cell needs to be drawn.
+ R will be the row number of the header being redrawn,
+ C will be zero,
+ X/Y/W/H will be the fltk drawing area of the row header in the window
\p Fl_Table::CONTEXT_COL_HEADERWhenever a column header cell needs to be drawn.
+ R will be zero,
+ C will be the column number of the header being redrawn,
+ X/Y/W/H will be the fltk drawing area of the column header in the window
\p Fl_Table::CONTEXT_CELLWhenever a data cell in the table needs to be drawn.
+ R/C will be the row/column of the cell to be drawn,
+ X/Y/W/H will be the fltk drawing area of the cell in the window
\p Fl_Table::CONTEXT_RC_RESIZEWhenever table or row/column is resized or scrolled, + either interactively or via col_width() or row_height().
+ R/C/X/Y/W/H will all be zero. +

+ Useful for fltk containers that need to resize or move + the child fltk widgets.

- \p row and \p col will be set to the row and column number - of the cell being drawn. In the case of row headers, \p col will be \a 0. - In the case of column headers, \p row will be \a 0. + \p row and \p col will be set to the row and column number + of the cell being drawn. In the case of row headers, \p col will be \a 0. + In the case of column headers, \p row will be \a 0. - x/y/w/h will be the position and dimensions of where the cell - should be drawn. + x/y/w/h will be the position and dimensions of where the cell + should be drawn. - In the case of custom widgets, a minimal draw_cell() override might - look like the following. With custom widgets it is up to the caller to handle - drawing everything within the dimensions of the cell, including handling the - selection color. Note all clipping must be handled as well; this allows drawing - outside the dimensions of the cell if so desired for 'custom effects'. + In the case of custom widgets, a minimal draw_cell() override might + look like the following. With custom widgets it is up to the caller to handle + drawing everything within the dimensions of the cell, including handling the + selection color. Note all clipping must be handled as well; this allows drawing + outside the dimensions of the cell if so desired for 'custom effects'. - \code - // 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 it's starting to draw page - fl_font(FL_HELVETICA, 16); - return; - - case CONTEXT_ROW_HEADER: // Fl_Table telling us to 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; + \code + // 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 it's starting to draw page + fl_font(FL_HELVETICA, 16); + return; + + case CONTEXT_ROW_HEADER: // Fl_Table telling us to 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 } @@ -440,6 +389,9 @@ protected: 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) + /** + Does the table contain any child fltk widgets? + */ int is_fltk_container() { // does table contain fltk widgets? return( Fl_Group::children() > 3 ); // (ie. more than box and 2 scrollbars?) } @@ -448,6 +400,10 @@ protected: void damage_zone(int r1, int c1, int r2, int c2, int r3 = 0, int c3 = 0); + /** + Define region of cells to be redrawn by specified range of rows/cols, + and then sets damage(DAMAGE_CHILD). Extends any previously defined range to redraw. + */ void redraw_range(int topRow, int botRow, int leftCol, int rightCol) { if ( _redraw_toprow == -1 ) { // Initialize redraw range @@ -462,31 +418,24 @@ 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. - This creates an empty table with no rows or columns, - 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 (rows(0)), zero columns (cols(0)), and clears any widgets (table->clear()) that were added with begin()/end() or add()/insert()/etc. \see rows(int), cols(int) - */ - virtual void clear() { rows(0); cols(0); table->clear(); } + */ + virtual void clear() { + rows(0); + cols(0); + table->clear(); + } // \todo: add topline(), middleline(), bottomline() @@ -494,7 +443,7 @@ public: Sets the kind of box drawn around the data table, the default being FL_NO_BOX. Changing this value will cause the table to redraw. - */ + */ inline void table_box(Fl_Boxtype val) { table->box(val); table_resized(); @@ -502,63 +451,57 @@ public: /** Returns the current box type used for the data table. - */ + */ inline Fl_Boxtype table_box( void ) { return(table->box()); } - /** - Sets the number of rows in the table, and the table is redrawn. - */ virtual void rows(int val); // set/get number of rows /** Returns the number of rows in the table. - */ + */ inline int rows() { return(_rows); } - /** - Set the number of columns in the table and redraw. - */ virtual void cols(int val); // set/get number of columns /** Get the number of columns in the table. - */ + */ inline int cols() { return(_cols); } /** - Returns the range of row and column numbers for all visible - and partially visible cells in the table. + Returns the range of row and column numbers for all 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. + 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 - : : - toprow .. .-------------------. - | | - | V I S I B L E | - | | - | T A B L E | - | | - botrow .. '-------------------` - \endcode + \code + leftcol rightcol + : : + toprow .. .-------------------. + | | + | 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: + 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; r2 = botrow; @@ -567,89 +510,90 @@ public: } /** - Returns 1 if someone is interactively resizing a row or column. - You can currently call this only from within your callback(). - */ + Returns 1 if someone is interactively resizing a row or column. + You can currently call this only from within your callback(). + */ int is_interactive_resize() { return(_resizing_row != -1 || _resizing_col != -1); } /** - Returns if row resizing by the user is allowed. - */ + Returns if row resizing by the user is allowed. + */ inline int row_resize() { return(_row_resize); } /** - Allows/disallows row resizing by the user. - 1=allow interactive resizing, 0=disallow interactive resizing. - Since interactive resizing is done via the row headers, - row_header() must also be enabled to allow resizing. - */ + Allows/disallows row resizing by the user. + 1=allow interactive resizing, 0=disallow interactive resizing. + Since interactive resizing is done via the row headers, + row_header() must also be enabled to allow resizing. + */ void row_resize(int flag) { // enable row resizing _row_resize = flag; } /** - Returns if column resizing by the user is allowed. - */ + Returns if column resizing by the user is allowed. + */ inline int col_resize() { return(_col_resize); } + /** - Allows/disallows column resizing by the user. - 1=allow interactive resizing, 0=disallow interactive resizing. - Since interactive resizing is done via the column headers, - \p col_header() must also be enabled to allow resizing. - */ + Allows/disallows column resizing by the user. + 1=allow interactive resizing, 0=disallow interactive resizing. + Since interactive resizing is done via the column headers, + \p col_header() must also be enabled to allow resizing. + */ void col_resize(int flag) { // enable col resizing _col_resize = flag; } /** - Returns the current column minimum resize value. - */ + Returns the current column minimum resize value. + */ inline int col_resize_min() { // column minimum resizing width return(_col_resize_min); } /** - Sets the current column minimum resize value. - This is used to prevent the user from interactively resizing - any column to be smaller than 'pixels'. Must be a value >=1. - */ + Sets the current column minimum resize value. + This is used to prevent the user from interactively resizing + any column to be smaller than 'pixels'. Must be a value >=1. + */ void col_resize_min(int val) { _col_resize_min = ( val < 1 ) ? 1 : val; } /** - Returns the current row minimum resize value. - */ + Returns the current row minimum resize value. + */ inline int row_resize_min() { // column minimum resizing width return(_row_resize_min); } /** - Sets the current row minimum resize value. - This is used to prevent the user from interactively resizing - any row to be smaller than 'pixels'. Must be a value >=1. - */ + Sets the current row minimum resize value. + This is used to prevent the user from interactively resizing + any row to be smaller than 'pixels'. Must be a value >=1. + */ void row_resize_min(int val) { _row_resize_min = ( val < 1 ) ? 1 : val; } /** - Returns if row headers are enabled or not. - */ + Returns if row headers are enabled or not. + */ inline int row_header() { // set/get row header enable flag return(_row_header); } /** - Enables/disables showing the row headers. 1=enabled, 0=disabled. - If changed, the table is redrawn. - */ + Enables/disables showing the row headers. 1=enabled, 0=disabled. + If changed, the table is redrawn. + */ void row_header(int flag) { _row_header = flag; table_resized(); @@ -657,16 +601,16 @@ public: } /** - Returns if column headers are enabled or not. - */ + Returns if column headers are enabled or not. + */ inline int col_header() { // set/get col header enable flag return(_col_header); } /** - Enable or disable column headers. - If changed, the table is redrawn. - */ + Enable or disable column headers. + If changed, the table is redrawn. + */ void col_header(int flag) { _col_header = flag; table_resized(); @@ -674,8 +618,8 @@ public: } /** - Sets the height in pixels for column headers and redraws the table. - */ + Sets the height in pixels for column headers and redraws the table. + */ inline void col_header_height(int height) { // set/get col header height _col_header_h = height; table_resized(); @@ -683,15 +627,15 @@ public: } /** - Gets the column header height. - */ + Gets the column header height. + */ inline int col_header_height() { return(_col_header_h); } /** - Sets the row header width to n and causes the screen to redraw. - */ + Sets the row header width to n and causes the screen to redraw. + */ inline void row_header_width(int width) { // set/get row header width _row_header_w = width; table_resized(); @@ -699,75 +643,64 @@ public: } /** - Returns the current row header width (in pixels). - */ + Returns the current row header width (in pixels). + */ inline int row_header_width() { return(_row_header_w); } /** - Sets the row header color and causes the screen to redraw. - */ + Sets the row header color and causes the screen to redraw. + */ inline void row_header_color(Fl_Color val) { // set/get row header color _row_header_color = val; redraw(); } /** - Returns the current row header color. - */ + Returns the current row header color. + */ inline Fl_Color row_header_color() { return(_row_header_color); } /** - Sets the color for column headers and redraws the table. - */ + Sets the color for column headers and redraws the table. + */ inline void col_header_color(Fl_Color val) { // set/get col header color _col_header_color = val; redraw(); } /** - Gets the color for column headers. - */ + Gets the color for column headers. + */ inline Fl_Color col_header_color() { return(_col_header_color); } - /** - Sets the height of the specified row in pixels, - and the table is redrawn. - callback() will be invoked with CONTEXT_RC_RESIZE - if the row's height was actually changed, and when() is FL_WHEN_CHANGED. - */ void row_height(int row, int height); // set/get row height /** - Returns the current height of the specified row as a value in pixels. - */ + Returns the current height of the specified row as a value in pixels. + */ 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 - if the column's width was actually changed, and when() is FL_WHEN_CHANGED. - */ void col_width(int col, int width); // set/get a column's width /** - Returns the current width of the specified column in pixels. - */ + Returns the current width of the specified column in pixels. + */ inline int col_width(int col) { return((col<0 || col>=(int)_colwidths.size()) ? 0 : _colwidths[col]); } /** - Convenience method to set the height of all rows to the - same value, in pixels. The screen is redrawn. - */ + Convenience method to set the height of all rows to the + same value, in pixels. The screen is redrawn. + */ void row_height_all(int height) { // set all row/col heights for ( int r=0; rinit_sizes(); table->redraw(); } + + /** + The specified widget is removed from its current group (if any) + and added to the end of Fl_Table's group. + */ void add(Fl_Widget& wgt) { table->add(wgt); if ( table->children() > 2 ) { @@ -860,21 +792,45 @@ public: table->hide(); } } + + /** + The specified widget is removed from its current group (if any) + and added to the end of Fl_Table's group. + */ void add(Fl_Widget* wgt) { add(*wgt); } + + /** + The specified widget is removed from its current group (if any) + and inserted into the Fl_Table's group at position 'n'. + */ void insert(Fl_Widget& wgt, int n) { table->insert(wgt,n); } + + /** + The specified widget is removed from its current group (if any) + and inserted into Fl_Table's group before widget 'w2'. + This will append if 'w2' is not in Fl_Table's group. + */ void insert(Fl_Widget& wgt, Fl_Widget* w2) { table->insert(wgt,w2); } + + /** + The specified widget is removed from Fl_Table's group. + */ void remove(Fl_Widget& wgt) { table->remove(wgt); } + + // (doxygen will substitute Fl_Group's docs here) void begin() { table->begin(); } + + // (doxygen will substitute Fl_Group's docs here) void end() { table->end(); // HACK: Avoid showing Fl_Scroll; seems to erase screen @@ -887,74 +843,91 @@ public: } Fl_Group::current(Fl_Group::parent()); } - Fl_Widget * const *array() { + + /** + Returns a pointer to the array of children. This pointer is only + valid until the next time a child is added or removed. + */ + Fl_Widget*const* array() { return(table->array()); } /** - Returns the child widget by an index. - - When using the Fl_Table as a container for FLTK widgets, this method returns - the widget pointer from the internal array of widgets in the container. - - Typically used in loops, eg: - \code - for ( int i=0; ichild(n)); } /** - Returns the number of children in the table. - - When using the Fl_Table as a container for FLTK widgets, this method returns - how many child widgets the table has. - - \see child(int) - */ + Returns the number of children in the table. + + When using the Fl_Table as a container for FLTK widgets, this method returns + how many child widgets the table has. + + \see child(int) + */ int children() const { return(table->children()-2); // -2: skip Fl_Scroll's h/v scrollbar widgets } + + // (doxygen will substitute Fl_Group's docs here) int find(const Fl_Widget *wgt) const { return(table->find(wgt)); } + + // (doxygen will substitute Fl_Group's docs here) int find(const Fl_Widget &wgt) const { return(table->find(wgt)); } + // CALLBACKS /** - * Returns the current row the event occurred on. - * - * This function should only be used from within the user's callback function. - */ + Returns the current row the event occurred on. + + This function should only be used from within the user's callback function. + */ int callback_row() { return(_callback_row); } /** - * Returns the current column the event occurred on. - * - * This function should only be used from within the user's callback function. - */ + Returns the current column the event occurred on. + + This function should only be used from within the user's callback function. + */ int callback_col() { return(_callback_col); } /** - * Returns the current 'table context'. - * - * This function should only be used from within the user's callback function. - */ + Returns the current 'table context'. + + This function should only be used from within the user's callback function. + */ TableContext callback_context() { return(_callback_context); } + /** + Calls the widget callback. + + Saves the specified 'context', 'row', and 'col' values, so that the user's + callback can then access them with the member functions + callback_context(), callback_row() and callback_col(). + */ void do_callback(TableContext context, int row, int col) { _callback_context = context; _callback_row = row; @@ -964,114 +937,114 @@ public: #ifdef FL_DOXYGEN /** - The Fl_Widget::when() function is used to set a group of flags, determining - when the widget callback is called: + The Fl_Widget::when() function is used to set a group of flags, determining + when the widget callback is called: - - - - - - - - -
\p FL_WHEN_CHANGED - callback() will be called when rows or columns are resized (interactively or - via col_width() or row_height()), passing CONTEXT_RC_RESIZE via - callback_context(). -
\p FL_WHEN_RELEASE - callback() will be called during FL_RELEASE events, such as when someone - releases a mouse button somewhere on the table. -
+ + + + + + + + +
\p FL_WHEN_CHANGED + callback() will be called when rows or columns are resized (interactively or + via col_width() or row_height()), passing CONTEXT_RC_RESIZE via + callback_context(). +
\p FL_WHEN_RELEASE + callback() will be called during FL_RELEASE events, such as when someone + releases a mouse button somewhere on the table. +
- The callback() routine is sent a TableContext that indicates the context the - event occurred in, such as in a cell, in a header, or elsewhere on the table. - When an event occurs in a cell or header, callback_row() and - callback_col() can be used to determine the row and column. The callback - can also look at the regular fltk event values (ie. Fl::event() and - Fl::event_button()) to determine what kind of event is occurring. - */ + The callback() routine is sent a TableContext that indicates the context the + event occurred in, such as in a cell, in a header, or elsewhere on the table. + When an event occurs in a cell or header, callback_row() and + callback_col() can be used to determine the row and column. The callback + can also look at the regular fltk event values (ie. Fl::event() and + Fl::event_button()) to determine what kind of event is occurring. + */ void when(Fl_When flags); #endif #ifdef FL_DOXYGEN /** - Callbacks will be called depending on the setting of Fl_Widget::when(). + 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: + 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 + - 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_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: + callback_context() will return one of the following: - - - - - - - - - + +
Fl_Table::CONTEXT_ROW_HEADERSomeone clicked on a row header. Excludes resizing.
Fl_Table::CONTEXT_COL_HEADERSomeone clicked on a column header. Excludes resizing.
Fl_Table::CONTEXT_CELL - Someone clicked on a cell. + + + + + + + + + - - - + + + - -
Fl_Table::CONTEXT_ROW_HEADERSomeone clicked on a row header. Excludes resizing.
Fl_Table::CONTEXT_COL_HEADERSomeone clicked on a column header. Excludes resizing.
Fl_Table::CONTEXT_CELL + Someone clicked on a cell. - To receive callbacks for FL_RELEASE events, you must set - when(FL_WHEN_RELEASE). -
Fl_Table::CONTEXT_RC_RESIZE - Someone is resizing rows/columns either interactively, - or via the col_width() or row_height() API. + To receive callbacks for FL_RELEASE events, you must set + when(FL_WHEN_RELEASE). +
Fl_Table::CONTEXT_RC_RESIZE + Someone is resizing rows/columns either interactively, + or via the col_width() or row_height() API. - Use is_interactive_resize() - to determine interactive resizing. + Use is_interactive_resize() + to determine interactive resizing. - If resizing a column, R=0 and C=column being resized. + If resizing a column, R=0 and C=column being resized. - If resizing a row, C=0 and R=row 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). -
+ NOTE: To receive resize events, you must set when(FL_WHEN_CHANGED). +
- \code - class MyTable : public Fl_Table { - [..] - 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->event_callback2(); - } - - public: - // Constructor - MyTable() { - [..] - table.callback(&event_callback, (void*)this); // setup callback - table.when(FL_WHEN_CHANGED|FL_WHEN_RELEASE); // when to call it - } - }; - \endcode - */ + \code + class MyTable : public Fl_Table { + [..] + 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->event_callback2(); + } + + public: + // Constructor + MyTable() { + [..] + 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/src/Fl_Table.cxx b/src/Fl_Table.cxx index 55e0a9f35..918d40e7a 100644 --- a/src/Fl_Table.cxx +++ b/src/Fl_Table.cxx @@ -25,7 +25,9 @@ #include // currently only Windows and Linux #endif -// Scroll display so 'row' is at top +/** Sets the vertical scroll position so 'row' is at the top, + and causes the screen to redraw. +*/ void Fl_Table::row_position(int row) { if ( _row_position == row ) return; // OPTIMIZATION: no change? avoid redraw if ( row < 0 ) row = 0; @@ -41,7 +43,10 @@ void Fl_Table::row_position(int row) { _row_position = row; // HACK: override what table_scrolled() came up with } -// Scroll display so 'col' is at left +/** + Sets the horizontal scroll position so 'col' is at the left, + and causes the screen to redraw. +*/ void Fl_Table::col_position(int col) { if ( _col_position == col ) return; // OPTIMIZATION: no change? avoid redraw if ( col < 0 ) col = 0; @@ -57,7 +62,9 @@ void Fl_Table::col_position(int col) { _col_position = col; // HACK: override what table_scrolled() came up with } -// Find scroll position of a row (in pixels) +/** + Returns the scroll position (in pixels) of the specified 'row'. +*/ long Fl_Table::row_scroll_position(int row) { int startrow = 0; long scroll = 0; @@ -74,7 +81,9 @@ long Fl_Table::row_scroll_position(int row) { return(scroll); } -// Find scroll position of a column (in pixels) +/** + Returns the scroll position (in pixels) of the specified column 'col'. +*/ long Fl_Table::col_scroll_position(int col) { int startcol = 0; long scroll = 0; @@ -91,7 +100,11 @@ long Fl_Table::col_scroll_position(int col) { return(scroll); } -// Ctor +/** + The constructor for Fl_Table. + This creates an empty table with no rows or columns, + with headers and row/column resize behavior disabled. +*/ Fl_Table::Fl_Table(int X, int Y, int W, int H, const char *l) : Fl_Group(X,Y,W,H,l) { _rows = 0; _cols = 0; @@ -156,12 +169,21 @@ Fl_Table::Fl_Table(int X, int Y, int W, int H, const char *l) : Fl_Group(X,Y,W,H table->begin(); // leave with fltk children getting added to the scroll } -// Dtor + +/** + The destructor for Fl_Table. + Destroys the table and its associated widgets. +*/ Fl_Table::~Fl_Table() { // The parent Fl_Group takes care of destroying scrollbars } -// Set height of a row +/** + Sets the height of the specified row in pixels, + and the table is redrawn. + callback() will be invoked with CONTEXT_RC_RESIZE + if the row's height was actually changed, and when() is FL_WHEN_CHANGED. +*/ void Fl_Table::row_height(int row, int height) { if ( row < 0 ) return; if ( row < (int)_rowheights.size() && _rowheights[row] == height ) { @@ -185,7 +207,11 @@ void Fl_Table::row_height(int row, int height) { } } -// Set width of a column +/** + Sets the width of the specified column in pixels, and the table is redrawn. + callback() will be invoked with CONTEXT_RC_RESIZE + if the column's width was actually changed, and when() is FL_WHEN_CHANGED. +*/ void Fl_Table::col_width(int col, int width) { if ( col < 0 ) return; @@ -211,7 +237,11 @@ void Fl_Table::col_width(int col, int width) } } -// Return row/col clamped to reality +/** + Return specfied row/col values R and C to within the table's + current row/col limits. + \returns 0 if no changes were made, or 1 if they were. +*/ int Fl_Table::row_col_clamp(TableContext context, int &R, int &C) { int clamped = 0; if ( R < 0 ) { R = 0; clamped = 1; } @@ -237,7 +267,9 @@ int Fl_Table::row_col_clamp(TableContext context, int &R, int &C) { return(clamped); } -// Return bounding region for given context +/** + Returns the (X,Y,W,H) bounding region for the specified 'context'. +*/ void Fl_Table::get_bounds(TableContext context, int &X, int &Y, int &W, int &H) { switch ( context ) { case CONTEXT_COL_HEADER: @@ -269,11 +301,11 @@ void Fl_Table::get_bounds(TableContext context, int &X, int &Y, int &W, int &H) //NOTREACHED } -// Find row/col beneath cursor -// -// Returns R/C and context. -// Also returns resizeflag, if mouse is hovered over a resize boundary. -// +/** + Find row/col for the recent mouse event. + Returns the context, and the row/column values in R/C. + Also returns 'resizeflag' if mouse is hovered over a resize boundary. +*/ Fl_Table::TableContext Fl_Table::cursor2rowcol(int &R, int &C, ResizeFlag &resizeflag) { // return values R = C = 0; @@ -350,10 +382,12 @@ Fl_Table::TableContext Fl_Table::cursor2rowcol(int &R, int &C, ResizeFlag &resiz return(CONTEXT_NONE); } -// Find X/Y/W/H for cell at R/C -// If R or C are out of range, returns -1 -// with X/Y/W/H set to zero. -// +/** + Find a cell's X/Y/W/H region for the specified cell in row 'R', column 'C'. + \returns + - 0 -- on success, XYWH returns the region of the specified cell. + - -1 -- if R or C are out of range, and X/Y/W/H will be set to zero. +*/ int Fl_Table::find_cell(TableContext context, int R, int C, int &X, int &Y, int &W, int &H) { if ( row_col_clamp(context, R, C) ) { // row or col out of range? error X=Y=W=H=0; @@ -458,7 +492,10 @@ void Fl_Table::_auto_drag_cb() { } } -// Recalculate the window dimensions +/** + Recalculate the dimensions of the table, and affect any children. + Internally, Fl_Group::resize() and init_sizes() are called. +*/ void Fl_Table::recalc_dimensions() { // Recalc to* (Table Outer), ti* (Table Inner), wi* ( Widget Inner) wix = ( x() + Fl::box_dx(box())); tox = wix; tix = tox + Fl::box_dx(table->box()); @@ -494,12 +531,12 @@ void Fl_Table::recalc_dimensions() { table->init_sizes(); } -// Recalculate internals after a scroll. -// -// Call this if table has been scrolled or resized. -// Does not handle redraw(). -// TODO: Assumes ti[xywh] has already been recalculated. -// +/** + Recalculate internals after a scroll. + Call this if table has been scrolled or resized. + Does not handle redraw(). + TODO: Assumes ti[xywh] has already been recalculated. +*/ void Fl_Table::table_scrolled() { // Find top row int y, row, voff = vscrollbar->value(); @@ -537,11 +574,10 @@ void Fl_Table::table_scrolled() { draw_cell(CONTEXT_RC_RESIZE, 0,0,0,0,0,0); } -// Table resized: recalc internal data -// Call this whenever the window is resized. -// Recalculates the scrollbar sizes. -// Makes no assumptions about any pre-initialized data. -// +/** + Call this if table was resized, to recalculate internal data. + Calls recall_dimensions(), and recalculates scrollbar sizes. +*/ void Fl_Table::table_resized() { table_h = row_scroll_position(rows()); table_w = col_scroll_position(cols()); @@ -582,7 +618,9 @@ void Fl_Table::table_resized() { // redraw(); } -// Someone moved a scrollbar +/** + Callback for when someone moves a scrollbar. +*/ void Fl_Table::scroll_cb(Fl_Widget*w, void *data) { Fl_Table *o = (Fl_Table*)data; o->recalc_dimensions(); // recalc tix, tiy, etc. @@ -590,7 +628,9 @@ void Fl_Table::scroll_cb(Fl_Widget*w, void *data) { o->redraw(); } -// Set number of rows +/** + Sets the number of rows in the table, and the table is redrawn. +*/ void Fl_Table::rows(int val) { int oldrows = _rows; _rows = val; @@ -612,7 +652,9 @@ void Fl_Table::rows(int val) { } } -// Set number of cols +/** + Set the number of columns in the table and redraw. +*/ void Fl_Table::cols(int val) { _cols = val; { @@ -627,7 +669,9 @@ void Fl_Table::cols(int val) { redraw(); } -// Change mouse cursor to different type +/** + Change mouse cursor to different type +*/ void Fl_Table::change_cursor(Fl_Cursor newcursor) { if ( newcursor != _last_cursor ) { fl_cursor(newcursor, FL_BLACK, FL_WHITE); @@ -635,6 +679,10 @@ void Fl_Table::change_cursor(Fl_Cursor newcursor) { } } +/** + Sets the damage zone to the specified row/col values. + Calls redraw_range(). +*/ void Fl_Table::damage_zone(int r1, int c1, int r2, int c2, int r3, int c3) { int R1 = r1, C1 = c1; int R2 = r2, C2 = c2; @@ -661,6 +709,32 @@ void Fl_Table::damage_zone(int r1, int c1, int r2, int c2, int r3, int c3) { redraw_range(R1, R2, C1, C2); } +/** + Moves the selection cursor a relative number of rows/columns specifed by R/C. + R/C can be positive or negative, depending on the direction to move. + A value of 0 for R or C prevents cursor movement on that axis. + + If shiftselect is set, the selection range is extended to the new + cursor position. If clear, the cursor is simply moved, and any previous + selection is cancelled. + + Used mainly by keyboard events (e.g. Fl_Right, FL_Home, FL_End..) + to let the user keyboard navigate the selection cursor around. + + The scroll positions may be modified if the selection cursor traverses + into cells off the screen's edge. + + Internal variables select_row/select_col and current_row/current_col + are modified, among others. + + \code + Examples: + R=1, C=0 -- moves the selection cursor one row downward. + R=5, C=0 -- moves the selection cursor 5 rows downward. + R=-5, C=0 -- moves the cursor 5 rows upward. + R=2, C=2 -- moves the cursor 2 rows down and 2 columns to the right. + \endcode +*/ int Fl_Table::move_cursor(int R, int C, int shiftselect) { if (select_row == -1) R++; if (select_col == -1) C++; @@ -683,6 +757,9 @@ int Fl_Table::move_cursor(int R, int C, int shiftselect) { return 1; } +/** + Same as move_cursor(R,C,1); +*/ int Fl_Table::move_cursor(int R, int C) { return move_cursor(R,C,1); } @@ -696,7 +773,9 @@ int Fl_Table::move_cursor(int R, int C) { #define PRINTEVENT #endif -// Handle FLTK events +/** + Handle FLTK events. +*/ int Fl_Table::handle(int event) { PRINTEVENT; int ret = Fl_Group::handle(event); // let FLTK group handle events first @@ -1051,9 +1130,10 @@ int Fl_Table::handle(int event) { return(ret); } -// Resize FLTK override -// Handle resize events if user resizes parent window. -// +/** + Handle resize events if user resizes parent window. + This changes the size of Fl_Table, causing it to redraw. +*/ void Fl_Table::resize(int X, int Y, int W, int H) { // Tell group to resize, and recalc our own widget as well Fl_Group::resize(X, Y, W, H); @@ -1070,9 +1150,9 @@ void Fl_Table::_redraw_cell(TableContext context, int r, int c) { } /** - See if the cell at row \p r and column \p c is selected. - \returns 1 if the cell is selected, 0 if not. - */ + See if the cell at row \p r and column \p c is selected. + \returns 1 if the cell is selected, 0 if not. +*/ int Fl_Table::is_selected(int r, int c) { int s_left, s_right, s_top, s_bottom; @@ -1141,10 +1221,11 @@ void Fl_Table::set_selection(int row_top, int col_left, int row_bot, int col_rig damage_zone(current_row, current_col, select_row, select_col); } -// Draw the entire Fl_Table -// Override the draw() routine to draw the table. -// Then tell the group to draw over us. -// +/** + Draws the entire Fl_Table. + Lets fltk widgets draw themselves first, followed by the cells + via calls to draw_cell(). +*/ void Fl_Table::draw() { int scrollsize = _scrollbar_size ? _scrollbar_size : Fl::scrollbar_size(); // Check if scrollbar size changed