fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

Fl_Table_Row.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: Fl_Table_Row.cxx 7950 2010-12-05 01:22:53Z greg.ercolano $"
00003 //
00004 // Fl_Table_Row -- A row oriented table widget
00005 //
00006 //    A class specializing in a table of rows.
00007 //    Handles row-specific selection behavior.
00008 //
00009 // Copyright 2002 by Greg Ercolano.
00010 //
00011 // This library is free software; you can redistribute it and/or
00012 // modify it under the terms of the GNU Library General Public
00013 // License as published by the Free Software Foundation; either
00014 // version 2 of the License, or (at your option) any later version.
00015 //
00016 // This library is distributed in the hope that it will be useful,
00017 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019 // Library General Public License for more details.
00020 //
00021 // You should have received a copy of the GNU Library General Public
00022 // License along with this library; if not, write to the Free Software
00023 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00024 // USA.
00025 //
00026 // Please report all bugs and problems to "erco at seriss dot com".
00027 //
00028 //
00029 // TODO:
00030 //    o Row headings (only column headings supported currently)
00031 //
00032 
00033 #include <stdio.h>              // for debugging
00034 #include <FL/Fl.H>
00035 #include <FL/fl_draw.H>
00036 #include <FL/Fl_Table_Row.H>
00037 
00038 // Is row selected?
00039 int Fl_Table_Row::row_selected(int row) {
00040   if ( row < 0 || row >= rows() ) return(-1);
00041   return(_rowselect[row]);
00042 }
00043 
00044 // Change row selection type
00045 void Fl_Table_Row::type(TableRowSelectMode val) {
00046   _selectmode = val;
00047   switch ( _selectmode ) {
00048     case SELECT_NONE: {
00049       for ( int row=0; row<rows(); row++ ) {
00050         _rowselect[row] = 0;
00051       }
00052       redraw();
00053       break;
00054     }
00055     case SELECT_SINGLE: {
00056       int count = 0;
00057       for ( int row=0; row<rows(); row++ ) {
00058         if ( _rowselect[row] ) {
00059           if ( ++count > 1 ) {  // only one allowed
00060             _rowselect[row] = 0;
00061           }
00062         }
00063       }
00064       redraw();
00065       break;
00066     }
00067     case SELECT_MULTI:
00068       break;
00069   }
00070 }
00071 
00072 // Change selection state for row
00073 //
00074 //     flag:
00075 //        0 - clear selection
00076 //        1 - set selection
00077 //        2 - toggle selection
00078 //
00079 //     Returns:
00080 //        0 - selection state did not change
00081 //        1 - selection state changed
00082 //       -1 - row out of range or incorrect selection mode
00083 //
00084 int Fl_Table_Row::select_row(int row, int flag) {
00085   int ret = 0;
00086   if ( row < 0 || row >= rows() ) { return(-1); }
00087   switch ( _selectmode ) {
00088     case SELECT_NONE:
00089       return(-1);
00090       
00091     case SELECT_SINGLE: {
00092       int oldval;
00093       for ( int t=0; t<rows(); t++ ) {
00094         if ( t == row ) {
00095           oldval = _rowselect[row];
00096           if ( flag == 2 ) { _rowselect[row] ^= 1; }
00097           else             { _rowselect[row] = flag; }
00098           if ( oldval != _rowselect[row] ) {
00099             redraw_range(row, row, leftcol, rightcol);
00100             ret = 1;
00101           }
00102         }
00103         else if ( _rowselect[t] ) {
00104           _rowselect[t] = 0;
00105           redraw_range(t, t, leftcol, rightcol);
00106         }
00107       }
00108       break;
00109     }
00110       
00111     case SELECT_MULTI: {
00112       int oldval = _rowselect[row];
00113       if ( flag == 2 ) { _rowselect[row] ^= 1; }
00114       else             { _rowselect[row] = flag; }
00115       if ( _rowselect[row] != oldval ) {                // select state changed?
00116         if ( row >= toprow && row <= botrow ) {         // row visible?
00117           // Extend partial redraw range
00118           redraw_range(row, row, leftcol, rightcol);
00119         }
00120         ret = 1;
00121       }
00122     }
00123   }
00124   return(ret);
00125 }
00126 
00127 // Select all rows to a known state
00128 void Fl_Table_Row::select_all_rows(int flag) {
00129   switch ( _selectmode ) {
00130     case SELECT_NONE:
00131       return;
00132       
00133     case SELECT_SINGLE:
00134       if ( flag != 0 ) return;
00135       //FALLTHROUGH
00136       
00137     case SELECT_MULTI: {
00138       char changed = 0;
00139       if ( flag == 2 ) {
00140         for ( int row=0; row<(int)_rowselect.size(); row++ ) {
00141           _rowselect[row] ^= 1;
00142         }
00143         changed = 1;
00144       } else {
00145         for ( int row=0; row<(int)_rowselect.size(); row++ ) {
00146           changed |= (_rowselect[row] != flag)?1:0;
00147           _rowselect[row] = flag; 
00148         }
00149       }
00150       if ( changed ) {
00151         redraw();
00152       }
00153     }
00154   }
00155 }
00156 
00157 // Set number of rows
00158 void Fl_Table_Row::rows(int val) {
00159   Fl_Table::rows(val);
00160   while ( val > (int)_rowselect.size() ) { _rowselect.push_back(0); }   // enlarge
00161   while ( val < (int)_rowselect.size() ) { _rowselect.pop_back(); }     // shrink
00162 }
00163 
00164 // #include "eventnames.h"              // debugging
00165 // #include <stdio.h>
00166 
00167 // Handle events
00168 int Fl_Table_Row::handle(int event) {
00169   
00170   //  fprintf(stderr, "** EVENT: %s: EVENT XY=%d,%d\n", 
00171   //      eventnames[event], Fl::event_x(), Fl::event_y());     // debugging
00172   
00173   // Let base class handle event
00174   int ret = Fl_Table::handle(event);
00175   
00176   // The following code disables cell selection.. why was it added? -erco 05/18/03
00177   // if ( ret ) { _last_y = Fl::event_y(); return(1); } // base class 'handled' it (eg. column resize)
00178   
00179   int shiftstate = (Fl::event_state() & FL_CTRL) ? FL_CTRL :
00180   (Fl::event_state() & FL_SHIFT) ? FL_SHIFT : 0;
00181   
00182   // Which row/column are we over?
00183   int R, C;                             // row/column being worked on
00184   ResizeFlag resizeflag;                // which resizing area are we over? (0=none)
00185   TableContext context = cursor2rowcol(R, C, resizeflag);
00186   switch ( event ) {
00187     case FL_PUSH:
00188       if ( Fl::event_button() == 1 ) {
00189         _last_push_x = Fl::event_x();   // save regardless of context
00190         _last_push_y = Fl::event_y();   // " "
00191         
00192         // Handle selection in table.
00193         //     Select cell under cursor, and enable drag selection mode.
00194         //
00195         if ( context == CONTEXT_CELL ) {
00196           // Ctrl key? Toggle selection state
00197           switch ( shiftstate ) {
00198             case FL_CTRL:
00199               select_row(R, 2);         // toggle
00200               break;
00201               
00202             case FL_SHIFT: {
00203               select_row(R, 1);
00204               if ( _last_row > -1 ) {
00205                 int srow = R, erow = _last_row;
00206                 if ( srow > erow ) {
00207                   srow = _last_row;
00208                   erow = R;
00209                 }
00210                 for ( int row = srow; row <= erow; row++ ) {
00211                   select_row(row, 1);
00212                 }
00213               }
00214               break;
00215             }
00216               
00217             default:
00218               select_all_rows(0);       // clear all previous selections
00219               select_row(R, 1);
00220               break;
00221           }
00222           
00223           _last_row = R;
00224           _dragging_select = 1;
00225           ret = 1;      // FL_PUSH handled (ensures FL_DRAG will be sent)
00226           // redraw();  // redraw() handled by select_row()
00227         }
00228       } 
00229       break;
00230       
00231     case FL_DRAG: {
00232       if ( _dragging_select ) {
00233         // Dragged off table edges? Handle scrolling
00234         int offtop = toy - _last_y;                     // >0 if off top of table
00235         int offbot = _last_y - (toy + toh);             // >0 if off bottom of table
00236         
00237         if ( offtop > 0 && row_position() > 0 ) {
00238           // Only scroll in upward direction
00239           int diff = _last_y - Fl::event_y();
00240           if ( diff < 1 ) {
00241             ret = 1;
00242             break;
00243           }
00244           row_position(row_position() - diff);
00245           context = CONTEXT_CELL; C = 0; R = row_position();  // HACK: fake it
00246           if ( R < 0 || R > rows() ) { ret = 1; break; }      // HACK: ugly
00247         }
00248         else if ( offbot > 0 && botrow < rows() ) {
00249           // Only scroll in downward direction
00250           int diff = Fl::event_y() - _last_y;
00251           if ( diff < 1 ) {
00252             ret = 1;
00253             break;
00254           }
00255           row_position(row_position() + diff);
00256           context = CONTEXT_CELL; C = 0; R = botrow;            // HACK: fake it
00257           if ( R < 0 || R > rows() ) { ret = 1; break; }        // HACK: ugly
00258         }
00259         if ( context == CONTEXT_CELL ) {
00260           switch ( shiftstate ) {
00261             case FL_CTRL:
00262               if ( R != _last_row ) {           // toggle if dragged to new row
00263                 select_row(R, 2);               // 2=toggle
00264               }
00265               break;
00266               
00267             case FL_SHIFT:
00268             default:
00269               select_row(R, 1);
00270               if ( _last_row > -1 ) {
00271                 int srow = R, erow = _last_row;
00272                 if ( srow > erow ) {
00273                   srow = _last_row;
00274                   erow = R;
00275                 }
00276                 for ( int row = srow; row <= erow; row++ ) {
00277                   select_row(row, 1);
00278                 }
00279               }
00280               break;
00281           }
00282           ret = 1;                              // drag handled
00283           _last_row = R;
00284         }
00285       }
00286       break;
00287     }
00288       
00289     case FL_RELEASE:
00290       if ( Fl::event_button() == 1 ) {
00291         _dragging_select = 0;
00292         ret = 1;                        // release handled
00293         // Clicked off edges of data table? 
00294         //    A way for user to clear the current selection.
00295         //
00296         int databot = tiy + table_h,
00297         dataright = tix + table_w;
00298         if ( 
00299             ( _last_push_x > dataright && Fl::event_x() > dataright ) ||
00300             ( _last_push_y > databot && Fl::event_y() > databot )
00301             ) {
00302           select_all_rows(0);                   // clear previous selections
00303         }
00304       }
00305       break;
00306       
00307     default:
00308       break;
00309   }
00310   _last_y = Fl::event_y();
00311   return(ret);
00312 }
00313 
00314 //
00315 // End of "$Id: Fl_Table_Row.cxx 7950 2010-12-05 01:22:53Z greg.ercolano $".
00316 //