Browse Source

Clean "CR" and some fixes to work with the way squilu interface it.

mingodad 10 years ago
parent
commit
8f55acd02f
5 changed files with 1678 additions and 1670 deletions
  1. 1 1
      fltk/FL/Fl_Group.H
  2. 9 5
      fltk/FL/Flv_List.H
  3. 0 4
      fltk/FL/Flv_Table.H
  4. 7 7
      fltk/src/Flv_List.cxx
  5. 1661 1653
      fltk/src/Flv_Table.cxx

+ 1 - 1
fltk/FL/Fl_Group.H

@@ -116,7 +116,7 @@ public:
     \sa void remove(Fl_Widget&)
   */
   void remove(Fl_Widget* o) {remove(*o);}
-  void clear();
+  virtual void clear(); //make it virtual so derived classes will work properly when casted to Fl_Group
 
   /**
     See void Fl_Group::resizable(Fl_Widget *box)

+ 9 - 5
fltk/FL/Flv_List.H

@@ -268,6 +268,10 @@ public:
     {
         return feature_test(FLVF_FULL_RESIZE);
     }
+    bool select_row(void)	//	Selecting row convenience function
+    {
+        return feature_test(FLVF_ROW_SELECT);
+    }
 
     void get_default_style( Flv_Style &s );	//	Fill in s with default style
     int get_row( int x, int y );	//	Get row from X value
@@ -283,7 +287,7 @@ public:
     }
     Flv_ShowScrollbar has_scrollbar( Flv_ShowScrollbar v );
 
-    bool move_row(int amount);	//	Change row # by amount
+    virtual bool move_row(int amount);	//	Change row # by amount
 
     int row(void)	//	Get/set current row
     {
@@ -364,9 +368,9 @@ public:
     Flv_Style_List row_style;	//	Row styles
 
     int handle(int event);
-	
+
     DECLARE_CLASS_CHEAP_RTTI_2(Flv_List, Fl_Group)
-	
+
 protected:
     int vedit_when;	//	When does editing start
     int edit_row;
@@ -384,9 +388,9 @@ protected:
     int page_size(void);	//	Calculate useable page size
 
     int vrow;	//	Current selected row
-	
+
 	int last_click_timestamp;
-	
+
     unsigned char vmax_clicks;	//	Max clicks allowed
     unsigned char vclicks;
     bool vediting;	//	Are we editing now?

+ 0 - 4
fltk/FL/Flv_Table.H

@@ -91,10 +91,6 @@ public:
     {
         return (Flv_Feature)(feature() & FLVF_COL_DIVIDER)!=0;
     }
-    bool select_row(void)	//	Selecting row convenience function
-    {
-        return feature_test(FLVF_ROW_SELECT);
-    }
 
     //	These are guaranteed style retrieval functions and get
     //	the trickle down style information.  Any style elements

+ 7 - 7
fltk/src/Flv_List.cxx

@@ -895,18 +895,20 @@ void Flv_List::draw_scrollbars(int &X, int &Y, int &W, int &H )
 
     if (sh>0)
     {
+	int mylinesize = 10;
         hscrollbar.damage_resize(X,Y+H,W,vscrollbar_width);
-        hscrollbar.value( vrow_offset, 50,	0, vrow_width );	//	Fake out page size
-        hscrollbar.linesize( 10 );
+        hscrollbar.value( vrow_offset, 50,	0, vrow_width);	//	Fake out page size
+        hscrollbar.linesize( mylinesize );
         hscrollbar.minimum(0);
         hscrollbar.maximum(vrow_width-W);
 #ifdef FLTK_2
-        x = W - vrow_width/10 - vscrollbar_width*2;
+        x = W - vrow_width/mylinesize - vscrollbar_width*2;
         if (x<vscrollbar_width) x = vscrollbar_width;
         hscrollbar.slider_size(x);
 #else
-        x = vrow_width / 10;
-        hscrollbar.slider_size( (double)((double)x/(double)(W-vscrollbar_width*2)));
+        x = vrow_width / mylinesize;
+	double slider_size = ((double)x/(double)(W-vscrollbar_width*2));
+        hscrollbar.slider_size( slider_size / (vrow_width > W ? vrow_width / W : 1));
 #endif
         hscrollbar.Fl_Valuator::value( vrow_offset );	//	, 1,	0, vrows );
         if (!hscrollbar.visible())
@@ -1433,5 +1435,3 @@ Fl_Style* Flv_List::default_style =
     new Fl_Named_Style("Browser", revert, &Flv_List::default_style);
 #endif
 
-
-

+ 1661 - 1653
fltk/src/Flv_Table.cxx

@@ -1,1655 +1,1663 @@
-//	======================================================================
-//	File:    Flv_Table.cxx - Flv_Table implementation
-//	Program: Flv_Table - FLTK Table Widget
-//	Version: 0.1.0
-//	Started: 11/21/99
-//
-//	Copyright (C) 1999 Laurence Charlton
-//
-//	Description:
-//	Flv_Table implements a table/grid.  No data is stored
-//	in the widget.  Supports headers/footers for rows and columns,
-//	natively supports a single row height and column width per table.
-//	Row and column grids can be turned on and off.  Supports no scroll
-//	bars as well as horizontal/vertical automatic or always on scroll bars.
-//	Also support cell selection and row selection modes.  In row selection
-//	mode it acts like a pumped-up list widget.
-//	Uses absolute cell references.
-//
-//	row -1 is defined as the row header
-//	row -2 is defined as the row footer
-//
-// 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.
-//	======================================================================
-
-#include <FL/Flv_Table.H>
-#include <FL/Enumerations.H>
-#include <FL/fl_draw.H>
-#include <stdio.h>
-
-#define DOcb(x) ((callback_when() & (x))==(x))
-
-//	Resizing constants
-#define FUDGE 2
-#define MOVE_X 1
-#define MOVE_Y 2
-#define MOVE_XY (MOVE_X|MOVE_Y)
-
-#ifndef max
-#define max(a,b) ((a)>(b)?(a):(b))
-#endif
-#ifndef min
-#define min(a,b) ((a)<(b)?(a):(b))
-#endif
-
-static Fl_Cursor last_cursor = FL_CURSOR_DEFAULT;
-static int drag_col=-4, drag_row=-4, anchor_left, anchor_top;
-
-
-Flv_Table::Flv_Table( int X, int Y, int W, int H, const char *l ) :
-    Flv_List(X,Y,W,H,l)
-{
-    edit_col = -1;
-    vcol = 0;
-    vcols = 0;
-    vcol_width = 40;
-    vmove_on_enter = FLV_MOVE_ON_ENTER_COL_ROW;
-    vselect_col = 0;
-    vbuttons = FLV_BUTTON1 | FLV_BUTTON2 | FLV_BUTTON3;
-}
-
-Flv_Table::~Flv_Table()
-{
-}
-
-//	Probbably won't need to over-ride this for future table widgets
-void Flv_Table::draw_row( int Offset, int &X, int &Y, int &, int &H, int R )
-{
-    int c, cw, CX, FW;
-    int dX, dY, dW, dH;
-    int TX, TY, TW, TH;
-    Flv_Style s;
-
-    //	Calculate clipping height
-    client_area(dX,dY,dW,dH);
-
-    FW = (col_footer()?col_width(-2):0);
-
-    CX = X;
-
-    //	Draw column header
-    if (col_header())
-    {
-        cw = col_width(-1);		//	Column width
-        TX = CX;
-        TY = Y;
-        TW = cw;
-        TH = H;
-        draw_cell( 0, TX, TY, TW, TH, R, -1 );
-        CX += cw;
-        dX += cw;
-        dW -= cw;
-    }
-
-    dW -= FW;
-    //	Draw column footer
-    if (FW)
-    {
-        TX = dX+dW;
-        TY = Y;
-        TW = FW;
-        TH = H;
-        draw_cell( 0, TX, TY, TW, TH, R, -2 );
-    }
-
-    fl_clip( dX, Y, dW, H );			//	Clip data area
-    for (c=0;	c<vcols && CX-Offset<dX+dW;	c++, CX+=cw )
-    {
-        cw = col_width(c);					//	Column width
-        if (CX-Offset+cw<dX)				//	Before left
-            continue;
-        fl_clip( CX-Offset, Y, cw, H );
-        TX = CX;
-        TY = Y;
-        TW = cw;
-        TH = H;
-        draw_cell( Offset, TX, TY, TW, TH, R, c );
-        fl_pop_clip();
-    }
-    //	If we're selecting a row, put the box around it.
-    if (R==row() && select_row() )
-    {
-        fl_color( fl_contrast(FL_BLACK, selection_color()) );
-        fl_rect( dX, Y, dW, H );
-    }
-    //	Fill-in area at right of list
-    if (CX-Offset<dX+dW)
-    {
-        cw = dX+dW-(CX-Offset);
-        fl_color( dead_space_color() );
-        fl_rectf( CX-Offset, Y, cw, H );
-    }
-    fl_pop_clip();
-}
-
-//	You will certainly want to override this
-void Flv_Table::draw_cell( int Offset, int &X, int &Y, int &W, int &H, int R, int C )
-{
-    Fl_Boxtype bt;
-    Flv_Style s;
-
-    X -= Offset;
-
-    get_style(s, R, C);
-    if (Fl::focus()==this || persist_select())
-        add_selection_style(s, R, C);
-
-    if (row_divider())
-        s.border( s.border()|FLVB_BOTTOM );
-    if (col_divider())
-        s.border( s.border()|FLVB_RIGHT );
-
-    draw_border( s, X, Y, W, H );
-    bt = s.frame();
-
-    fl_color( s.background() );
-    fl_rectf(X,Y,W,H );
-#ifdef FLTK_2
-    bt->draw(X,Y,W,H,s.background());
-    //	Normally you would use the next line to get the client area to draw
-    bt->inset( X, Y, W, H );
-#else
-    draw_box( bt, X, Y, W, H, s.background() );
-    //	Normally you would use the next lines to get the client area to draw
-    X+= (Fl::box_dx(bt));
-    Y+= (Fl::box_dy(bt));
-    W-= (Fl::box_dw(bt));
-    H-= (Fl::box_dh(bt));
-#endif
-    //	Drawing selection rectangle for cell
-    if (R>-1 && C>-1 && R==row() && C==col() && !select_row() &&
-            (Fl::focus()==this || persist_select()))
-    {
-        fl_color( fl_contrast(text_color(), selection_color()) );
-        fl_rect( X, Y, W, H);
-    }
-
-    X+=s.x_margin();
-    Y+=s.y_margin();
-    W-=s.x_margin()*2;
-    H-=s.y_margin()*2;
-    X += Offset;
-    //	Get set-up to draw text
-    fl_font( s.font(), s.font_size() );
-    if (!active())
-        s.foreground( fl_inactive(s.foreground()) );
-    fl_color(s.foreground());
-}
-
-bool Flv_Table::get_cell_bounds( int &X, int &Y, int &W, int &H, int R, int C )
-{
-    int x, y, w, h, r, rh, B, cx;
-
-    X = Y = W = H = 0;
-    cell_area(x,y,w,h);
-    B = y+h;
-
-    for (r=top_row();	r<rows() && r<R;	y += rh, r++ )
-    {
-        rh = row_height(r);
-        if (y>B)
-            break;
-    }
-    if (r!=R)
-        return false;
-    Y = y;
-    H = row_height(R);
-    if (Y+H>B)
-        H = B-Y;
-
-    cx = x - row_offset();
-    for (r=0;	r<cols() && r<C;	cx += rh, r++ )
-    {
-        rh = col_width(r);
-        if (cx>x+w)
-            break;
-    }
-    rh = col_width(r);
-    if (r!=C || cx+rh<x)
-    {
-        X = Y = W = H = 0;
-        return false;
-    }
-
-    X = cx;
-    if (X<x)
-    {
-        rh -= (x-X);
-        X = x;
-    }
-    if (X+rh>x+w)
-        rh = (x+w)-X;
-    if (rh>w)
-        rh = w;
-    if (rh<0)
-        rh = 0;
-    W = rh;
-    return true;
-}
-
-void Flv_Table::draw(void)
-{
-    int r, rh, rw;
-    int X, Y, W, H, B, FW;
-    int CX, CY, CW, CH;
-    Flv_Style s;
-    int t, c;
-    //char buf[30];
-
-    //	Initially verify we aren't on a locked cell
-    r = row();
-    c = col();
-    while(!select_locked())
-    {
-        get_style(s,r,c);
-        if (!s.locked())
-        {
-            row(r);
-            col(c);
-            break;
-        }
-        c++;
-        if (c==cols())
-        {
-            c = 0;
-            r++;
-            if (r==rows())
-                break;
-        }
-    }
-
-    //	Make sure we have an editor if editing!
-//	if (!veditor && vediting)
-//		switch_editor(row(),col());
-
-    //	We need to know what the row width will be
-    //	so we'll calculate that and then let normal drawing
-    //	take over.
-    if (!feature_test(FLVF_MULTI_SELECT))
-        select_start_col(vcol);
-
-    for (c=cols(), rw=t=0;	t<c;	t++ )
-        rw += col_width(t);
-    if (col_header())
-        rw += col_width(-1);
-    if (col_footer())
-        rw += col_width(-2);
-
-    row_width(rw);					//	Set the row width so we can draw intelligently
-
-    start_draw(X,Y,W,H,rw);
-
-    //	This is why draw is here and we're not using the code from
-    //	Flv_List... It sucks, but I really didn't like the flickering
-    //	from the column footers getting erased and then redrawn...
-    FW = (col_footer()?col_width(-2):0);
-
-    B = W-(rw-row_offset())-FW;
-    //	Fill-in area at right of list
-    if (B>0)
-    {
-        fl_color( dead_space_color() );
-        fl_rectf( X+rw-row_offset(), Y, B, H );
-    }
-
-    B = Y + H;
-    fl_clip( X, Y, W, H );
-    //	Draw rows
-    for (	r=top_row();	Y<B && r<rows();	r++, Y+=rh )
-    {
-        rh = row_height(r);
-        if ( vlast_row==row() || (vlast_row!=row() && (r==vlast_row || r==row())) )
-        {
-            fl_clip( X, Y, W, rh);
-            CX=X;
-            CY=Y;
-            CW=rw;
-            CH=rh;
-            draw_row( row_offset(), CX, CY, CW, CH, r );
-            fl_pop_clip();
-        }
-    }
-    vlast_row = row();
-
-    //	Fill-in area at bottom of list
-    if (Y<B)
-    {
-        fl_color( dead_space_color() );
-        fl_rectf( X, Y, W, B-Y );
-    }
-    fl_pop_clip();
-}
-
-void Flv_Table::add_selection_style( Flv_Style &s, int R, int C )
-{
-    if (!multi_select())		//	If not multi row selection
-    {
-        select_start_row( row() );
-        select_start_col( col() );
-    }
-    if (R>-1 && C>-1)
-        if ( (select_row() && row_selected(R)) ||
-                (!select_row() && cell_selected(R,C)) )
-        {
-            if(Fl::focus() != this)
-            {
-                s.background( fl_color_average(selection_color(), FL_WHITE, 0.4) );
-                s.foreground( text_color());
-            }
-            else
-            {
-                s.background( selection_color() );
-                s.foreground( selection_text_color());
-            }
-        }
-}
-
-void Flv_Table::cell_area(int &X, int &Y, int &W, int &H )
-{
-    client_area(X,Y,W,H);
-    if (label() && *label())
-    {
-        Y += row_height(FLV_TITLE);
-        H -= row_height(FLV_TITLE);
-    }
-
-    if (row_header())
-    {
-        Y += row_height(FLV_ROW_HEADER);
-        H -= row_height(FLV_ROW_HEADER);
-    }
-    if (row_footer())
-    {
-        H -= row_height(FLV_ROW_FOOTER);
-    }
-    if (col_header())
-    {
-        X += col_width(FLV_COL_HEADER);
-        W -= col_width(FLV_COL_HEADER);
-    }
-    if (col_footer())
-    {
-        W -= col_width(FLV_COL_FOOTER);
-    }
-}
-
-bool Flv_Table::cell_selected(int R, int C)
-{
-    return (col_selected(C) && row_selected(R));
-}
-
-int Flv_Table::col_width(int C)					//	Get column width
-{
-    int fw = vcol_width;
-    Flv_Style *cols;
-
-    if (global_style.width_defined())
-        fw = global_style.width();
-    cols = col_style.find(C);
-    if (cols)
-        if (cols->width_defined())
-            fw = cols->width();
-    return fw;
-}
-
-int Flv_Table::col_width(int n, int c)	//	Set column width
-{
-    int cw = col_width(c);
-
-    if (c<-3)	c=-3;
-    if (c>=vcols) c=vcols-1;
-    if (n<0) n=0;
-    if (n!=cw)
-    {
-        col_style[c].width(n);
-        damage(FL_DAMAGE_CHILD);
-    }
-    return col_width(c);
-}
-
-void Flv_Table::get_style( Flv_Style &s, int R, int C )
-{
-    Flv_Style *rows, *cols, *cells;
-
-    Flv_List::get_style( s, R );
-    rows = row_style.skip_to(R);
-
-    if (R!=-3)
-    {
-        cols = col_style.skip_to(C);
-        if (cols) s = *cols;
-    }
-
-    if (C<0 || R<0)							//	Headers/Labels have different default
-    {
-        //	Note: we can still override at cell level
-        if (parent())
-            s.background( parent()->color() );
-        else
-            s.background( FL_WHITE );
-        s.frame(FL_THIN_UP_BOX);
-        s.border( FLVB_NONE );
-        s.border_spacing(0);
-    }
-
-    cells = (rows?rows->cell_style.skip_to(C):NULL);
-    if (cells)	s = *cells;
-}
-
-int Flv_Table::handle(int event)
-{
-    int stat=0, x, y, X,Y,W,H, r, c;
-    Flv_Style s;
-
-    switch(event)
-    {
-    case FL_RELEASE:
-    case FL_DRAG:
-        if (!vediting || !veditor)
-            break;
-
-    case FL_PUSH:
-        if (Fl::event_button1()==0)
-            break;
-        if (drag_row!=-4 || drag_col!=-4)
-            break;
-        x = Fl::event_x();
-        y = Fl::event_y();
-        if (!vediting)
-        {
-            if (edit_when()==FLV_EDIT_MANUAL)
-                break;
-            r = row();
-            c = col();
-            if (r<0 || c<0)
-                break;
-            cell_area(X,Y,W,H);
-            stat = internal_handle(event);
-            if (stat && r==row() && c==col() && x>=X && x<X+W && y>=Y && y<Y+H )
-            {
-                start_edit();
-                return 1;
-            }
-            return 0;
-        }
-
-        //	If these are occur outside the editor, we don't want the
-        //	child widget processing them
-        if (x<veditor->x() || y<veditor->y() || x>veditor->x()+veditor->w() ||
-                y>veditor->y()+veditor->h())
-            break;
-        stat = veditor->handle(event);
-        if (stat)
-        {
-            veditor->draw();
-            return 1;
-        }
-        break;
-    }
-
-    if (event==FL_SHORTCUT && vediting)
-    {
-        if (Fl::event_key()==FL_Enter)
-        {
-            end_edit();													//	Save editor/ quit editing
-            Fl::focus(this);
-//			take_focus();
-            internal_handle(FL_KEYBOARD);
-            damage(FL_DAMAGE_CHILD);
-            return 1;
-        }
-        switch( Fl::event_key() )
-        {
-        case FL_Shift_L:
-        case FL_Shift_R:
-        case FL_Control_L:
-        case FL_Control_R:
-        case FL_Meta_L:
-        case FL_Meta_R:
-        case FL_Alt_L:
-        case FL_Alt_R:
-            break;
-        default:
-            stat = internal_handle(FL_KEYBOARD);
-        }
-    }
-    else
-    {
-        stat = internal_handle(event);
-        if (!stat)
-        {
-            //	Jump start editing if automatic
-            if (event==FL_KEYBOARD && !vediting && edit_when()==FLV_EDIT_AUTOMATIC )
-            {
-                switch( Fl::event_key() )
-                {
-                case FL_Shift_L:
-                case FL_Shift_R:
-                case FL_Control_L:
-                case FL_Control_R:
-                case FL_Meta_L:
-                case FL_Meta_R:
-                case FL_Alt_L:
-                case FL_Alt_R:
-                    break;
-                default:
-                    start_edit();
-                    if (veditor)
-                    {
-                        stat = veditor->handle(event);
-                        if (stat)
-                        {
-                            Fl::focus(veditor);
-//								veditor->take_focus();
-                            veditor->draw();
-                            return 1;
-                        }
-                    }
-                    cancel_edit();
-                }
-            }
-        }
-    }
-
-    if (veditor && Fl::focus()==this)
-    {
-        Fl::focus(veditor);
-//		veditor->take_focus();
-        veditor->handle(FL_FOCUS);
-    }
-    if (stat && veditor)
-        veditor->draw();
-    return stat;
-}
-
-static int _last_click_y = 0;
-static int _scroll_direction = 0;
-static int _timeout_count = 0;
-
-static void _scrollerCB(void *ud)
-{
-	if(_timeout_count){
-		_timeout_count--;
-		Flv_Table *table = (Flv_Table*)ud;
-		Fl::repeat_timeout( 0.05, _scrollerCB, table );
-		//redraw();
-		Fl::e_keysym = _scroll_direction < 0 ? FL_Up : FL_Down;
-		table->handle(FL_KEYBOARD);
-	}
-}
-
-int Flv_Table::internal_handle(int event)
-{
-    int TX, TY, r, c, cd, rd;
-    Flv_Style s;
-    static int LX, LY;
-
-
-    switch( event )
-    {
-    case FL_KEYBOARD:
-        break;
-
-    case FL_ENTER:
-    case FL_LEAVE:
-        vclicks = 0;
-        return Fl_Group::handle(event);
-
-    case FL_FOCUS:
-        if(rows() == 0) return 0;
-    case FL_UNFOCUS:
-        if(rows() > 0) redraw();
-        return 1;
-
-    case FL_MOVE:
-        TY = Fl::event_y();
-        TX = Fl::event_x();
-        if ( LX-TX<-3 || LX-TX>3 || LY-TY<-3 || LY-TY>3 )
-        {
-            LX = TX;
-            LY = TY;
-            vclicks = 0;
-        }
-        check_cursor();
-        return Fl_Group::handle(event);
-
-    case FL_RELEASE:
-		if(is_dragging){
+//	======================================================================
+//	File:    Flv_Table.cxx - Flv_Table implementation
+//	Program: Flv_Table - FLTK Table Widget
+//	Version: 0.1.0
+//	Started: 11/21/99
+//
+//	Copyright (C) 1999 Laurence Charlton
+//
+//	Description:
+//	Flv_Table implements a table/grid.  No data is stored
+//	in the widget.  Supports headers/footers for rows and columns,
+//	natively supports a single row height and column width per table.
+//	Row and column grids can be turned on and off.  Supports no scroll
+//	bars as well as horizontal/vertical automatic or always on scroll bars.
+//	Also support cell selection and row selection modes.  In row selection
+//	mode it acts like a pumped-up list widget.
+//	Uses absolute cell references.
+//
+//	row -1 is defined as the row header
+//	row -2 is defined as the row footer
+//
+// 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.
+//	======================================================================
+
+#include <FL/Flv_Table.H>
+#include <FL/Enumerations.H>
+#include <FL/fl_draw.H>
+#include <stdio.h>
+
+#define DOcb(x) ((callback_when() & (x))==(x))
+
+//	Resizing constants
+#define FUDGE 2
+#define MOVE_X 1
+#define MOVE_Y 2
+#define MOVE_XY (MOVE_X|MOVE_Y)
+
+#ifndef max
+#define max(a,b) ((a)>(b)?(a):(b))
+#endif
+#ifndef min
+#define min(a,b) ((a)<(b)?(a):(b))
+#endif
+
+static Fl_Cursor last_cursor = FL_CURSOR_DEFAULT;
+static int drag_col=-4, drag_row=-4, anchor_left, anchor_top;
+
+
+Flv_Table::Flv_Table( int X, int Y, int W, int H, const char *l ) :
+    Flv_List(X,Y,W,H,l)
+{
+    edit_col = -1;
+    vcol = 0;
+    vcols = 0;
+    vcol_width = 40;
+    vmove_on_enter = FLV_MOVE_ON_ENTER_COL_ROW;
+    vselect_col = 0;
+    vbuttons = FLV_BUTTON1 | FLV_BUTTON2 | FLV_BUTTON3;
+}
+
+Flv_Table::~Flv_Table()
+{
+}
+
+//	Probbably won't need to over-ride this for future table widgets
+void Flv_Table::draw_row( int Offset, int &X, int &Y, int &, int &H, int R )
+{
+    int c, cw, CX, FW;
+    int dX, dY, dW, dH;
+    int TX, TY, TW, TH;
+    Flv_Style s;
+
+    //	Calculate clipping height
+    client_area(dX,dY,dW,dH);
+
+    FW = (col_footer()?col_width(-2):0);
+
+    CX = X;
+
+    //	Draw column header
+    if (col_header())
+    {
+        cw = col_width(-1);		//	Column width
+        TX = CX;
+        TY = Y;
+        TW = cw;
+        TH = H;
+        draw_cell( 0, TX, TY, TW, TH, R, -1 );
+        CX += cw;
+        dX += cw;
+        dW -= cw;
+    }
+
+    dW -= FW;
+    //	Draw column footer
+    if (FW)
+    {
+        TX = dX+dW;
+        TY = Y;
+        TW = FW;
+        TH = H;
+        draw_cell( 0, TX, TY, TW, TH, R, -2 );
+    }
+
+    fl_clip( dX, Y, dW, H );			//	Clip data area
+    for (c=0;	c<vcols && CX-Offset<dX+dW;	c++, CX+=cw )
+    {
+        cw = col_width(c);					//	Column width
+        if (CX-Offset+cw<dX)				//	Before left
+            continue;
+        fl_clip( CX-Offset, Y, cw, H );
+        TX = CX;
+        TY = Y;
+        TW = cw;
+        TH = H;
+        draw_cell( Offset, TX, TY, TW, TH, R, c );
+        fl_pop_clip();
+    }
+    //	If we're selecting a row, put the box around it.
+    if (R==row() && select_row() )
+    {
+        fl_color( fl_contrast(FL_BLACK, selection_color()) );
+        fl_rect( dX, Y, dW, H );
+    }
+    //	Fill-in area at right of list
+    if (CX-Offset<dX+dW)
+    {
+        cw = dX+dW-(CX-Offset);
+        fl_color( dead_space_color() );
+        fl_rectf( CX-Offset, Y, cw, H );
+    }
+    fl_pop_clip();
+}
+
+//	You will certainly want to override this
+void Flv_Table::draw_cell( int Offset, int &X, int &Y, int &W, int &H, int R, int C )
+{
+    Fl_Boxtype bt;
+    Flv_Style s;
+
+    X -= Offset;
+
+    get_style(s, R, C);
+    if (Fl::focus()==this || persist_select())
+        add_selection_style(s, R, C);
+
+    if (row_divider())
+        s.border( s.border()|FLVB_BOTTOM );
+    if (col_divider())
+        s.border( s.border()|FLVB_RIGHT );
+
+    draw_border( s, X, Y, W, H );
+    bt = s.frame();
+
+    fl_color( s.background() );
+    fl_rectf(X,Y,W,H );
+#ifdef FLTK_2
+    bt->draw(X,Y,W,H,s.background());
+    //	Normally you would use the next line to get the client area to draw
+    bt->inset( X, Y, W, H );
+#else
+    draw_box( bt, X, Y, W, H, s.background() );
+    //	Normally you would use the next lines to get the client area to draw
+    X+= (Fl::box_dx(bt));
+    Y+= (Fl::box_dy(bt));
+    W-= (Fl::box_dw(bt));
+    H-= (Fl::box_dh(bt));
+#endif
+    //	Drawing selection rectangle for cell
+    if (R>-1 && C>-1 && R==row() && C==col() && !select_row() &&
+            (Fl::focus()==this || persist_select()))
+    {
+        fl_color( fl_contrast(text_color(), selection_color()) );
+        fl_rect( X, Y, W, H);
+    }
+
+    X+=s.x_margin();
+    Y+=s.y_margin();
+    W-=s.x_margin()*2;
+    H-=s.y_margin()*2;
+    X += Offset;
+    //	Get set-up to draw text
+    fl_font( s.font(), s.font_size() );
+    if (!active())
+        s.foreground( fl_inactive(s.foreground()) );
+    fl_color(s.foreground());
+}
+
+bool Flv_Table::get_cell_bounds( int &X, int &Y, int &W, int &H, int R, int C )
+{
+    int x, y, w, h, r, rh, B, cx;
+
+    X = Y = W = H = 0;
+    cell_area(x,y,w,h);
+    B = y+h;
+
+    for (r=top_row();	r<rows() && r<R;	y += rh, r++ )
+    {
+        rh = row_height(r);
+        if (y>B)
+            break;
+    }
+    if (r!=R)
+        return false;
+    Y = y;
+    H = row_height(R);
+    if (Y+H>B)
+        H = B-Y;
+
+    cx = x - row_offset();
+    for (r=0;	r<cols() && r<C;	cx += rh, r++ )
+    {
+        rh = col_width(r);
+        if (cx>x+w)
+            break;
+    }
+    rh = col_width(r);
+    if (r!=C || cx+rh<x)
+    {
+        X = Y = W = H = 0;
+        return false;
+    }
+
+    X = cx;
+    if (X<x)
+    {
+        rh -= (x-X);
+        X = x;
+    }
+    if (X+rh>x+w)
+        rh = (x+w)-X;
+    if (rh>w)
+        rh = w;
+    if (rh<0)
+        rh = 0;
+    W = rh;
+    return true;
+}
+
+void Flv_Table::draw(void)
+{
+    int r, rh, rw;
+    int X, Y, W, H, B, FW;
+    int CX, CY, CW, CH;
+    Flv_Style s;
+    int t, c;
+    //char buf[30];
+
+    //	Initially verify we aren't on a locked cell
+    r = row();
+    c = col();
+    while(!select_locked())
+    {
+        get_style(s,r,c);
+        if (!s.locked())
+        {
+            row(r);
+            col(c);
+            break;
+        }
+        c++;
+        if (c==cols())
+        {
+            c = 0;
+            r++;
+            if (r==rows())
+                break;
+        }
+    }
+
+    //	Make sure we have an editor if editing!
+//	if (!veditor && vediting)
+//		switch_editor(row(),col());
+
+    //	We need to know what the row width will be
+    //	so we'll calculate that and then let normal drawing
+    //	take over.
+    if (!feature_test(FLVF_MULTI_SELECT))
+        select_start_col(vcol);
+
+    for (c=cols(), rw=t=0;	t<c;	t++ )
+        rw += col_width(t);
+    if (col_header())
+        rw += col_width(-1);
+    if (col_footer())
+        rw += col_width(-2);
+
+    row_width(rw);					//	Set the row width so we can draw intelligently
+
+    start_draw(X,Y,W,H,rw);
+
+    //	This is why draw is here and we're not using the code from
+    //	Flv_List... It sucks, but I really didn't like the flickering
+    //	from the column footers getting erased and then redrawn...
+    FW = (col_footer()?col_width(-2):0);
+
+    B = W-(rw-row_offset())-FW;
+    //	Fill-in area at right of list
+    if (B>0)
+    {
+        fl_color( dead_space_color() );
+        fl_rectf( X+rw-row_offset(), Y, B, H );
+    }
+
+    B = Y + H;
+    fl_clip( X, Y, W, H );
+    //	Draw rows
+    for (	r=top_row();	Y<B && r<rows();	r++, Y+=rh )
+    {
+        rh = row_height(r);
+        if ( vlast_row==row() || (vlast_row!=row() && (r==vlast_row || r==row())) )
+        {
+            fl_clip( X, Y, W, rh);
+            CX=X;
+            CY=Y;
+            CW=rw;
+            CH=rh;
+            draw_row( row_offset(), CX, CY, CW, CH, r );
+            fl_pop_clip();
+        }
+    }
+    vlast_row = row();
+
+    //	Fill-in area at bottom of list
+    if (Y<B)
+    {
+        fl_color( dead_space_color() );
+        fl_rectf( X, Y, W, B-Y );
+    }
+    fl_pop_clip();
+}
+
+void Flv_Table::add_selection_style( Flv_Style &s, int R, int C )
+{
+    if (!multi_select())		//	If not multi row selection
+    {
+        select_start_row( row() );
+        select_start_col( col() );
+    }
+    if (R>-1 && C>-1)
+        if ( (select_row() && row_selected(R)) ||
+                (!select_row() && cell_selected(R,C)) )
+        {
+            if(Fl::focus() != this)
+            {
+                s.background( fl_color_average(selection_color(), FL_WHITE, 0.4) );
+                s.foreground( text_color());
+            }
+            else
+            {
+                s.background( selection_color() );
+                s.foreground( selection_text_color());
+            }
+        }
+}
+
+void Flv_Table::cell_area(int &X, int &Y, int &W, int &H )
+{
+    client_area(X,Y,W,H);
+    if (label() && *label())
+    {
+        Y += row_height(FLV_TITLE);
+        H -= row_height(FLV_TITLE);
+    }
+
+    if (row_header())
+    {
+        Y += row_height(FLV_ROW_HEADER);
+        H -= row_height(FLV_ROW_HEADER);
+    }
+    if (row_footer())
+    {
+        H -= row_height(FLV_ROW_FOOTER);
+    }
+    if (col_header())
+    {
+        X += col_width(FLV_COL_HEADER);
+        W -= col_width(FLV_COL_HEADER);
+    }
+    if (col_footer())
+    {
+        W -= col_width(FLV_COL_FOOTER);
+    }
+}
+
+bool Flv_Table::cell_selected(int R, int C)
+{
+    return (col_selected(C) && row_selected(R));
+}
+
+int Flv_Table::col_width(int C)					//	Get column width
+{
+    int fw = vcol_width;
+    Flv_Style *cols;
+
+    if (global_style.width_defined())
+        fw = global_style.width();
+    cols = col_style.find(C);
+    if (cols)
+        if (cols->width_defined())
+            fw = cols->width();
+    return fw;
+}
+
+int Flv_Table::col_width(int n, int c)	//	Set column width
+{
+    int cw = col_width(c);
+
+    if (c<-3)	c=-3;
+    if (c>=vcols) c=vcols-1;
+    if (n<0) n=0;
+    if (n!=cw)
+    {
+        col_style[c].width(n);
+        damage(FL_DAMAGE_CHILD);
+    }
+    return col_width(c);
+}
+
+void Flv_Table::get_style( Flv_Style &s, int R, int C )
+{
+    Flv_Style *rows, *cols, *cells;
+
+    Flv_List::get_style( s, R );
+    rows = row_style.skip_to(R);
+
+    if (R!=-3)
+    {
+        cols = col_style.skip_to(C);
+        if (cols) s = *cols;
+    }
+
+    if (C<0 || R<0)							//	Headers/Labels have different default
+    {
+        //	Note: we can still override at cell level
+        if (parent())
+            s.background( parent()->color() );
+        else
+            s.background( FL_WHITE );
+        s.frame(FL_THIN_UP_BOX);
+        s.border( FLVB_NONE );
+        s.border_spacing(0);
+    }
+
+    cells = (rows?rows->cell_style.skip_to(C):NULL);
+    if (cells)	s = *cells;
+}
+
+int Flv_Table::handle(int event)
+{
+    int stat=0, x, y, X,Y,W,H, r, c;
+    Flv_Style s;
+
+    switch(event)
+    {
+    case FL_RELEASE:
+    case FL_DRAG:
+        if (!vediting || !veditor)
+            break;
+
+    case FL_PUSH:
+        if (Fl::event_button1()==0)
+            break;
+        if (drag_row!=-4 || drag_col!=-4)
+            break;
+        x = Fl::event_x();
+        y = Fl::event_y();
+        if (!vediting)
+        {
+            if (edit_when()==FLV_EDIT_MANUAL)
+                break;
+            r = row();
+            c = col();
+            if (r<0 || c<0)
+                break;
+            cell_area(X,Y,W,H);
+            stat = internal_handle(event);
+            if (stat && r==row() && c==col() && x>=X && x<X+W && y>=Y && y<Y+H )
+            {
+                start_edit();
+                return 1;
+            }
+            return 0;
+        }
+
+        //	If these are occur outside the editor, we don't want the
+        //	child widget processing them
+        if (x<veditor->x() || y<veditor->y() || x>veditor->x()+veditor->w() ||
+                y>veditor->y()+veditor->h())
+            break;
+        stat = veditor->handle(event);
+        if (stat)
+        {
+            veditor->draw();
+            return 1;
+        }
+        break;
+    }
+
+    if (event==FL_SHORTCUT && vediting)
+    {
+        if (Fl::event_key()==FL_Enter)
+        {
+            end_edit();													//	Save editor/ quit editing
+            Fl::focus(this);
+//			take_focus();
+            internal_handle(FL_KEYBOARD);
+            damage(FL_DAMAGE_CHILD);
+            return 1;
+        }
+        switch( Fl::event_key() )
+        {
+        case FL_Shift_L:
+        case FL_Shift_R:
+        case FL_Control_L:
+        case FL_Control_R:
+        case FL_Meta_L:
+        case FL_Meta_R:
+        case FL_Alt_L:
+        case FL_Alt_R:
+            break;
+        default:
+            stat = internal_handle(FL_KEYBOARD);
+        }
+    }
+    else
+    {
+        stat = internal_handle(event);
+        if (!stat)
+        {
+            //	Jump start editing if automatic
+            if (event==FL_KEYBOARD && !vediting && edit_when()==FLV_EDIT_AUTOMATIC )
+            {
+                switch( Fl::event_key() )
+                {
+                case FL_Shift_L:
+                case FL_Shift_R:
+                case FL_Control_L:
+                case FL_Control_R:
+                case FL_Meta_L:
+                case FL_Meta_R:
+                case FL_Alt_L:
+                case FL_Alt_R:
+                    break;
+                default:
+                    start_edit();
+                    if (veditor)
+                    {
+                        stat = veditor->handle(event);
+                        if (stat)
+                        {
+                            Fl::focus(veditor);
+//								veditor->take_focus();
+                            veditor->draw();
+                            return 1;
+                        }
+                    }
+                    cancel_edit();
+                }
+            }
+        }
+    }
+
+    if (veditor && Fl::focus()==this)
+    {
+        Fl::focus(veditor);
+//		veditor->take_focus();
+        veditor->handle(FL_FOCUS);
+    }
+    if (stat && veditor)
+        veditor->draw();
+    return stat;
+}
+
+static int _last_click_y = 0;
+static int _scroll_direction = 0;
+static int _timeout_count = 0;
+
+static void _scrollerCB(void *ud)
+{
+	if(_timeout_count){
+		_timeout_count--;
+		Flv_Table *table = (Flv_Table*)ud;
+		Fl::repeat_timeout( 0.05, _scrollerCB, table );
+		//redraw();
+		Fl::e_keysym = _scroll_direction < 0 ? FL_Up : FL_Down;
+		table->handle(FL_KEYBOARD);
+	}
+}
+
+int Flv_Table::internal_handle(int event)
+{
+    int TX, TY, r, c, cd, rd;
+    Flv_Style s;
+    static int LX, LY;
+
+
+    switch( event )
+    {
+    case FL_KEYBOARD:
+        break;
+
+    case FL_ENTER:
+    case FL_LEAVE:
+        vclicks = 0;
+        return Fl_Group::handle(event);
+
+    case FL_FOCUS:
+        if(rows() == 0) return 0;
+    case FL_UNFOCUS:
+        if(rows() > 0) redraw();
+        return 1;
+
+    case FL_MOVE:
+        TY = Fl::event_y();
+        TX = Fl::event_x();
+        if ( LX-TX<-3 || LX-TX>3 || LY-TY<-3 || LY-TY>3 )
+        {
+            LX = TX;
+            LY = TY;
+            vclicks = 0;
+        }
+        check_cursor();
+        return Fl_Group::handle(event);
+
+    case FL_RELEASE:
+		if(is_dragging){
 			is_dragging = false;
-/*
-			int time_span = Fl::getMilliSpan(last_click_timestamp);
-			if(time_span <= 50){
-				_scroll_direction = Fl::event_y() - _last_click_y;
-				_timeout_count = (50-time_span)/2;
-				Fl::add_timeout( 0.1, _scrollerCB, this );
+/*
+			int time_span = Fl::getMilliSpan(last_click_timestamp);
+			if(time_span <= 50){
+				_scroll_direction = Fl::event_y() - _last_click_y;
+				_timeout_count = (50-time_span)/2;
+				Fl::add_timeout( 0.1, _scrollerCB, this );
 			}
-*/
-		}
-        drag_row = drag_col = -4;
-        Fl_Group::handle(event);
-        return 1;
-
-    case FL_DRAG:
-        vclicks=0;
-		is_dragging = true;
-        if (check_resize())
-            return 1;
-    case FL_PUSH:
-		last_click_timestamp = Fl::getMilliCount();
-		_timeout_count = 0;
-		if(!is_dragging)_last_click_y = Fl::event_y();
-        //	Dragging not clicking
-        if (drag_row!=-4 || drag_col != -4)
-            return 1;
-        r = 0;
-        if (Fl::event_button1() && (buttons() & FLV_BUTTON1)) r=1;
-        if (Fl::event_button2() && (buttons() & FLV_BUTTON2)) r=1;
-        if (Fl::event_button3() && (buttons() & FLV_BUTTON3)) r=1;
-        if (r==0)
-        {
-            vclicks = 0;
-            return 0;
-        }
-
-        //	Determine if col was clicked and highlight it
-        TY = Fl::event_y();
-        TX = Fl::event_x();
-        r = get_row(TX,TY);
-        c = get_col(TX,TY);
-        //bug that prevents handle click on scrollbars
-        //if (r==-4 && c==-4)
-        if (r<0 && c<0)
-        {
-            vclicks = 0;
-            return Fl_Group::handle(event);
-        }
-        if ( LX-TX>-3 && LX-TX<3 && LY-TY>-3 && LY-TY<3)
-            vclicks++;
-        else
-        {
-            vclicks=1;
-            LX = TX;
-            LY = TY;
-        }
-
-        damage(FL_DAMAGE_CHILD);
-        rd = (r>row()?1:r==row()?0:-1);
-        cd = (c>col()?1:c==col()?0:-1);
-        if (r>=0)
-            row(r);
-        if (c>=0)
-            col(c);
-
-        if (!multi_select() ||
-                (event==FL_PUSH && !Fl::event_state(FL_SHIFT)))
-        {
-            select_start_row(row());
-            select_start_col(col());
-        }
-
-        //	At least one header clicked
-        if (r<0 || c<0)
-        {
-            if (r>-4 && c>-4 && r<0 && c<0 && r!=-3)
-            {
-                if ( DOcb(FLVEcb_ALL_CLICKED) )
-                {
-                    vwhy_event = FLVE_ALL_CLICKED;
-                    do_callback(this, user_data());
-                    vwhy_event = 0;
-                }
-                return 1;
-            }
-
-            if ( c>=0 || r==-3 )
-            {
-                vwhy_event = 0;
-                switch( r )
-                {
-                case -3:
-                    if (DOcb(FLVEcb_TITLE_CLICKED))
-                        vwhy_event = FLVE_TITLE_CLICKED;
-                    break;
-                case -2:
-                    if (DOcb(FLVEcb_ROW_FOOTER_CLICKED))
-                        vwhy_event = FLVE_ROW_FOOTER_CLICKED;
-                    break;
-                case -1:
-                    if (DOcb(FLVEcb_ROW_HEADER_CLICKED))
-                        vwhy_event = FLVE_ROW_HEADER_CLICKED;
-                    break;
-                }
-                if (vwhy_event)
-                {
-                    do_callback(this, user_data());
-                    vwhy_event = 0;
-                    return 1;
-                }
-            }
-            if ( r>=0 )
-            {
-                vwhy_event = 0;
-                switch( c )
-                {
-                case -2:
-                    if (DOcb(FLVEcb_COL_FOOTER_CLICKED))
-                        vwhy_event = FLVE_COL_FOOTER_CLICKED;
-                    break;
-                case -1:
-                    if (DOcb(FLVEcb_COL_HEADER_CLICKED))
-                        vwhy_event = FLVE_COL_HEADER_CLICKED;
-                    break;
-                }
-                if (vwhy_event)
-                {
-                    do_callback(this, user_data());
-                    vwhy_event = 0;
-                    return 1;
-                }
-            }
-            return 0;
-        }
-
-
-        if (event==FL_PUSH && (rd || cd))
-        {
-            //	Skip over locked cells
-            while(!select_locked())
-            {
-                get_style(s,r,c);
-                if (!s.locked())
-                {
-                    if (r!=row() || c!=col())
-                        vclicks=0;
-                    row(r);
-                    col(c);
-                    break;
-                }
-                r += rd;
-                c += cd;
-                if ( r<0 || r>=rows() || c<0 || c>=cols() )
-                    break;
-            }
-        }
-        if (event==FL_PUSH)
-        {
-            if (DOcb(FLVEcb_CLICKED))
-            {
-                vwhy_event = FLVE_CLICKED;
-                do_callback(this, user_data());
-                vwhy_event = 0;
-            }
-            if (vclicks>=vmax_clicks)
-                vclicks=0;
-        }
-        return 1;
-
-    default:
-        return Fl_Group::handle(event);
-    }
-
-    switch(Fl::event_key())
-    {
-    case FL_Enter:
-        switch( vmove_on_enter)
-        {
-        case FLV_MOVE_ON_ENTER_ROW_COL:
-            if (!move_row(1))
-            {
-                row(0);
-                col(col()+1);
-                if (!select_locked())
-                {
-                    //get_style(s,r,col());
-                    get_style(s,r,col());
-                    if (!s.locked())
-                        move_row(1);
-                }
-            }
-            return 1;
-        case FLV_MOVE_ON_ENTER_COL_ROW:
-            if (!move_col(1))
-            {
-                col(0);
-                row(row()+1);
-                if (!select_locked())
-                {
-                    get_style(s,r,col());
-                    if (!s.locked())
-                        move_row(1);
-                }
-            }
-            return 1;
-        }
-        return 0;
-
-    case FL_Up:
-        if (Fl::event_state(FL_CTRL))
-            move_row(-row());
-        else
-            move_row(-1);
-        break;
-
-    case FL_Down:
-        if (Fl::event_state(FL_CTRL))
-            move_row(rows());
-        else
-            move_row(1);
-        break;
-
-    case FL_Page_Down:
-        if (Fl::event_state(FL_CTRL))
-            move_row( rows() );
-        else
-            move_row(page_size());
-        break;
-
-    case FL_Page_Up:
-        if (Fl::event_state(FL_CTRL))
-            move_row(-row());
-        else
-            move_row(-page_size());
-        break;
-
-    case FL_Home:
-        //	Adjust rows before columns so we redraw everything
-        if (Fl::event_state(FL_CTRL))
-            move_row(-rows());
-        move_col(-cols());
-        break;
-    case FL_End:
-        //	Adjust rows before columns so we redraw everything
-        if (Fl::event_state(FL_CTRL))
-            move_row(rows());
-        move_col(cols());
-        break;
-
-    case FL_Right:
-        if (select_row())
-            return 0;
-        if (Fl::event_state(FL_CTRL))
-            move_col(cols());
-        else
-            move_col(1);
-        break;
-
-    case FL_Left:
-        if (select_row())
-            return 0;
-        if (Fl::event_state(FL_CTRL))
-            move_col(-col());
-        else
-            move_col(-1);
-        break;
-
-    default:
-        return Fl_Group::handle(event);
-    }
-
-    if (!multi_select() || !Fl::event_state(FL_SHIFT))
-    {
-        select_start_col(col());
-        select_start_row(row());
-    }
-    return 1;
-}
-
-int Flv_Table::row(int n)
-{
-    int X,Y,W,H;
-
-    if (n>=rows())
-        n=rows()-1;
-    if (n<0)
-        n=0;
-    if (n!=vrow)
-    {
-        vrow = n;
-        client_area(X,Y,W,H);
-        update_top_row(H);
-        end_edit();
-        if (edit_when()==FLV_EDIT_ALWAYS)
-            switch_editor( row(), col() );
-        vlast_row = vrow;
-        if (DOcb(FLVEcb_ROW_CHANGED))
-        {
-            vwhy_event = FLVE_ROW_CHANGED;
-            do_callback(this, user_data());
-            vwhy_event = 0;
-        }
-        damage(FL_DAMAGE_CHILD);
-    }
-    return vrow;
-}
-
-int Flv_Table::col( int n )
-{
-    Flv_Style s;
-
-    if (n>=vcols)
-        n=vcols-1;
-    if (n<0)
-        n=0;
-    if (n!=vcol)
-    {
-        vcol = n;
-        end_edit();
-        if (edit_when()==FLV_EDIT_ALWAYS)
-            switch_editor( row(), col() );
-
-        adjust_for_cell();
-        if (DOcb(FLVEcb_COL_CHANGED))
-        {
-            vwhy_event = FLVE_COL_CHANGED;
-            do_callback(this, user_data());
-            vwhy_event = 0;
-        }
-        damage(FL_DAMAGE_CHILD);
-    }
-    return vcol;
-}
-
-bool Flv_Table::col_resizable(int c)								//	Get/set column locked status
-{
-    Flv_Style *s;
-    bool l=true;
-    if (global_style.resizable_defined())
-        l = global_style.resizable();
-    s = col_style.find(c);
-    if (s)
-        if (s->resizable_defined())
-            l = s->resizable();
-    return l;
-}
-
-bool Flv_Table::col_resizable( bool n, int c)
-{
-    col_style[c].resizable(n);
-    return n;
-}
-
-int Flv_Table::cols( int n )
-{
-    if (n>=0 && n!=vcols)
-    {
-        vcols = n;
-        if (vcol>=vcols)
-            col(vcols-1);
-        if (vselect_col>vcol)
-            select_start_col(vcol);
-        update_width();
-        if (DOcb(FLVEcb_COLS_CHANGED))
-        {
-            vwhy_event = FLVE_COLS_CHANGED;
-            do_callback(this, user_data());
-            vwhy_event = 0;
-        }
-        damage(FL_DAMAGE_CHILD);
-    }
-    return vcols;
-}
-
-bool Flv_Table::col_selected(int n)
-{
-    if (vselect_col<vcol)
-        return (vselect_col<=n && n<=vcol);
-    else
-        return (vcol<=n && n<=vselect_col);
-}
-
-//	Get column from x,y
-int Flv_Table::get_col( int x, int y )
-{
-    int X, Y, W, H, CX;
-    int rw, cw, t, Offset;
-
-    client_area(X,Y,W,H);
-    if (label())
-    {
-        cw = row_height(-3);
-        Y+=cw;
-        H-=cw;
-    }
-    if (col_header())
-    {
-        cw = col_width(-1);
-        if (X<=x && x<=X+cw)
-            return -1;
-        X+=cw;
-        W-=cw;
-    }
-    if (col_footer())
-    {
-        cw = col_width(-2);
-        if (X+W>=x && x>=X+W-cw)
-            return -2;
-        W -= cw;
-    }
-
-    rw = row_width();
-    if (!rw)
-        rw = W;
-    if ( x<X || x>=X+W || y<Y || y>=Y+H || x>X-row_offset()+rw)
-        return -4;
-
-    Offset = row_offset();
-    for (CX=X, t=0;	t<vcols && CX-Offset<X+W;	t++, CX+=cw )
-    {
-        cw = col_width(t);
-        if (x>=CX-Offset && x<CX-Offset+cw)
-            return t;
-    }
-    return -4;	//	In grey area at bottom?
-}
-
-int Flv_Table::select_start_col(int n)
-{
-    if (n>=vcols)
-        n=vcols-1;
-    if (n<0)
-        n=0;
-    if (n!=vselect_col)
-    {
-        vselect_col = n;
-        if (DOcb(FLVEcb_SELECTION_CHANGED))
-        {
-            vwhy_event = FLVE_SELECTION_CHANGED;
-            do_callback(this, user_data());
-            vwhy_event = 0;
-        }
-        damage(FL_DAMAGE_CHILD);
-    }
-    return vselect_col;
-}
-
-void Flv_Table::update_width()
-{
-    int rw, n;
-
-    for (rw=n=0;	n<vcols;	n++ )
-        rw+=(col_width(n));
-    if (col_header())
-        rw+=col_width(-1);
-    if (col_footer())
-        rw+=col_width(-2);
-    if (rw!=row_width())
-    {
-        row_width(rw);
-        damage(FL_DAMAGE_CHILD);
-    }
-}
-
-void Flv_Table::adjust_for_cell()
-{
-    int n, o, cw;
-    int X, Y, W, H;
-
-    for (n=o=0;	n<col();	n++ )
-        o+=col_width(n);
-    if (row_offset()>o)
-        row_offset(o);
-    else
-    {
-        client_area(X,Y,W,H);
-        if (col_footer())
-            W -= col_width(-2);
-        if (col_header())
-            W -= col_width(-2);
-        cw = col_width(col());
-        if (o+cw-row_offset()>W)
-        {
-            row_offset(o+cw-W);
-            damage(FL_DAMAGE_CHILD);
-        }
-    }
-}
-
-bool Flv_Table::check_resize(void)
-{
-    int ex, ey, v;
-    int X, Y, W, H;
-
-    if (drag_row<-3 && drag_col<-2)
-        return false;
-
-    client_area(X,Y,W,H);
-    ex = Fl::event_x();
-    ey = Fl::event_y();
-
-    if (drag_row==-3)
-    {
-        v = ey-anchor_top;
-        if (v<2) v=2;
-        row_style[drag_row].height(v);
-        damage(FL_DAMAGE_CHILD);
-        return true;
-    }
-
-    if (label() && *label())
-    {
-        Y += row_height(-3);
-        H -= row_height(-3);
-    }
-
-    if (drag_col>-3)
-    {
-        if (drag_col==-2)
-        {
-            v = anchor_left - ex + col_width(drag_col);
-            if (col_header())
-            {
-                X += col_width(-1);
-                W -= col_width(-1);
-            }
-            if (v>W-1)
-            {
-                v = W-1;
-                anchor_left = X+W-v;
-            }
-            if (v<2)
-            {
-                v=2;
-                anchor_left = X+W-2;
-            }
-            col_style[drag_col].width(v);
-            damage(FL_DAMAGE_CHILD);
-            if (v!=W-1 && v!=2)
-                anchor_left = ex;
-        }
-        else
-        {
-            v = ex-anchor_left;
-            if (drag_col==-1)
-            {
-                //	Make sure it's in the grid
-                if (col_footer())
-                    W-=col_width(-2);
-                if (v > W-1 )
-                    v = W-1;
-            }
-            if (v<2)
-                v=2;
-            col_width(v,drag_col);
-            damage(FL_DAMAGE_CHILD);
-        }
-    }
-
-    //	Resize row
-    if (drag_row>-4)
-    {
-        if (drag_row==-2)
-        {
-            v = anchor_top - ey + row_height(drag_row);
-            if (row_header())
-            {
-                H-=row_height(-1);
-                Y+=row_height(-1);
-            }
-            if (v>H-1)
-            {
-                v = H-1;
-                anchor_top = Y+H-v;
-            }
-            if (v<2)
-            {
-                v = 2;
-                anchor_top = Y+H-2;
-            }
-            row_style[drag_row].height(v);
-            damage(FL_DAMAGE_CHILD);
-            if (v!=2 && v!=H-1)
-                anchor_top = ey;
-        }
-        else
-        {
-            v = ey-anchor_top;
-            if (drag_row==-1)
-            {
-                if (row_footer())
-                    H-=row_height(-2);
-                if (v>H-1)
-                    v = H-1;
-            }
-            if (v<2) v=2;
-            row_height(v,drag_row);
-            damage(FL_DAMAGE_CHILD);
-        }
-    }
-    return true;
-}
-
-//	See if we can resize, if so change cursor
-void Flv_Table::check_cursor(void)
-{
-    int X, Y, W, H, R, ey, ex, move=0, WW, size;
-    int v;
-    bool resize, inh, inv;
-    Fl_Cursor cursor;
-
-    //	Assume total miss
-    drag_row = drag_col = -4;
-    cursor = FL_CURSOR_DEFAULT;
-
-    ex = Fl::event_x();
-    ey = Fl::event_y();
-    client_area(X,Y,W,H);
-    inh = (ex>=X && ex<X+W);
-    inv = (ey>=Y && ey<Y+H);
-
-    if (label() && *label())
-    {
-        size = row_height(-3);
-        Y+=size;
-        H-=size;
-        resize = (ey>=Y-FUDGE && ey<=Y+FUDGE && inh);
-        if (resize)
-        {
-            if (row_resizable(-3))
-            {
-                drag_row = -3;
-                anchor_top = Y-size;
-                move |= MOVE_Y;
-            }
-        }
-    }
-
-    //	Trival tests to see if we're in region
-    resize = full_resize();
-    if (!resize)
-    {
-        if (row_header())
-        {
-            size = row_height(-1);
-            resize |= (ey>=Y && ey<=Y+size+FUDGE && inh);
-        }
-        if (!resize)
-        {
-            if (row_footer())
-            {
-                size = row_height(-2);
-                resize |= (ey<=Y+H && ey>=Y+H-size-FUDGE && inh);
-            }
-            if (!resize)
-            {
-                if (col_header())
-                {
-                    size = col_width(-1);
-                    resize |= (ex>=X && ex<=X+size+FUDGE && inh);
-                }
-                if (!resize)
-                {
-                    if (col_footer())
-                    {
-                        size = col_width(-2);
-                        resize |= (ex<=X+W && ex>=X+W-size-FUDGE && inh);
-                    }
-                }
-            }
-        }
-    }
-
-    if (!resize)	//	In general region?
-    {
-        if (cursor!=last_cursor)
-        {
-            fl_cursor(cursor,FL_BLACK,FL_WHITE);
-            last_cursor = cursor;
-        }
-        return;
-    }
-
-    //	==================================================================
-    //	Sweep columns
-    WW = X;
-    if (col_header())
-    {
-        size = col_width(-1);
-        if (ex>=WW+size-FUDGE && ex<=WW+size+FUDGE && inv)
-        {
-            if (col_resizable(-1) && (move & MOVE_Y)==0)
-            {
-                drag_col = -1;
-                anchor_left = WW;
-                move |= MOVE_X;
-            }
-        }
-        WW += size;
-        X += size;
-        W -= size;
-    }
-
-    if (col_footer())
-    {
-        size = col_width(-2);
-        if (ex>=X+W-size-FUDGE && ex<=X+W-size+FUDGE && inv)
-        {
-            if (col_resizable(-2))
-            {
-                drag_col = -2;
-                anchor_left = ex;
-                move |= MOVE_X;
-            }
-        }
-        W -= size;
-    }
-
-    if ( (move & MOVE_X)==0 )
-    {
-        R = X-row_offset()+row_width()+FUDGE;		//	Right edge of row
-        for (WW-=row_offset(), v=0;	WW<R && WW<X+W && v<cols();	WW+=size, v++ )
-        {
-            size = col_width(v);
-            if (WW+size<X)		//	Off left
-                continue;
-            if (ex>=WW+size-FUDGE && ex<=WW+size+FUDGE && inv)
-            {
-                if (col_resizable(v))
-                {
-                    drag_col = v;
-                    anchor_left = WW;
-                    move |= MOVE_X;		//	Moving col
-                }
-                break;
-            }
-        }
-    }
-    if (col_header())
-    {
-        X-=col_width(-1);
-        W+=col_width(-1);
-    }
-    if (col_footer())
-        W+=col_width(-2);
-
-    //	==================================================================
-    //	Sweep rows
-    WW = Y;
-    if (row_header())
-    {
-        size = row_height(-1);
-        if (ey>=WW+size-FUDGE && ey<=WW+size+FUDGE && inh)
-        {
-            if (row_resizable(-1))
-            {
-                drag_row = -1;
-                anchor_top = WW;
-                move |= MOVE_Y;
-            }
-        }
-        WW += size;
-        Y += size;
-        H -= size;
-    }
-    if (row_footer())
-    {
-        size = row_height(-2);
-        if (ey>=Y+H-size-FUDGE && ey<=Y+H-size+FUDGE && inh)
-        {
-            if (row_resizable(-2))
-            {
-                drag_row = -2;
-                anchor_top = ey;
-                move |= MOVE_Y;
-            }
-        }
-        H -= size;
-    }
-    if ( (move & MOVE_Y)==0 )
-    {
-        for (v=top_row();	v<rows();	WW+=size, v++ )
-        {
-            size = row_height(v);
-            if (WW+size-FUDGE>=Y+H)
-                break;
-            if (ey>=WW+size-FUDGE && ey<=WW+size+FUDGE && inh)
-            {
-                if (row_resizable(v))
-                {
-                    drag_row = v;
-                    anchor_top = WW;
-                    move |= MOVE_Y;		//	Moving
-                }
-                break;
-            }
-        }
-    }
-
-    switch( move )
-    {
-    case MOVE_X:
-        cursor = FL_CURSOR_WE;
-        drag_row=-4;
-        break;
-    case MOVE_Y:
-        cursor = FL_CURSOR_NS;
-        drag_col=-4;
-        break;
-    case MOVE_XY:
-        cursor = FL_CURSOR_NWSE;
-        break;
-    default:
-        drag_row = drag_col = -4;
-        cursor = FL_CURSOR_DEFAULT;
-        break;
-    }
-    if (cursor!=last_cursor)
-    {
-        fl_cursor(cursor,FL_BLACK,FL_WHITE);
-        last_cursor = cursor;
-    }
-}
-
-bool Flv_Table::move_row( int amount )
-{
-    Flv_Style s;
-    int r = row();
-
-    if (!amount)
-        return true;
-
-    r += amount;
-    if (r>=rows())
-        r = rows()-1;
-    if (r<0)
-        r = 0;
-
-    while(!select_locked())
-    {
-        get_style(s,r,col());
-        if (!s.locked())
-            break;
-        r += (amount<0?-1:1);
-        if ( r<0 || r>=rows() )
-            return false;
-    }
-    if (r!=row())
-    {
-        row(r);
-        return true;
-    }
-    return false;
-}
-
-bool Flv_Table::move_col( int amount )
-{
-    Flv_Style s;
-    int c = col();
-
-    if (!amount)
-        return true;
-
-    c += amount;
-    if (c>=cols())
-        c = cols()-1;
-    if (c<0)
-        c = 0;
-
-    while(!select_locked())
-    {
-        get_style(s,row(),c);
-        if (!s.locked())
-            break;
-        c += (amount<0?-1:1);
-        if ( c<0 || c>=rows() )
-            return false;
-    }
-    if (c!=col())
-    {
-        col(c);
-        return true;
-    }
-    return false;
-}
-
-
-int Flv_Table::edit_when( int v )
-{
-    int wfocused = (Fl::focus()==veditor);
-    if (v!=vedit_when)
-    {
-        vedit_when = v;
-        if (vedit_when!=FLV_EDIT_ALWAYS)
-            end_edit();
-        else
-            start_edit();
-    }
-    if (wfocused && !vediting)
-    {
-        Fl::focus(this);
-//		take_focus();
-        redraw();
-    }
-    return vedit_when;
-}
-
-
-void Flv_Table::start_edit(void)											//	Start editing
-{
-    if (!vediting)
-    {
-        vediting = true;
-        switch_editor( row(), col() );
-    }
-}
-
-void Flv_Table::end_edit(void)
-{
-    int wfocused = (Fl::focus()==veditor);
-    if (veditor)
-        switch_editor(-1,-1);
-    if (wfocused && !vediting)
-    {
-        Fl::focus(this);
-//		take_focus();
-        redraw();
-    }
-}
-
-void Flv_Table::cancel_edit(void)											//	Cancel editing
-{
-    int wfocused = (Fl::focus()==veditor);
-    if (veditor)
-    {
-        veditor->hide();
-        veditor->draw();
-    }
-    veditor = NULL;
-    edit_row = -1;
-    edit_col = -1;
-    vediting = false;
-//	switch_editor(-1, -1);
-    if (wfocused && !vediting)
-    {
-        Fl::focus(this);
-//		take_focus();
-        redraw();
-    }
-}
-
-void Flv_Table::switch_editor( int nr, int nc )
-{
-    Flv_Style s;
-    int x, y, w, h, wfocused;
-    //char buf[30];
-
-    wfocused = (Fl::focus()==veditor);
-
-    if (veditor)
-    {
-        if (edit_row>-1 && edit_col>-1)
-            save_editor( veditor, edit_row, edit_col );
-        edit_row=-1;
-        edit_col=-1;
-        veditor->hide();
-        veditor->draw();
-        veditor = NULL;
-    }
-    if (edit_when()==FLV_EDIT_ALWAYS)
-    {
-        vediting = true;
-        if (nr<0)
-            nr = row();
-        if (nc<0)
-            nc = col();
-    }
-
-    if (nr>-1 && nc>-1 && vediting)
-    {
-        get_style( s, nr, nc );
-        if (s.editor_defined() && !s.locked())
-        {
-            veditor = s.editor();
-            if (veditor)
-            {
-                edit_row = nr;
-                edit_col = nc;
-                veditor->hide();
-                get_cell_bounds(x,y,w,h,nr,nc);
-                position_editor(veditor, x,y,w,h, s);
-                load_editor( veditor, nr, nc );
-                veditor->show();
-                Fl::focus(veditor);
-//				veditor->take_focus();
-                veditor->handle(FL_FOCUS);
-                veditor->damage(FL_DAMAGE_ALL);
-                veditor->draw();
-            }
-        }
-    }
-    if (!veditor)
-    {
-        vediting=false;
-        edit_row=-1;
-        edit_col=-1;
-    }
-    if (!veditor && wfocused)
-    {
-        Fl::focus(this);
-//		take_focus();
-        handle(FL_FOCUS);
-    }
-}
-
+*/
+		}
+        drag_row = drag_col = -4;
+        Fl_Group::handle(event);
+        return 1;
+
+    case FL_DRAG:
+        vclicks=0;
+		is_dragging = true;
+        if (check_resize())
+            return 1;
+    case FL_PUSH:
+		last_click_timestamp = Fl::getMilliCount();
+		_timeout_count = 0;
+		if(!is_dragging)_last_click_y = Fl::event_y();
+        //	Dragging not clicking
+        if (drag_row!=-4 || drag_col != -4)
+            return 1;
+        r = 0;
+        if (Fl::event_button1() && (buttons() & FLV_BUTTON1)) r=1;
+        if (Fl::event_button2() && (buttons() & FLV_BUTTON2)) r=1;
+        if (Fl::event_button3() && (buttons() & FLV_BUTTON3)) r=1;
+        if (r==0)
+        {
+            vclicks = 0;
+            return 0;
+        }
+
+        //	Determine if col was clicked and highlight it
+        TY = Fl::event_y();
+        TX = Fl::event_x();
+        r = get_row(TX,TY);
+        c = get_col(TX,TY);
+        //bug that prevents handle click on scrollbars
+        //if (r==-4 && c==-4)
+        if (r<0 && c<0)
+        {
+            vclicks = 0;
+            return Fl_Group::handle(event);
+        }
+        if ( LX-TX>-3 && LX-TX<3 && LY-TY>-3 && LY-TY<3)
+            vclicks++;
+        else
+        {
+            vclicks=1;
+            LX = TX;
+            LY = TY;
+        }
+
+        damage(FL_DAMAGE_CHILD);
+        rd = (r>row()?1:r==row()?0:-1);
+        cd = (c>col()?1:c==col()?0:-1);
+        if (r>=0)
+            row(r);
+        if (c>=0)
+            col(c);
+
+        if (!multi_select() ||
+                (event==FL_PUSH && !Fl::event_state(FL_SHIFT)))
+        {
+            select_start_row(row());
+            select_start_col(col());
+        }
+
+        //	At least one header clicked
+        if (r<0 || c<0)
+        {
+            if (r>-4 && c>-4 && r<0 && c<0 && r!=-3)
+            {
+                if ( DOcb(FLVEcb_ALL_CLICKED) )
+                {
+                    vwhy_event = FLVE_ALL_CLICKED;
+                    do_callback(this, user_data());
+                    vwhy_event = 0;
+                }
+                return 1;
+            }
+
+            if ( c>=0 || r==-3 )
+            {
+                vwhy_event = 0;
+                switch( r )
+                {
+                case -3:
+                    if (DOcb(FLVEcb_TITLE_CLICKED))
+                        vwhy_event = FLVE_TITLE_CLICKED;
+                    break;
+                case -2:
+                    if (DOcb(FLVEcb_ROW_FOOTER_CLICKED))
+                        vwhy_event = FLVE_ROW_FOOTER_CLICKED;
+                    break;
+                case -1:
+                    if (DOcb(FLVEcb_ROW_HEADER_CLICKED))
+                        vwhy_event = FLVE_ROW_HEADER_CLICKED;
+                    break;
+                }
+                if (vwhy_event)
+                {
+                    do_callback(this, user_data());
+                    vwhy_event = 0;
+                    return 1;
+                }
+            }
+            if ( r>=0 )
+            {
+                vwhy_event = 0;
+                switch( c )
+                {
+                case -2:
+                    if (DOcb(FLVEcb_COL_FOOTER_CLICKED))
+                        vwhy_event = FLVE_COL_FOOTER_CLICKED;
+                    break;
+                case -1:
+                    if (DOcb(FLVEcb_COL_HEADER_CLICKED))
+                        vwhy_event = FLVE_COL_HEADER_CLICKED;
+                    break;
+                }
+                if (vwhy_event)
+                {
+                    do_callback(this, user_data());
+                    vwhy_event = 0;
+                    return 1;
+                }
+            }
+            return 0;
+        }
+
+
+        if (event==FL_PUSH && (rd || cd))
+        {
+            //	Skip over locked cells
+            while(!select_locked())
+            {
+                get_style(s,r,c);
+                if (!s.locked())
+                {
+                    if (r!=row() || c!=col())
+                        vclicks=0;
+                    row(r);
+                    col(c);
+                    break;
+                }
+                r += rd;
+                c += cd;
+                if ( r<0 || r>=rows() || c<0 || c>=cols() )
+                    break;
+            }
+        }
+        if (event==FL_PUSH)
+        {
+            if (DOcb(FLVEcb_CLICKED))
+            {
+                vwhy_event = FLVE_CLICKED;
+                do_callback(this, user_data());
+                vwhy_event = 0;
+            }
+            if (vclicks>=vmax_clicks)
+                vclicks=0;
+        }
+        return 1;
+
+    default:
+        return Fl_Group::handle(event);
+    }
+
+    switch(Fl::event_key())
+    {
+    case FL_Enter:
+        switch( vmove_on_enter)
+        {
+        case FLV_MOVE_ON_ENTER_ROW_COL:
+            if (!move_row(1))
+            {
+                row(0);
+                col(col()+1);
+                if (!select_locked())
+                {
+                    //get_style(s,r,col());
+                    get_style(s,r,col());
+                    if (!s.locked())
+                        move_row(1);
+                }
+            }
+            return 1;
+        case FLV_MOVE_ON_ENTER_COL_ROW:
+            if (!move_col(1))
+            {
+                col(0);
+                row(row()+1);
+                if (!select_locked())
+                {
+                    get_style(s,r,col());
+                    if (!s.locked())
+                        move_row(1);
+                }
+            }
+            return 1;
+        }
+        return 0;
+
+    case FL_Up:
+        if (Fl::event_state(FL_CTRL))
+            move_row(-row());
+        else
+            move_row(-1);
+        break;
+
+    case FL_Down:
+        if (Fl::event_state(FL_CTRL))
+            move_row(rows());
+        else
+            move_row(1);
+        break;
+
+    case FL_Page_Down:
+        if (Fl::event_state(FL_CTRL))
+            move_row( rows() );
+        else
+            move_row(page_size());
+        break;
+
+    case FL_Page_Up:
+        if (Fl::event_state(FL_CTRL))
+            move_row(-row());
+        else
+            move_row(-page_size());
+        break;
+
+    case FL_Home:
+        //	Adjust rows before columns so we redraw everything
+        if (Fl::event_state(FL_CTRL))
+            move_row(-rows());
+        move_col(-cols());
+        break;
+    case FL_End:
+        //	Adjust rows before columns so we redraw everything
+        if (Fl::event_state(FL_CTRL))
+            move_row(rows());
+        move_col(cols());
+        break;
+
+    case FL_Right:
+        if (select_row())
+            return 0;
+        if (Fl::event_state(FL_CTRL))
+            move_col(cols());
+        else
+            move_col(1);
+        break;
+
+    case FL_Left:
+        if (select_row())
+            return 0;
+        if (Fl::event_state(FL_CTRL))
+            move_col(-col());
+        else
+            move_col(-1);
+        break;
+
+    default:
+        return Fl_Group::handle(event);
+    }
+
+    if (!multi_select() || !Fl::event_state(FL_SHIFT))
+    {
+        select_start_col(col());
+        select_start_row(row());
+    }
+    return 1;
+}
+
+int Flv_Table::row(int n)
+{
+    int X,Y,W,H;
+
+    if (n>=rows())
+        n=rows()-1;
+    if (n<0)
+        n=0;
+    if (n!=vrow)
+    {
+        vrow = n;
+        client_area(X,Y,W,H);
+        update_top_row(H);
+        end_edit();
+        if (edit_when()==FLV_EDIT_ALWAYS)
+            switch_editor( row(), col() );
+        vlast_row = vrow;
+        if (DOcb(FLVEcb_ROW_CHANGED))
+        {
+            vwhy_event = FLVE_ROW_CHANGED;
+            do_callback(this, user_data());
+            vwhy_event = 0;
+        }
+        damage(FL_DAMAGE_CHILD);
+    }
+    return vrow;
+}
+
+int Flv_Table::col( int n )
+{
+    Flv_Style s;
+
+    if (n>=vcols)
+        n=vcols-1;
+    if (n<0)
+        n=0;
+    if(n==0)
+   {
+	if(hscrollbar.value())
+	{
+            hscrollbar.value(0);
+            hscrollbar.do_callback();
+	}
+    }
+    if (n!=vcol)
+    {
+        vcol = n;
+        end_edit();
+        if (edit_when()==FLV_EDIT_ALWAYS)
+            switch_editor( row(), col() );
+
+        adjust_for_cell();
+        if (DOcb(FLVEcb_COL_CHANGED))
+        {
+            vwhy_event = FLVE_COL_CHANGED;
+            do_callback(this, user_data());
+            vwhy_event = 0;
+        }
+        damage(FL_DAMAGE_CHILD);
+    }
+    return vcol;
+}
+
+bool Flv_Table::col_resizable(int c)								//	Get/set column locked status
+{
+    Flv_Style *s;
+    bool l=true;
+    if (global_style.resizable_defined())
+        l = global_style.resizable();
+    s = col_style.find(c);
+    if (s)
+        if (s->resizable_defined())
+            l = s->resizable();
+    return l;
+}
+
+bool Flv_Table::col_resizable( bool n, int c)
+{
+    col_style[c].resizable(n);
+    return n;
+}
+
+int Flv_Table::cols( int n )
+{
+    if (n>=0 && n!=vcols)
+    {
+        vcols = n;
+        if (vcol>=vcols)
+            col(vcols-1);
+        if (vselect_col>vcol)
+            select_start_col(vcol);
+        update_width();
+        if (DOcb(FLVEcb_COLS_CHANGED))
+        {
+            vwhy_event = FLVE_COLS_CHANGED;
+            do_callback(this, user_data());
+            vwhy_event = 0;
+        }
+        damage(FL_DAMAGE_CHILD);
+    }
+    return vcols;
+}
+
+bool Flv_Table::col_selected(int n)
+{
+    if (vselect_col<vcol)
+        return (vselect_col<=n && n<=vcol);
+    else
+        return (vcol<=n && n<=vselect_col);
+}
+
+//	Get column from x,y
+int Flv_Table::get_col( int x, int y )
+{
+    int X, Y, W, H, CX;
+    int rw, cw, t, Offset;
+
+    client_area(X,Y,W,H);
+    if (label())
+    {
+        cw = row_height(-3);
+        Y+=cw;
+        H-=cw;
+    }
+    if (col_header())
+    {
+        cw = col_width(-1);
+        if (X<=x && x<=X+cw)
+            return -1;
+        X+=cw;
+        W-=cw;
+    }
+    if (col_footer())
+    {
+        cw = col_width(-2);
+        if (X+W>=x && x>=X+W-cw)
+            return -2;
+        W -= cw;
+    }
+
+    rw = row_width();
+    if (!rw)
+        rw = W;
+    if ( x<X || x>=X+W || y<Y || y>=Y+H || x>X-row_offset()+rw)
+        return -4;
+
+    Offset = row_offset();
+    for (CX=X, t=0;	t<vcols && CX-Offset<X+W;	t++, CX+=cw )
+    {
+        cw = col_width(t);
+        if (x>=CX-Offset && x<CX-Offset+cw)
+            return t;
+    }
+    return -4;	//	In grey area at bottom?
+}
+
+int Flv_Table::select_start_col(int n)
+{
+    if (n>=vcols)
+        n=vcols-1;
+    if (n<0)
+        n=0;
+    if (n!=vselect_col)
+    {
+        vselect_col = n;
+        if (DOcb(FLVEcb_SELECTION_CHANGED))
+        {
+            vwhy_event = FLVE_SELECTION_CHANGED;
+            do_callback(this, user_data());
+            vwhy_event = 0;
+        }
+        damage(FL_DAMAGE_CHILD);
+    }
+    return vselect_col;
+}
+
+void Flv_Table::update_width()
+{
+    int rw, n;
+
+    for (rw=n=0;	n<vcols;	n++ )
+        rw+=(col_width(n));
+    if (col_header())
+        rw+=col_width(-1);
+    if (col_footer())
+        rw+=col_width(-2);
+    if (rw!=row_width())
+    {
+        row_width(rw);
+        damage(FL_DAMAGE_CHILD);
+    }
+}
+
+void Flv_Table::adjust_for_cell()
+{
+    int n, o, cw;
+    int X, Y, W, H;
+
+    for (n=o=0;	n<col();	n++ )
+        o+=col_width(n);
+    if (row_offset()>o)
+        row_offset(o);
+    else
+    {
+        client_area(X,Y,W,H);
+        if (col_footer())
+            W -= col_width(-2);
+        if (col_header())
+            W -= col_width(-2);
+        cw = col_width(col());
+        if (o+cw-row_offset()>W)
+        {
+            row_offset(o+cw-W);
+            damage(FL_DAMAGE_CHILD);
+        }
+    }
+}
+
+bool Flv_Table::check_resize(void)
+{
+    int ex, ey, v;
+    int X, Y, W, H;
+
+    if (drag_row<-3 && drag_col<-2)
+        return false;
+
+    client_area(X,Y,W,H);
+    ex = Fl::event_x();
+    ey = Fl::event_y();
+
+    if (drag_row==-3)
+    {
+        v = ey-anchor_top;
+        if (v<2) v=2;
+        row_style[drag_row].height(v);
+        damage(FL_DAMAGE_CHILD);
+        return true;
+    }
+
+    if (label() && *label())
+    {
+        Y += row_height(-3);
+        H -= row_height(-3);
+    }
+
+    if (drag_col>-3)
+    {
+        if (drag_col==-2)
+        {
+            v = anchor_left - ex + col_width(drag_col);
+            if (col_header())
+            {
+                X += col_width(-1);
+                W -= col_width(-1);
+            }
+            if (v>W-1)
+            {
+                v = W-1;
+                anchor_left = X+W-v;
+            }
+            if (v<2)
+            {
+                v=2;
+                anchor_left = X+W-2;
+            }
+            col_style[drag_col].width(v);
+            damage(FL_DAMAGE_CHILD);
+            if (v!=W-1 && v!=2)
+                anchor_left = ex;
+        }
+        else
+        {
+            v = ex-anchor_left;
+            if (drag_col==-1)
+            {
+                //	Make sure it's in the grid
+                if (col_footer())
+                    W-=col_width(-2);
+                if (v > W-1 )
+                    v = W-1;
+            }
+            if (v<2)
+                v=2;
+            col_width(v,drag_col);
+            damage(FL_DAMAGE_CHILD);
+        }
+    }
+
+    //	Resize row
+    if (drag_row>-4)
+    {
+        if (drag_row==-2)
+        {
+            v = anchor_top - ey + row_height(drag_row);
+            if (row_header())
+            {
+                H-=row_height(-1);
+                Y+=row_height(-1);
+            }
+            if (v>H-1)
+            {
+                v = H-1;
+                anchor_top = Y+H-v;
+            }
+            if (v<2)
+            {
+                v = 2;
+                anchor_top = Y+H-2;
+            }
+            row_style[drag_row].height(v);
+            damage(FL_DAMAGE_CHILD);
+            if (v!=2 && v!=H-1)
+                anchor_top = ey;
+        }
+        else
+        {
+            v = ey-anchor_top;
+            if (drag_row==-1)
+            {
+                if (row_footer())
+                    H-=row_height(-2);
+                if (v>H-1)
+                    v = H-1;
+            }
+            if (v<2) v=2;
+            row_height(v,drag_row);
+            damage(FL_DAMAGE_CHILD);
+        }
+    }
+    return true;
+}
+
+//	See if we can resize, if so change cursor
+void Flv_Table::check_cursor(void)
+{
+    int X, Y, W, H, R, ey, ex, move=0, WW, size;
+    int v;
+    bool resize, inh, inv;
+    Fl_Cursor cursor;
+
+    //	Assume total miss
+    drag_row = drag_col = -4;
+    cursor = FL_CURSOR_DEFAULT;
+
+    ex = Fl::event_x();
+    ey = Fl::event_y();
+    client_area(X,Y,W,H);
+    inh = (ex>=X && ex<X+W);
+    inv = (ey>=Y && ey<Y+H);
+
+    if (label() && *label())
+    {
+        size = row_height(-3);
+        Y+=size;
+        H-=size;
+        resize = (ey>=Y-FUDGE && ey<=Y+FUDGE && inh);
+        if (resize)
+        {
+            if (row_resizable(-3))
+            {
+                drag_row = -3;
+                anchor_top = Y-size;
+                move |= MOVE_Y;
+            }
+        }
+    }
+
+    //	Trival tests to see if we're in region
+    resize = full_resize();
+    if (!resize)
+    {
+        if (row_header())
+        {
+            size = row_height(-1);
+            resize |= (ey>=Y && ey<=Y+size+FUDGE && inh);
+        }
+        if (!resize)
+        {
+            if (row_footer())
+            {
+                size = row_height(-2);
+                resize |= (ey<=Y+H && ey>=Y+H-size-FUDGE && inh);
+            }
+            if (!resize)
+            {
+                if (col_header())
+                {
+                    size = col_width(-1);
+                    resize |= (ex>=X && ex<=X+size+FUDGE && inh);
+                }
+                if (!resize)
+                {
+                    if (col_footer())
+                    {
+                        size = col_width(-2);
+                        resize |= (ex<=X+W && ex>=X+W-size-FUDGE && inh);
+                    }
+                }
+            }
+        }
+    }
+
+    if (!resize)	//	In general region?
+    {
+        if (cursor!=last_cursor)
+        {
+            fl_cursor(cursor,FL_BLACK,FL_WHITE);
+            last_cursor = cursor;
+        }
+        return;
+    }
+
+    //	==================================================================
+    //	Sweep columns
+    WW = X;
+    if (col_header())
+    {
+        size = col_width(-1);
+        if (ex>=WW+size-FUDGE && ex<=WW+size+FUDGE && inv)
+        {
+            if (col_resizable(-1) && (move & MOVE_Y)==0)
+            {
+                drag_col = -1;
+                anchor_left = WW;
+                move |= MOVE_X;
+            }
+        }
+        WW += size;
+        X += size;
+        W -= size;
+    }
+
+    if (col_footer())
+    {
+        size = col_width(-2);
+        if (ex>=X+W-size-FUDGE && ex<=X+W-size+FUDGE && inv)
+        {
+            if (col_resizable(-2))
+            {
+                drag_col = -2;
+                anchor_left = ex;
+                move |= MOVE_X;
+            }
+        }
+        W -= size;
+    }
+
+    if ( (move & MOVE_X)==0 )
+    {
+        R = X-row_offset()+row_width()+FUDGE;		//	Right edge of row
+        for (WW-=row_offset(), v=0;	WW<R && WW<X+W && v<cols();	WW+=size, v++ )
+        {
+            size = col_width(v);
+            if (WW+size<X)		//	Off left
+                continue;
+            if (ex>=WW+size-FUDGE && ex<=WW+size+FUDGE && inv)
+            {
+                if (col_resizable(v))
+                {
+                    drag_col = v;
+                    anchor_left = WW;
+                    move |= MOVE_X;		//	Moving col
+                }
+                break;
+            }
+        }
+    }
+    if (col_header())
+    {
+        X-=col_width(-1);
+        W+=col_width(-1);
+    }
+    if (col_footer())
+        W+=col_width(-2);
+
+    //	==================================================================
+    //	Sweep rows
+    WW = Y;
+    if (row_header())
+    {
+        size = row_height(-1);
+        if (ey>=WW+size-FUDGE && ey<=WW+size+FUDGE && inh)
+        {
+            if (row_resizable(-1))
+            {
+                drag_row = -1;
+                anchor_top = WW;
+                move |= MOVE_Y;
+            }
+        }
+        WW += size;
+        Y += size;
+        H -= size;
+    }
+    if (row_footer())
+    {
+        size = row_height(-2);
+        if (ey>=Y+H-size-FUDGE && ey<=Y+H-size+FUDGE && inh)
+        {
+            if (row_resizable(-2))
+            {
+                drag_row = -2;
+                anchor_top = ey;
+                move |= MOVE_Y;
+            }
+        }
+        H -= size;
+    }
+    if ( (move & MOVE_Y)==0 )
+    {
+        for (v=top_row();	v<rows();	WW+=size, v++ )
+        {
+            size = row_height(v);
+            if (WW+size-FUDGE>=Y+H)
+                break;
+            if (ey>=WW+size-FUDGE && ey<=WW+size+FUDGE && inh)
+            {
+                if (row_resizable(v))
+                {
+                    drag_row = v;
+                    anchor_top = WW;
+                    move |= MOVE_Y;		//	Moving
+                }
+                break;
+            }
+        }
+    }
+
+    switch( move )
+    {
+    case MOVE_X:
+        cursor = FL_CURSOR_WE;
+        drag_row=-4;
+        break;
+    case MOVE_Y:
+        cursor = FL_CURSOR_NS;
+        drag_col=-4;
+        break;
+    case MOVE_XY:
+        cursor = FL_CURSOR_NWSE;
+        break;
+    default:
+        drag_row = drag_col = -4;
+        cursor = FL_CURSOR_DEFAULT;
+        break;
+    }
+    if (cursor!=last_cursor)
+    {
+        fl_cursor(cursor,FL_BLACK,FL_WHITE);
+        last_cursor = cursor;
+    }
+}
+
+bool Flv_Table::move_row( int amount )
+{
+    Flv_Style s;
+    int r = row();
+
+    if (!amount)
+        return true;
+
+    r += amount;
+    if (r>=rows())
+        r = rows()-1;
+    if (r<0)
+        r = 0;
+
+    while(!select_locked())
+    {
+        get_style(s,r,col());
+        if (!s.locked())
+            break;
+        r += (amount<0?-1:1);
+        if ( r<0 || r>=rows() )
+            return false;
+    }
+    if (r!=row())
+    {
+        row(r);
+        return true;
+    }
+    return false;
+}
+
+bool Flv_Table::move_col( int amount )
+{
+    Flv_Style s;
+    int c = col();
+
+    if (!amount)
+        return true;
+
+    c += amount;
+    if (c>=cols())
+        c = cols()-1;
+    if (c<0)
+        c = 0;
+
+    while(!select_locked())
+    {
+        get_style(s,row(),c);
+        if (!s.locked())
+            break;
+        c += (amount<0?-1:1);
+        if ( c<0 || c>=rows() )
+            return false;
+    }
+    if (c!=col())
+    {
+        col(c);
+        return true;
+    }
+    return false;
+}
+
+
+int Flv_Table::edit_when( int v )
+{
+    int wfocused = (Fl::focus()==veditor);
+    if (v!=vedit_when)
+    {
+        vedit_when = v;
+        if (vedit_when!=FLV_EDIT_ALWAYS)
+            end_edit();
+        else
+            start_edit();
+    }
+    if (wfocused && !vediting)
+    {
+        Fl::focus(this);
+//		take_focus();
+        redraw();
+    }
+    return vedit_when;
+}
+
+
+void Flv_Table::start_edit(void)											//	Start editing
+{
+    if (!vediting)
+    {
+        vediting = true;
+        switch_editor( row(), col() );
+    }
+}
+
+void Flv_Table::end_edit(void)
+{
+    int wfocused = (Fl::focus()==veditor);
+    if (veditor)
+        switch_editor(-1,-1);
+    if (wfocused && !vediting)
+    {
+        Fl::focus(this);
+//		take_focus();
+        redraw();
+    }
+}
+
+void Flv_Table::cancel_edit(void)											//	Cancel editing
+{
+    int wfocused = (Fl::focus()==veditor);
+    if (veditor)
+    {
+        veditor->hide();
+        veditor->draw();
+    }
+    veditor = NULL;
+    edit_row = -1;
+    edit_col = -1;
+    vediting = false;
+//	switch_editor(-1, -1);
+    if (wfocused && !vediting)
+    {
+        Fl::focus(this);
+//		take_focus();
+        redraw();
+    }
+}
+
+void Flv_Table::switch_editor( int nr, int nc )
+{
+    Flv_Style s;
+    int x, y, w, h, wfocused;
+    //char buf[30];
+
+    wfocused = (Fl::focus()==veditor);
+
+    if (veditor)
+    {
+        if (edit_row>-1 && edit_col>-1)
+            save_editor( veditor, edit_row, edit_col );
+        edit_row=-1;
+        edit_col=-1;
+        veditor->hide();
+        veditor->draw();
+        veditor = NULL;
+    }
+    if (edit_when()==FLV_EDIT_ALWAYS)
+    {
+        vediting = true;
+        if (nr<0)
+            nr = row();
+        if (nc<0)
+            nc = col();
+    }
+
+    if (nr>-1 && nc>-1 && vediting)
+    {
+        get_style( s, nr, nc );
+        if (s.editor_defined() && !s.locked())
+        {
+            veditor = s.editor();
+            if (veditor)
+            {
+                edit_row = nr;
+                edit_col = nc;
+                veditor->hide();
+                get_cell_bounds(x,y,w,h,nr,nc);
+                position_editor(veditor, x,y,w,h, s);
+                load_editor( veditor, nr, nc );
+                veditor->show();
+                Fl::focus(veditor);
+//				veditor->take_focus();
+                veditor->handle(FL_FOCUS);
+                veditor->damage(FL_DAMAGE_ALL);
+                veditor->draw();
+            }
+        }
+    }
+    if (!veditor)
+    {
+        vediting=false;
+        edit_row=-1;
+        edit_col=-1;
+    }
+    if (!veditor && wfocused)
+    {
+        Fl::focus(this);
+//		take_focus();
+        handle(FL_FOCUS);
+    }
+}
+