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