// // "$Id$" // // Fl_Table_Row -- A row oriented table widget // // A class specializing in a table of rows. // Handles row-specific selection behavior. // // Copyright 2002 by Greg Ercolano. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 // USA. // // Please report all bugs and problems to "erco at seriss dot com". // // // TODO: // o Row headings (only column headings supported currently) // #include // for debugging #include #include #include // Is row selected? int Fl_Table_Row::row_selected(int row) { if ( row < 0 || row >= rows() ) return(-1); return(_rowselect[row]); } // Change row selection type void Fl_Table_Row::type(TableRowSelectMode val) { _selectmode = val; switch ( _selectmode ) { case SELECT_NONE: { for ( int row=0; row 1 ) { // only one allowed _rowselect[row] = 0; } } } redraw(); break; } case SELECT_MULTI: break; } } // Change selection state for row // // flag: // 0 - clear selection // 1 - set selection // 2 - toggle selection // // Returns: // 0 - selection state did not change // 1 - selection state changed // -1 - row out of range or incorrect selection mode // int Fl_Table_Row::select_row(int row, int flag) { int ret = 0; if ( row < 0 || row >= rows() ) { return(-1); } switch ( _selectmode ) { case SELECT_NONE: return(-1); case SELECT_SINGLE: { int oldval; for ( int t=0; t= toprow && row <= botrow ) { // row visible? // Extend partial redraw range redraw_range(row, row, leftcol, rightcol); } ret = 1; } } } return(ret); } // Select all rows to a known state void Fl_Table_Row::select_all_rows(int flag) { switch ( _selectmode ) { case SELECT_NONE: return; case SELECT_SINGLE: if ( flag != 0 ) return; //FALLTHROUGH case SELECT_MULTI: { char changed = 0; if ( flag == 2 ) { for ( int row=0; row<(int)_rowselect.size(); row++ ) { _rowselect[row] ^= 1; } changed = 1; } else { for ( int row=0; row<(int)_rowselect.size(); row++ ) { changed |= (_rowselect[row] != flag)?1:0; _rowselect[row] = flag; } } if ( changed ) { redraw(); } } } } // Set number of rows void Fl_Table_Row::rows(int val) { Fl_Table::rows(val); while ( val > (int)_rowselect.size() ) { _rowselect.push_back(0); } // enlarge while ( val < (int)_rowselect.size() ) { _rowselect.pop_back(); } // shrink } // #include "eventnames.h" // debugging // #include // Handle events int Fl_Table_Row::handle(int event) { // fprintf(stderr, "** EVENT: %s: EVENT XY=%d,%d\n", // eventnames[event], Fl::event_x(), Fl::event_y()); // debugging // Let base class handle event int ret = Fl_Table::handle(event); // The following code disables cell selection.. why was it added? -erco 05/18/03 // if ( ret ) { _last_y = Fl::event_y(); return(1); } // base class 'handled' it (eg. column resize) int shiftstate = (Fl::event_state() & FL_CTRL) ? FL_CTRL : (Fl::event_state() & FL_SHIFT) ? FL_SHIFT : 0; // Which row/column are we over? int R, C; // row/column being worked on ResizeFlag resizeflag; // which resizing area are we over? (0=none) TableContext context = cursor2rowcol(R, C, resizeflag); switch ( event ) { case FL_PUSH: if ( Fl::event_button() == 1 ) { _last_push_x = Fl::event_x(); // save regardless of context _last_push_y = Fl::event_y(); // " " // Handle selection in table. // Select cell under cursor, and enable drag selection mode. // if ( context == CONTEXT_CELL ) { // Ctrl key? Toggle selection state switch ( shiftstate ) { case FL_CTRL: select_row(R, 2); // toggle break; case FL_SHIFT: { select_row(R, 1); if ( _last_row > -1 ) { int srow = R, erow = _last_row; if ( srow > erow ) { srow = _last_row; erow = R; } for ( int row = srow; row <= erow; row++ ) { select_row(row, 1); } } break; } default: select_all_rows(0); // clear all previous selections select_row(R, 1); break; } _last_row = R; _dragging_select = 1; ret = 1; // FL_PUSH handled (ensures FL_DRAG will be sent) // redraw(); // redraw() handled by select_row() } } break; case FL_DRAG: { if ( _dragging_select ) { // Dragged off table edges? Handle scrolling int offtop = toy - _last_y; // >0 if off top of table int offbot = _last_y - (toy + toh); // >0 if off bottom of table if ( offtop > 0 && row_position() > 0 ) { // Only scroll in upward direction int diff = _last_y - Fl::event_y(); if ( diff < 1 ) { ret = 1; break; } row_position(row_position() - diff); context = CONTEXT_CELL; C = 0; R = row_position(); // HACK: fake it if ( R < 0 || R > rows() ) { ret = 1; break; } // HACK: ugly } else if ( offbot > 0 && botrow < rows() ) { // Only scroll in downward direction int diff = Fl::event_y() - _last_y; if ( diff < 1 ) { ret = 1; break; } row_position(row_position() + diff); context = CONTEXT_CELL; C = 0; R = botrow; // HACK: fake it if ( R < 0 || R > rows() ) { ret = 1; break; } // HACK: ugly } if ( context == CONTEXT_CELL ) { switch ( shiftstate ) { case FL_CTRL: if ( R != _last_row ) { // toggle if dragged to new row select_row(R, 2); // 2=toggle } break; case FL_SHIFT: default: select_row(R, 1); if ( _last_row > -1 ) { int srow = R, erow = _last_row; if ( srow > erow ) { srow = _last_row; erow = R; } for ( int row = srow; row <= erow; row++ ) { select_row(row, 1); } } break; } ret = 1; // drag handled _last_row = R; } } break; } case FL_RELEASE: if ( Fl::event_button() == 1 ) { _dragging_select = 0; ret = 1; // release handled // Clicked off edges of data table? // A way for user to clear the current selection. // int databot = tiy + table_h, dataright = tix + table_w; if ( ( _last_push_x > dataright && Fl::event_x() > dataright ) || ( _last_push_y > databot && Fl::event_y() > databot ) ) { select_all_rows(0); // clear previous selections } } break; default: break; } _last_y = Fl::event_y(); return(ret); } // // End of "$Id$". //