FLTK 1.3.0
|
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 //