TableBase.h
//
// TableBase -- A table widget
//
// Copyright 2002 by Greg Ercolano.
// Copyright (c) 2004 O'ksi'D
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
// Please report all bugs and problems to "erco at seriss dot com".
//
// TODO:
// o Auto scroll during dragged selection
// o Keyboard navigation (up/down/left/right arrow)
//
#ifndef __EDELIB_TABLEBASE_H__
#define __EDELIB_TABLEBASE_H__
#include "edelib-global.h"
#include <sys/types.h>
#include <string.h> // memcpy
#ifdef _WIN32
# include <malloc.h> // WINDOWS: malloc/realloc
#else
# include <stdlib.h> // UNIX: malloc/realloc
#endif
#include <FL/Fl.H>
#include <FL/Fl_Group.H>
#include <FL/Fl_Scroll.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Scrollbar.H>
EDELIB_NS_BEGIN
class EDELIB_API TableBase : public Fl_Group {
public:
enum TableContext {
CONTEXT_NONE = 0,
CONTEXT_STARTPAGE = 0x01,
CONTEXT_ENDPAGE = 0x02,
CONTEXT_ROW_HEADER = 0x04,
CONTEXT_COL_HEADER = 0x08,
CONTEXT_CELL = 0x10,
CONTEXT_TABLE = 0x20,
CONTEXT_RC_RESIZE = 0x40
};
private:
int _rows, _cols, // total rows/cols
_row_header_w, // width of row header
_col_header_h, // height of column header
_row_position, // last row_position set (not necessarily == toprow!)
_col_position; // last col_position set (not necessarily == leftcol!)
char _row_header, // row header enabled?
_col_header, // col header enabled?
_row_resize, // row resizing enabled?
_col_resize; // col resizing enabled?
int
_row_resize_min, // row minimum resizing height (default=1)
_col_resize_min; // col minimum resizing width (default=1)
// OPTIMIZATION: partial row/column redraw variables
int _redraw_toprow, _redraw_botrow,
_redraw_leftcol, _redraw_rightcol;
Fl_Color _row_header_color,
_col_header_color;
int _auto_drag;
int _selecting;
class IntVector {
private:
int *arr;
unsigned int _size;
void init() { arr = NULL; _size = 0; }
void copy(int *newarr, unsigned int newsize) { size(newsize); memcpy(arr, newarr, newsize * sizeof(int)); }
public:
IntVector() { init(); }
~IntVector() { if ( arr ) free(arr); arr = NULL; }
IntVector(IntVector&o) { init(); copy(o.arr, o._size); }
IntVector& operator=(IntVector&o) { init(); copy(o.arr, o._size); return(*this); }
int operator[](int x) const { return(arr[x]); }
int& operator[](int x) { return(arr[x]); }
unsigned int size() { return(_size); }
void size(unsigned int count) {
if ( count != _size )
{ arr = (int*)realloc(arr, count * sizeof(int)); _size = count; }
}
int pop_back() { int tmp = arr[_size-1]; _size--; return(tmp); }
void push_back(int val) { unsigned int x = _size; size(_size+1); arr[x] = val; }
int back() { return(arr[_size-1]); }
};
IntVector
_colwidths, // column widths in pixels
_rowheights; // row heights in pixels
Fl_Cursor _last_cursor; // last mouse cursor before changed to 'resize' cursor
// EVENT CALLBACK DATA
TableContext _callback_context; // event context
int _callback_row, _callback_col; // event row/col
// handle() state variables.
// Put here instead of local statics in handle(), so more
// than one TableBase can exist without crosstalk between them.
//
int _resizing_col, // column being dragged
_resizing_row, // row being dragged
_dragging_x, // starting x position for horiz drag
_dragging_y, // starting y position for vert drag
_last_row; // last row we FL_PUSH'ed
// Redraw single cell
void _redraw_cell(TableContext context, int R, int C);
void _start_auto_drag();
void _stop_auto_drag();
void _auto_drag_cb();
static void _auto_drag_cb2(void *d);
protected:
#ifndef SKIP_DOCS
enum ResizeFlag {
RESIZE_NONE = 0,
RESIZE_COL_LEFT = 1,
RESIZE_COL_RIGHT = 2,
RESIZE_ROW_ABOVE = 3,
RESIZE_ROW_BELOW = 4
};
int table_w, table_h; // table's virtual size (in pixels)
int toprow, botrow, // four corners of viewable table
leftcol, rightcol;
// selection
int current_row, current_col;
int select_row, select_col;
// OPTIMIZATION: Precomputed scroll positions for the toprow/leftcol
int toprow_scrollpos,
leftcol_scrollpos;
// Dimensions
int tix, tiy, tiw, tih, // data table inner dimension xywh
tox, toy, tow, toh, // data table outer dimension xywh
wix, wiy, wiw, wih; // widget inner dimension xywh
Fl_Scroll *table; // container for child fltk widgets (if any)
Fl_Scrollbar *vscrollbar, // vertical scrollbar
*hscrollbar; // horizontal scrollbar
// Fltk
int handle(int e); // fltk handle() override
// Class maintenance
void recalc_dimensions();
void table_resized(); // table resized; recalc
void table_scrolled(); // table scrolled; recalc
void get_bounds(TableContext context, // return x/y/w/h bounds for context
int &X, int &Y, int &W, int &H);
void change_cursor(Fl_Cursor newcursor); // change mouse cursor to some other shape
TableContext cursor2rowcol(int &R, int &C, ResizeFlag &resizeflag);
// find r/c given current x/y event
int find_cell(TableContext context, // find cell's x/y/w/h given r/c
int R, int C, int &X, int &Y, int &W, int &H);
int row_col_clamp(TableContext context, int &R, int &C);
// clamp r/c to known universe
// Called to draw cells
virtual void draw_cell(TableContext context, int R=0, int C=0,
int X=0, int Y=0, int W=0, int H=0)
{ } // overridden by deriving class
long row_scroll_position(int row); // find scroll position of row (in pixels)
long col_scroll_position(int col); // find scroll position of col (in pixels)
int is_fltk_container() // does table contain fltk widgets?
{ return( Fl_Group::children() > 3 ); } // (ie. more than box and 2 scrollbars?)
static void scroll_cb(Fl_Widget*,void*); // h/v scrollbar callback
void damage_zone(int r1, int c1, int r2, int c2, int r3 = 0, int c3 = 0);
void redraw_range(int trow, int brow, int lcol, int rcol) {
if ( _redraw_toprow == -1 ) {
// Initialize redraw range
_redraw_toprow = trow;
_redraw_botrow = brow;
_redraw_leftcol = lcol;
_redraw_rightcol = rcol;
} else {
// Extend redraw range
if ( trow < _redraw_toprow ) _redraw_toprow = trow;
if ( brow > _redraw_botrow ) _redraw_botrow = brow;
if ( lcol < _redraw_leftcol ) _redraw_leftcol = lcol;
if ( rcol > _redraw_rightcol ) _redraw_rightcol = rcol;
}
// Indicate partial redraw needed of some cells
damage(FL_DAMAGE_CHILD);
}
// TODO: maybe _redraw_cell() put protected directly?
void redraw_cell(TableContext context, int R, int C) { _redraw_cell(context, R, C); }
#endif
public:
TableBase(int X, int Y, int W, int H, const char *l=0);
~TableBase();
virtual void clear() { rows(0); cols(0); }
inline void table_box(Fl_Boxtype val) { table->box(val); table_resized(); }
inline Fl_Boxtype table_box( void ) { return(table->box()); }
virtual void rows(int val);
inline int rows() { return _rows; }
virtual void cols(int val);
inline int cols() { return _cols; }
inline void visible_cells(int& r1, int& r2, int& c1, int& c2) { r1 = toprow; r2 = botrow; c1 = leftcol; c2 = rightcol; }
int is_interactive_resize() { return (_resizing_row != -1 || _resizing_col != -1); }
void row_resize(int flag) { _row_resize = flag; }
inline int row_resize() { return _row_resize; }
void col_resize(int flag) { _col_resize = flag; }
inline int col_resize() { return _col_resize; }
void col_resize_min(int val) { _col_resize_min = ( val < 1 ) ? 1 : val; }
inline int col_resize_min() { return _col_resize_min; }
void row_resize_min(int val) { _row_resize_min = ( val < 1 ) ? 1 : val; }
inline int row_resize_min() { return _row_resize_min; }
void row_header(int flag) { _row_header = flag; table_resized(); redraw(); }
inline int row_header() { return _row_header; }
void col_header(int flag) { _col_header = flag; table_resized(); redraw(); }
inline int col_header() { return(_col_header); }
inline void col_header_height(int height) { _col_header_h = height; table_resized(); redraw(); }
inline int col_header_height() { return _col_header_h; }
inline void row_header_width(int width) { _row_header_w = width; table_resized(); redraw(); }
inline int row_header_width() { return _row_header_w; }
inline void row_header_color(Fl_Color val) { _row_header_color = val; redraw(); }
inline Fl_Color row_header_color() { return _row_header_color; }
inline void col_header_color(Fl_Color val) { _col_header_color = val; redraw(); }
inline Fl_Color col_header_color() { return _col_header_color; }
void row_height(int row, int height);
inline int row_height(int row) { return ((row<0 || row>=(int)_rowheights.size()) ? 0 : _rowheights[row]); }
void col_width(int col, int width);
inline int col_width(int col) { return ((col<0 || col>=(int)_colwidths.size()) ? 0 : _colwidths[col]); }
void row_height_all(int height) { for ( int r=0; r<rows(); r++ ) row_height(r, height); }
void col_width_all(int width) { for ( int c=0; c<cols(); c++ ) col_width(c, width); }
void row_position(int row);
int row_position() { return _row_position; }
void col_position(int col);
int col_position() { return _col_position; }
inline void top_row(int row) { row_position(row); }
inline int top_row() { return row_position(); }
int is_selected(int r, int c);
void get_selection(int& s_top, int& s_left, int& s_bottom, int& s_right);
void set_selection(int s_top, int s_left, int s_bottom, int s_right);
int move_cursor(int R, int C);
void resize(int X, int Y, int W, int H);
void draw(void);
void init_sizes() { table->init_sizes(); table->redraw(); }
void add(Fl_Widget& widget) { table->add(widget); }
void add(Fl_Widget* widget) { table->add(widget); }
void insert(Fl_Widget& widget, int n) { table->insert(widget,n); }
void insert(Fl_Widget& widget1, Fl_Widget* widget2) { table->insert(widget1,widget2); }
void remove(Fl_Widget& widget) { table->remove(widget); }
void begin() { table->begin(); }
void end() {
table->end();
// HACK: Avoid showing Fl_Scroll; seems to erase screen
// causing unnecessary flicker, even if its box() is FL_NO_BOX.
//
if ( table->children() > 2 )
table->show();
else
table->hide();
Fl_Group::current((Fl_Group*)(Fl_Group::parent()));
}
#ifndef SKIP_DOCS
Fl_Widget * const *array() { return table->array(); }
Fl_Widget *child(int n) const { return table->child(n); }
int children() const { return table->children()-2; } // -2: skip Fl_Scroll's h/v scrollbar widgets
int find(const Fl_Widget *widget) const { return table->find(widget); }
int find(const Fl_Widget &widget) const { return table->find(widget); }
#endif
int callback_row() { return _callback_row; }
int callback_col() { return _callback_col; }
TableContext callback_context() { return _callback_context; }
void do_callback(TableContext context, int row, int col) {
_callback_context = context;
_callback_row = row;
_callback_col = col;
Fl_Widget::do_callback();
}
};
EDELIB_NS_END
#endif
edelib::TableBase::col_header_color
Fl_Color col_header_color()
Definition: TableBase.h:526
edelib::TableBase::row_header
int row_header()
Definition: TableBase.h:475
edelib::TableBase
A base class for table widgets.
Definition: TableBase.h:166
edelib::TableBase::begin
void begin()
Definition: TableBase.h:661
edelib::TableBase::col_header_color
void col_header_color(Fl_Color val)
Definition: TableBase.h:521
edelib::TableBase::is_interactive_resize
int is_interactive_resize()
Definition: TableBase.h:422
edelib::TableBase::add
void add(Fl_Widget &widget)
Definition: TableBase.h:636
edelib::TableBase::col_header
int col_header()
Definition: TableBase.h:486
edelib::TableBase::row_position
int row_position()
Definition: TableBase.h:568
edelib::TableBase::do_callback
void do_callback(TableContext context, int row, int col)
Definition: TableBase.h:708
edelib::TableBase::row_resize_min
int row_resize_min()
Definition: TableBase.h:464
edelib::TableBase::col_resize_min
int col_resize_min()
Definition: TableBase.h:454
edelib::TableBase::row_resize
void row_resize(int flag)
Definition: TableBase.h:428
edelib::TableBase::row_resize
int row_resize()
Definition: TableBase.h:433
edelib::TableBase::insert
void insert(Fl_Widget &widget, int n)
Definition: TableBase.h:646
edelib::TableBase::row_resize_min
void row_resize_min(int val)
Definition: TableBase.h:459
edelib::TableBase::col_resize
int col_resize()
Definition: TableBase.h:444
edelib::TableBase::col_resize_min
void col_resize_min(int val)
Definition: TableBase.h:449
edelib::TableBase::table_box
void table_box(Fl_Boxtype val)
Definition: TableBase.h:383
edelib::TableBase::callback_row
int callback_row()
Definition: TableBase.h:692
edelib::TableBase::row_header_color
void row_header_color(Fl_Color val)
Definition: TableBase.h:511
edelib::TableBase::cols
int cols()
Definition: TableBase.h:408
edelib::TableBase::col_header_height
int col_header_height()
Definition: TableBase.h:496
edelib::TableBase::callback_col
int callback_col()
Definition: TableBase.h:698
edelib::TableBase::top_row
void top_row(int row)
Definition: TableBase.h:583
edelib::TableBase::TableContext
TableContext
What happened in table callback.
Definition: TableBase.h:172
edelib::TableBase::add
void add(Fl_Widget *widget)
Definition: TableBase.h:641
edelib::TableBase::row_height_all
void row_height_all(int height)
Definition: TableBase.h:553
edelib::TableBase::col_width
int col_width(int col)
Definition: TableBase.h:548
edelib::TableBase::row_header_width
void row_header_width(int width)
Definition: TableBase.h:501
edelib::TableBase::top_row
int top_row()
Definition: TableBase.h:588
edelib::TableBase::insert
void insert(Fl_Widget &widget1, Fl_Widget *widget2)
Definition: TableBase.h:651
edelib::TableBase::init_sizes
void init_sizes()
Definition: TableBase.h:631
edelib::TableBase::col_position
int col_position()
Definition: TableBase.h:578
edelib::TableBase::end
void end()
Definition: TableBase.h:666
edelib::TableBase::callback_context
TableContext callback_context()
Definition: TableBase.h:703
edelib::TableBase::clear
virtual void clear()
Definition: TableBase.h:377
edelib::TableBase::rows
int rows()
Definition: TableBase.h:398
edelib::TableBase::row_header_width
int row_header_width()
Definition: TableBase.h:506
edelib::TableBase::col_header
void col_header(int flag)
Definition: TableBase.h:481
edelib::TableBase::table_box
Fl_Boxtype table_box(void)
Definition: TableBase.h:388
edelib::TableBase::col_resize
void col_resize(int flag)
Definition: TableBase.h:439
edelib::TableBase::row_header_color
Fl_Color row_header_color()
Definition: TableBase.h:516
edelib::TableBase::col_width_all
void col_width_all(int width)
Definition: TableBase.h:558
edelib::TableBase::col_header_height
void col_header_height(int height)
Definition: TableBase.h:491
edelib::TableBase::visible_cells
void visible_cells(int &r1, int &r2, int &c1, int &c2)
Definition: TableBase.h:417
edelib::TableBase::row_height
int row_height(int row)
Definition: TableBase.h:537
edelib::TableBase::row_header
void row_header(int flag)
Definition: TableBase.h:470