1 //
2 // "$Id$"
3 //
4 // Fl_Table -- A table widget
5 //
6 // Copyright 2002 by Greg Ercolano.
7 // Copyright (c) 2004 O'ksi'D
8 //
9 // This library is free software. Distribution and use rights are outlined in
10 // the file "COPYING" which should have been included with this file.  If this
11 // file is missing or damaged, see the license at:
12 //
13 //     http://www.fltk.org/COPYING.php
14 //
15 // Please report all bugs and problems on the following page:
16 //
17 //     http://www.fltk.org/str.php
18 //
19 
20 #ifndef _FL_TABLE_H
21 #define _FL_TABLE_H
22 
23 #include <sys/types.h>
24 #include <string.h>		// memcpy
25 #ifdef WIN32
26 #include <malloc.h>		// WINDOWS: malloc/realloc
27 #else /*WIN32*/
28 #include <stdlib.h>		// UNIX: malloc/realloc
29 #endif /*WIN32*/
30 
31 #include <FL/Fl.H>
32 #include <FL/Fl_Group.H>
33 #include <FL/Fl_Scroll.H>
34 #include <FL/Fl_Box.H>
35 #include <FL/Fl_Scrollbar.H>
36 
37 /**
38  A table of widgets or other content.
39 
40  This is the base class for table widgets.
41 
42  To be useful it must be subclassed and several virtual functions defined.
43  Normally applications use widgets derived from this widget, and do not use this
44  widget directly; this widget is usually too low level to be used directly by
45  applications.
46 
47  This widget does \em not handle the data in the table. The draw_cell()
48  method must be overridden by a subclass to manage drawing the contents of
49  the cells.
50 
51  This widget can be used in several ways:
52 
53  - As a custom widget; see examples/table-simple.cxx and test/table.cxx.
54    Very optimal for even extremely large tables.
55  - As a table made up of a single FLTK widget instanced all over the table,
56    simulating a numeric spreadsheet. See examples/table-spreadsheet.cxx and
57    examples/table-spreadsheet-with-keyboard-nav.cxx. Optimal for large tables.
58  - As a regular container of FLTK widgets, one widget per cell.
59    See examples/table-as-container.cxx. \em Not recommended for large tables.
60 
61  \image html table-simple.png
62  \image latex table-simple.png "table-simple example" width=6cm
63 
64  \image html table-as-container.png
65  \image latex table-as-container.png "table-as-container example" width=6cm
66 
67  When acting as part of a custom widget, events on the cells and/or headings
68  generate callbacks when they are clicked by the user. You control when events
69  are generated based on the setting for Fl_Table::when().
70 
71  When acting as a container for FLTK widgets, the FLTK widgets maintain
72  themselves. Although the draw_cell() method must be overridden, its contents
73  can be very simple. See the draw_cell() code in examples/table-simple.cxx.
74 
75  The following variables are available to classes deriving from Fl_Table:
76 
77  \image html table-dimensions.png
78  \image latex table-dimensions.png "Fl_Table Dimensions" width=6cm
79 
80  <table border=0>
81  <tr><td>x()/y()/w()/h()</td>
82  <td>Fl_Table widget's outer dimension. The outer edge of the border of the
83  Fl_Table. (Red in the diagram above)</td></tr>
84 
85  <tr><td>wix/wiy/wiw/wih</td>
86  <td>Fl_Table widget's inner dimension. The inner edge of the border of the
87  Fl_Table. eg. if the Fl_Table's box() is FL_NO_BOX, these values are the same
88  as x()/y()/w()/h(). (Yellow in the diagram above)</td></tr>
89 
90  <tr><td>tox/toy/tow/toh</td>
91  <td>The table's outer dimension. The outer edge of the border around the cells,
92  but inside the row/col headings and scrollbars. (Green in the diagram above)
93  </td></tr>
94 
95  <tr><td>tix/tiy/tiw/tih</td>
96  <td>The table's inner dimension. The inner edge of the border around the cells,
97  but inside the row/col headings and scrollbars. AKA the table's clip region.
98  eg. if the table_box() is FL_NO_BOX, these values are the same as
99  tox/toy/tow/toh. (Blue in the diagram above)
100  </td></tr></table>
101 
102  CORE DEVELOPERS
103 
104  - Greg Ercolano : 12/16/2002 - initial implementation 12/16/02. Fl_Table, Fl_Table_Row, docs.
105  - Jean-Marc Lienher : 02/22/2004 - added keyboard nav + mouse selection, and ported Fl_Table into fltk-utf8-1.1.4
106 
107  OTHER CONTRIBUTORS
108 
109  - Inspired by the Feb 2000 version of FLVW's Flvw_Table widget. Mucho thanks to those folks.
110  - Mister Satan : 04/07/2003 - MinGW porting mods, and singleinput.cxx; a cool Fl_Input oriented spreadsheet example
111  - Marek Paliwoda : 01/08/2003 - Porting mods for Borland
112  - Ori Berger : 03/16/2006 - Optimizations for >500k rows/cols
113 
114  LICENSE
115 
116  Greg added the following license to the original distribution of Fl_Table. He
117  kindly gave his permission to integrate Fl_Table and Fl_Table_Row into FLTK,
118  allowing FLTK license to apply while his widgets are part of the library.
119 
120  If used on its own, this is the license that applies:
121 
122  \verbatim
123  Fl_Table License
124  December 16, 2002
125 
126  The Fl_Table library and included programs are provided under the terms
127  of the GNU Library General Public License (LGPL) with the following
128  exceptions:
129 
130  1. Modifications to the Fl_Table configure script, config
131  header file, and makefiles by themselves to support
132  a specific platform do not constitute a modified or
133  derivative work.
134 
135  The authors do request that such modifications be
136  contributed to the Fl_Table project - send all
137  contributions to "erco at seriss dot com".
138 
139  2. Widgets that are subclassed from Fl_Table widgets do not
140  constitute a derivative work.
141 
142  3. Static linking of applications and widgets to the
143  Fl_Table library does not constitute a derivative work
144  and does not require the author to provide source
145  code for the application or widget, use the shared
146  Fl_Table libraries, or link their applications or
147  widgets against a user-supplied version of Fl_Table.
148 
149  If you link the application or widget to a modified
150  version of Fl_Table, then the changes to Fl_Table must be
151  provided under the terms of the LGPL in sections
152  1, 2, and 4.
153 
154  4. You do not have to provide a copy of the Fl_Table license
155  with programs that are linked to the Fl_Table library, nor
156  do you have to identify the Fl_Table license in your
157  program or documentation as required by section 6
158  of the LGPL.
159 
160  However, programs must still identify their use of Fl_Table.
161  The following example statement can be included in user
162  documentation to satisfy this requirement:
163 
164  [program/widget] is based in part on the work of
165  the Fl_Table project http://seriss.com/people/erco/fltk/Fl_Table/
166  \endverbatim
167 
168 
169  */
170 class FL_EXPORT Fl_Table : public Fl_Group {
171 public:
172   /**
173    The context bit flags for Fl_Table related callbacks.
174 
175    Used in draw_cell(), callback(), etc.
176    */
177   enum TableContext {
178     CONTEXT_NONE       = 0,	///< no known context
179     CONTEXT_STARTPAGE  = 0x01,	///< before a page is redrawn
180     CONTEXT_ENDPAGE    = 0x02,	///< after a page is redrawn
181     CONTEXT_ROW_HEADER = 0x04,	///< in the row header
182     CONTEXT_COL_HEADER = 0x08,	///< in the col header
183     CONTEXT_CELL       = 0x10,	///< in one of the cells
184     CONTEXT_TABLE      = 0x20,	///< in a dead zone of table
185     CONTEXT_RC_RESIZE  = 0x40 	///< column or row being resized
186   };
187 
188 private:
189   int _rows, _cols;	// total rows/cols
190   int _row_header_w;	// width of row header
191   int _col_header_h;	// height of column header
192   int _row_position;	// last row_position set (not necessarily == toprow!)
193   int _col_position;	// last col_position set (not necessarily == leftcol!)
194 
195   char _row_header;	// row header enabled?
196   char _col_header;	// col header enabled?
197   char _row_resize;	// row resizing enabled?
198   char _col_resize;	// col resizing enabled?
199   int _row_resize_min;	// row minimum resizing height (default=1)
200   int _col_resize_min;	// col minimum resizing width (default=1)
201 
202   // OPTIMIZATION: partial row/column redraw variables
203   int _redraw_toprow;
204   int _redraw_botrow;
205   int _redraw_leftcol;
206   int _redraw_rightcol;
207   Fl_Color _row_header_color;
208   Fl_Color _col_header_color;
209 
210   int _auto_drag;
211   int _selecting;
212 #if FLTK_ABI_VERSION >= 10301
213   int _scrollbar_size;
214 #endif
215 #if FLTK_ABI_VERSION >= 10303
216   enum {
217     TABCELLNAV = 1<<0,			///> tab cell navigation flag
218   };
219   unsigned int flags_;
220 #endif
221 
222   // An STL-ish vector without templates
223   class FL_EXPORT IntVector {
224     int *arr;
225     unsigned int _size;
init()226     void init() {
227       arr = NULL;
228       _size = 0;
229     }
copy(int * newarr,unsigned int newsize)230     void copy(int *newarr, unsigned int newsize) {
231       size(newsize);
232       memcpy(arr, newarr, newsize * sizeof(int));
233     }
234   public:
IntVector()235     IntVector() { init(); }					// CTOR
~IntVector()236     ~IntVector() { if ( arr ) free(arr); arr = NULL; }		// DTOR
IntVector(IntVector & o)237     IntVector(IntVector&o) { init(); copy(o.arr, o._size); }	// COPY CTOR
238     IntVector& operator=(IntVector&o) {				// ASSIGN
239       init();
240       copy(o.arr, o._size);
241       return(*this);
242     }
243     int operator[](int x) const { return(arr[x]); }
244     int& operator[](int x) { return(arr[x]); }
size()245     unsigned int size() { return(_size); }
size(unsigned int count)246     void size(unsigned int count) {
247       if ( count != _size ) {
248         arr = (int*)realloc(arr, count * sizeof(int));
249         _size = count;
250       }
251     }
pop_back()252     int pop_back() { int tmp = arr[_size-1]; _size--; return(tmp); }
push_back(int val)253     void push_back(int val) { unsigned int x = _size; size(_size+1); arr[x] = val; }
back()254     int back() { return(arr[_size-1]); }
255   };
256 
257   IntVector _colwidths;			// column widths in pixels
258   IntVector _rowheights;		// row heights in pixels
259 
260   Fl_Cursor _last_cursor;		// last mouse cursor before changed to 'resize' cursor
261 
262   // EVENT CALLBACK DATA
263   TableContext _callback_context;	// event context
264   int _callback_row, _callback_col;	// event row/col
265 
266   // handle() state variables.
267   //    Put here instead of local statics in handle(), so more
268   //    than one Fl_Table can exist without crosstalk between them.
269   //
270   int _resizing_col;			// column being dragged
271   int _resizing_row;			// row being dragged
272   int _dragging_x;			// starting x position for horiz drag
273   int _dragging_y;			// starting y position for vert drag
274   int _last_row;			// last row we FL_PUSH'ed
275 
276   // Redraw single cell
277   void _redraw_cell(TableContext context, int R, int C);
278 
279   void _start_auto_drag();
280   void _stop_auto_drag();
281   void _auto_drag_cb();
282   static void _auto_drag_cb2(void *d);
283 
284 protected:
285   enum ResizeFlag {
286     RESIZE_NONE      = 0,
287     RESIZE_COL_LEFT  = 1,
288     RESIZE_COL_RIGHT = 2,
289     RESIZE_ROW_ABOVE = 3,
290     RESIZE_ROW_BELOW = 4
291   };
292 
293   int table_w, table_h;				// table's virtual size (in pixels)
294   int toprow, botrow, leftcol, rightcol;	// four corners of viewable table
295 
296   // selection
297   int current_row, current_col;
298   int select_row, select_col;
299 
300   // OPTIMIZATION: Precomputed scroll positions for the toprow/leftcol
301   int toprow_scrollpos;
302   int leftcol_scrollpos;
303 
304   // Dimensions
305   int tix, tiy, tiw, tih;			// data table inner dimension xywh
306   int tox, toy, tow, toh;			// data table outer dimension xywh
307   int wix, wiy, wiw, wih;			// widget inner dimension xywh
308 
309   Fl_Scroll *table;				// container for child fltk widgets (if any)
310   Fl_Scrollbar *vscrollbar; 			// vertical scrollbar
311   Fl_Scrollbar *hscrollbar;			// horizontal scrollbar
312 
313   // Fltk
314   int handle(int e);				// fltk handle() override
315 
316   // Class maintenance
317   void recalc_dimensions();
318   void table_resized();				// table resized; recalc
319   void table_scrolled();			// table scrolled; recalc
320   void get_bounds(TableContext context,		// return x/y/w/h bounds for context
321                   int &X, int &Y, int &W, int &H);
322   void change_cursor(Fl_Cursor newcursor);	// change mouse cursor to some other shape
323   TableContext cursor2rowcol(int &R, int &C, ResizeFlag &resizeflag);
324   // find r/c given current x/y event
325   int find_cell(TableContext context,		// find cell's x/y/w/h given r/c
326                 int R, int C, int &X, int &Y, int &W, int &H);
327   int row_col_clamp(TableContext context, int &R, int &C);
328   // clamp r/c to known universe
329 
330   /**
331    Subclass should override this method to handle drawing the cells.
332 
333    This method will be called whenever the table is redrawn, once per cell.
334 
335    Only cells that are completely (or partially) visible will be told to draw.
336 
337    \p context will be one of the following:
338 
339    <table border=1>
340    <tr>
341    <td>\p Fl_Table::CONTEXT_STARTPAGE</td>
342    <td>When table, or parts of the table, are about to be redrawn.<br>
343        Use to initialize static data, such as font selections.<p>
344        R/C will be zero,<br>
345        X/Y/W/H will be the dimensions of the table's entire data area.<br>
346        (Useful for locking a database before accessing; see
347        also visible_cells())</td>
348    </tr><tr>
349    <td>\p Fl_Table::CONTEXT_ENDPAGE</td>
350    <td>When table has completed being redrawn.<br>
351        R/C will be zero, X/Y/W/H dimensions of table's data area.<br>
352        (Useful for unlocking a database after accessing)</td>
353    </tr><tr>
354    <td>\p Fl_Table::CONTEXT_ROW_HEADER</td>
355    <td>Whenever a row header cell needs to be drawn.<br>
356        R will be the row number of the header being redrawn,<br>
357        C will be zero,<br>
358        X/Y/W/H will be the fltk drawing area of the row header in the window </td>
359    </tr><tr>
360    <td>\p Fl_Table::CONTEXT_COL_HEADER</td>
361    <td>Whenever a column header cell needs to be drawn.<br>
362        R will be zero, <br>
363        C will be the column number of the header being redrawn,<br>
364        X/Y/W/H will be the fltk drawing area of the column header in the window </td>
365    </tr><tr>
366    <td>\p Fl_Table::CONTEXT_CELL</td>
367    <td>Whenever a data cell in the table needs to be drawn.<br>
368        R/C will be the row/column of the cell to be drawn,<br>
369        X/Y/W/H will be the fltk drawing area of the cell in the window </td>
370    </tr><tr>
371    <td>\p Fl_Table::CONTEXT_RC_RESIZE</td>
372    <td>Whenever table or row/column is resized or scrolled,
373        either interactively or via col_width() or row_height().<br>
374        R/C/X/Y/W/H will all be zero.
375        <p>
376        Useful for fltk containers that need to resize or move
377        the child fltk widgets.</td>
378    </tr>
379    </table>
380 
381    \p row and \p col will be set to the row and column number
382    of the cell being drawn. In the case of row headers, \p col will be \a 0.
383    In the case of column headers, \p row will be \a 0.
384 
385    <tt>x/y/w/h</tt> will be the position and dimensions of where the cell
386    should be drawn.
387 
388    In the case of custom widgets, a minimal draw_cell() override might
389    look like the following. With custom widgets it is up to the caller to handle
390    drawing everything within the dimensions of the cell, including handling the
391    selection color.  Note all clipping must be handled as well; this allows drawing
392    outside the dimensions of the cell if so desired for 'custom effects'.
393 
394    \code
395    // This is called whenever Fl_Table wants you to draw a cell
396    void MyTable::draw_cell(TableContext context, int R=0, int C=0, int X=0, int Y=0, int W=0, int H=0) {
397        static char s[40];
398        sprintf(s, "%d/%d", R, C);              // text for each cell
399        switch ( context ) {
400 	   case CONTEXT_STARTPAGE:             // Fl_Table telling us it's starting to draw page
401 	       fl_font(FL_HELVETICA, 16);
402 	       return;
403 
404 	   case CONTEXT_ROW_HEADER:            // Fl_Table telling us to draw row/col headers
405 	   case CONTEXT_COL_HEADER:
406 	       fl_push_clip(X, Y, W, H);
407 	       {
408 		   fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, color());
409 		   fl_color(FL_BLACK);
410 		   fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
411 	       }
412 	       fl_pop_clip();
413 	       return;
414 
415 	   case CONTEXT_CELL:                  // Fl_Table telling us to draw cells
416 	       fl_push_clip(X, Y, W, H);
417 	       {
418 		   // BG COLOR
419 		   fl_color( row_selected(R) ? selection_color() : FL_WHITE);
420 		   fl_rectf(X, Y, W, H);
421 
422 		   // TEXT
423 		   fl_color(FL_BLACK);
424 		   fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
425 
426 		   // BORDER
427 		   fl_color(FL_LIGHT2);
428 		   fl_rect(X, Y, W, H);
429 	       }
430 	       fl_pop_clip();
431 	       return;
432 
433        default:
434 	   return;
435        }
436        //NOTREACHED
437    }
438    \endcode
439    */
440   virtual void draw_cell(TableContext context, int R=0, int C=0,
441                          int X=0, int Y=0, int W=0, int H=0)
442   { }						// overridden by deriving class
443 
444   long row_scroll_position(int row);		// find scroll position of row (in pixels)
445   long col_scroll_position(int col);		// find scroll position of col (in pixels)
446 
is_fltk_container()447   int is_fltk_container() { 			// does table contain fltk widgets?
448     return( Fl_Group::children() > 3 );		// (ie. more than box and 2 scrollbars?)
449   }
450 
451   static void scroll_cb(Fl_Widget*,void*);	// h/v scrollbar callback
452 
453   void damage_zone(int r1, int c1, int r2, int c2, int r3 = 0, int c3 = 0);
454 
redraw_range(int topRow,int botRow,int leftCol,int rightCol)455   void redraw_range(int topRow, int botRow, int leftCol, int rightCol) {
456     if ( _redraw_toprow == -1 ) {
457       // Initialize redraw range
458       _redraw_toprow = topRow;
459       _redraw_botrow = botRow;
460       _redraw_leftcol = leftCol;
461       _redraw_rightcol = rightCol;
462     } else {
463       // Extend redraw range
464       if ( topRow < _redraw_toprow ) _redraw_toprow = topRow;
465       if ( botRow > _redraw_botrow ) _redraw_botrow = botRow;
466       if ( leftCol < _redraw_leftcol ) _redraw_leftcol = leftCol;
467       if ( rightCol > _redraw_rightcol ) _redraw_rightcol = rightCol;
468     }
469 
470     // Indicate partial redraw needed of some cells
471     damage(FL_DAMAGE_CHILD);
472   }
473 
474 public:
475   /**
476    The constructor for the Fl_Table.
477    This creates an empty table with no rows or columns,
478    with headers and row/column resize behavior disabled.
479    */
480   Fl_Table(int X, int Y, int W, int H, const char *l=0);
481 
482   /**
483    The destructor for the Fl_Table.
484    Destroys the table and its associated widgets.
485    */
486   ~Fl_Table();
487 
488   /**
489    Clears the table to zero rows (rows(0)), zero columns (cols(0)), and clears
490    any widgets (table->clear()) that were added with begin()/end() or add()/insert()/etc.
491    \see rows(int), cols(int)
492    */
clear()493   virtual void clear() { rows(0); cols(0); table->clear(); }
494 
495   // \todo: add topline(), middleline(), bottomline()
496 
497   /**
498    Sets the kind of box drawn around the data table,
499    the default being FL_NO_BOX. Changing this value will cause the table
500    to redraw.
501    */
table_box(Fl_Boxtype val)502   inline void table_box(Fl_Boxtype val) {
503     table->box(val);
504     table_resized();
505   }
506 
507   /**
508    Returns the current box type used for the data table.
509    */
table_box(void)510   inline Fl_Boxtype table_box( void ) {
511     return(table->box());
512   }
513 
514   /**
515    Sets the number of rows in the table, and the table is redrawn.
516    */
517   virtual void rows(int val);			// set/get number of rows
518 
519   /**
520    Returns the number of rows in the table.
521    */
rows()522   inline int rows() {
523     return(_rows);
524   }
525 
526   /**
527    Set the number of columns in the table and redraw.
528    */
529   virtual void cols(int val);			// set/get number of columns
530 
531   /**
532    Get the number of columns in the table.
533    */
cols()534   inline int cols() {
535     return(_cols);
536   }
537 
538   /**
539    Returns the range of row and column numbers for all visible
540    and partially visible cells in the table.
541 
542    These values can be used e.g. by your draw_cell() routine during
543    CONTEXT_STARTPAGE to figure out what cells are about to be redrawn
544    for the purposes of locking the data from a database before it's drawn.
545 
546    \code
547           leftcol             rightcol
548              :                   :
549    toprow .. .-------------------.
550              |                   |
551              |  V I S I B L E    |
552              |                   |
553              |    T A B L E      |
554              |                   |
555    botrow .. '-------------------`
556    \endcode
557 
558    e.g. in a table where the visible rows are 5-20, and the
559    visible columns are 100-120, then those variables would be:
560 
561    - toprow = 5
562    - botrow = 20
563    - leftcol = 100
564    - rightcol = 120
565    */
visible_cells(int & r1,int & r2,int & c1,int & c2)566   inline void visible_cells(int& r1, int& r2, int& c1, int& c2) {
567     r1 = toprow;
568     r2 = botrow;
569     c1 = leftcol;
570     c2 = rightcol;
571   }
572 
573   /**
574    Returns 1 if someone is interactively resizing a row or column.
575    You can currently call this only from within your callback().
576    */
is_interactive_resize()577   int is_interactive_resize() {
578     return(_resizing_row != -1 || _resizing_col != -1);
579   }
580 
581   /**
582    Returns if row resizing by the user is allowed.
583    */
row_resize()584   inline int row_resize() {
585     return(_row_resize);
586   }
587 
588   /**
589    Allows/disallows row resizing by the user.
590    1=allow interactive resizing, 0=disallow interactive resizing.
591    Since interactive resizing is done via the row headers,
592    row_header() must also be enabled to allow resizing.
593    */
row_resize(int flag)594   void row_resize(int flag) {			// enable row resizing
595     _row_resize = flag;
596   }
597 
598   /**
599    Returns if column resizing by the user is allowed.
600    */
col_resize()601   inline int col_resize() {
602     return(_col_resize);
603   }
604   /**
605    Allows/disallows column resizing by the user.
606    1=allow interactive resizing, 0=disallow interactive resizing.
607    Since interactive resizing is done via the column headers,
608    \p col_header() must also be enabled to allow resizing.
609    */
col_resize(int flag)610   void col_resize(int flag) {			// enable col resizing
611     _col_resize = flag;
612   }
613 
614   /**
615    Returns the current column minimum resize value.
616    */
col_resize_min()617   inline int col_resize_min() {			// column minimum resizing width
618     return(_col_resize_min);
619   }
620 
621   /**
622    Sets the current column minimum resize value.
623    This is used to prevent the user from interactively resizing
624    any column to be smaller than 'pixels'. Must be a value >=1.
625    */
col_resize_min(int val)626   void col_resize_min(int val) {
627     _col_resize_min = ( val < 1 ) ? 1 : val;
628   }
629 
630   /**
631    Returns the current row minimum resize value.
632    */
row_resize_min()633   inline int row_resize_min() {			// column minimum resizing width
634     return(_row_resize_min);
635   }
636 
637   /**
638    Sets the current row minimum resize value.
639    This is used to prevent the user from interactively resizing
640    any row to be smaller than 'pixels'. Must be a value >=1.
641    */
row_resize_min(int val)642   void row_resize_min(int val) {
643     _row_resize_min = ( val < 1 ) ? 1 : val;
644   }
645 
646   /**
647    Returns if row headers are enabled or not.
648    */
row_header()649   inline int row_header() {			// set/get row header enable flag
650     return(_row_header);
651   }
652 
653   /**
654    Enables/disables showing the row headers. 1=enabled, 0=disabled.
655    If changed, the table is redrawn.
656    */
row_header(int flag)657   void row_header(int flag) {
658     _row_header = flag;
659     table_resized();
660     redraw();
661   }
662 
663   /**
664    Returns if column headers are enabled or not.
665    */
col_header()666   inline int col_header() {			// set/get col header enable flag
667     return(_col_header);
668   }
669 
670   /**
671    Enable or disable column headers.
672    If changed, the table is redrawn.
673    */
col_header(int flag)674   void col_header(int flag) {
675     _col_header = flag;
676     table_resized();
677     redraw();
678   }
679 
680   /**
681    Sets the height in pixels for column headers and redraws the table.
682    */
col_header_height(int height)683   inline void col_header_height(int height) {	// set/get col header height
684     _col_header_h = height;
685     table_resized();
686     redraw();
687   }
688 
689   /**
690    Gets the column header height.
691    */
col_header_height()692   inline int col_header_height() {
693     return(_col_header_h);
694   }
695 
696   /**
697    Sets the row header width to n and causes the screen to redraw.
698    */
row_header_width(int width)699   inline void row_header_width(int width) {	// set/get row header width
700     _row_header_w = width;
701     table_resized();
702     redraw();
703   }
704 
705   /**
706    Returns the current row header width (in pixels).
707    */
row_header_width()708   inline int row_header_width() {
709     return(_row_header_w);
710   }
711 
712   /**
713    Sets the row header color and causes the screen to redraw.
714    */
row_header_color(Fl_Color val)715   inline void row_header_color(Fl_Color val) {	// set/get row header color
716     _row_header_color = val;
717     redraw();
718   }
719 
720   /**
721    Returns the current row header color.
722    */
row_header_color()723   inline Fl_Color row_header_color() {
724     return(_row_header_color);
725   }
726 
727   /**
728    Sets the color for column headers and redraws the table.
729    */
col_header_color(Fl_Color val)730   inline void col_header_color(Fl_Color val) {	// set/get col header color
731     _col_header_color = val;
732     redraw();
733   }
734 
735   /**
736    Gets the color for column headers.
737    */
col_header_color()738   inline Fl_Color col_header_color() {
739     return(_col_header_color);
740   }
741 
742   /**
743    Sets the height of the specified row in pixels,
744    and the table is redrawn.
745    callback() will be invoked with CONTEXT_RC_RESIZE
746    if the row's height was actually changed, and when() is FL_WHEN_CHANGED.
747    */
748   void row_height(int row, int height);		// set/get row height
749 
750   /**
751    Returns the current height of the specified row as a value in pixels.
752    */
row_height(int row)753   inline int row_height(int row) {
754     return((row<0 || row>=(int)_rowheights.size()) ? 0 : _rowheights[row]);
755   }
756 
757   /**
758    Sets the width of the specified column in pixels, and the table is redrawn.
759    callback() will be invoked with CONTEXT_RC_RESIZE
760    if the column's width was actually changed, and when() is FL_WHEN_CHANGED.
761    */
762   void col_width(int col, int width);		// set/get a column's width
763 
764   /**
765    Returns the current width of the specified column in pixels.
766    */
col_width(int col)767   inline int col_width(int col) {
768     return((col<0 || col>=(int)_colwidths.size()) ? 0 : _colwidths[col]);
769   }
770 
771   /**
772    Convenience method to set the height of all rows to the
773    same value, in pixels. The screen is redrawn.
774    */
row_height_all(int height)775   void row_height_all(int height) {		// set all row/col heights
776     for ( int r=0; r<rows(); r++ ) {
777       row_height(r, height);
778     }
779   }
780 
781   /**
782    Convenience method to set the width of all columns to the
783    same value, in pixels. The screen is redrawn.
784    */
col_width_all(int width)785   void col_width_all(int width) {
786     for ( int c=0; c<cols(); c++ ) {
787       col_width(c, width);
788     }
789   }
790 
791   /**
792    Sets the row scroll position to 'row', and causes the screen to redraw.
793    */
794   void row_position(int row);			// set/get table's current scroll position
795 
796   /**
797    Sets the column scroll position to column 'col', and causes the screen to redraw.
798    */
799   void col_position(int col);
800 
801   /**
802    Returns the current row scroll position as a row number.
803    */
row_position()804   int row_position() {				// current row position
805     return(_row_position);
806   }
807 
808   /**
809    Returns the current column scroll position as a column number.
810    */
col_position()811   int col_position() {				// current col position
812     return(_col_position);
813   }
814 
815   /**
816    Sets which row should be at the top of the table,
817    scrolling as necessary, and the table is redrawn. If the table
818    cannot be scrolled that far, it is scrolled as far as possible.
819    */
top_row(int row)820   inline void top_row(int row) {		// set/get top row (deprecated)
821     row_position(row);
822   }
823 
824   /**
825    Returns the current top row shown in the table.
826    This row may be partially obscured.
827    */
top_row()828   inline int top_row() {
829     return(row_position());
830   }
831   int is_selected(int r, int c);		// selected cell
832   void get_selection(int &row_top, int &col_left, int &row_bot, int &col_right);
833   void set_selection(int row_top, int col_left, int row_bot, int col_right);
834   int move_cursor(int R, int C, int shiftselect);
835   int move_cursor(int R, int C);
836 
837   /**
838    Changes the size of the Fl_Table, causing it to redraw.
839    */
840   void resize(int X, int Y, int W, int H);	// fltk resize() override
841   void draw(void);				// fltk draw() override
842 
843   // This crashes sortapp() during init.
844   //  void box(Fl_Boxtype val) {
845   //    Fl_Group::box(val);
846   //    if ( table ) {
847   //      resize(x(), y(), w(), h());
848   //    }
849   //  }
850   //  Fl_Boxtype box(void) const {
851   //    return(Fl_Group::box());
852   //  }
853 
854   // Child group
init_sizes()855   void init_sizes() {
856     table->init_sizes();
857     table->redraw();
858   }
add(Fl_Widget & wgt)859   void add(Fl_Widget& wgt) {
860     table->add(wgt);
861     if ( table->children() > 2 ) {
862       table->show();
863     } else {
864       table->hide();
865     }
866   }
add(Fl_Widget * wgt)867   void add(Fl_Widget* wgt) {
868     add(*wgt);
869   }
insert(Fl_Widget & wgt,int n)870   void insert(Fl_Widget& wgt, int n) {
871     table->insert(wgt,n);
872   }
insert(Fl_Widget & wgt,Fl_Widget * w2)873   void insert(Fl_Widget& wgt, Fl_Widget* w2) {
874     table->insert(wgt,w2);
875   }
remove(Fl_Widget & wgt)876   void remove(Fl_Widget& wgt) {
877     table->remove(wgt);
878   }
begin()879   void begin() {
880     table->begin();
881   }
end()882   void end() {
883     table->end();
884     // HACK: Avoid showing Fl_Scroll; seems to erase screen
885     //       causing unnecessary flicker, even if its box() is FL_NO_BOX.
886     //
887     if ( table->children() > 2 ) {
888       table->show();
889     } else {
890       table->hide();
891     }
892     Fl_Group::current(Fl_Group::parent());
893   }
array()894   Fl_Widget * const *array() {
895     return(table->array());
896   }
897 
898   /**
899    Returns the child widget by an index.
900 
901    When using the Fl_Table as a container for FLTK widgets, this method returns
902    the widget pointer from the internal array of widgets in the container.
903 
904    Typically used in loops, eg:
905    \code
906    for ( int i=0; i<children(); i++ ) {
907      Fl_Widget *w = child(i);
908      [..]
909    }
910    \endcode
911    */
child(int n)912   Fl_Widget *child(int n) const {
913     return(table->child(n));
914   }
915 
916   /**
917    Returns the number of children in the table.
918 
919    When using the Fl_Table as a container for FLTK widgets, this method returns
920    how many child widgets the table has.
921 
922    \see child(int)
923    */
children()924   int children() const {
925     return(table->children()-2);    // -2: skip Fl_Scroll's h/v scrollbar widgets
926   }
find(const Fl_Widget * wgt)927   int find(const Fl_Widget *wgt) const {
928     return(table->find(wgt));
929   }
find(const Fl_Widget & wgt)930   int find(const Fl_Widget &wgt) const {
931     return(table->find(wgt));
932   }
933   // CALLBACKS
934 
935   /**
936    * Returns the current row the event occurred on.
937    *
938    * This function should only be used from within the user's callback function.
939    */
callback_row()940   int callback_row() {
941     return(_callback_row);
942   }
943 
944   /**
945    * Returns the current column the event occurred on.
946    *
947    * This function should only be used from within the user's callback function.
948    */
callback_col()949   int callback_col() {
950     return(_callback_col);
951   }
952 
953   /**
954    * Returns the current 'table context'.
955    *
956    * This function should only be used from within the user's callback function.
957    */
callback_context()958   TableContext callback_context() {
959     return(_callback_context);
960   }
961 
do_callback(TableContext context,int row,int col)962   void do_callback(TableContext context, int row, int col) {
963     _callback_context = context;
964     _callback_row = row;
965     _callback_col = col;
966     Fl_Widget::do_callback();
967   }
968 
969 #ifdef FL_DOXYGEN
970   /**
971    The Fl_Widget::when() function is used to set a group of flags, determining
972    when the widget callback is called:
973 
974    <table border=1>
975    <tr>
976    <td>\p FL_WHEN_CHANGED</td>
977    <td>
978    callback() will be called when rows or columns are resized (interactively or
979    via col_width() or row_height()), passing CONTEXT_RC_RESIZE via
980    callback_context().
981    </td>
982    </tr><tr>
983    <td>\p FL_WHEN_RELEASE</td>
984    <td>
985    callback() will be called during FL_RELEASE events, such as when someone
986    releases a mouse button somewhere on the table.
987    </td>
988    </tr>
989    </table>
990 
991    The callback() routine is sent a TableContext that indicates the context the
992    event occurred in, such as in a cell, in a header, or elsewhere on the table.
993    When an event occurs in a cell or header, callback_row() and
994    callback_col() can be used to determine the row and column. The callback
995    can also look at the regular fltk event values (ie. Fl::event() and
996    Fl::event_button()) to determine what kind of event is occurring.
997    */
998   void when(Fl_When flags);
999 #endif
1000 
1001 #ifdef FL_DOXYGEN
1002   /**
1003    Callbacks will be called depending on the setting of Fl_Widget::when().
1004 
1005    Callback functions should use the following functions to determine the
1006    context/row/column:
1007 
1008    - Fl_Table::callback_row() returns current row
1009    - Fl_Table::callback_col() returns current column
1010    - Fl_Table::callback_context() returns current table context
1011 
1012    callback_row() and callback_col() will be set to the row and column number the
1013    event occurred on. If someone clicked on a row header, \p col will be \a 0.
1014    If someone clicked on a column header, \p row will be \a 0.
1015 
1016    callback_context() will return one of the following:
1017 
1018    <table border=1>
1019    <tr><td><tt>Fl_Table::CONTEXT_ROW_HEADER</tt></td>
1020    <td>Someone clicked on a row header. Excludes resizing.</td>
1021    </tr><tr>
1022    <td><tt>Fl_Table::CONTEXT_COL_HEADER</tt></td>
1023    <td>Someone clicked on a column header. Excludes resizing.</td>
1024    </tr><tr>
1025    <td><tt>Fl_Table::CONTEXT_CELL</tt></td>
1026    <td>
1027    Someone clicked on a cell.
1028 
1029    To receive callbacks for FL_RELEASE events, you must set
1030    when(FL_WHEN_RELEASE).
1031    </td>
1032    </tr><tr>
1033    <td><tt>Fl_Table::CONTEXT_RC_RESIZE</tt></td>
1034    <td>
1035    Someone is resizing rows/columns either interactively,
1036    or via the col_width() or row_height() API.
1037 
1038    Use is_interactive_resize()
1039    to determine interactive resizing.
1040 
1041    If resizing a column, R=0 and C=column being resized.
1042 
1043    If resizing a row, C=0 and R=row being resized.
1044 
1045    NOTE: To receive resize events, you must set when(FL_WHEN_CHANGED).
1046    </td>
1047    </tr>
1048    </table>
1049 
1050    \code
1051    class MyTable : public Fl_Table {
1052      [..]
1053    private:
1054      // Handle events that happen on the table
1055      void event_callback2() {
1056        int R = callback_row(),                         // row where event occurred
1057        C = callback_col();                             // column where event occurred
1058        TableContext context = callback_context();      // which part of table
1059        fprintf(stderr, "callback: Row=%d Col=%d Context=%d Event=%d\n",
1060                R, C, (int)context, (int)Fl::event());
1061      }
1062 
1063      // Actual static callback
1064      static void event_callback(Fl_Widget*, void* data) {
1065        MyTable *o = (MyTable*)data;
1066        o->event_callback2();
1067      }
1068 
1069    public:
1070      // Constructor
1071      MyTable() {
1072        [..]
1073        table.callback(&event_callback, (void*)this);   // setup callback
1074        table.when(FL_WHEN_CHANGED|FL_WHEN_RELEASE);    // when to call it
1075      }
1076    };
1077    \endcode
1078    */
1079   void callback(Fl_Widget*, void*);
1080 #endif
1081 
1082 #if FLTK_ABI_VERSION >= 10301
1083   // NEW
1084   /**
1085     Gets the current size of the scrollbars' troughs, in pixels.
1086 
1087     If this value is zero (default), this widget will use the
1088     Fl::scrollbar_size() value as the scrollbar's width.
1089 
1090     \returns Scrollbar size in pixels, or 0 if the global Fl::scrollbar_size() is being used.
1091     \see Fl::scrollbar_size(int)
1092   */
scrollbar_size()1093   int scrollbar_size() const {
1094       return(_scrollbar_size);
1095   }
1096   /**
1097     Sets the pixel size of the scrollbars' troughs to \p newSize, in pixels.
1098 
1099     Normally you should not need this method, and should use
1100     Fl::scrollbar_size(int) instead to manage the size of ALL your
1101     widgets' scrollbars. This ensures your application has a consistent
1102     UI, is the default behavior, and is normally what you want.
1103 
1104     Only use THIS method if you really need to override the global
1105     scrollbar size. The need for this should be rare.
1106 
1107     Setting \p newSize to the special value of 0 causes the widget to
1108     track the global Fl::scrollbar_size(), which is the default.
1109 
1110     \param[in] newSize Sets the scrollbar size in pixels.\n
1111                     If 0 (default), scrollbar size tracks the global Fl::scrollbar_size()
1112     \see Fl::scrollbar_size()
1113   */
scrollbar_size(int newSize)1114   void scrollbar_size(int newSize) {
1115       if ( newSize != _scrollbar_size ) redraw();
1116       _scrollbar_size = newSize;
1117   }
1118 #endif
1119 #if FLTK_ABI_VERSION >= 10303
1120   /**
1121     Flag to control if Tab navigates table cells or not.
1122 
1123     If on, Tab key navigates table cells.
1124     If off, Tab key navigates fltk widget focus. (default)
1125 
1126     As of fltk 1.3, the default behavior of the Tab key is to navigate focus off
1127     of the current widget, and on to the next one.  But in some applications,
1128     it's useful for Tab to be used to navigate cells in the Fl_Table.
1129 
1130     \param [in] val If \p val is 1, Tab key navigates cells in table, not fltk widgets.<BR>
1131                     If \p val is 0, Tab key will advance focus to the next fltk widget (default), and does not navigate cells in table.
1132   */
tab_cell_nav(int val)1133   void tab_cell_nav(int val) {
1134     if ( val ) flags_ |=  TABCELLNAV;
1135     else       flags_ &= ~TABCELLNAV;
1136   }
1137 
1138   /**
1139     Get state of table's 'Tab' key cell navigation flag.
1140 
1141     \returns 1 if Tab configured to navigate cells in table<br>0 to navigate widget focus (default)
1142 
1143     \see tab_cell_nav(int)
1144   */
tab_cell_nav()1145   int tab_cell_nav() const {
1146     return(flags_ & TABCELLNAV ? 1 : 0);
1147   }
1148 #endif
1149 };
1150 
1151 #endif /*_FL_TABLE_H*/
1152 
1153 //
1154 // End of "$Id$".
1155 //
1156