Fix for problem with posting 'popup menus' during user callback

causing change in row/col selection of Fl_Table_Row.
As reported by David Lopez in fltk.general on 11/09/2011, Subject: Popup menu over Fl_Table.



git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@9172 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Greg Ercolano 2011-11-13 02:46:10 +00:00
parent 3086c07eec
commit baca25f902
2 changed files with 76 additions and 43 deletions

View File

@ -708,10 +708,20 @@ int Fl_Table::handle(int event) {
return 1;
}
}
// Make snapshots of realtime event states *before* we service user's cb,
// which may do things like post popup menus that return with unexpected button states.
int _event_button = Fl::event_button();
int _event_clicks = Fl::event_clicks();
int _event_x = Fl::event_x();
int _event_y = Fl::event_y();
int _event_key = Fl::event_key();
int _event_state = Fl::event_state();
Fl_Widget *_focus = Fl::focus();
switch ( event ) {
case FL_PUSH:
if (Fl::event_button() == 1 && !Fl::event_clicks()) {
if (Fl::focus() != this) {
// Single left-click on table? do user's callback with CONTEXT_TABLE
if (_event_button == 1 && !_event_clicks) {
if (_focus == this) {
take_focus();
do_callback(CONTEXT_TABLE, -1, -1);
ret = 1;
@ -726,21 +736,27 @@ int Fl_Table::handle(int event) {
current_col = select_col = -1;
}
}
// Need this for eg. right click to pop up a menu
// A click on table with user's callback defined?
// Need this for eg. right click to pop up a menu
//
if ( Fl_Widget::callback() && // callback defined?
resizeflag == RESIZE_NONE ) { // not resizing?
do_callback(context, R, C); // do callback
resizeflag == RESIZE_NONE ) { // not resizing?
do_callback(context, R, C); // do callback with context (cell, header, etc)
}
// Handle selection if handling a left-click
// Use snapshot of _event_button we made before servicing user's cb's
// to avoid checking realtime state of buttons which may have changed
// during the user's callbacks.
//
switch ( context ) {
case CONTEXT_CELL:
// FL_PUSH on a cell?
ret = 1; // express interest in FL_RELEASE
ret = 1; // express interest in FL_RELEASE
break;
case CONTEXT_NONE:
// FL_PUSH on table corner?
if ( Fl::event_button() == 1 &&
Fl::event_x() < x() + row_header_width()) {
if ( _event_button == 1 && _event_x < x() + row_header_width()) {
current_col = 0;
select_col = cols() - 1;
current_row = 0;
@ -752,7 +768,7 @@ int Fl_Table::handle(int event) {
case CONTEXT_COL_HEADER:
// FL_PUSH on a column header?
if ( Fl::event_button() == 1) {
if ( _event_button == 1) {
// Resizing? Handle it
if ( resizeflag ) {
// Start resize if left click on column border.
@ -762,7 +778,7 @@ int Fl_Table::handle(int event) {
//
_resizing_col = ( resizeflag & RESIZE_COL_LEFT ) ? C-1 : C;
_resizing_row = -1;
_dragging_x = Fl::event_x();
_dragging_x = _event_x;
ret = 1;
} else {
// Not resizing? Select the column
@ -778,7 +794,7 @@ int Fl_Table::handle(int event) {
case CONTEXT_ROW_HEADER:
// FL_PUSH on a row header?
if ( Fl::event_button() == 1 ) {
if ( _event_button == 1 ) {
// Resizing? Handle it
if ( resizeflag ) {
// Start resize if left mouse clicked on row border.
@ -788,7 +804,7 @@ int Fl_Table::handle(int event) {
//
_resizing_row = ( resizeflag & RESIZE_ROW_ABOVE ) ? R-1 : R;
_resizing_col = -1;
_dragging_y = Fl::event_y();
_dragging_y = _event_y;
ret = 1;
} else {
// Not resizing? Select the row
@ -821,11 +837,11 @@ int Fl_Table::handle(int event) {
// 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 offset = _dragging_x - _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();
_dragging_x = _event_x;
table_resized();
redraw();
change_cursor(FL_CURSOR_WE);
@ -841,11 +857,11 @@ int Fl_Table::handle(int event) {
// 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 offset = _dragging_y - _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();
_dragging_y = _event_y;
table_resized();
redraw();
change_cursor(FL_CURSOR_NS);
@ -854,7 +870,7 @@ int Fl_Table::handle(int event) {
do_callback(CONTEXT_RC_RESIZE, R, C);
}
} else {
if (Fl::event_button() == 1 &&
if (_event_button == 1 &&
_selecting == CONTEXT_CELL &&
context == CONTEXT_CELL) {
if (select_row != R || select_col != C) {
@ -864,7 +880,7 @@ int Fl_Table::handle(int event) {
select_col = C;
ret = 1;
}
else if (Fl::event_button() == 1 &&
else if (_event_button == 1 &&
_selecting == CONTEXT_ROW_HEADER &&
context & (CONTEXT_ROW_HEADER|CONTEXT_COL_HEADER|CONTEXT_CELL)) {
if (select_row != R) {
@ -873,7 +889,7 @@ int Fl_Table::handle(int event) {
select_row = R;
ret = 1;
}
else if (Fl::event_button() == 1 &&
else if (_event_button == 1 &&
_selecting == CONTEXT_COL_HEADER
&& context & (CONTEXT_ROW_HEADER|CONTEXT_COL_HEADER|CONTEXT_CELL)) {
if (select_col != C) {
@ -885,10 +901,10 @@ int Fl_Table::handle(int event) {
}
// Enable autodrag if not resizing, and mouse has moved off table edge
if ( _resizing_row < 0 && _resizing_col < 0 && _auto_drag == 0 &&
( Fl::event_x() > x() + w() - 20 ||
Fl::event_x() < x() + row_header_width() ||
Fl::event_y() > y() + h() - 20 ||
Fl::event_y() < y() + col_header_height()
( _event_x > x() + w() - 20 ||
_event_x < x() + row_header_width() ||
_event_y > y() + h() - 20 ||
_event_y < y() + col_header_height()
) ) {
_start_auto_drag();
}
@ -903,7 +919,7 @@ int Fl_Table::handle(int event) {
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
Fl_Widget::callback() && // callback defined
when() & FL_WHEN_RELEASE && // on button release
_last_row == R ) { // release on same row PUSHed?
// Need this for eg. left clicking on a cell to select it
@ -914,7 +930,7 @@ int Fl_Table::handle(int event) {
default:
break;
}
if ( Fl::event_button() == 1 ) {
if ( _event_button == 1 ) {
change_cursor(FL_CURSOR_DEFAULT);
_resizing_col = -1;
_resizing_row = -1;
@ -964,7 +980,7 @@ int Fl_Table::handle(int event) {
ret = 0;
int is_row = select_row;
int is_col = select_col;
switch(Fl::event_key()) {
switch(_event_key) {
case FL_Home:
ret = move_cursor(0, -1000000);
break;
@ -990,7 +1006,7 @@ int Fl_Table::handle(int event) {
ret = move_cursor(1, 0);
break;
case FL_Tab:
if ( Fl::event_state() & FL_SHIFT ) {
if ( _event_state & FL_SHIFT ) {
ret = move_cursor(0, -1); // shift-tab -> left
} else {
ret = move_cursor(0, 1); // tab -> right

View File

@ -155,23 +155,40 @@ void Fl_Table_Row::rows(int val) {
while ( val < (int)_rowselect.size() ) { _rowselect.pop_back(); } // shrink
}
// #include "eventnames.h" // debugging
// #include <stdio.h>
//#define DEBUG 1
#ifdef DEBUG
#include <FL/names.h>
#define PRINTEVENT \
fprintf(stderr,"TableRow %s: ** Event: %s --\n", (label()?label():"none"), fl_eventnames[event]);
#else
#define PRINTEVENT
#endif
// Handle events
int Fl_Table_Row::handle(int event) {
// fprintf(stderr, "** EVENT: %s: EVENT XY=%d,%d\n",
// eventnames[event], Fl::event_x(), Fl::event_y()); // debugging
PRINTEVENT;
// Make snapshots of realtime event states *before* we service user's cb,
// which may do things like post popup menus that return with unexpected button states.
int _event_button = Fl::event_button();
//int _event_clicks = Fl::event_clicks(); // uncomment if needed
int _event_x = Fl::event_x();
int _event_y = Fl::event_y();
//int _event_key = Fl::event_key(); // uncomment if needed
int _event_state = Fl::event_state();
//Fl_Widget *_focus = Fl::focus(); // uncomment if needed
// Let base class handle event
// Note: base class may invoke user callbacks that post menus,
// so from here on use event state snapshots (above).
//
int ret = Fl_Table::handle(event);
// The following code disables cell selection.. why was it added? -erco 05/18/03
// if ( ret ) { _last_y = Fl::event_y(); return(1); } // base class 'handled' it (eg. column resize)
int shiftstate = (Fl::event_state() & FL_CTRL) ? FL_CTRL :
(Fl::event_state() & FL_SHIFT) ? FL_SHIFT : 0;
int shiftstate = (_event_state & FL_CTRL) ? FL_CTRL :
(_event_state & FL_SHIFT) ? FL_SHIFT : 0;
// Which row/column are we over?
int R, C; // row/column being worked on
@ -179,9 +196,9 @@ int Fl_Table_Row::handle(int event) {
TableContext context = cursor2rowcol(R, C, resizeflag);
switch ( event ) {
case FL_PUSH:
if ( Fl::event_button() == 1 ) {
_last_push_x = Fl::event_x(); // save regardless of context
_last_push_y = Fl::event_y(); // " "
if ( _event_button == 1 ) {
_last_push_x = _event_x; // save regardless of context
_last_push_y = _event_y; // " "
// Handle selection in table.
// Select cell under cursor, and enable drag selection mode.
@ -230,7 +247,7 @@ int Fl_Table_Row::handle(int event) {
if ( offtop > 0 && row_position() > 0 ) {
// Only scroll in upward direction
int diff = _last_y - Fl::event_y();
int diff = _last_y - _event_y;
if ( diff < 1 ) {
ret = 1;
break;
@ -241,7 +258,7 @@ int Fl_Table_Row::handle(int event) {
}
else if ( offbot > 0 && botrow < rows() ) {
// Only scroll in downward direction
int diff = Fl::event_y() - _last_y;
int diff = _event_y - _last_y;
if ( diff < 1 ) {
ret = 1;
break;
@ -281,7 +298,7 @@ int Fl_Table_Row::handle(int event) {
}
case FL_RELEASE:
if ( Fl::event_button() == 1 ) {
if ( _event_button == 1 ) {
_dragging_select = 0;
ret = 1; // release handled
// Clicked off edges of data table?
@ -290,8 +307,8 @@ int Fl_Table_Row::handle(int event) {
int databot = tiy + table_h,
dataright = tix + table_w;
if (
( _last_push_x > dataright && Fl::event_x() > dataright ) ||
( _last_push_y > databot && Fl::event_y() > databot )
( _last_push_x > dataright && _event_x > dataright ) ||
( _last_push_y > databot && _event_y > databot )
) {
select_all_rows(0); // clear previous selections
}
@ -301,7 +318,7 @@ int Fl_Table_Row::handle(int event) {
default:
break;
}
_last_y = Fl::event_y();
_last_y = _event_y;
return(ret);
}