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:
@@ -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
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
||||||
|
@@ -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
|
||||||
|
@@ -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;
|
||||||
|
@@ -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)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -444,7 +444,13 @@ void MyListModel::GetValueByRow( wxVariant &variant,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Col_Custom:
|
case Col_Custom:
|
||||||
|
{
|
||||||
|
IntToStringMap::const_iterator it = m_customColValues.find(row);
|
||||||
|
if ( it != m_customColValues.end() )
|
||||||
|
variant = it->second;
|
||||||
|
else
|
||||||
variant = wxString::Format("%d", row % 100);
|
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" );
|
||||||
}
|
}
|
||||||
|
@@ -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];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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))
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
@@ -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
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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 );
|
||||||
|
@@ -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() )
|
if ( IsMultiLine() )
|
||||||
// Clear the DLGC_HASSETSEL bit from the return value
|
{
|
||||||
lRc &= ~DLGC_HASSETSEL;
|
// 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@@ -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
|
|
||||||
{
|
btn = MSWGetDefaultButtonFor(win);
|
||||||
win = wxGetTopLevelParent(win);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wxTopLevelWindow * const
|
if ( MSWClickButtonIfPossible(btn) )
|
||||||
tlw = wxDynamicCast(win, wxTopLevelWindow);
|
|
||||||
if ( tlw )
|
|
||||||
{
|
|
||||||
btn = wxDynamicCast(tlw->GetDefaultItem(),
|
|
||||||
wxButton);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( btn && btn->IsEnabled() && btn->IsShownOnScreen() )
|
|
||||||
{
|
|
||||||
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
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user