Cleanup of wxDataViewCtrl cell activation code.

Fix confusion of what cell activation is and inconsistence with native
handling in GTK+. Document the distinction between activating (~
editing) a cell and activating (double-clicking) the whole item.

Deprecate wxDataViewCustomRenderer::LeftClick() and Activate() methods,
replace them with single ActivateCell() that is called for both kinds of
activation.

Fix implementations so that ActivateCell() is not called on
double-click, when it shouldn't, and vice versa: don't send
wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED for cell activation.

Partially reverts r67099 -- restores old 2.9 signatures of compatibility
LeftClick() and Activate() methods.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@69473 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Václav Slavík 2011-10-19 16:20:17 +00:00
parent 4a99d59750
commit dc73d7f5d4
9 changed files with 229 additions and 167 deletions

View File

@ -184,9 +184,13 @@ Changes in behaviour not resulting in compilation errors, please read this!
wxAutomationInstance_SilentIfNone flag to prevent the error message if no
currently running instances of this object are available.
- Signatures of wxDataViewCustomRenderer::Activate(), LeftClick() and
StartDrag() virtual methods changed. You will need to change them in your
derived renderer class too if you override them.
- Signature of wxDataViewCustomRenderer::StartDrag() virtual method changed.
You will need to change it in your derived renderer class too if you override
it.
- wxDataViewCustomRenderer::Activate() and LeftClick() were replaced with the
new ActivateCell() method. You will need to change it in your derived
renderer class accordingly.
- wxThread::Wait() and wxThread::Delete() used to dispatch the events while
waiting for the thread to exit in wxMSW. They still do it in default build
@ -482,6 +486,7 @@ All (GUI):
- Fix tooltips in wxSearchCtrl and other composite controls (Catalin Raceanu).
- Allow converting to and from wxGraphicsBitmap and wxImage directly.
- Allow wxGraphicsFont creation without passing by wxFont.
- Added wxDataViewCustomRenderer::ActivateCell().
OSX:

View File

@ -177,10 +177,14 @@ Finally, a few structure fields, notable @c wxCmdLineEntryDesc::shortName,
available for the scroll target as function of the main window size, please
see the documentation of this method for more details.
- Signatures of wxDataViewCustomRenderer::Activate(),
wxDataViewCustomRenderer::LeftClick() and
wxDataViewCustomRenderer::StartDrag() virtual methods changed. You will need
to change them in your derived renderer class too if you override them.
- Signature of wxDataViewCustomRenderer::StartDrag() virtual method changed.
You will need to change it in your derived renderer class too if you override
it.
- wxDataViewCustomRenderer::Activate() and
wxDataViewCustomRenderer::LeftClick() were replaced with the new
wxDataViewCustomRenderer::ActivateCell() method. You will need to change it
in your derived renderer class accordingly.
*/

View File

@ -228,23 +228,39 @@ public:
// Return the size of the item appropriate to its current value.
virtual wxSize GetSize() const = 0;
// Define virtual function which are called when the item is activated
// (double-clicked or Enter is pressed on it), clicked or the user starts
// to drag it: by default they all simply return false indicating that the
// events are not handled
// Define virtual function which are called when a key is pressed on the
// item, clicked or the user starts to drag it: by default they all simply
// return false indicating that the events are not handled
virtual bool Activate(const wxRect& WXUNUSED(cell),
wxDataViewModel *WXUNUSED(model),
const wxDataViewItem & WXUNUSED(item),
unsigned int WXUNUSED(col))
{ return false; }
virtual bool ActivateCell(const wxRect& cell,
wxDataViewModel *model,
const wxDataViewItem & item,
unsigned int col,
const wxMouseEvent* mouseEvent)
{
// Compatibility code
if ( mouseEvent )
return LeftClick(mouseEvent->GetPosition(), cell, model, item, col);
else
return Activate(cell, model, item, col);
}
virtual bool LeftClick(const wxPoint& WXUNUSED(cursor),
const wxRect& WXUNUSED(cell),
wxDataViewModel *WXUNUSED(model),
const wxDataViewItem & WXUNUSED(item),
unsigned int WXUNUSED(col) )
{ return false; }
// Deprecated, use (and override) ActivateCell() instead
wxDEPRECATED_BUT_USED_INTERNALLY_INLINE(
virtual bool Activate(wxRect WXUNUSED(cell),
wxDataViewModel *WXUNUSED(model),
const wxDataViewItem & WXUNUSED(item),
unsigned int WXUNUSED(col)),
return false; )
// Deprecated, use (and override) ActivateCell() instead
wxDEPRECATED_BUT_USED_INTERNALLY_INLINE(
virtual bool LeftClick(wxPoint WXUNUSED(cursor),
wxRect WXUNUSED(cell),
wxDataViewModel *WXUNUSED(model),
const wxDataViewItem & WXUNUSED(item),
unsigned int WXUNUSED(col)),
return false; )
virtual bool StartDrag(const wxPoint& WXUNUSED(cursor),
const wxRect& WXUNUSED(cell),

View File

@ -41,23 +41,16 @@ public:
// implementation
// These callbacks are used by generic implementation of wxDVC itself.
// They're different from the corresponding Activate/LeftClick() methods
// which should only be overridable for the custom renderers while the
// generic implementation uses these ones for all of them, including the
// standard ones.
// This callback is used by generic implementation of wxDVC itself. It's
// different from the corresponding ActivateCell() method which should only
// be overridable for the custom renderers while the generic implementation
// uses this one for all of them, including the standard ones.
virtual bool WXOnActivate(const wxRect& WXUNUSED(cell),
wxDataViewModel *WXUNUSED(model),
const wxDataViewItem & WXUNUSED(item),
unsigned int WXUNUSED(col))
{ return false; }
virtual bool WXOnLeftClick(const wxPoint& WXUNUSED(cursor),
const wxRect& WXUNUSED(cell),
wxDataViewModel *WXUNUSED(model),
const wxDataViewItem & WXUNUSED(item),
unsigned int WXUNUSED(col) )
virtual bool WXActivateCell(const wxRect& WXUNUSED(cell),
wxDataViewModel *WXUNUSED(model),
const wxDataViewItem & WXUNUSED(item),
unsigned int WXUNUSED(col),
const wxMouseEvent* WXUNUSED(mouseEvent))
{ return false; }
private:

View File

@ -26,21 +26,13 @@ public:
// see the explanation of the following WXOnXXX() methods in wx/generic/dvrenderer.h
virtual bool WXOnActivate(const wxRect& cell,
wxDataViewModel *model,
const wxDataViewItem& item,
unsigned int col)
virtual bool WXActivateCell(const wxRect& cell,
wxDataViewModel *model,
const wxDataViewItem& item,
unsigned int col,
const wxMouseEvent *mouseEvent)
{
return Activate(cell, model, item, col);
}
virtual bool WXOnLeftClick(const wxPoint& cursor,
const wxRect& cell,
wxDataViewModel *model,
const wxDataViewItem &item,
unsigned int col)
{
return LeftClick(cursor, cell, model, item, col);
return ActivateCell(cell, model, item, col, mouseEvent);
}
private:
@ -121,16 +113,11 @@ public:
wxSize GetSize() const;
// Implementation only, don't use nor override
virtual bool WXOnLeftClick(const wxPoint& cursor,
const wxRect& cell,
wxDataViewModel *model,
const wxDataViewItem& item,
unsigned int col);
virtual bool WXOnActivate(const wxRect& cell,
wxDataViewModel *model,
const wxDataViewItem& item,
unsigned int col);
virtual bool WXActivateCell(const wxRect& cell,
wxDataViewModel *model,
const wxDataViewItem& item,
unsigned int col,
const wxMouseEvent *mouseEvent);
private:
bool m_toggle;

View File

@ -1322,18 +1322,54 @@ public:
*/
enum wxDataViewCellMode
{
/**
The cell only displays information and cannot be manipulated or
otherwise interacted with in any way.
Note that this doesn't mean that the row being drawn can't be selected,
just that a particular element of it cannot be individually modified.
*/
wxDATAVIEW_CELL_INERT,
/**
Indicates that the user can double click the cell and something will
happen (e.g. a window for editing a date will pop up).
Indicates that the cell can be @em activated by clicking it or using
keyboard.
Activating a cell is an alternative to showing inline editor when the
value can be edited in a simple way that doesn't warrant full editor
control. The most typical use of cell activation is toggling the
checkbox in wxDataViewToggleRenderer; others would be e.g. an embedded
volume slider or a five-star rating column.
The exact means of activating a cell are platform-dependent, but they
are usually similar to those used for inline editing of values.
Typically, a cell would be activated by Space or Enter keys or by left
mouse click.
@note Do not confuse this with item activation in wxDataViewCtrl
and the wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED event. That one is
used for activating the item (or, to put it differently, the
entire row) similarly to analogous messages in wxTreeCtrl and
wxListCtrl, and the effect differs (play a song, open a file
etc.). Cell activation, on the other hand, is all about
interacting with the individual cell.
@see wxDataViewCustomRenderer::ActivateCell()
*/
wxDATAVIEW_CELL_ACTIVATABLE,
/**
Indicates that the user can edit the data in-place, i.e. an control
will show up after a slow click on the cell. This behaviour is best
known from changing the filename in most file managers etc.
Indicates that the user can edit the data in-place in an inline editor
control that will show up when the user wants to edit the cell.
A typical example of this behaviour is changing the filename in a file
managers.
Editing is typically triggered by slowly double-clicking the cell or by
a platform-dependent keyboard shortcut (F2 is typical on Windows, Space
and/or Enter is common elsewhere and supported on Windows too).
@see wxDataViewCustomRenderer::CreateEditorCtrl()
*/
wxDATAVIEW_CELL_EDITABLE
};
@ -1692,20 +1728,72 @@ public:
virtual ~wxDataViewCustomRenderer();
/**
Override this to react to double clicks or ENTER.
This method will only be called in wxDATAVIEW_CELL_ACTIVATABLE mode.
Override this to react to cell @em activation. Activating a cell is an
alternative to showing inline editor when the value can be edited in a
simple way that doesn't warrant full editor control. The most typical
use of cell activation is toggling the checkbox in
wxDataViewToggleRenderer; others would be e.g. an embedded volume
slider or a five-star rating column.
The exact means of activating a cell are platform-dependent, but they
are usually similar to those used for inline editing of values.
Typically, a cell would be activated by Space or Enter keys or by left
mouse click.
This method will only be called if the cell has the
wxDATAVIEW_CELL_ACTIVATABLE mode.
@param cell
Coordinates of the activated cell's area.
@param model
The model to manipulate in response.
@param item
Activated item.
@param col
Activated column of @a item.
@param mouseEvent
If the activation was triggered by mouse click, contains the
corresponding event. Is @NULL otherwise (for keyboard activation).
Mouse coordinates are adjusted to be relative to the cell.
@since 2.9.3
@note Do not confuse this method with item activation in wxDataViewCtrl
and the wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED event. That one is
used for activating the item (or, to put it differently, the
entire row) similarly to analogous messages in wxTreeCtrl and
wxListCtrl, and the effect differs (play a song, open a file
etc.). Cell activation, on the other hand, is all about
interacting with the individual cell.
@see CreateEditorCtrl()
*/
virtual bool Activate( const wxRect& cell,
wxDataViewModel* model,
const wxDataViewItem & item,
unsigned int col );
virtual bool ActivateCell(const wxRect& cell,
wxDataViewModel* model,
const wxDataViewItem & item,
unsigned int col,
const wxMouseEvent *mouseEvent);
/**
Override this to create the actual editor control once editing
is about to start.
@a parent is the parent of the editor control, @a labelRect indicates the
position and size of the editor control and @a value is its initial value:
This method will only be called if the cell has the
wxDATAVIEW_CELL_EDITABLE mode. Editing is typically triggered by slowly
double-clicking the cell or by a platform-dependent keyboard shortcut
(F2 is typical on Windows, Space and/or Enter is common elsewhere and
supported on Windows too).
@param parent
The parent of the editor control.
@param labelRect
Indicates the position and size of the editor control. The control
should be created in place of the cell and @a labelRect should be
respected as much as possible.
@param value
Initial value of the editor.
An example:
@code
{
long l = value;
@ -1713,6 +1801,8 @@ public:
labelRect.GetTopLeft(), labelRect.GetSize(), 0, 0, 100, l );
}
@endcode
@see ActivateCell()
*/
virtual wxWindow* CreateEditorCtrl(wxWindow* parent,
wxRect labelRect,

View File

@ -189,22 +189,18 @@ public:
return true;
}
virtual bool Activate( const wxRect& WXUNUSED(cell),
wxDataViewModel *WXUNUSED(model),
const wxDataViewItem &WXUNUSED(item),
unsigned int WXUNUSED(col) )
virtual bool ActivateCell(const wxRect& WXUNUSED(cell),
wxDataViewModel *WXUNUSED(model),
const wxDataViewItem &WXUNUSED(item),
unsigned int WXUNUSED(col),
const wxMouseEvent *mouseEvent)
{
wxLogMessage( "MyCustomRenderer Activate()" );
return false;
}
virtual bool LeftClick(const wxPoint& cursor,
const wxRect& WXUNUSED(cell),
wxDataViewModel *WXUNUSED(model),
const wxDataViewItem &WXUNUSED(item),
unsigned int WXUNUSED(col) )
{
wxLogMessage( "MyCustomRenderer LeftClick( %d, %d )", cursor.x, cursor.y );
wxString position;
if ( mouseEvent )
position = wxString::Format("via mouse at %d, %d", mouseEvent->m_x, mouseEvent->m_y);
else
position = "from keyboard";
wxLogMessage("MyCustomRenderer ActivateCell() %s", position);
return false;
}

View File

@ -986,31 +986,24 @@ bool wxDataViewToggleRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state
return true;
}
bool wxDataViewToggleRenderer::WXOnLeftClick(const wxPoint& cursor,
const wxRect& cell,
wxDataViewModel *model,
const wxDataViewItem& item,
unsigned int col)
bool wxDataViewToggleRenderer::WXActivateCell(const wxRect& WXUNUSED(cell),
wxDataViewModel *model,
const wxDataViewItem& item,
unsigned int col,
const wxMouseEvent *mouseEvent)
{
// only react to clicks directly on the checkbox, not elsewhere in the same cell:
if (!wxRect(GetSize()).Contains(cursor))
if ( !model->IsEnabled(item, col) )
return false;
return WXOnActivate(cell, model, item, col);
}
bool wxDataViewToggleRenderer::WXOnActivate(const wxRect& WXUNUSED(cell),
wxDataViewModel *model,
const wxDataViewItem& item,
unsigned int col)
{
if (model->IsEnabled(item, col))
if ( mouseEvent )
{
model->ChangeValue(!m_toggle, item, col);
return true;
// only react to clicks directly on the checkbox, not elsewhere in the same cell:
if ( !wxRect(GetSize()).Contains(mouseEvent->GetPosition()) )
return false;
}
return false;
model->ChangeValue(!m_toggle, item, col);
return true;
}
wxSize wxDataViewToggleRenderer::GetSize() const
@ -3414,7 +3407,7 @@ void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
wxDataViewRenderer *cell = activatableCol->GetRenderer();
cell->PrepareForItem(GetModel(), item, colIdx);
cell->WXOnActivate(cell_rect, GetModel(), item, colIdx);
cell->WXActivateCell(cell_rect, GetModel(), item, colIdx, NULL);
}
}
break;
@ -3886,31 +3879,15 @@ void wxDataViewMainWindow::OnMouse( wxMouseEvent &event )
}
else if ( current == m_lineLastClicked )
{
bool activated = false;
wxWindow *parent = GetParent();
wxDataViewEvent le(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, parent->GetId());
le.SetItem( item );
le.SetColumn( col->GetModelColumn() );
le.SetDataViewColumn( col );
le.SetEventObject(parent);
le.SetModel(GetModel());
if ((!ignore_other_columns) && (cell->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE))
{
const unsigned colIdx = col->GetModelColumn();
cell->PrepareForItem(model, item, colIdx);
wxRect cell_rect( xpos, GetLineStart( current ),
col->GetWidth(), GetLineHeight( current ) );
activated = cell->WXOnActivate( cell_rect, model, item, colIdx );
}
if ( !activated )
{
wxWindow *parent = GetParent();
wxDataViewEvent le(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, parent->GetId());
le.SetItem( item );
le.SetColumn( col->GetModelColumn() );
le.SetDataViewColumn( col );
le.SetEventObject(parent);
le.SetModel(GetModel());
parent->ProcessWindowEvent(le);
}
parent->ProcessWindowEvent(le);
return;
}
else
@ -4054,7 +4031,7 @@ void wxDataViewMainWindow::OnMouse( wxMouseEvent &event )
m_lastOnSame = !simulateClick && ((col == oldCurrentCol) &&
(current == oldCurrentRow)) && oldWasSelected;
// Call LeftClick after everything else as under GTK+
// Call ActivateCell() after everything else as under GTK+
if (cell->GetMode() & wxDATAVIEW_CELL_ACTIVATABLE)
{
// notify cell about click
@ -4095,14 +4072,19 @@ void wxDataViewMainWindow::OnMouse( wxMouseEvent &event )
}
}
wxPoint pos( event.GetPosition() );
pos.x -= rectItem.x;
pos.y -= rectItem.y;
wxMouseEvent event2(event);
event2.m_x -= rectItem.x;
event2.m_y -= rectItem.y;
m_owner->CalcUnscrolledPosition(event2.m_x, event2.m_y, &event2.m_x, &event2.m_y);
m_owner->CalcUnscrolledPosition( pos.x, pos.y, &pos.x, &pos.y );
/* ignore ret */ cell->WXOnLeftClick( pos, cell_rect,
model, item, col->GetModelColumn());
/* ignore ret */ cell->WXActivateCell
(
cell_rect,
model,
item,
col->GetModelColumn(),
&event2
);
}
}
}

View File

@ -34,6 +34,7 @@
#include "wx/gtk/private/gdkconv.h"
#include "wx/gtk/private/list.h"
#include "wx/gtk/private/event.h"
using namespace wxGTKImpl;
class wxGtkDataViewModelNotifier;
@ -1209,7 +1210,6 @@ struct _GtkWxCellRenderer
/*< private >*/
wxDataViewCustomRenderer *cell;
guint32 last_click;
};
struct _GtkWxCellRendererClass
@ -1294,7 +1294,6 @@ static void
gtk_wx_cell_renderer_init (GtkWxCellRenderer *cell)
{
cell->cell = NULL;
cell->last_click = 0;
}
static void
@ -1510,37 +1509,27 @@ gtk_wx_cell_renderer_activate(
unsigned int model_col = cell->GetOwner()->GetModelColumn();
if (!event)
if ( !event )
{
bool ret = false;
// activated by <ENTER>
if (cell->Activate( renderrect, model, item, model_col ))
ret = true;
return ret;
return cell->ActivateCell(renderrect, model, item, model_col, NULL);
}
else if (event->type == GDK_BUTTON_PRESS)
else if ( event->type == GDK_BUTTON_PRESS )
{
GdkEventButton *button_event = (GdkEventButton*) event;
wxPoint pt( ((int) button_event->x) - renderrect.x,
((int) button_event->y) - renderrect.y );
bool ret = false;
if (button_event->button == 1)
GdkEventButton *button_event = (GdkEventButton*)event;
if ( button_event->button == 1 )
{
if (cell->LeftClick( pt, renderrect, model, item, model_col ))
ret = true;
// TODO: query system double-click time
if (button_event->time - wxrenderer->last_click < 400)
if (cell->Activate( renderrect, model, item, model_col ))
ret = true;
}
wxrenderer->last_click = button_event->time;
wxMouseEvent mouse_event(wxEVT_LEFT_DOWN);
InitMouseEvent(ctrl, mouse_event, button_event);
return ret;
mouse_event.m_x -= renderrect.x;
mouse_event.m_y -= renderrect.y;
return cell->ActivateCell(renderrect, model, item, model_col, &mouse_event);
}
}
wxLogDebug("unexpected event type in gtk_wx_cell_renderer_activate()");
return false;
}