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. Distribution and use rights are outlined in
00010 // the file "COPYING" which should have been included with this file.  If this
00011 // file is missing or damaged, see the license at:
00012 //
00013 //     http://www.fltk.org/COPYING.php
00014 //
00015 // Please report all bugs and problems on the following page:
00016 //
00017 //     http://www.fltk.org/str.php
00018 //
00019 
00020 #ifndef _FL_TABLE_H
00021 #define _FL_TABLE_H
00022 
00023 #include <sys/types.h>
00024 #include <string.h>             // memcpy
00025 #ifdef WIN32
00026 #include <malloc.h>             // WINDOWS: malloc/realloc
00027 #else /*WIN32*/
00028 #include <stdlib.h>             // UNIX: malloc/realloc
00029 #endif /*WIN32*/
00030 
00031 #include <FL/Fl.H>
00032 #include <FL/Fl_Group.H>
00033 #include <FL/Fl_Scroll.H>
00034 #include <FL/Fl_Box.H>
00035 #include <FL/Fl_Scrollbar.H>
00036 
00170 class FL_EXPORT Fl_Table : public Fl_Group {
00171 public:
00175   enum TableContext {
00176     CONTEXT_NONE       = 0,     
00177     CONTEXT_STARTPAGE  = 0x01,  
00178     CONTEXT_ENDPAGE    = 0x02,  
00179     CONTEXT_ROW_HEADER = 0x04,  
00180     CONTEXT_COL_HEADER = 0x08,  
00181     CONTEXT_CELL       = 0x10,  
00182     CONTEXT_TABLE      = 0x20,  
00183     CONTEXT_RC_RESIZE  = 0x40   
00184   };
00185   
00186 private:
00187   int _rows, _cols;     // total rows/cols
00188   int _row_header_w;    // width of row header
00189   int _col_header_h;    // height of column header
00190   int _row_position;    // last row_position set (not necessarily == toprow!)
00191   int _col_position;    // last col_position set (not necessarily == leftcol!)
00192   
00193   char _row_header;     // row header enabled?
00194   char _col_header;     // col header enabled?
00195   char _row_resize;     // row resizing enabled?
00196   char _col_resize;     // col resizing enabled?
00197   int _row_resize_min;  // row minimum resizing height (default=1)
00198   int _col_resize_min;  // col minimum resizing width (default=1)
00199   
00200   // OPTIMIZATION: partial row/column redraw variables
00201   int _redraw_toprow;
00202   int _redraw_botrow;
00203   int _redraw_leftcol;
00204   int _redraw_rightcol;
00205   Fl_Color _row_header_color;
00206   Fl_Color _col_header_color;
00207   
00208   int _auto_drag;
00209   int _selecting;
00210 #if FLTK_ABI_VERSION >= 10302
00211   int _scrollbar_size;
00212 #endif
00213   
00214   // An STL-ish vector without templates
00215   class FL_EXPORT IntVector {
00216     int *arr;
00217     unsigned int _size;
00218     void init() {
00219       arr = NULL;
00220       _size = 0;
00221     }
00222     void copy(int *newarr, unsigned int newsize) {
00223       size(newsize);
00224       memcpy(arr, newarr, newsize * sizeof(int));
00225     }
00226   public:
00227     IntVector() { init(); }                                     // CTOR
00228     ~IntVector() { if ( arr ) free(arr); arr = NULL; }          // DTOR
00229     IntVector(IntVector&o) { init(); copy(o.arr, o._size); }    // COPY CTOR
00230     IntVector& operator=(IntVector&o) {                         // ASSIGN
00231       init();
00232       copy(o.arr, o._size);
00233       return(*this);
00234     }
00235     int operator[](int x) const { return(arr[x]); }
00236     int& operator[](int x) { return(arr[x]); }
00237     unsigned int size() { return(_size); }
00238     void size(unsigned int count) {
00239       if ( count != _size ) {
00240         arr = (int*)realloc(arr, count * sizeof(int));
00241         _size = count;
00242       }
00243     }
00244     int pop_back() { int tmp = arr[_size-1]; _size--; return(tmp); }
00245     void push_back(int val) { unsigned int x = _size; size(_size+1); arr[x] = val; }
00246     int back() { return(arr[_size-1]); }
00247   };
00248   
00249   IntVector _colwidths;                 // column widths in pixels
00250   IntVector _rowheights;                // row heights in pixels
00251   
00252   Fl_Cursor _last_cursor;               // last mouse cursor before changed to 'resize' cursor
00253   
00254   // EVENT CALLBACK DATA
00255   TableContext _callback_context;       // event context
00256   int _callback_row, _callback_col;     // event row/col
00257   
00258   // handle() state variables.
00259   //    Put here instead of local statics in handle(), so more
00260   //    than one Fl_Table can exist without crosstalk between them.
00261   //
00262   int _resizing_col;                    // column being dragged
00263   int _resizing_row;                    // row being dragged
00264   int _dragging_x;                      // starting x position for horiz drag
00265   int _dragging_y;                      // starting y position for vert drag
00266   int _last_row;                        // last row we FL_PUSH'ed
00267   
00268   // Redraw single cell
00269   void _redraw_cell(TableContext context, int R, int C);
00270   
00271   void _start_auto_drag();
00272   void _stop_auto_drag();
00273   void _auto_drag_cb();
00274   static void _auto_drag_cb2(void *d);
00275   
00276 protected:
00277   enum ResizeFlag {
00278     RESIZE_NONE      = 0,
00279     RESIZE_COL_LEFT  = 1,
00280     RESIZE_COL_RIGHT = 2,
00281     RESIZE_ROW_ABOVE = 3,
00282     RESIZE_ROW_BELOW = 4
00283   };
00284   
00285   int table_w, table_h;                         // table's virtual size (in pixels)
00286   int toprow, botrow, leftcol, rightcol;        // four corners of viewable table
00287   
00288   // selection
00289   int current_row, current_col;
00290   int select_row, select_col;
00291   
00292   // OPTIMIZATION: Precomputed scroll positions for the toprow/leftcol
00293   int toprow_scrollpos;
00294   int leftcol_scrollpos;
00295   
00296   // Dimensions
00297   int tix, tiy, tiw, tih;                       // data table inner dimension xywh
00298   int tox, toy, tow, toh;                       // data table outer dimension xywh
00299   int wix, wiy, wiw, wih;                       // widget inner dimension xywh
00300   
00301   Fl_Scroll *table;                             // container for child fltk widgets (if any)
00302   Fl_Scrollbar *vscrollbar;                     // vertical scrollbar
00303   Fl_Scrollbar *hscrollbar;                     // horizontal scrollbar
00304   
00305   // Fltk
00306   int handle(int e);                            // fltk handle() override
00307   
00308   // Class maintenance
00309   void recalc_dimensions();
00310   void table_resized();                         // table resized; recalc
00311   void table_scrolled();                        // table scrolled; recalc
00312   void get_bounds(TableContext context,         // return x/y/w/h bounds for context
00313                   int &X, int &Y, int &W, int &H);
00314   void change_cursor(Fl_Cursor newcursor);      // change mouse cursor to some other shape
00315   TableContext cursor2rowcol(int &R, int &C, ResizeFlag &resizeflag);
00316   // find r/c given current x/y event
00317   int find_cell(TableContext context,           // find cell's x/y/w/h given r/c
00318                 int R, int C, int &X, int &Y, int &W, int &H);
00319   int row_col_clamp(TableContext context, int &R, int &C);
00320   // clamp r/c to known universe
00321   
00432   virtual void draw_cell(TableContext context, int R=0, int C=0, 
00433                          int X=0, int Y=0, int W=0, int H=0)
00434   { }                                           // overridden by deriving class
00435   
00436   long row_scroll_position(int row);            // find scroll position of row (in pixels)
00437   long col_scroll_position(int col);            // find scroll position of col (in pixels)
00438   
00439   int is_fltk_container() {                     // does table contain fltk widgets?
00440     return( Fl_Group::children() > 3 );         // (ie. more than box and 2 scrollbars?)
00441   }
00442   
00443   static void scroll_cb(Fl_Widget*,void*);      // h/v scrollbar callback
00444   
00445   void damage_zone(int r1, int c1, int r2, int c2, int r3 = 0, int c3 = 0);
00446   
00447   void redraw_range(int topRow, int botRow, int leftCol, int rightCol) {
00448     if ( _redraw_toprow == -1 ) {
00449       // Initialize redraw range
00450       _redraw_toprow = topRow;
00451       _redraw_botrow = botRow;
00452       _redraw_leftcol = leftCol;
00453       _redraw_rightcol = rightCol;
00454     } else {
00455       // Extend redraw range
00456       if ( topRow < _redraw_toprow ) _redraw_toprow = topRow;
00457       if ( botRow > _redraw_botrow ) _redraw_botrow = botRow;
00458       if ( leftCol < _redraw_leftcol ) _redraw_leftcol = leftCol;
00459       if ( rightCol > _redraw_rightcol ) _redraw_rightcol = rightCol;
00460     }
00461     
00462     // Indicate partial redraw needed of some cells
00463     damage(FL_DAMAGE_CHILD);
00464   }
00465   
00466 public:
00472   Fl_Table(int X, int Y, int W, int H, const char *l=0);
00473   
00478   ~Fl_Table();
00479   
00485   virtual void clear() { rows(0); cols(0); }
00486   
00487   // \todo: add topline(), middleline(), bottomline()
00488   
00494   inline void table_box(Fl_Boxtype val) {
00495     table->box(val);
00496     table_resized();
00497   }
00498   
00502   inline Fl_Boxtype table_box( void ) {
00503     return(table->box());
00504   }
00505   
00509   virtual void rows(int val);                   // set/get number of rows
00510   
00514   inline int rows() {
00515     return(_rows);
00516   }
00517   
00521   virtual void cols(int val);                   // set/get number of columns
00522   
00526   inline int cols() {
00527     return(_cols);
00528   }
00529   
00558   inline void visible_cells(int& r1, int& r2, int& c1, int& c2) {
00559     r1 = toprow;
00560     r2 = botrow;
00561     c1 = leftcol;
00562     c2 = rightcol;
00563   } 
00564   
00569   int is_interactive_resize() {
00570     return(_resizing_row != -1 || _resizing_col != -1);
00571   } 
00572   
00576   inline int row_resize() {
00577     return(_row_resize);
00578   }
00579   
00586   void row_resize(int flag) {                   // enable row resizing
00587     _row_resize = flag;
00588   }
00589   
00593   inline int col_resize() {
00594     return(_col_resize);
00595   }
00602   void col_resize(int flag) {                   // enable col resizing
00603     _col_resize = flag;
00604   }
00605   
00611   inline int col_resize_min() {                 // column minimum resizing width
00612     return(_col_resize_min);
00613   }
00614   
00618   void col_resize_min(int val) {
00619     _col_resize_min = ( val < 1 ) ? 1 : val;
00620   } 
00621   
00625   inline int row_resize_min() {                 // column minimum resizing width
00626     return(_row_resize_min);
00627   }
00628   
00634   void row_resize_min(int val) {
00635     _row_resize_min = ( val < 1 ) ? 1 : val;
00636   }
00637   
00641   inline int row_header() {                     // set/get row header enable flag
00642     return(_row_header);
00643   }
00644   
00649   void row_header(int flag) {
00650     _row_header = flag;
00651     table_resized();
00652     redraw();
00653   }
00654   
00658   inline int col_header() {                     // set/get col header enable flag
00659     return(_col_header);
00660   }
00661   
00666   void col_header(int flag) {
00667     _col_header = flag;
00668     table_resized();
00669     redraw();
00670   }
00671   
00675   inline void col_header_height(int height) {   // set/get col header height
00676     _col_header_h = height;
00677     table_resized();
00678     redraw();
00679   }
00680   
00684   inline int col_header_height() {
00685     return(_col_header_h);
00686   }
00687   
00691   inline void row_header_width(int width) {     // set/get row header width
00692     _row_header_w = width;
00693     table_resized();
00694     redraw();
00695   }
00696   
00700   inline int row_header_width() {
00701     return(_row_header_w);
00702   }
00703   
00707   inline void row_header_color(Fl_Color val) {  // set/get row header color
00708     _row_header_color = val;
00709     redraw();
00710   }
00711   
00715   inline Fl_Color row_header_color() {
00716     return(_row_header_color);
00717   } 
00718   
00722   inline void col_header_color(Fl_Color val) {  // set/get col header color
00723     _col_header_color = val;
00724     redraw();
00725   }
00726   
00730   inline Fl_Color col_header_color() {
00731     return(_col_header_color);
00732   }
00733   
00740   void row_height(int row, int height);         // set/get row height
00741   
00745   inline int row_height(int row) {
00746     return((row<0 || row>=(int)_rowheights.size()) ? 0 : _rowheights[row]);
00747   }
00748   
00754   void col_width(int col, int width);           // set/get a column's width
00755   
00759   inline int col_width(int col) {
00760     return((col<0 || col>=(int)_colwidths.size()) ? 0 : _colwidths[col]);
00761   }
00762   
00767   void row_height_all(int height) {             // set all row/col heights
00768     for ( int r=0; r<rows(); r++ ) {
00769       row_height(r, height);
00770     }
00771   }
00772   
00777   void col_width_all(int width) {
00778     for ( int c=0; c<cols(); c++ ) {
00779       col_width(c, width);
00780     }
00781   }
00782   
00786   void row_position(int row);                   // set/get table's current scroll position
00787   
00791   void col_position(int col);
00792   
00796   int row_position() {                          // current row position
00797     return(_row_position);
00798   }
00799   
00803   int col_position() {                          // current col position
00804     return(_col_position);
00805   }
00806   
00812   inline void top_row(int row) {                // set/get top row (deprecated)
00813     row_position(row);
00814   }
00815   
00820   inline int top_row() {
00821     return(row_position());
00822   }
00823   int is_selected(int r, int c);                // selected cell
00824   void get_selection(int &row_top, int &col_left, int &row_bot, int &col_right);
00825   void set_selection(int row_top, int col_left, int row_bot, int col_right);
00826   int move_cursor(int R, int C);
00827   
00831   void resize(int X, int Y, int W, int H);      // fltk resize() override
00832   void draw(void);                              // fltk draw() override
00833   
00834   // This crashes sortapp() during init.
00835   //  void box(Fl_Boxtype val) {
00836   //    Fl_Group::box(val);
00837   //    if ( table ) {
00838   //      resize(x(), y(), w(), h());
00839   //    }
00840   //  }
00841   //  Fl_Boxtype box(void) const {
00842   //    return(Fl_Group::box());
00843   //  }
00844   
00845   // Child group
00846   void init_sizes() {
00847     table->init_sizes();
00848     table->redraw();
00849   }
00850   void add(Fl_Widget& wgt) {
00851     table->add(wgt);
00852     if ( table->children() > 2 ) {
00853       table->show();
00854     } else {
00855       table->hide();
00856     } 
00857   }
00858   void add(Fl_Widget* wgt) {
00859     add(*wgt);
00860   }
00861   void insert(Fl_Widget& wgt, int n) {
00862     table->insert(wgt,n);
00863   }
00864   void insert(Fl_Widget& wgt, Fl_Widget* w2) {
00865     table->insert(wgt,w2);
00866   }
00867   void remove(Fl_Widget& wgt) {
00868     table->remove(wgt);
00869   }
00870   void begin() {
00871     table->begin();
00872   }
00873   void end() {
00874     table->end();
00875     // HACK: Avoid showing Fl_Scroll; seems to erase screen
00876     //       causing unnecessary flicker, even if its box() is FL_NO_BOX.
00877     //
00878     if ( table->children() > 2 ) {
00879       table->show();
00880     } else {
00881       table->hide();
00882     } 
00883     Fl_Group::current(Fl_Group::parent());
00884   }
00885   Fl_Widget * const *array() {
00886     return(table->array());
00887   }
00888   
00903   Fl_Widget *child(int n) const {
00904     return(table->child(n));
00905   }
00906   
00915   int children() const {
00916     return(table->children()-2);    // -2: skip Fl_Scroll's h/v scrollbar widgets
00917   }
00918   int find(const Fl_Widget *wgt) const {
00919     return(table->find(wgt));
00920   }
00921   int find(const Fl_Widget &wgt) const {
00922     return(table->find(wgt));
00923   } 
00924   // CALLBACKS
00925   
00931   int callback_row() {
00932     return(_callback_row);
00933   }
00934   
00940   int callback_col() {
00941     return(_callback_col);
00942   }
00943   
00949   TableContext callback_context() {
00950     return(_callback_context);
00951   }
00952   
00953   void do_callback(TableContext context, int row, int col) {
00954     _callback_context = context;
00955     _callback_row = row;
00956     _callback_col = col;
00957     Fl_Widget::do_callback();
00958   }
00959   
00960 #if FL_DOXYGEN
00961 
00989   void when(Fl_When flags);
00990 #endif
00991   
00992 #if FL_DOXYGEN
00993 
01070   void callback(Fl_Widget*, void*);
01071 #endif
01072 
01073 #if FLTK_ABI_VERSION >= 10302
01074   // NEW
01084   int scrollbar_size() const {
01085       return(_scrollbar_size);
01086   }
01105   void scrollbar_size(int newSize) {
01106       if ( newSize != _scrollbar_size ) redraw();
01107       _scrollbar_size = newSize;
01108   }   
01109 #endif
01110 };
01111 
01112 #endif /*_FL_TABLE_H*/
01113 
01114 //
01115 // End of "$Id$".
01116 //