edelib
2.0.0
|
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