Merge miscellaneous wxDataViewCtrl-related bug fixes

Make it possible to define custom renderers using text controls reacting to
error presses in at least wxMSW and wxGTK.

Closes https://github.com/wxWidgets/wxWidgets/pull/221
This commit is contained in:
Vadim Zeitlin
2016-02-27 18:06:13 +01:00
17 changed files with 261 additions and 85 deletions

View File

@@ -180,6 +180,9 @@ public:
// wxDVR_DEFAULT_ALIGNMENT. // wxDVR_DEFAULT_ALIGNMENT.
int GetEffectiveAlignment() const; int GetEffectiveAlignment() const;
// Send wxEVT_DATAVIEW_ITEM_EDITING_STARTED event.
void NotifyEditingStarted(const wxDataViewItem& item);
protected: protected:
// These methods are called from PrepareForItem() and should do whatever is // These methods are called from PrepareForItem() and should do whatever is
// needed for the current platform to ensure that the item is rendered // needed for the current platform to ensure that the item is rendered
@@ -199,7 +202,7 @@ protected:
wxString m_variantType; wxString m_variantType;
wxDataViewColumn *m_owner; wxDataViewColumn *m_owner;
wxWeakRef<wxWindow> m_editorCtrl; wxWeakRef<wxWindow> m_editorCtrl;
wxDataViewItem m_item; // for m_editorCtrl wxDataViewItem m_item; // Item being currently edited, if valid.
// internal utility, may be used anywhere the window associated with the // internal utility, may be used anywhere the window associated with the
// renderer is required // renderer is required

View File

@@ -3671,6 +3671,15 @@ protected:
virtual bool TryParent(wxEvent& event), return DoTryApp(event); ) virtual bool TryParent(wxEvent& event), return DoTryApp(event); )
#endif // WXWIN_COMPATIBILITY_2_8 #endif // WXWIN_COMPATIBILITY_2_8
// Overriding this method allows filtering the event handlers dynamically
// connected to this object. If this method returns false, the handler is
// not connected at all. If it returns true, it is connected using the
// possibly modified fields of the given entry.
virtual bool OnDynamicBind(wxDynamicEventTableEntry& WXUNUSED(entry))
{
return true;
}
static const wxEventTable sm_eventTable; static const wxEventTable sm_eventTable;
virtual const wxEventTable *GetEventTable() const; virtual const wxEventTable *GetEventTable() const;

View File

@@ -181,7 +181,10 @@ public:
void OnSetFocus(wxFocusEvent& event); void OnSetFocus(wxFocusEvent& event);
// intercept WM_GETDLGCODE // intercept WM_GETDLGCODE
virtual WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam); virtual bool MSWHandleMessage(WXLRESULT *result,
WXUINT message,
WXWPARAM wParam,
WXLPARAM lParam);
virtual bool MSWShouldPreProcessMessage(WXMSG* pMsg); virtual bool MSWShouldPreProcessMessage(WXMSG* pMsg);
virtual WXDWORD MSWGetStyle(long style, WXDWORD *exstyle) const; virtual WXDWORD MSWGetStyle(long style, WXDWORD *exstyle) const;

View File

@@ -14,6 +14,8 @@
#include "wx/settings.h" // solely for wxSystemColour #include "wx/settings.h" // solely for wxSystemColour
class WXDLLIMPEXP_FWD_CORE wxButton;
// if this is set to 1, we use deferred window sizing to reduce flicker when // if this is set to 1, we use deferred window sizing to reduce flicker when
// resizing complicated window hierarchies, but this can in theory result in // resizing complicated window hierarchies, but this can in theory result in
// different behaviour than the old code so we keep the possibility to use it // different behaviour than the old code so we keep the possibility to use it
@@ -534,6 +536,16 @@ public:
virtual wxMenu* MSWFindMenuFromHMENU(WXHMENU hMenu); virtual wxMenu* MSWFindMenuFromHMENU(WXHMENU hMenu);
#endif // wxUSE_MENUS && !__WXUNIVERSAL__ #endif // wxUSE_MENUS && !__WXUNIVERSAL__
// Return the default button for the TLW containing this window or NULL if
// none.
static wxButton* MSWGetDefaultButtonFor(wxWindow* win);
// Simulate a click on the given button if it is non-null, enabled and
// shown.
//
// Return true if the button was clicked, false otherwise.
static bool MSWClickButtonIfPossible(wxButton* btn);
protected: protected:
// this allows you to implement standard control borders without // this allows you to implement standard control borders without
// repeating the code in different classes that are not derived from // repeating the code in different classes that are not derived from

View File

@@ -743,6 +743,11 @@ public:
} }
protected: protected:
// Override wxEvtHandler method to check for a common problem of binding
// wxEVT_TEXT_ENTER to a control without wxTE_PROCESS_ENTER style, which is
// never going to work.
virtual bool OnDynamicBind(wxDynamicEventTableEntry& entry);
// override streambuf method // override streambuf method
#if wxHAS_TEXT_WINDOW_STREAM #if wxHAS_TEXT_WINDOW_STREAM
int overflow(int i) wxOVERRIDE; int overflow(int i) wxOVERRIDE;

View File

@@ -173,10 +173,12 @@ private:
class MyCustomRenderer: public wxDataViewCustomRenderer class MyCustomRenderer: public wxDataViewCustomRenderer
{ {
public: public:
MyCustomRenderer() // This renderer can be either activatable or editable, for demonstration
: wxDataViewCustomRenderer("string", // purposes. In real programs, you should select whether the user should be
wxDATAVIEW_CELL_ACTIVATABLE, // able to activate or edit the cell and it doesn't make sense to switch
wxALIGN_CENTER) // between the two -- but this is just an example, so it doesn't stop us.
explicit MyCustomRenderer(wxDataViewCellMode mode)
: wxDataViewCustomRenderer("string", mode, wxALIGN_CENTER)
{ } { }
virtual bool Render( wxRect rect, wxDC *dc, int state ) wxOVERRIDE virtual bool Render( wxRect rect, wxDC *dc, int state ) wxOVERRIDE
@@ -223,6 +225,34 @@ public:
virtual bool GetValue( wxVariant &WXUNUSED(value) ) const wxOVERRIDE { return true; } virtual bool GetValue( wxVariant &WXUNUSED(value) ) const wxOVERRIDE { return true; }
virtual bool HasEditorCtrl() const wxOVERRIDE { return true; }
virtual wxWindow*
CreateEditorCtrl(wxWindow* parent,
wxRect labelRect,
const wxVariant& value) wxOVERRIDE
{
wxTextCtrl* text = new wxTextCtrl(parent, wxID_ANY, value,
labelRect.GetPosition(),
labelRect.GetSize(),
wxTE_PROCESS_ENTER);
text->SetInsertionPointEnd();
return text;
}
virtual bool
GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) wxOVERRIDE
{
wxTextCtrl* text = wxDynamicCast(ctrl, wxTextCtrl);
if ( !text )
return false;
value = text->GetValue();
return true;
}
private: private:
wxString m_value; wxString m_value;
}; };
@@ -614,7 +644,7 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l
// column 5 of the view control: // column 5 of the view control:
MyCustomRenderer *cr = new MyCustomRenderer; MyCustomRenderer *cr = new MyCustomRenderer(wxDATAVIEW_CELL_ACTIVATABLE);
wxDataViewColumn *column5 = wxDataViewColumn *column5 =
new wxDataViewColumn( "custom", cr, 5, -1, wxALIGN_LEFT, new wxDataViewColumn( "custom", cr, 5, -1, wxALIGN_LEFT,
wxDATAVIEW_COL_RESIZABLE ); wxDATAVIEW_COL_RESIZABLE );
@@ -662,7 +692,7 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l
m_ctrl[1]->AppendColumn( m_ctrl[1]->AppendColumn(
new wxDataViewColumn("custom renderer", new wxDataViewColumn("custom renderer",
new MyCustomRenderer, new MyCustomRenderer(wxDATAVIEW_CELL_EDITABLE),
MyListModel::Col_Custom) MyListModel::Col_Custom)
); );
} }

View File

@@ -444,7 +444,13 @@ void MyListModel::GetValueByRow( wxVariant &variant,
break; break;
case Col_Custom: case Col_Custom:
variant = wxString::Format("%d", row % 100); {
IntToStringMap::const_iterator it = m_customColValues.find(row);
if ( it != m_customColValues.end() )
variant = it->second;
else
variant = wxString::Format("%d", row % 100);
}
break; break;
case Col_Max: case Col_Max:
@@ -531,10 +537,13 @@ bool MyListModel::SetValueByRow( const wxVariant &variant,
case Col_Date: case Col_Date:
case Col_TextWithAttr: case Col_TextWithAttr:
case Col_Custom:
wxLogError("Cannot edit the column %d", col); wxLogError("Cannot edit the column %d", col);
break; break;
case Col_Custom:
m_customColValues[row] = variant.GetString();
break;
case Col_Max: case Col_Max:
wxFAIL_MSG( "invalid column" ); wxFAIL_MSG( "invalid column" );
} }

View File

@@ -8,6 +8,10 @@
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#include "wx/hashmap.h"
WX_DECLARE_HASH_MAP(unsigned, wxString, wxIntegerHash, wxIntegerEqual,
IntToStringMap);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// MyMusicTreeModelNode: a node inside MyMusicTreeModel // MyMusicTreeModelNode: a node inside MyMusicTreeModel
@@ -235,6 +239,7 @@ public:
private: private:
wxArrayString m_textColValues; wxArrayString m_textColValues;
wxArrayString m_iconColValues; wxArrayString m_iconColValues;
IntToStringMap m_customColValues;
wxIcon m_icon[2]; wxIcon m_icon[2];
}; };

View File

@@ -2603,7 +2603,14 @@ void TestDefaultActionDialog::OnCatchListBoxDClick(wxCommandEvent& WXUNUSED(even
void TestDefaultActionDialog::OnTextEnter(wxCommandEvent& event) void TestDefaultActionDialog::OnTextEnter(wxCommandEvent& event)
{ {
wxLogMessage("Text \"%s\" entered.", event.GetString()); const wxString& text = event.GetString();
if ( text.empty() )
{
event.Skip();
return;
}
wxLogMessage("Text \"%s\" entered.", text);
} }
void MyFrame::OnTestDefaultActionDialog(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnTestDefaultActionDialog(wxCommandEvent& WXUNUSED(event))

View File

@@ -681,8 +681,6 @@ bool wxDataViewRendererBase::StartEditing( const wxDataViewItem &item, wxRect la
if( !start_event.IsAllowed() ) if( !start_event.IsAllowed() )
return false; return false;
m_item = item; // remember for later
unsigned int col = GetOwner()->GetModelColumn(); unsigned int col = GetOwner()->GetModelColumn();
const wxVariant& value = CheckedGetValue(dv_ctrl->GetModel(), item, col); const wxVariant& value = CheckedGetValue(dv_ctrl->GetModel(), item, col);
@@ -703,15 +701,23 @@ bool wxDataViewRendererBase::StartEditing( const wxDataViewItem &item, wxRect la
m_editorCtrl->SetFocus(); m_editorCtrl->SetFocus();
#endif #endif
// Now we should send Editing Started event return true;
}
void wxDataViewRendererBase::NotifyEditingStarted(const wxDataViewItem& item)
{
// Remember the item being edited for use in FinishEditing() later.
m_item = item;
wxDataViewColumn* const column = GetOwner();
wxDataViewCtrl* const dv_ctrl = column->GetOwner();
wxDataViewEvent event( wxEVT_DATAVIEW_ITEM_EDITING_STARTED, dv_ctrl->GetId() ); wxDataViewEvent event( wxEVT_DATAVIEW_ITEM_EDITING_STARTED, dv_ctrl->GetId() );
event.SetDataViewColumn( GetOwner() ); event.SetDataViewColumn( column );
event.SetModel( dv_ctrl->GetModel() ); event.SetModel( dv_ctrl->GetModel() );
event.SetItem( item ); event.SetItem( item );
event.SetEventObject( dv_ctrl ); event.SetEventObject( dv_ctrl );
dv_ctrl->GetEventHandler()->ProcessEvent( event ); dv_ctrl->GetEventHandler()->ProcessEvent( event );
return true;
} }
void wxDataViewRendererBase::DestroyEditControl() void wxDataViewRendererBase::DestroyEditControl()
@@ -745,9 +751,10 @@ bool wxDataViewRendererBase::FinishEditing()
if (!m_editorCtrl) if (!m_editorCtrl)
return true; return true;
// Try to get the value, normally we should succeed but if we fail, don't
// return immediately, we still need to destroy the edit control.
wxVariant value; wxVariant value;
if ( !GetValueFromEditorCtrl(m_editorCtrl, value) ) const bool gotValue = GetValueFromEditorCtrl(m_editorCtrl, value);
return false;
wxDataViewCtrl* dv_ctrl = GetOwner()->GetOwner(); wxDataViewCtrl* dv_ctrl = GetOwner()->GetOwner();
@@ -755,6 +762,9 @@ bool wxDataViewRendererBase::FinishEditing()
dv_ctrl->GetMainWindow()->SetFocus(); dv_ctrl->GetMainWindow()->SetFocus();
if ( !gotValue )
return false;
bool isValid = Validate(value); bool isValid = Validate(value);
unsigned int col = GetOwner()->GetModelColumn(); unsigned int col = GetOwner()->GetModelColumn();
@@ -769,13 +779,16 @@ bool wxDataViewRendererBase::FinishEditing()
event.SetEventObject( dv_ctrl ); event.SetEventObject( dv_ctrl );
dv_ctrl->GetEventHandler()->ProcessEvent( event ); dv_ctrl->GetEventHandler()->ProcessEvent( event );
bool accepted = false;
if ( isValid && event.IsAllowed() ) if ( isValid && event.IsAllowed() )
{ {
dv_ctrl->GetModel()->ChangeValue(value, m_item, col); dv_ctrl->GetModel()->ChangeValue(value, m_item, col);
return true; accepted = true;
} }
return false; m_item = wxDataViewItem();
return accepted;
} }
wxVariant wxVariant
@@ -1044,17 +1057,20 @@ void wxDataViewEditorCtrlEvtHandler::OnChar( wxKeyEvent &event )
{ {
switch ( event.m_keyCode ) switch ( event.m_keyCode )
{ {
case WXK_RETURN:
m_finished = true;
m_owner->FinishEditing();
break;
case WXK_ESCAPE: case WXK_ESCAPE:
{
m_finished = true; m_finished = true;
m_owner->CancelEditing(); m_owner->CancelEditing();
break; break;
}
case WXK_RETURN:
if ( !event.HasAnyModifiers() )
{
m_finished = true;
m_owner->FinishEditing();
break;
}
wxFALLTHROUGH; // Ctrl/Alt/Shift-Enter is not handled specially
default: default:
event.Skip(); event.Skip();
} }

View File

@@ -1693,6 +1693,13 @@ void wxEvtHandler::DoBind(int id,
wxDynamicEventTableEntry *entry = wxDynamicEventTableEntry *entry =
new wxDynamicEventTableEntry(eventType, id, lastId, func, userData); new wxDynamicEventTableEntry(eventType, id, lastId, func, userData);
// Check if the derived class allows binding such event handlers.
if ( !OnDynamicBind(*entry) )
{
delete entry;
return;
}
if (!m_dynamicEvents) if (!m_dynamicEvents)
m_dynamicEvents = new DynamicEvents; m_dynamicEvents = new DynamicEvents;

View File

@@ -1194,6 +1194,21 @@ void wxTextCtrlBase::DoUpdateWindowUI(wxUpdateUIEvent& event)
} }
} }
bool wxTextCtrlBase::OnDynamicBind(wxDynamicEventTableEntry& entry)
{
if ( entry.m_eventType == wxEVT_TEXT_ENTER )
{
wxCHECK_MSG
(
HasFlag(wxTE_PROCESS_ENTER),
false,
wxS("Must have wxTE_PROCESS_ENTER for wxEVT_TEXT_ENTER to work")
);
}
return wxControl::OnDynamicBind(entry);
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// hit testing // hit testing
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@@ -120,8 +120,8 @@ wxDataViewColumn* GetExpanderColumnOrFirstOne(wxDataViewCtrl* dataview)
wxTextCtrl *CreateEditorTextCtrl(wxWindow *parent, const wxRect& labelRect, const wxString& value) wxTextCtrl *CreateEditorTextCtrl(wxWindow *parent, const wxRect& labelRect, const wxString& value)
{ {
wxTextCtrl* ctrl = new wxTextCtrl(parent, wxID_ANY, value, wxTextCtrl* ctrl = new wxTextCtrl(parent, wxID_ANY, value,
wxPoint(labelRect.x,labelRect.y), labelRect.GetPosition(),
wxSize(labelRect.width,labelRect.height), labelRect.GetSize(),
wxTE_PROCESS_ENTER); wxTE_PROCESS_ENTER);
// Adjust size of wxTextCtrl editor to fit text, even if it means being // Adjust size of wxTextCtrl editor to fit text, even if it means being
@@ -2251,6 +2251,8 @@ wxDataViewMainWindow::StartEditing(const wxDataViewItem& item,
const wxRect itemRect = GetItemRect(item, col); const wxRect itemRect = GetItemRect(item, col);
if ( renderer->StartEditing(item, itemRect) ) if ( renderer->StartEditing(item, itemRect) )
{ {
renderer->NotifyEditingStarted(item);
// Save the renderer to be able to finish/cancel editing it later and // Save the renderer to be able to finish/cancel editing it later and
// save the control to be able to detect if we're still editing it. // save the control to be able to detect if we're still editing it.
m_editorRenderer = renderer; m_editorRenderer = renderer;
@@ -3632,7 +3634,17 @@ void wxDataViewMainWindow::OnCharHook(wxKeyEvent& event)
return; return;
case WXK_RETURN: case WXK_RETURN:
// Shift-Enter is not special neither.
if ( event.ShiftDown() )
break;
wxFALLTHROUGH;
case WXK_TAB: case WXK_TAB:
// Ctrl/Alt-Tab or Enter could be used for something else, so
// don't handle them here.
if ( event.HasModifiers() )
break;
m_editorRenderer->FinishEditing(); m_editorRenderer->FinishEditing();
return; return;
} }

View File

@@ -1749,20 +1749,11 @@ bool wxGtkDataViewModelNotifier::Cleared()
// wxDataViewRenderer // wxDataViewRenderer
// --------------------------------------------------------- // ---------------------------------------------------------
static gpointer s_user_data = NULL;
static void static void
wxgtk_cell_editable_editing_done( GtkCellEditable *WXUNUSED(editable), wxgtk_cell_editable_editing_done( GtkCellEditable *WXUNUSED(editable),
wxDataViewRenderer *wxrenderer ) wxDataViewRenderer *wxrenderer )
{ {
wxDataViewColumn *column = wxrenderer->GetOwner(); wxrenderer->FinishEditing();
wxDataViewCtrl *dv = column->GetOwner();
wxDataViewEvent event( wxEVT_DATAVIEW_ITEM_EDITING_DONE, dv->GetId() );
event.SetDataViewColumn( column );
event.SetModel( dv->GetModel() );
wxDataViewItem item( s_user_data );
event.SetItem( item );
dv->HandleWindowEvent( event );
} }
static void static void
@@ -1774,17 +1765,11 @@ wxgtk_renderer_editing_started( GtkCellRenderer *WXUNUSED(cell), GtkCellEditable
wxDataViewColumn *column = wxrenderer->GetOwner(); wxDataViewColumn *column = wxrenderer->GetOwner();
wxDataViewCtrl *dv = column->GetOwner(); wxDataViewCtrl *dv = column->GetOwner();
wxDataViewEvent event( wxEVT_DATAVIEW_ITEM_EDITING_STARTED, dv->GetId() );
event.SetDataViewColumn( column );
event.SetModel( dv->GetModel() );
wxDataViewItem item(dv->GTKPathToItem(wxGtkTreePath(path))); wxDataViewItem item(dv->GTKPathToItem(wxGtkTreePath(path)));
event.SetItem( item ); wxrenderer->NotifyEditingStarted(item);
dv->HandleWindowEvent( event );
if (GTK_IS_CELL_EDITABLE(editable)) if (GTK_IS_CELL_EDITABLE(editable))
{ {
s_user_data = item.GetID();
g_signal_connect (editable, "editing_done", g_signal_connect (editable, "editing_done",
G_CALLBACK (wxgtk_cell_editable_editing_done), G_CALLBACK (wxgtk_cell_editable_editing_done),
(gpointer) wxrenderer ); (gpointer) wxrenderer );

View File

@@ -2058,14 +2058,48 @@ void wxTextCtrl::OnKeyDown(wxKeyEvent& event)
event.Skip(); event.Skip();
} }
WXLRESULT wxTextCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) bool
wxTextCtrl::MSWHandleMessage(WXLRESULT *rc,
WXUINT nMsg,
WXWPARAM wParam,
WXLPARAM lParam)
{ {
WXLRESULT lRc = wxTextCtrlBase::MSWWindowProc(nMsg, wParam, lParam); bool processed = wxTextCtrlBase::MSWHandleMessage(rc, nMsg, wParam, lParam);
// Handle the special case of "Enter" key: the user code needs to specify
// wxTE_PROCESS_ENTER style to get it in the first place, but if this flag
// is used, then even if the wxEVT_TEXT_ENTER handler skips the event, the
// normal action of this key is not performed because IsDialogMessage() is
// not called and, also, an annoying beep is generated by EDIT default
// WndProc.
//
// Fix these problems by explicitly performing the default function of this
// key (which would be done by MSWProcessMessage() if we didn't have
// wxTE_PROCESS_ENTER) and preventing the default WndProc from getting it.
if ( nMsg == WM_CHAR &&
!processed &&
HasFlag(wxTE_PROCESS_ENTER) &&
wParam == VK_RETURN &&
!wxIsAnyModifierDown() )
{
MSWClickButtonIfPossible(MSWGetDefaultButtonFor(this));
processed = true;
}
switch ( nMsg ) switch ( nMsg )
{ {
case WM_GETDLGCODE: case WM_GETDLGCODE:
{ {
// Ensure that the result value is initialized even if the base
// class didn't handle WM_GETDLGCODE but just update the value
// returned by it if it did handle it.
if ( !processed )
{
*rc = MSWDefWindowProc(nMsg, wParam, lParam);
processed = true;
}
// we always want the chars and the arrows: the arrows for // we always want the chars and the arrows: the arrows for
// navigation and the chars because we want Ctrl-C to work even // navigation and the chars because we want Ctrl-C to work even
// in a read only control // in a read only control
@@ -2089,7 +2123,7 @@ WXLRESULT wxTextCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
if ( HasFlag(wxTE_PROCESS_TAB) ) if ( HasFlag(wxTE_PROCESS_TAB) )
lDlgCode |= DLGC_WANTTAB; lDlgCode |= DLGC_WANTTAB;
lRc |= lDlgCode; *rc |= lDlgCode;
} }
else // !editable else // !editable
{ {
@@ -2098,11 +2132,17 @@ WXLRESULT wxTextCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
// including DLGC_WANTMESSAGE). This is strange (how // including DLGC_WANTMESSAGE). This is strange (how
// does it work in the native Win32 apps?) but for now // does it work in the native Win32 apps?) but for now
// live with it. // live with it.
lRc = lDlgCode; *rc = lDlgCode;
}
if ( IsMultiLine() )
{
// The presence of this style, coming from the default EDIT
// WndProc, indicates that the control contents should be
// selected when it gets focus, but we don't want this to
// happen for the multiline controls, so clear it.
*rc &= ~DLGC_HASSETSEL;
} }
if (IsMultiLine())
// Clear the DLGC_HASSETSEL bit from the return value
lRc &= ~DLGC_HASSETSEL;
} }
break; break;
@@ -2122,7 +2162,7 @@ WXLRESULT wxTextCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
#endif // wxUSE_MENUS #endif // wxUSE_MENUS
} }
return lRc; return processed;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@@ -2316,7 +2316,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
// currently active button should get enter press even // currently active button should get enter press even
// if there is a default button elsewhere so check if // if there is a default button elsewhere so check if
// this window is a button first // this window is a button first
wxWindow *btn = NULL; wxButton *btn = NULL;
if ( lDlgCode & DLGC_DEFPUSHBUTTON ) if ( lDlgCode & DLGC_DEFPUSHBUTTON )
{ {
// let IsDialogMessage() handle this for all // let IsDialogMessage() handle this for all
@@ -2325,8 +2325,11 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
long style = ::GetWindowLong(msg->hwnd, GWL_STYLE); long style = ::GetWindowLong(msg->hwnd, GWL_STYLE);
if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW ) if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW )
{ {
// emulate the button click btn = wxDynamicCast
btn = wxFindWinFromHandle(msg->hwnd); (
wxFindWinFromHandle(msg->hwnd),
wxButton
);
} }
} }
else // not a button itself, do we have default button? else // not a button itself, do we have default button?
@@ -2367,25 +2370,12 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
); );
} }
} }
else // bCtrlDown
{
win = wxGetTopLevelParent(win);
}
wxTopLevelWindow * const btn = MSWGetDefaultButtonFor(win);
tlw = wxDynamicCast(win, wxTopLevelWindow);
if ( tlw )
{
btn = wxDynamicCast(tlw->GetDefaultItem(),
wxButton);
}
} }
if ( btn && btn->IsEnabled() && btn->IsShownOnScreen() ) if ( MSWClickButtonIfPossible(btn) )
{
btn->MSWCommand(BN_CLICKED, 0 /* unused */);
return true; return true;
}
// This "Return" key press won't be actually used for // This "Return" key press won't be actually used for
// navigation so don't generate wxNavigationKeyEvent // navigation so don't generate wxNavigationKeyEvent
@@ -2544,6 +2534,36 @@ bool wxWindowMSW::MSWSafeIsDialogMessage(WXMSG* msg)
#endif // __WXUNIVERSAL__ #endif // __WXUNIVERSAL__
/* static */
wxButton* wxWindowMSW::MSWGetDefaultButtonFor(wxWindow* win)
{
#if wxUSE_BUTTON
win = wxGetTopLevelParent(win);
wxTopLevelWindow *const tlw = wxDynamicCast(win, wxTopLevelWindow);
if ( tlw )
return wxDynamicCast(tlw->GetDefaultItem(), wxButton);
#endif // wxUSE_BUTTON
return NULL;
}
/* static */
bool wxWindowMSW::MSWClickButtonIfPossible(wxButton* btn)
{
#if wxUSE_BUTTON
if ( btn && btn->IsEnabled() && btn->IsShownOnScreen() )
{
btn->MSWCommand(BN_CLICKED, 0 /* unused */);
return true;
}
#endif // wxUSE_BUTTON
wxUnusedVar(btn);
return false;
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// message params unpackers // message params unpackers
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@@ -1886,22 +1886,20 @@ outlineView:(NSOutlineView*)outlineView
wxDataViewColumn* const wxDataViewColumn* const
col([static_cast<wxDVCNSTableColumn*>(tableColumn) getColumnPointer]); col([static_cast<wxDVCNSTableColumn*>(tableColumn) getColumnPointer]);
wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl();
// stop editing of a custom item first (if necessary) // stop editing of a custom item first (if necessary)
dvc->FinishCustomItemEditing(); dvc->FinishCustomItemEditing();
// now, send the event: // now, send the event:
wxDataViewEvent wxDataViewRenderer* const renderer = col->GetRenderer();
event(wxEVT_DATAVIEW_ITEM_EDITING_STARTED,dvc->GetId()); if ( renderer )
{
event.SetEventObject(dvc); renderer->NotifyEditingStarted
event.SetItem( (
wxDataViewItemFromItem([self itemAtRow:currentlyEditedRow])); wxDataViewItemFromItem([self itemAtRow:currentlyEditedRow])
event.SetColumn(dvc->GetColumnPosition(col)); );
event.SetDataViewColumn(col); }
dvc->GetEventHandler()->ProcessEvent(event); //else: we should always have a renderer but don't crash if for some
// unfathomable reason we don't have it
} }
-(void) textDidEndEditing:(NSNotification*)notification -(void) textDidEndEditing:(NSNotification*)notification