FLTK 1.3.0
Fl_Table.H
00001 //
00002 // "$Id$"
00003 //
00004 // Fl_Table -- A table widget
00005 //
00006 // Copyright 2002 by Greg Ercolano.
00007 // Copyright (c) 2004 O'ksi'D
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Library General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2 of the License, or (at your option) any later version.
00013 //
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Library General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU Library General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00022 // USA.
00023 //
00024 // Please report all bugs and problems to "erco at seriss dot com".
00025 //
00026 // TODO:
00027 //    o Auto scroll during dragged selection
00028 //    o Keyboard navigation (up/down/left/right arrow)
00029 //
00030 
00031 #ifndef _FL_TABLE_H
00032 #define _FL_TABLE_H
00033 
00034 #include <sys/types.h>
00035 #include <string.h>             // memcpy
00036 #ifdef WIN32
00037 #include <malloc.h>             // WINDOWS: malloc/realloc
00038 #else /*WIN32*/
00039 #include <stdlib.h>             // UNIX: malloc/realloc
00040 #endif /*WIN32*/
00041 
00042 #include <FL/Fl.H>
00043 #include <FL/Fl_Group.H>
00044 #include <FL/Fl_Scroll.H>
00045 #include <FL/Fl_Box.H>
00046 #include <FL/Fl_Scrollbar.H>
00047 
00181 class FL_EXPORT Fl_Table : public Fl_Group {
00182 public:
00186   enum TableContext {
00187     CONTEXT_NONE       = 0,     
00188     CONTEXT_STARTPAGE  = 0x01,  
00189     CONTEXT_ENDPAGE    = 0x02,  
00190     CONTEXT_ROW_HEADER = 0x04,  
00191     CONTEXT_COL_HEADER = 0x08,  
00192     CONTEXT_CELL       = 0x10,  
00193     CONTEXT_TABLE      = 0x20,  
00194     CONTEXT_RC_RESIZE  = 0x40   
00195   };
00196   
00197 private:
00198   int _rows, _cols;     // total rows/cols
00199   int _row_header_w;    // width of row header
00200   int _col_header_h;    // height of column header
00201   int _row_position;    // last row_position set (not necessarily == toprow!)
00202   int _col_position;    // last col_position set (not necessarily == leftcol!)
00203   
00204   char _row_header;     // row header enabled?
00205   char _col_header;     // col header enabled?
00206   char _row_resize;     // row resizing enabled?
00207   char _col_resize;     // col resizing enabled?
00208   int _row_resize_min;  // row minimum resizing height (default=1)
00209   int _col_resize_min;  // col minimum resizing width (default=1)
00210   
00211   // OPTIMIZATION: partial row/column redraw variables
00212   int _redraw_toprow;
00213   int _redraw_botrow;
00214   int _redraw_leftcol;
00215   int _redraw_rightcol;
00216   Fl_Color _row_header_color;
00217   Fl_Color _col_header_color;
00218   
00219   int _auto_drag;
00220   int _selecting;
00221   
00222   // An STL-ish vector without templates
00223   class FL_EXPORT IntVector {
00224     int *arr;
00225     unsigned int _size;
00226     void init() {
00227       arr = NULL;
00228       _size = 0;
00229     }
00230     void copy(int *newarr, unsigned int newsize) {
00231       size(newsize);
00232       memcpy(arr, newarr, newsize * sizeof(int));
00233     }
00234   public:
00235     IntVector() { init(); }                                     // CTOR
00236     ~IntVector() { if ( arr ) free(arr); arr = NULL; }          // DTOR
00237     IntVector(IntVector&o) { init(); copy(o.arr, o._size); }    // COPY CTOR
00238     IntVector& operator=(IntVector&o) {                         // ASSIGN
00239       init();
00240       copy(o.arr, o._size);
00241       return(*this);
00242     }
00243     int operator[](int x) const { return(arr[x]); }
00244     int& operator[](int x) { return(arr[x]); }
00245     unsigned int size() { return(_size); }
00246     void size(unsigned int count) {
00247       if ( count != _size ) {
00248         arr = (int*)realloc(arr, count * sizeof(int));
00249         _size = count;
00250       }
00251     }
00252     int pop_back() { int tmp = arr[_size-1]; _size--; return(tmp); }
00253     void push_back(int val) { unsigned int x = _size; size(_size+1); arr[x] = val; }
00254     int back() { return(arr[_size-1]); }
00255   };
00256   
00257   IntVector _colwidths;                 // column widths in pixels
00258   IntVector _rowheights;                // row heights in pixels
00259   
00260   Fl_Cursor _last_cursor;               // last mouse cursor before changed to 'resize' cursor
00261   
00262   // EVENT CALLBACK DATA
00263   TableContext _callback_context;       // event context
00264   int _callback_row, _callback_col;     // event row/col
00265   
00266   // handle() state variables.
00267   //    Put here instead of local statics in handle(), so more
00268   //    than one Fl_Table can exist without crosstalk between them.
00269   //
00270   int _resizing_col;                    // column being dragged
00271   int _resizing_row;                    // row being dragged
00272   int _dragging_x;                      // starting x position for horiz drag
00273   int _dragging_y;                      // starting y position for vert drag
00274   int _last_row;                        // last row we FL_PUSH'ed
00275   
00276   // Redraw single cell
00277   void _redraw_cell(TableContext context, int R, int C);
00278   
00279   void _start_auto_drag();
00280   void _stop_auto_drag();
00281   void _auto_drag_cb();
00282   static void _auto_drag_cb2(void *d);
00283   
00284 protected:
00285   enum ResizeFlag {
00286     RESIZE_NONE      = 0,
00287     RESIZE_COL_LEFT  = 1,
00288     RESIZE_COL_RIGHT = 2,
00289     RESIZE_ROW_ABOVE = 3,
00290     RESIZE_ROW_BELOW = 4
00291   };
00292   
00293   int table_w, table_h;                         // table's virtual size (in pixels)
00294   int toprow, botrow, leftcol, rightcol;        // four corners of viewable table
00295   
00296   // selection
00297   int current_row, current_col;
00298   int select_row, select_col;
00299   
00300   // OPTIMIZATION: Precomputed scroll positions for the toprow/leftcol
00301   int toprow_scrollpos;
00302   int leftcol_scrollpos;
00303   
00304   // Dimensions
00305   int tix, tiy, tiw, tih;                       // data table inner dimension xywh
00306   int tox, toy, tow, toh;                       // data table outer dimension xywh
00307   int wix, wiy, wiw, wih;                       // widget inner dimension xywh
00308   
00309   Fl_Scroll *table;                             // container for child fltk widgets (if any)
00310   Fl_Scrollbar *vscrollbar;                     // vertical scrollbar
00311   Fl_Scrollbar *hscrollbar;                     // horizontal scrollbar
00312   
00313   // Fltk
00314   int handle(int e);                            // fltk handle() override
00315   
00316   // Class maintenance
00317   void recalc_dimensions();
00318   void table_resized();                         // table resized; recalc
00319   void table_scrolled();                        // table scrolled; recalc
00320   void get_bounds(TableContext context,         // return x/y/w/h bounds for context
00321                   int &X, int &Y, int &W, int &H);
00322   void change_cursor(Fl_Cursor newcursor);      // change mouse cursor to some other shape
00323   TableContext cursor2rowcol(int &R, int &C, ResizeFlag &resizeflag);
00324   // find r/c given current x/y event
00325   int find_cell(TableContext context,           // find cell's x/y/w/h given r/c
00326                 int R, int C, int &X, int &Y, int &W, int &H);
00327   int row_col_clamp(TableContext context, int &R, int &C);
00328   // clamp r/c to known universe
00329   
00440   virtual void draw_cell(TableContext context, int R=0, int C=0, 
00441                          int X=0, int Y=0, int W=0, int H=0)
00442   { }                                           // overridden by deriving class
00443   
00444   long row_scroll_position(int row);            // find scroll position of row (in pixels)
00445   long col_scroll_position(int col);            // find scroll position of col (in pixels)
00446   
00447   int is_fltk_container() {                     // does table contain fltk widgets?
00448     return( Fl_Group::children() > 3 );         // (ie. more than box and 2 scrollbars?)
00449   }
00450   
00451   static void scroll_cb(Fl_Widget*,void*);      // h/v scrollbar callback
00452   
00453   void damage_zone(int r1, int c1, int r2, int c2, int r3 = 0, int c3 = 0);
00454   
00455   void redraw_range(int toprow, int botrow, int leftcol, int rightcol) {
00456     if ( _redraw_toprow == -1 ) {
00457       // Initialize redraw range
00458       _redraw_toprow = toprow;
00459       _redraw_botrow = botrow;
00460       _redraw_leftcol = leftcol;
00461       _redraw_rightcol = rightcol;
00462     } else {
00463       // Extend redraw range
00464       if ( toprow < _redraw_toprow ) _redraw_toprow = toprow;
00465       if ( botrow > _redraw_botrow ) _redraw_botrow = botrow;
00466       if ( leftcol < _redraw_leftcol ) _redraw_leftcol = leftcol;
00467       if ( rightcol > _redraw_rightcol ) _redraw_rightcol = rightcol;
00468     }
00469     
00470     // Indicate partial redraw needed of some cells
00471     damage(FL_DAMAGE_CHILD);
00472   }
00473   
00474 public:
00480   Fl_Table(int X, int Y, int W, int H, const char *l=0);
00481   
00486   ~Fl_Table();
00487   
00493   virtual void clear() { rows(0); cols(0); }
00494   
00495   // \todo: add topline(), middleline(), bottomline()
00496   
00502   inline void table_box(Fl_Boxtype val) {
00503     table->box(val);
00504     table_resized();
00505   }
00506   
00510   inline Fl_Boxtype table_box( void ) {
00511     return(table->box());
00512   }
00513   
00517   virtual void rows(int val);                   // set/get number of rows
00518   
00522   inline int rows() {
00523     return(_rows);
00524   }
00525   
00529   virtual void cols(int val);                   // set/get number of columns
00530   
00534   inline int cols() {
00535     return(_cols);
00536   }
00537   
00566   inline void visible_cells(int& r1, int& r2, int& c1, int& c2) {
00567     r1 = toprow;
00568     r2 = botrow;
00569     c1 = leftcol;
00570     c2 = rightcol;
00571   } 
00572   
00577   int is_interactive_resize() {
00578     return(_resizing_row != -1 || _resizing_col != -1);
00579   } 
00580   
00584   inline int row_resize() {
00585     return(_row_resize);
00586   }
00587   
00594   void row_resize(int flag) {                   // enable row resizing
00595     _row_resize = flag;
00596   }
00597   
00601   inline int col_resize() {
00602     return(_col_resize);
00603   }
00610   void col_resize(int flag) {                   // enable col resizing
00611     _col_resize = flag;
00612   }
00613   
00619   inline int col_resize_min() {                 // column minimum resizing width
00620     return(_col_resize_min);
00621   }
00622   
00626   void col_resize_min(int val) {
00627     _col_resize_min = ( val < 1 ) ? 1 : val;
00628   } 
00629   
00633   inline int row_resize_min() {                 // column minimum resizing width
00634     return(_row_resize_min);
00635   }
00636   
00642   void row_resize_min(int val) {
00643     _row_resize_min = ( val < 1 ) ? 1 : val;
00644   }
00645   
00649   inline int row_header() {                     // set/get row header enable flag
00650     return(_row_header);
00651   }
00652   
00657   void row_header(int flag) {
00658     _row_header = flag;
00659     table_resized();
00660     redraw();
00661   }
00662   
00666   inline int col_header() {                     // set/get col header enable flag
00667     return(_col_header);
00668   }
00669   
00674   void col_header(int flag) {
00675     _col_header = flag;
00676     table_resized();
00677     redraw();
00678   }
00679   
00683   inline void col_header_height(int height) {   // set/get col header height
00684     _col_header_h = height;
00685     table_resized();
00686     redraw();
00687   }
00688   
00692   inline int col_header_height() {
00693     return(_col_header_h);
00694   }
00695   
00699   inline void row_header_width(int width) {     // set/get row header width
00700     _row_header_w = width;
00701     table_resized();
00702     redraw();
00703   }
00704   
00708   inline int row_header_width() {
00709     return(_row_header_w);
00710   }
00711   
00715   inline void row_header_color(Fl_Color val) {  // set/get row header color
00716     _row_header_color = val;
00717     redraw();
00718   }
00719   
00723   inline Fl_Color row_header_color() {
00724     return(_row_header_color);
00725   } 
00726   
00730   inline void col_header_color(Fl_Color val) {  // set/get col header color
00731     _col_header_color = val;
00732     redraw();
00733   }
00734   
00738   inline Fl_Color col_header_color() {
00739     return(_col_header_color);
00740   }
00741   
00748   void row_height(int row, int height);         // set/get row height
00749   
00753   inline int row_height(int row) {
00754     return((row<0 || row>=(int)_rowheights.size()) ? 0 : _rowheights[row]);
00755   }
00756   
00762   void col_width(int col, int width);           // set/get a column's width
00763   
00767   inline int col_width(int col) {
00768     return((col<0 || col>=(int)_colwidths.size()) ? 0 : _colwidths[col]);
00769   }
00770   
00775   void row_height_all(int height) {             // set all row/col heights
00776     for ( int r=0; r<rows(); r++ ) {
00777       row_height(r, height);
00778     }
00779   }
00780   
00785   void col_width_all(int width) {
00786     for ( int c=0; c<cols(); c++ ) {
00787       col_width(c, width);
00788     }
00789   }
00790   
00794   void row_position(int row);                   // set/get table's current scroll position
00795   
00799   void col_position(int col);
00800   
00804   int row_position() {                          // current row position
00805     return(_row_position);
00806   }
00807   
00811   int col_position() {                          // current col position
00812     return(_col_position);
00813   }
00814   
00820   inline void top_row(int row) {                // set/get top row (deprecated)
00821     row_position(row);
00822   }
00823   
00828   inline int top_row() {
00829     return(row_position());
00830   }
00831   int is_selected(int r, int c);                // selected cell
00832   void get_selection(int &row_top, int &col_left, int &row_bot, int &col_right);
00833   void set_selection(int row_top, int col_left, int row_bot, int col_right);
00834   int move_cursor(int R, int C);
00835   
00839   void resize(int X, int Y, int W, int H);      // fltk resize() override
00840   void draw(void);                              // fltk draw() override
00841   
00842   // This crashes sortapp() during init.
00843   //  void box(Fl_Boxtype val) {
00844   //    Fl_Group::box(val);
00845   //    if ( table ) {
00846   //      resize(x(), y(), w(), h());
00847   //    }
00848   //  }
00849   //  Fl_Boxtype box(void) const {
00850   //    return(Fl_Group::box());
00851   //  }
00852   
00853   // Child group
00854   void init_sizes() {
00855     table->init_sizes();
00856     table->redraw();
00857   }
00858   void add(Fl_Widget& w) {
00859     table->add(w);
00860   }
00861   void add(Fl_Widget* w) {
00862     table->add(w);
00863   }
00864   void insert(Fl_Widget& w, int n) {
00865     table->insert(w,n);
00866   }
00867   void insert(Fl_Widget& w, Fl_Widget* w2) {
00868     table->insert(w,w2);
00869   }
00870   void remove(Fl_Widget& w) {
00871     table->remove(w);
00872   }
00873   void begin() {
00874     table->begin();
00875   }
00876   void end() {
00877     table->end();
00878     // HACK: Avoid showing Fl_Scroll; seems to erase screen
00879     //       causing unnecessary flicker, even if its box() is FL_NO_BOX.
00880     //
00881     if ( table->children() > 2 ) {
00882       table->show();
00883     } else {
00884       table->hide();
00885     } 
00886     Fl_Group::current(Fl_Group::parent());
00887   }
00888   Fl_Widget * const *array() {
00889     return(table->array());
00890   }
00891   
00906   Fl_Widget *child(int n) const {
00907     return(table->child(n));
00908   }
00909   
00918   int children() const {
00919     return(table->children()-2);    // -2: skip Fl_Scroll's h/v scrollbar widgets
00920   }
00921   int find(const Fl_Widget *w) const {
00922     return(table->find(w));
00923   }
00924   int find(const Fl_Widget &w) const {
00925     return(table->find(w));
00926   } 
00927   // CALLBACKS
00928   
00934   int callback_row() {
00935     return(_callback_row);
00936   }
00937   
00943   int callback_col() {
00944     return(_callback_col);
00945   }
00946   
00952   TableContext callback_context() {
00953     return(_callback_context);
00954   }
00955   
00956   void do_callback(TableContext context, int row, int col) {
00957     _callback_context = context;
00958     _callback_row = row;
00959     _callback_col = col;
00960     Fl_Widget::do_callback();
00961   }
00962   
00963 #if FL_DOXYGEN
00964 
00992   void when(Fl_When flags);
00993 #endif
00994   
00995 #if FL_DOXYGEN
00996 
01073   void callback(Fl_Widget*, void*);
01074 #endif
01075 };
01076 
01077 #endif /*_FL_TABLE_H*/
01078 
01079 //
01080 // End of "$Id$".
01081 //