edelib  2.0.0
edelib/TableBase.h
00001 //
00002 // TableBase -- A table widget
00003 //
00004 // Copyright 2002 by Greg Ercolano.
00005 // Copyright (c) 2004 O'ksi'D
00006 //
00007 // This library is free software; you can redistribute it and/or
00008 // modify it under the terms of the GNU Library General Public
00009 // License as published by the Free Software Foundation; either
00010 // version 2 of the License, or (at your option) any later version.
00011 //
00012 // This library is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 // Library General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU Library General Public
00018 // License along with this library; if not, write to the Free Software
00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00020 // USA.
00021 //
00022 // Please report all bugs and problems to "erco at seriss dot com".
00023 //
00024 // TODO:
00025 //        o Auto scroll during dragged selection
00026 //        o Keyboard navigation (up/down/left/right arrow)
00027 //
00028 
00029 #ifndef __EDELIB_TABLEBASE_H__
00030 #define __EDELIB_TABLEBASE_H__
00031 
00032 #include "edelib-global.h"
00033 
00034 #include <sys/types.h>
00035 #include <string.h>                             // memcpy
00036 
00037 #ifdef _WIN32
00038 # include <malloc.h>                    // WINDOWS: malloc/realloc
00039 #else
00040 # include <stdlib.h>                    // UNIX: malloc/realloc
00041 #endif
00042 
00043 #include <FL/Fl.H>
00044 #include <FL/Fl_Group.H>
00045 #include <FL/Fl_Scroll.H>
00046 #include <FL/Fl_Box.H>
00047 #include <FL/Fl_Scrollbar.H>
00048 
00049 EDELIB_NS_BEGIN
00050 
00166 class EDELIB_API TableBase : public Fl_Group {
00167 public:
00172         enum TableContext {
00173                 CONTEXT_NONE       = 0,
00174                 CONTEXT_STARTPAGE  = 0x01,      
00175                 CONTEXT_ENDPAGE    = 0x02,      
00176                 CONTEXT_ROW_HEADER = 0x04,      
00177                 CONTEXT_COL_HEADER = 0x08,      
00178                 CONTEXT_CELL       = 0x10,      
00179                 CONTEXT_TABLE      = 0x20,      
00180                 CONTEXT_RC_RESIZE  = 0x40       
00181         };
00182 
00183 private:
00184         int _rows, _cols,                       // total rows/cols
00185                 _row_header_w,                  // width of row header
00186                 _col_header_h,                  // height of column header
00187                 _row_position,                  // last row_position set (not necessarily == toprow!)
00188                 _col_position;                  // last col_position set (not necessarily == leftcol!)
00189 
00190         char _row_header,                       // row header enabled?
00191                  _col_header,                   // col header enabled?
00192                  _row_resize,                   // row resizing enabled?
00193                  _col_resize;                   // col resizing enabled?
00194         int
00195                  _row_resize_min,               // row minimum resizing height (default=1)
00196                  _col_resize_min;               // col minimum resizing width (default=1)
00197 
00198         // OPTIMIZATION: partial row/column redraw variables
00199         int _redraw_toprow, _redraw_botrow,
00200                 _redraw_leftcol, _redraw_rightcol;
00201 
00202         Fl_Color _row_header_color,
00203                          _col_header_color;
00204 
00205         int _auto_drag;
00206         int _selecting;
00207 
00212         class IntVector {
00213                 private:
00214                         int *arr;
00215                         unsigned int _size;
00216 
00217                         void init() { arr = NULL; _size = 0; }
00218                         void copy(int *newarr, unsigned int newsize) { size(newsize); memcpy(arr, newarr, newsize * sizeof(int)); }
00219                 public:
00221                         IntVector() { init(); }
00223                         ~IntVector() { if ( arr ) free(arr); arr = NULL; }
00225                         IntVector(IntVector&o) { init(); copy(o.arr, o._size); }
00227                         IntVector& operator=(IntVector&o) { init(); copy(o.arr, o._size); return(*this); }
00229                         int operator[](int x) const { return(arr[x]); }
00231                         int& operator[](int x) { return(arr[x]); }
00233                         unsigned int size() { return(_size); }
00235                         void size(unsigned int count) {
00236                                 if ( count != _size )
00237                                 { arr = (int*)realloc(arr, count * sizeof(int)); _size = count; }
00238                         }
00240                         int pop_back() { int tmp = arr[_size-1]; _size--; return(tmp); }
00242                         void push_back(int val) { unsigned int x = _size; size(_size+1); arr[x] = val; }
00244                         int back() { return(arr[_size-1]); }
00245         };
00246 
00247         IntVector
00248                 _colwidths,                             // column widths in pixels
00249                 _rowheights;                    // row heights in pixels
00250 
00251         Fl_Cursor _last_cursor;         // last mouse cursor before changed to 'resize' cursor
00252 
00253         // EVENT CALLBACK DATA
00254         TableContext _callback_context;         // event context
00255         int _callback_row, _callback_col;       // event row/col
00256 
00257         // handle() state variables.
00258         //        Put here instead of local statics in handle(), so more
00259         //        than one TableBase can exist without crosstalk between them.
00260         //
00261         int _resizing_col,                                      // column being dragged
00262                 _resizing_row,                                  // row being dragged
00263                 _dragging_x,                                    // starting x position for horiz drag
00264                 _dragging_y,                                    // starting y position for vert drag
00265                 _last_row;                                              // last row we FL_PUSH'ed
00266 
00267         // Redraw single cell
00268         void _redraw_cell(TableContext context, int R, int C);
00269 
00270         void _start_auto_drag();
00271         void _stop_auto_drag();
00272         void _auto_drag_cb();
00273         static void _auto_drag_cb2(void *d);
00274 
00275 
00276 protected:
00277 #ifndef SKIP_DOCS
00278         enum ResizeFlag {
00279                 RESIZE_NONE              = 0,
00280                 RESIZE_COL_LEFT  = 1,
00281                 RESIZE_COL_RIGHT = 2,
00282                 RESIZE_ROW_ABOVE = 3,
00283                 RESIZE_ROW_BELOW = 4
00284         };
00285 
00286         int table_w, table_h;                                           // table's virtual size (in pixels)
00287         int toprow, botrow,                                                     // four corners of viewable table
00288                 leftcol, rightcol;
00289 
00290         // selection
00291         int current_row, current_col;
00292         int select_row, select_col;
00293 
00294         // OPTIMIZATION: Precomputed scroll positions for the toprow/leftcol
00295         int toprow_scrollpos,
00296                 leftcol_scrollpos;
00297 
00298         // Dimensions
00299         int tix, tiy, tiw, tih,                                         // data table inner dimension xywh
00300                 tox, toy, tow, toh,                                             // data table outer dimension xywh
00301                 wix, wiy, wiw, wih;                                             // widget inner dimension xywh
00302 
00303         Fl_Scroll *table;                                                       // container for child fltk widgets (if any)
00304         Fl_Scrollbar *vscrollbar,                                       // vertical scrollbar
00305                                  *hscrollbar;                                   // horizontal scrollbar
00306 
00307         // Fltk
00308         int handle(int e);                                                      // fltk handle() override
00309 
00310         // Class maintenance
00311         void recalc_dimensions();
00312         void table_resized();                                           // table resized; recalc
00313         void table_scrolled();                                          // table scrolled; recalc
00314         void get_bounds(TableContext context,           // return x/y/w/h bounds for context
00315                                         int &X, int &Y, int &W, int &H);
00316         void change_cursor(Fl_Cursor newcursor);        // change mouse cursor to some other shape
00317         TableContext cursor2rowcol(int &R, int &C, ResizeFlag &resizeflag);
00318                                                                                                 // find r/c given current x/y event
00319         int find_cell(TableContext context,                     // find cell's x/y/w/h given r/c
00320                                  int R, int C, int &X, int &Y, int &W, int &H);
00321         int row_col_clamp(TableContext context, int &R, int &C);
00322                                                                                                 // clamp r/c to known universe
00323 
00324         // Called to draw cells
00325         virtual void draw_cell(TableContext context, int R=0, int C=0, 
00326                                                    int X=0, int Y=0, int W=0, int H=0)
00327                 { }                                                                             // overridden by deriving class
00328 
00329         long row_scroll_position(int row);                      // find scroll position of row (in pixels)
00330         long col_scroll_position(int col);                      // find scroll position of col (in pixels)
00331 
00332         int is_fltk_container()                                         // does table contain fltk widgets?
00333                 { return( Fl_Group::children() > 3 ); } // (ie. more than box and 2 scrollbars?)
00334 
00335         static void scroll_cb(Fl_Widget*,void*);        // h/v scrollbar callback
00336 
00337         void damage_zone(int r1, int c1, int r2, int c2, int r3 = 0, int c3 = 0);
00338 
00339         void redraw_range(int trow, int brow, int lcol, int rcol) {
00340                 if ( _redraw_toprow == -1 ) {
00341                         // Initialize redraw range
00342                         _redraw_toprow = trow;
00343                         _redraw_botrow = brow;
00344                         _redraw_leftcol = lcol;
00345                         _redraw_rightcol = rcol;
00346                 } else {
00347                         // Extend redraw range
00348                         if ( trow < _redraw_toprow ) _redraw_toprow = trow;
00349                         if ( brow > _redraw_botrow ) _redraw_botrow = brow;
00350                         if ( lcol < _redraw_leftcol ) _redraw_leftcol = lcol;
00351                         if ( rcol > _redraw_rightcol ) _redraw_rightcol = rcol;
00352                 }
00353 
00354                 // Indicate partial redraw needed of some cells
00355                 damage(FL_DAMAGE_CHILD);
00356         }
00357 
00358         // TODO: maybe _redraw_cell() put protected directly?
00359         void redraw_cell(TableContext context, int R, int C) { _redraw_cell(context, R, C); }
00360 #endif
00361 
00362 public:
00367         TableBase(int X, int Y, int W, int H, const char *l=0);
00368 
00372         ~TableBase();
00373 
00377         virtual void clear() { rows(0); cols(0); }
00378 
00383         inline void table_box(Fl_Boxtype val) { table->box(val); table_resized(); }
00384 
00388         inline Fl_Boxtype table_box( void ) { return(table->box()); }
00389 
00393         virtual void rows(int val);
00394 
00398         inline int rows() { return _rows; }
00399 
00403         virtual void cols(int val);
00404 
00408         inline int cols() { return _cols; }
00409 
00417         inline void visible_cells(int& r1, int& r2, int& c1, int& c2) { r1 = toprow; r2 = botrow; c1 = leftcol; c2 = rightcol; }
00418 
00422         int is_interactive_resize() { return (_resizing_row != -1 || _resizing_col != -1); }
00423 
00428         void row_resize(int flag) { _row_resize = flag; }
00429 
00433         inline int row_resize() { return _row_resize; }
00434 
00439         void col_resize(int flag) { _col_resize = flag; }
00440 
00444         inline int col_resize() { return _col_resize; }
00445 
00449         void col_resize_min(int val) { _col_resize_min = ( val < 1 ) ? 1 : val; }
00450 
00454         inline int col_resize_min() { return _col_resize_min; }
00455 
00459         void row_resize_min(int val) { _row_resize_min = ( val < 1 ) ? 1 : val; }
00460 
00464         inline int row_resize_min()     { return _row_resize_min; }
00465 
00470         void row_header(int flag) { _row_header = flag; table_resized(); redraw(); }
00471 
00475         inline int row_header() { return _row_header; }
00476 
00481         void col_header(int flag) { _col_header = flag; table_resized(); redraw(); }
00482 
00486         inline int col_header() { return(_col_header); }
00487 
00491         inline void col_header_height(int height) { _col_header_h = height; table_resized(); redraw(); }
00492 
00496         inline int col_header_height() { return _col_header_h; }
00497 
00501         inline void row_header_width(int width) { _row_header_w = width; table_resized(); redraw(); }
00502 
00506         inline int row_header_width() { return _row_header_w; }
00507 
00511         inline void row_header_color(Fl_Color val) { _row_header_color = val; redraw(); }
00512 
00516         inline Fl_Color row_header_color() { return _row_header_color; }
00517 
00521         inline void col_header_color(Fl_Color val) { _col_header_color = val; redraw(); }
00522 
00526         inline Fl_Color col_header_color() { return _col_header_color; }
00527 
00532         void row_height(int row, int height);
00533 
00537         inline int row_height(int row) { return ((row<0 || row>=(int)_rowheights.size()) ? 0 : _rowheights[row]); }
00538 
00543         void col_width(int col, int width);
00544 
00548         inline int col_width(int col) { return ((col<0 || col>=(int)_colwidths.size()) ? 0 : _colwidths[col]); }
00549 
00553         void row_height_all(int height) { for ( int r=0; r<rows(); r++ ) row_height(r, height); }
00554 
00558         void col_width_all(int width) { for ( int c=0; c<cols(); c++ ) col_width(c, width); }
00559 
00563         void row_position(int row);
00564 
00568         int row_position() { return _row_position; }
00569 
00573         void col_position(int col);
00574 
00578         int col_position() { return _col_position; }
00579 
00583         inline void top_row(int row) { row_position(row); }
00584 
00588         inline int top_row() { return row_position(); }
00589 
00593         int is_selected(int r, int c);
00594 
00601         void get_selection(int& s_top, int& s_left, int& s_bottom, int& s_right);
00602 
00609         void set_selection(int s_top, int s_left, int s_bottom, int s_right);
00610 
00616         int move_cursor(int R, int C);
00617 
00621         void resize(int X, int Y, int W, int H);
00622 
00626         void draw(void);
00627 
00631         void init_sizes() { table->init_sizes(); table->redraw(); }
00632 
00636         void add(Fl_Widget& widget) { table->add(widget); }
00637 
00641         void add(Fl_Widget* widget) { table->add(widget); }
00642 
00646         void insert(Fl_Widget& widget, int n) { table->insert(widget,n); }
00647 
00651         void insert(Fl_Widget& widget1, Fl_Widget* widget2) { table->insert(widget1,widget2); }
00652 
00656         void remove(Fl_Widget& widget) { table->remove(widget); }
00657 
00661         void begin() { table->begin(); }
00662 
00666         void end() {
00667                 table->end();
00668 
00669                 // HACK: Avoid showing Fl_Scroll; seems to erase screen
00670                 //               causing unnecessary flicker, even if its box() is FL_NO_BOX.
00671                 //
00672                 if ( table->children() > 2 ) 
00673                         table->show();
00674                 else 
00675                         table->hide();
00676 
00677                 Fl_Group::current((Fl_Group*)(Fl_Group::parent()));
00678         }
00679 
00680 #ifndef SKIP_DOCS
00681         Fl_Widget * const *array() { return table->array(); }
00682         Fl_Widget *child(int n) const { return table->child(n); }
00683         int children() const { return table->children()-2; }    // -2: skip Fl_Scroll's h/v scrollbar widgets
00684         int find(const Fl_Widget *widget) const { return table->find(widget); }
00685         int find(const Fl_Widget &widget) const { return table->find(widget); }
00686 #endif
00687 
00692         int callback_row() { return _callback_row; }
00693 
00698         int callback_col() { return _callback_col; }
00699 
00703         TableContext callback_context() { return _callback_context; }
00704 
00708         void do_callback(TableContext context, int row, int col) {
00709                 _callback_context = context;
00710                 _callback_row = row;
00711                 _callback_col = col;
00712                 Fl_Widget::do_callback();
00713         }
00714 };
00715 
00716 EDELIB_NS_END
00717 #endif