Fl_Table.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:31k
- /*
- * ===========================================================================
- * PRODUCTION $Log: Fl_Table.cpp,v $
- * PRODUCTION Revision 1000.1 2004/06/01 21:06:18 gouriano
- * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.4
- * PRODUCTION
- * ===========================================================================
- */
- /*
- * This is a third-party file, and is maintained and copyrighted as below.
- * Please see LICENSE at the root of the NCBI C++ toolkit for details on its
- * redistribution
- *
- * ===========================================================================
- * $Log: Fl_Table.cpp,v $
- * Revision 1000.1 2004/06/01 21:06:18 gouriano
- * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.4
- *
- * Revision 1.4 2004/05/21 22:27:51 gorelenk
- * Added PCH ncbi_pch.hpp
- *
- * Revision 1.3 2003/09/24 18:29:57 dicuccio
- * Rearranged #include statements to avoid compiler warning on MSVC
- *
- * Revision 1.2 2003/08/01 19:02:21 dicuccio
- * Retabified / reindented. Changed calling of callback in Fl_Table::handle() -
- * was called only if the release happened in the same row as the initial push,
- * which prevenets a callback on click-drag-release for selection
- *
- * Revision 1.1 2003/07/25 13:37:45 dicuccio
- * Initial revision
- *
- * ===========================================================================
- */
- //
- // Fl_Table -- A table widget
- //
- // Copyright 2002 by Greg Ercolano.
- //
- // 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".
- //
- #include <ncbi_pch.hpp>
- #include <gui/widgets/Fl_Table/Fl_Table.H>
- #include <stdio.h> // fprintf
- #include <FL/fl_draw.H>
- #define SCROLLBAR_SIZE 16
- // Scroll display so 'row' is at top
- void Fl_Table::row_position(int row)
- {
- if ( _row_position == row ) return; // OPTIMIZATION: no change? avoid redraw
- if ( row < 0 ) row = 0;
- else if ( row >= rows() ) row = rows() - 1;
- if ( table_h <= tih ) return; // don't scroll if table smaller than window
- double newtop = row_scroll_position(row);
- if ( newtop > vscrollbar->maximum() )
- { newtop = vscrollbar->maximum(); }
- vscrollbar->Fl_Slider::value(newtop);
- table_scrolled();
- redraw();
- _row_position = row; // HACK: override what table_scrolled() came up with
- }
- // Scroll display so 'col' is at left
- void Fl_Table::col_position(int col)
- {
- if ( _col_position == col ) return; // OPTIMIZATION: no change? avoid redraw
- if ( col < 0 ) col = 0;
- else if ( col >= cols() ) col = cols() - 1;
- if ( table_w <= tiw ) return; // don't scroll if table smaller than window
- double newleft = col_scroll_position(col);
- if ( newleft > hscrollbar->maximum() )
- { newleft = hscrollbar->maximum(); }
- hscrollbar->Fl_Slider::value(newleft);
- table_scrolled();
- redraw();
- _col_position = col; // HACK: override what table_scrolled() came up with
- }
- // Find scroll position of a row (in pixels)
- long Fl_Table::row_scroll_position(int row)
- {
- int startrow = 0;
- long scroll = 0;
- // OPTIMIZATION:
- // Attempt to use precomputed row scroll position
- if ( toprow_scrollpos != -1 && row >= toprow )
- { scroll = toprow_scrollpos; startrow = toprow; }
- for ( int t=startrow; t<row; t++ )
- scroll += row_height(t);
- return(scroll);
- }
- // Find scroll position of a column (in pixels)
- long Fl_Table::col_scroll_position(int col)
- {
- int startcol = 0;
- long scroll = 0;
- // OPTIMIZATION:
- // Attempt to use precomputed row scroll position
- if ( leftcol_scrollpos != -1 && col >= leftcol )
- { scroll = leftcol_scrollpos; startcol = leftcol; }
- for ( int t=startcol; t<col; t++ )
- scroll += col_width(t);
- return(scroll);
- }
- // Ctor
- Fl_Table::Fl_Table(int X, int Y, int W, int H, const char *l) : Fl_Group(X,Y,W,H,l)
- {
- _rows = 0;
- _cols = 0;
- _row_header_w = 40;
- _col_header_h = 18;
- _row_header = 0;
- _col_header = 0;
- _row_header_color = color();
- _col_header_color = color();
- _row_resize = 0;
- _col_resize = 0;
- _row_resize_min = 1;
- _col_resize_min = 1;
- _redraw_toprow = -1;
- _redraw_botrow = -1;
- _redraw_leftcol = -1;
- _redraw_rightcol = -1;
- table_w = 0;
- table_h = 0;
- toprow = 0;
- botrow = 0;
- leftcol = 0;
- rightcol = 0;
- toprow_scrollpos = -1;
- leftcol_scrollpos = -1;
- _last_cursor = FL_CURSOR_DEFAULT;
- _resizing_col = -1;
- _resizing_row = -1;
- _dragging_x = -1;
- _dragging_y = -1;
- _last_row = -1;
- box(FL_THIN_DOWN_FRAME);
- vscrollbar = new Fl_Scrollbar(x()+w()-SCROLLBAR_SIZE, y(), SCROLLBAR_SIZE, h()-SCROLLBAR_SIZE);
- vscrollbar->type(FL_VERTICAL);
- vscrollbar->callback(scroll_cb, (void*)this);
- hscrollbar = new Fl_Scrollbar(x(), y()+h()-SCROLLBAR_SIZE, w(), SCROLLBAR_SIZE);
- hscrollbar->type(FL_HORIZONTAL);
- hscrollbar->callback(scroll_cb, (void*)this);
- table = new Fl_Scroll(x(), y(), w(), h());
- table->box(FL_NO_BOX);
- table->type(0); // don't show Fl_Scroll's scrollbars -- use our own
- table->hide(); // hide unless children are present
- table->end();
- table_resized();
- redraw();
- Fl_Group::end(); // end the group's begin()
- table->begin(); // leave with fltk children getting added to the scroll
- }
- // Dtor
- Fl_Table::~Fl_Table()
- {
- // The parent Fl_Group takes care of destroying scrollbars
- }
- // Set height of a row
- void Fl_Table::row_height(int row, int height)
- {
- if ( row < 0 ) return;
- if ( row < (int)_rowheights.size() && _rowheights[row] == height )
- { return; } // OPTIMIZATION: no change? avoid redraw
- // Add row heights, even if none yet
- while ( row >= (int)_rowheights.size() )
- { _rowheights.push_back(height); }
- _rowheights[row] = height;
- table_resized();
- if ( row <= botrow ) // OPTIMIZATION: only redraw if onscreen or above screen
- { redraw(); }
- }
- // Set width of a column
- void Fl_Table::col_width(int col, int width)
- {
- if ( col < 0 ) return;
- if ( col < (int)_colwidths.size() && _colwidths[col] == width )
- { return; } // OPTIMIZATION: no change? avoid redraw
- // Add column widths, even if none yet
- while ( col >= (int)_colwidths.size() )
- { _colwidths.push_back(width); }
- _colwidths[col] = width;
- table_resized();
- if ( col <= rightcol ) // OPTIMIZATION: only redraw if onscreen or to the left
- { redraw(); }
- }
- // Return row/col clamped to reality
- int Fl_Table::row_col_clamp(TableContext context, int &R, int &C)
- {
- int clamped = 0;
- if ( R < 0 ) { R = 0; clamped = 1; }
- if ( C < 0 ) { C = 0; clamped = 1; }
- switch ( context )
- {
- case CONTEXT_COL_HEADER:
- // Allow col headers to draw even if no rows
- if ( R >= _rows && R != 0 ) { R = _rows - 1; clamped = 1; }
- break;
- case CONTEXT_ROW_HEADER:
- // Allow row headers to draw even if no columns
- if ( C >= _cols && C != 0 ) { C = _cols - 1; clamped = 1; }
- break;
- case CONTEXT_CELL:
- default:
- // CLAMP R/C TO _rows/_cols
- if ( R >= _rows ) { R = _rows - 1; clamped = 1; }
- if ( C >= _cols ) { C = _cols - 1; clamped = 1; }
- break;
- }
- return(clamped);
- }
- // Return bounding region for given context
- void Fl_Table::get_bounds(TableContext context, int &X, int &Y, int &W, int &H)
- {
- switch ( context )
- {
- case CONTEXT_COL_HEADER:
- // Column header clipping.
- X = tox;
- Y = wiy;
- W = tow;
- H = col_header_height();
- return;
- case CONTEXT_ROW_HEADER:
- // Row header clipping.
- X = wix;
- Y = toy;
- W = row_header_width();
- H = toh;
- return;
- case CONTEXT_TABLE:
- // Table inner dimensions
- X = tix; Y = tiy; W = tiw; H = tih;
- return;
- // TODO: Add other contexts..
- default:
- fprintf(stderr, "Fl_Table::get_bounds(): context %d unimplementedn", (int)context);
- return;
- }
- //NOTREACHED
- }
- // Find row/col beneath cursor
- //
- // Returns R/C and context.
- // Also returns resizeflag, if mouse is hovered over a resize boundary.
- //
- Fl_Table::TableContext Fl_Table::cursor2rowcol(int &R, int &C, ResizeFlag &resizeflag)
- {
- // return values
- R = C = 0;
- resizeflag = RESIZE_NONE;
- int X, Y, W, H;
- // Row header?
- if ( row_header() )
- {
- // Inside a row heading?
- get_bounds(CONTEXT_ROW_HEADER, X, Y, W, H);
- if ( Fl::event_inside(X, Y, W, H) )
- {
- // Scan visible rows until found
- for ( R = toprow; R <= botrow; R++ )
- {
- find_cell(CONTEXT_ROW_HEADER, R, 0, X, Y, W, H);
- if ( Fl::event_y() >= Y && Fl::event_y() < (Y+H) )
- {
- // Found row?
- // If cursor over resize boundary, and resize enabled,
- // enable the appropriate resize flag.
- //
- if ( row_resize() )
- {
- if ( Fl::event_y() <= (Y+3-0) ) { resizeflag = RESIZE_ROW_ABOVE; }
- if ( Fl::event_y() >= (Y+H-3) ) { resizeflag = RESIZE_ROW_BELOW; }
- }
- return(CONTEXT_ROW_HEADER);
- }
- }
- // Must be in row header dead zone
- return(CONTEXT_NONE);
- }
- }
- // Column header?
- if ( col_header() )
- {
- // Inside a column heading?
- get_bounds(CONTEXT_COL_HEADER, X, Y, W, H);
- if ( Fl::event_inside(X, Y, W, H) )
- {
- // Scan visible columns until found
- for ( C = leftcol; C <= rightcol; C++ )
- {
- find_cell(CONTEXT_COL_HEADER, 0, C, X, Y, W, H);
- if ( Fl::event_x() >= X && Fl::event_x() < (X+W) )
- {
- // Found column?
- // If cursor over resize boundary, and resize enabled,
- // enable the appropriate resize flag.
- //
- if ( col_resize() )
- {
- if ( Fl::event_x() <= (X+3-0) ) { resizeflag = RESIZE_COL_LEFT; }
- if ( Fl::event_x() >= (X+W-3) ) { resizeflag = RESIZE_COL_RIGHT; }
- }
- return(CONTEXT_COL_HEADER);
- }
- }
- // Must be in column header dead zone
- return(CONTEXT_NONE);
- }
- }
- // Mouse somewhere in table?
- // Scan visible r/c's until we find it.
- //
- if ( Fl::event_inside(tox, toy, tow, toh) )
- {
- for ( R = toprow; R <= botrow; R++ )
- {
- for ( C = leftcol; C <= rightcol; C++ )
- {
- find_cell(CONTEXT_CELL, R, C, X, Y, W, H);
- if ( Fl::event_inside(X, Y, W, H) )
- { return(CONTEXT_CELL); } // found it
- }
- }
- // Must be in a dead zone of the table
- R = C = 0;
- return(CONTEXT_TABLE);
- }
- // Somewhere else
- return(CONTEXT_NONE);
- }
- // Find X/Y/W/H for cell at R/C
- // If R or C are out of range, returns -1
- // with X/Y/W/H set to zero.
- //
- int Fl_Table::find_cell(TableContext context, int R, int C, int &X, int &Y, int &W, int &H)
- {
- if ( row_col_clamp(context, R, C) ) // row or col out of range? error
- { X=Y=W=H=0; return(-1); }
- X = col_scroll_position(C) - hscrollbar->value() + tix;
- Y = row_scroll_position(R) - vscrollbar->value() + tiy;
- W = col_width(C);
- H = row_height(R);
- switch ( context )
- {
- case CONTEXT_COL_HEADER:
- Y = wiy;
- H = col_header_height();
- return(0);
- case CONTEXT_ROW_HEADER:
- X = wix;
- W = row_header_width();
- return(0);
- case CONTEXT_CELL:
- return(0);
- case CONTEXT_TABLE:
- return(0);
- // TODO -- HANDLE OTHER CONTEXTS
- default:
- fprintf(stderr, "Fl_Table::find_cell: unknown context %dn", (int)context);
- return(-1);
- }
- //NOTREACHED
- }
- // Recalculate the window dimensions
- void Fl_Table::recalc_dimensions()
- {
- // Recal to* (Table Outer), ti* (Table Inner), wi* ( Widget Inner)
- wix = ( x() + Fl::box_dx(box())); tox = wix; tix = tox + Fl::box_dx(table->box());
- wiy = ( y() + Fl::box_dy(box())); toy = wiy; tiy = toy + Fl::box_dy(table->box());
- wiw = ( w() - Fl::box_dw(box())); tow = wiw; tiw = tow - Fl::box_dw(table->box());
- wih = ( h() - Fl::box_dh(box())); toh = wih; tih = toh - Fl::box_dh(table->box());
- // Trim window if headers enabled
- if ( col_header() )
- {
- tiy += col_header_height(); toy += col_header_height();
- tih -= col_header_height(); toh -= col_header_height();
- }
- if ( row_header() )
- {
- tix += row_header_width(); tox += row_header_width();
- tiw -= row_header_width(); tow -= row_header_width();
- }
- // Make scroll bars disappear if window large enough
- {
- // First pass: can hide via window size?
- int hidev = (table_h <= tih),
- hideh = (table_w <= tiw);
- // Second pass: Check for interference
- if ( !hideh & hidev ) { hidev = (( table_h - tih + SCROLLBAR_SIZE ) <= 0 ); }
- if ( !hidev & hideh ) { hideh = (( table_w - tiw + SCROLLBAR_SIZE ) <= 0 ); }
- // Determine scrollbar visibility, trim ti[xywh]/to[xywh]
- if ( hidev ) { vscrollbar->hide(); }
- else { vscrollbar->show(); tiw -= SCROLLBAR_SIZE; tow -= SCROLLBAR_SIZE; }
- if ( hideh ) { hscrollbar->hide(); }
- else { hscrollbar->show(); tih -= SCROLLBAR_SIZE; toh -= SCROLLBAR_SIZE;}
- }
- // Resize the child table
- table->resize(tox, toy, tow, toh);
- table->init_sizes();
- }
- // Recalculate internals after a scroll.
- //
- // Call this if table has been scrolled or resized.
- // Does not handle redraw().
- // TODO: Assumes ti[xywh] has already been recalculated.
- //
- void Fl_Table::table_scrolled()
- {
- // Top row
- int y, row, voff = vscrollbar->value();
- for ( row=y=0; row < _rows; row++ )
- {
- y += row_height(row);
- if ( y >= voff ) { y -= row_height(row); break; }
- }
- _row_position = toprow = ( row >= _rows ) ? (row - 1) : row;
- toprow_scrollpos = y; // OPTIMIZATION: save for later use
- // Bottom row
- voff = vscrollbar->value() + tih;
- for ( ; row < _rows; row++ )
- {
- y += row_height(row);
- if ( y >= voff ) { break; }
- }
- botrow = ( row >= _rows ) ? (row - 1) : row;
- // Left column
- int x, col, hoff = hscrollbar->value();
- for ( col=x=0; col < _cols; col++ )
- {
- x += col_width(col);
- if ( x >= hoff ) { x -= col_width(col); break; }
- }
- _col_position = leftcol = ( col >= _cols ) ? (col - 1) : col;
- leftcol_scrollpos = x; // OPTIMIZATION: save for later use
- // Right column
- // Work with data left over from leftcol calculation
- //
- hoff = hscrollbar->value() + tiw;
- for ( ; col < _cols; col++ )
- {
- x += col_width(col);
- if ( x >= hoff ) { break; }
- }
- rightcol = ( col >= _cols ) ? (col - 1) : col;
- // First tell children to scroll
- draw_cell(CONTEXT_RC_RESIZE, 0,0,0,0,0,0);
- }
- // Table resized: recalc internal data
- // Call this whenever the window is resized.
- // Recalculates the scrollbar sizes.
- // Makes no assumptions about any pre-initialized data.
- //
- void Fl_Table::table_resized()
- {
- table_h = row_scroll_position(rows());
- table_w = col_scroll_position(cols());
- recalc_dimensions();
- // Recalc scrollbar sizes
- // Clamp scrollbar value() after a resize.
- // Resize scrollbars to enforce a constant trough width after a window resize.
- //
- {
- float vscrolltab = ( table_h == 0 || tih > table_h ) ? 1 : (float)tih / table_h;
- float hscrolltab = ( table_w == 0 || tiw > table_w ) ? 1 : (float)tiw / table_w;
- vscrollbar->bounds(0, table_h-tih);
- vscrollbar->precision(10);
- vscrollbar->slider_size(vscrolltab);
- vscrollbar->resize(wix+wiw-SCROLLBAR_SIZE, wiy,
- SCROLLBAR_SIZE, wih - ((hscrollbar->visible())?SCROLLBAR_SIZE:0));
- vscrollbar->Fl_Valuator::value(vscrollbar->clamp(vscrollbar->value()));
- hscrollbar->bounds(0, table_w-tiw);
- hscrollbar->precision(10);
- hscrollbar->slider_size(hscrolltab);
- hscrollbar->resize(wix, wiy+wih-SCROLLBAR_SIZE,
- wiw - ((vscrollbar->visible())?SCROLLBAR_SIZE:0), SCROLLBAR_SIZE);
- hscrollbar->Fl_Valuator::value(hscrollbar->clamp(hscrollbar->value()));
- }
- // Tell FLTK child widgets were resized
- Fl_Group::init_sizes();
- // Recalc top/bot/left/right
- table_scrolled();
- // DO *NOT* REDRAW -- LEAVE THIS UP TO THE CALLER
- // redraw();
- }
- // Someone moved a scrollbar
- void Fl_Table::scroll_cb(Fl_Widget*w, void *data)
- {
- Fl_Table *o = (Fl_Table*)data;
- o->recalc_dimensions(); // recalc tix, tiy, etc.
- o->table_scrolled();
- o->redraw();
- }
- // Set number of rows
- void Fl_Table::rows(int val)
- {
- int oldrows = _rows;
- _rows = val;
- {
- int default_h = ( _rowheights.size() > 0 ) ? _rowheights.back() : 25;
- while ( val > (int)_rowheights.size() ) { _rowheights.push_back(default_h); } // enlarge
- while ( val < (int)_rowheights.size() ) { _rowheights.pop_back(); } // shrink
- }
- table_resized();
- // OPTIMIZATION: redraw only if change is visible.
- if ( val >= oldrows && oldrows > botrow )
- { /* NO REDRAW */ }
- else
- { redraw(); }
- }
- // Set number of cols
- void Fl_Table::cols(int val)
- {
- _cols = val;
- {
- int default_w = ( _colwidths.size() > 0 ) ? _colwidths[_colwidths.size()-1] : 80;
- while ( val > (int)_colwidths.size() ) { _colwidths.push_back(default_w); } // enlarge
- while ( val < (int)_colwidths.size() ) { _colwidths.pop_back(); } // shrink
- }
- table_resized();
- redraw();
- }
- // Change mouse cursor to different type
- void Fl_Table::change_cursor(Fl_Cursor newcursor)
- {
- if ( newcursor != _last_cursor )
- {
- fl_cursor(newcursor, FL_BLACK, FL_WHITE);
- _last_cursor = newcursor;
- }
- }
- // #define DEBUG 1
- #ifdef DEBUG
- #include "eventnames.h"
- #define PRINTEVENT
- fprintf(stderr,"Table %s: ** Event: %s --n", (label()?label():"none"), eventnames[event]);
- #else
- #define PRINTEVENT
- #endif
- // Handle FLTK events
- int Fl_Table::handle(int event)
- {
- PRINTEVENT;
- int ret = Fl_Group::handle(event); // let FLTK group handle events first
- // Which row/column are we over?
- int R, C; // row/column being worked on
- ResizeFlag resizeflag; // which resizing area are we over? (0=none)
- TableContext context = cursor2rowcol(R, C, resizeflag);
- switch ( event )
- {
- case FL_PUSH:
- // Need this for eg. right click to pop up a menu
- if ( Fl_Widget::callback() && when() & FL_WHEN_CHANGED )
- { do_callback(context, R, C); }
- switch ( context )
- {
- case CONTEXT_CELL:
- // FL_PUSH on a cell?
- ret = 1; // express interest in FL_RELEASE
- break;
- case CONTEXT_COL_HEADER:
- // FL_PUSH on a column header?
- if ( Fl::event_button() == 1 && resizeflag )
- {
- // Start resize if left click on column border.
- // "ret=1" ensures we get drag events from now on.
- // (C-1) is used if mouse is over the left hand side of the cell,
- // so that we resize the next column over to the left.
- //
- _resizing_col = ( resizeflag & RESIZE_COL_LEFT ) ? C-1 : C;
- _resizing_row = -1;
- _dragging_x = Fl::event_x();
- ret = 1;
- }
- break;
- case CONTEXT_ROW_HEADER:
- // FL_PUSH on a row header?
- if ( Fl::event_button() == 1 && resizeflag )
- {
- // Start resize if left mouse clicked on row border.
- // "ret = 1" ensures we get drag events from now on.
- // (R-1) is used if mouse is over the top of the cell,
- // so that we resize the row above.
- //
- _resizing_row = ( resizeflag & RESIZE_ROW_ABOVE ) ? R-1 : R;
- _resizing_col = -1;
- _dragging_y = Fl::event_y();
- ret = 1;
- }
- break;
- default:
- ret = 0; // express disinterest
- break;
- }
- _last_row = R;
- break;
- case FL_DRAG:
- if ( _resizing_col > -1 )
- {
- // Dragging column?
- //
- // Let user drag even /outside/ the row/col widget.
- // Don't allow column width smaller than 1.
- // Continue to show FL_CURSOR_WE at all times during drag.
- //
- int offset = _dragging_x - Fl::event_x();
- int new_w = col_width(_resizing_col) - offset;
- if ( new_w < _col_resize_min ) new_w = _col_resize_min;
- col_width(_resizing_col, new_w);
- _dragging_x = Fl::event_x();
- table_resized();
- redraw();
- change_cursor(FL_CURSOR_WE);
- ret = 1;
- if ( Fl_Widget::callback() && when() & FL_WHEN_CHANGED )
- { do_callback(CONTEXT_RC_RESIZE, R, C); }
- }
- else if ( _resizing_row > -1 )
- {
- // Dragging row?
- //
- // Let user drag even /outside/ the row/col widget.
- // Don't allow row width smaller than 1.
- // Continue to show FL_CURSOR_NS at all times during drag.
- //
- int offset = _dragging_y - Fl::event_y();
- int new_h = row_height(_resizing_row) - offset;
- if ( new_h < _row_resize_min ) new_h = _row_resize_min;
- row_height(_resizing_row, new_h);
- _dragging_y = Fl::event_y();
- table_resized();
- redraw();
- change_cursor(FL_CURSOR_NS);
- ret = 1;
- if ( Fl_Widget::callback() && when() & FL_WHEN_CHANGED )
- { do_callback(CONTEXT_RC_RESIZE, R, C); }
- }
- break;
- case FL_RELEASE:
- switch ( context )
- {
- case CONTEXT_ROW_HEADER: // release on row header
- case CONTEXT_COL_HEADER: // release on col header
- case CONTEXT_CELL: // release on a cell
- case CONTEXT_TABLE: // release on dead zone
- if ( _resizing_col == -1 && // not resizing a column
- _resizing_row == -1 && // not resizing a row
- Fl_Widget::callback() && // callback defined
- when() & FL_WHEN_RELEASE) // on button release
- {
- // Need this for eg. left clicking on a cell to select it
- do_callback(context, R, C);
- }
- break;
- default:
- break;
- }
- if ( Fl::event_button() == 1 )
- {
- change_cursor(FL_CURSOR_DEFAULT);
- _resizing_col = -1;
- _resizing_row = -1;
- ret = 1;
- }
- break;
- case FL_MOVE:
- if ( context == CONTEXT_COL_HEADER && // in column header?
- resizeflag ) // resize enabled + near boundary?
- { change_cursor(FL_CURSOR_WE); } // show resize cursor
- else if ( context == CONTEXT_ROW_HEADER && // in row header?
- resizeflag ) // resize enabled + near boundary?
- { change_cursor(FL_CURSOR_NS); } // show resize cursor
- else
- { change_cursor(FL_CURSOR_DEFAULT); } // normal cursor
- ret = 1;
- break;
- case FL_ENTER: // See FLTK event docs on the FL_ENTER widget
- case FL_LEAVE: // We want to track the mouse if resizing is allowed.
- if ( resizeflag )
- { ret = 1; }
- if ( event == FL_LEAVE )
- { change_cursor(FL_CURSOR_DEFAULT); } // normal cursor
- break;
- case FL_FOCUS:
- case FL_UNFOCUS:
- // Currently no interest in keyboard focus.
- // This will likely change when we implement keyboard navigation of cells.
- //
- // if (Fl::visible_focus())
- // { ret = 1; }
- break;
- default:
- change_cursor(FL_CURSOR_DEFAULT);
- break;
- }
- return(ret);
- }
- // Resize FLTK override
- // Handle resize events if user resizes parent window.
- //
- void Fl_Table::resize(int X, int Y, int W, int H)
- {
- // Tell group to resize, and recalc our own widget as well
- Fl_Group::resize(X, Y, W, H);
- table_resized();
- redraw();
- }
- // Draw a cell
- void Fl_Table::_redraw_cell(TableContext context, int r, int c)
- {
- if ( r < 0 || c < 0 ) return;
- int X,Y,W,H;
- find_cell(context, r, c, X, Y, W, H); // find positions of cell
- draw_cell(context, r, c, X, Y, W, H); // call users' function to draw it
- }
- // Draw the entire Fl_Table
- // Override the draw() routine to draw the table.
- // Then tell the group to draw over us.
- //
- void Fl_Table::draw()
- {
- draw_cell(CONTEXT_STARTPAGE, 0, 0, // let user's drawing routine
- tix, tiy, tiw, tih); // prep new page
- // Let fltk widgets draw themselves first. Do this after
- // draw_cell(CONTEXT_STARTPAGE) in case user moves widgets around.
- // Use window 'inner' clip to prevent drawing into table border.
- // (unfortunately this clips FLTK's border, so we must draw it explicity below)
- //
- fl_push_clip(wix, wiy, wiw, wih);
- {
- Fl_Group::draw();
- }
- fl_pop_clip();
- // Explicitly draw border around widget, if any
- draw_box(box(), x(), y(), w(), h(), color());
- // If Fl_Scroll 'table' is hidden, draw its box
- // Do this after Fl_Group::draw() so we draw over scrollbars
- // that leak around the border.
- //
- if ( ! table->visible() )
- {
- if ( damage() & FL_DAMAGE_ALL || damage() & FL_DAMAGE_CHILD )
- { draw_box(table->box(), tox, toy, tow, toh, table->color()); }
- }
- // Clip all further drawing to the inner widget dimensions
- fl_push_clip(wix, wiy, wiw, wih);
- {
- // Only redraw a few cells?
- if ( ! ( damage() & FL_DAMAGE_ALL ) && _redraw_leftcol != -1 )
- {
- fl_push_clip(tix, tiy, tiw, tih);
- for ( int c = _redraw_leftcol; c <= _redraw_rightcol; c++ )
- for ( int r = _redraw_toprow; r <= _redraw_botrow; r++ )
- { _redraw_cell(CONTEXT_CELL, r, c); }
- fl_pop_clip();
- }
- if ( damage() & FL_DAMAGE_ALL )
- {
- int X,Y,W,H;
- // Draw row headers, if any
- if ( row_header() )
- {
- get_bounds(CONTEXT_ROW_HEADER, X, Y, W, H);
- fl_push_clip(X,Y,W,H);
- for ( int r = toprow; r <= botrow; r++ )
- {
- _redraw_cell(CONTEXT_ROW_HEADER, r, 0);
- }
- fl_pop_clip();
- }
- // Draw column headers, if any
- if ( col_header() )
- {
- get_bounds(CONTEXT_COL_HEADER, X, Y, W, H);
- fl_push_clip(X,Y,W,H);
- for ( int c = leftcol; c <= rightcol; c++ )
- {
- _redraw_cell(CONTEXT_COL_HEADER, 0, c);
- }
- fl_pop_clip();
- }
- // Draw all cells.
- // This includes cells partially obscured off edges of table.
- // No longer do this last; you might think it would be nice
- // to draw over dead zones, but on redraws it flickers. Avoid
- // drawing over deadzones; prevent deadzones by sizing columns.
- //
- fl_push_clip(tix, tiy, tiw, tih);
- {
- for ( int r = toprow; r <= botrow; r++ )
- {
- for ( int c = leftcol; c <= rightcol; c++ )
- {
- _redraw_cell(CONTEXT_CELL, r, c);
- }
- }
- }
- fl_pop_clip();
- // Draw little rectangle in corner of headers
- if ( row_header() && col_header() )
- { fl_rectf(wix, wiy, row_header_width(), col_header_height(), color()); }
- // Table has a boxtype? Close those few dead pixels
- if ( table->box() )
- {
- if ( col_header() )
- { fl_rectf(tox, wiy, Fl::box_dx(table->box()),
- col_header_height(), color()); }
- if ( row_header() )
- { fl_rectf(wix, toy, row_header_width(),
- Fl::box_dx(table->box()), color()); }
- }
- // Table width smaller than window? Fill remainder with rectangle
- if ( table_w < tiw )
- {
- fl_rectf(tix + table_w, tiy, tiw - table_w, tih, color());
- // Col header? fill that too
- if ( col_header() )
- {
- fl_rectf(tix + table_w,
- wiy,
- // get that corner just right..
- (tiw - table_w + Fl::box_dw(table->box()) -
- Fl::box_dx(table->box())),
- col_header_height(),
- color());
- }
- }
- // Table height smaller than window? Fill remainder with rectangle
- if ( table_h < tih )
- {
- fl_rectf(tix, tiy + table_h, tiw, tih - table_h, color());
- if ( row_header() )
- {
- // NOTE:
- // Careful with that lower corner; don't use tih; when eg.
- // table->box(FL_THIN_UPFRAME) and hscrollbar hidden,
- // leaves a row of dead pixels.
- //
- fl_rectf(wix, tiy + table_h, row_header_width(),
- (wiy+wih)-(tiy+table_h)-(hscrollbar->visible()?
- SCROLLBAR_SIZE:0),
- color());
- }
- }
- }
- // Both scrollbars? Draw little box in lower right
- if ( vscrollbar->visible() && hscrollbar->visible() )
- {
- fl_rectf(vscrollbar->x(), hscrollbar->y(),
- vscrollbar->w(), hscrollbar->h(), color());
- }
- draw_cell(CONTEXT_ENDPAGE, 0, 0, // let user's drawing
- tix, tiy, tiw, tih); // routines cleanup
- _redraw_leftcol = _redraw_rightcol = _redraw_toprow = _redraw_botrow = -1;
- }
- fl_pop_clip();
- }