ntk/src/Fl_Table_Row.cxx

317 lines
9.1 KiB
C++

//
// "$Id: Fl_Table_Row.cxx 7950 2010-12-05 01:22:53Z greg.ercolano $"
//
// 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 <stdio.h> // for debugging
#include <FL/Fl.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Table_Row.H>
// 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<rows(); row++ ) {
_rowselect[row] = 0;
}
redraw();
break;
}
case SELECT_SINGLE: {
int count = 0;
for ( int row=0; row<rows(); row++ ) {
if ( _rowselect[row] ) {
if ( ++count > 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<rows(); t++ ) {
if ( t == row ) {
oldval = _rowselect[row];
if ( flag == 2 ) { _rowselect[row] ^= 1; }
else { _rowselect[row] = flag; }
if ( oldval != _rowselect[row] ) {
redraw_range(row, row, leftcol, rightcol);
ret = 1;
}
}
else if ( _rowselect[t] ) {
_rowselect[t] = 0;
redraw_range(t, t, leftcol, rightcol);
}
}
break;
}
case SELECT_MULTI: {
int oldval = _rowselect[row];
if ( flag == 2 ) { _rowselect[row] ^= 1; }
else { _rowselect[row] = flag; }
if ( _rowselect[row] != oldval ) { // select state changed?
if ( row >= 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 <stdio.h>
// 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: Fl_Table_Row.cxx 7950 2010-12-05 01:22:53Z greg.ercolano $".
//