First <ESC> after an edit in a textEdit cancels the edit.
(Second will exit the dialog.) Fixes https://gitlab.com/kicad/code/kicad/issues/14514
This commit is contained in:
parent
f01e083f7c
commit
a914f6e992
|
@ -2,7 +2,7 @@
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||||
* Copyright (C) 2012-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 2012-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -67,10 +67,6 @@ public:
|
||||||
|
|
||||||
|
|
||||||
BEGIN_EVENT_TABLE( DIALOG_SHIM, wxDialog )
|
BEGIN_EVENT_TABLE( DIALOG_SHIM, wxDialog )
|
||||||
// If dialog has a grid and the grid has an active cell editor
|
|
||||||
// Esc key closes cell editor, otherwise Esc key closes the dialog.
|
|
||||||
EVT_GRID_EDITOR_SHOWN( DIALOG_SHIM::OnGridEditorShown )
|
|
||||||
EVT_GRID_EDITOR_HIDDEN( DIALOG_SHIM::OnGridEditorHidden )
|
|
||||||
EVT_CHAR_HOOK( DIALOG_SHIM::OnCharHook )
|
EVT_CHAR_HOOK( DIALOG_SHIM::OnCharHook )
|
||||||
END_EVENT_TABLE()
|
END_EVENT_TABLE()
|
||||||
|
|
||||||
|
@ -325,30 +321,38 @@ bool DIALOG_SHIM::Enable( bool enable )
|
||||||
// Recursive descent doing a SelectAll() in wxTextCtrls.
|
// Recursive descent doing a SelectAll() in wxTextCtrls.
|
||||||
// MacOS User Interface Guidelines state that when tabbing to a text control all its
|
// MacOS User Interface Guidelines state that when tabbing to a text control all its
|
||||||
// text should be selected. Since wxWidgets fails to implement this, we do it here.
|
// text should be selected. Since wxWidgets fails to implement this, we do it here.
|
||||||
static void selectAllInTextCtrls( wxWindowList& children )
|
void DIALOG_SHIM::selectAllInTextCtrls( wxWindowList& children )
|
||||||
{
|
{
|
||||||
for( wxWindow* child : children )
|
for( wxWindow* child : children )
|
||||||
{
|
{
|
||||||
if( wxTextCtrl* childTextCtrl = dynamic_cast<wxTextCtrl*>( child ) )
|
if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( child ) )
|
||||||
{
|
{
|
||||||
|
m_beforeEditValues[ textCtrl ] = textCtrl->GetValue();
|
||||||
|
textCtrl->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( DIALOG_SHIM::onChildSetFocus ),
|
||||||
|
nullptr, this );
|
||||||
|
|
||||||
// We don't currently run this on GTK because some window managers don't hide the
|
// We don't currently run this on GTK because some window managers don't hide the
|
||||||
// selection in non-active controls, and other window managers do the selection
|
// selection in non-active controls, and other window managers do the selection
|
||||||
// automatically anyway.
|
// automatically anyway.
|
||||||
#if defined( __WXMAC__ ) || defined( __WXMSW__ )
|
#if defined( __WXMAC__ ) || defined( __WXMSW__ )
|
||||||
if( !childTextCtrl->GetStringSelection().IsEmpty() )
|
if( !textCtrl->GetStringSelection().IsEmpty() )
|
||||||
{
|
{
|
||||||
// Respect an existing selection
|
// Respect an existing selection
|
||||||
}
|
}
|
||||||
else if( childTextCtrl->IsEditable() )
|
else if( textCtrl->IsEditable() )
|
||||||
{
|
{
|
||||||
childTextCtrl->SelectAll();
|
textCtrl->SelectAll();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
ignore_unused( childTextCtrl );
|
ignore_unused( textCtrl );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( child ) )
|
else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( child ) )
|
||||||
{
|
{
|
||||||
|
m_beforeEditValues[ scintilla ] = scintilla->GetText();
|
||||||
|
scintilla->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( DIALOG_SHIM::onChildSetFocus ),
|
||||||
|
nullptr, this );
|
||||||
|
|
||||||
if( !scintilla->GetSelectedText().IsEmpty() )
|
if( !scintilla->GetSelectedText().IsEmpty() )
|
||||||
{
|
{
|
||||||
// Respect an existing selection
|
// Respect an existing selection
|
||||||
|
@ -533,11 +537,6 @@ void DIALOG_SHIM::OnButton( wxCommandEvent& aEvent )
|
||||||
{
|
{
|
||||||
const int id = aEvent.GetId();
|
const int id = aEvent.GetId();
|
||||||
|
|
||||||
// If we are pressing a button to exit, we need to enable the escapeID
|
|
||||||
// otherwise the dialog does not process cancel
|
|
||||||
if( id == wxID_CANCEL )
|
|
||||||
SetEscapeId( wxID_ANY );
|
|
||||||
|
|
||||||
if( IsQuasiModal() )
|
if( IsQuasiModal() )
|
||||||
{
|
{
|
||||||
if( id == GetAffirmativeId() )
|
if( id == GetAffirmativeId() )
|
||||||
|
@ -555,7 +554,7 @@ void DIALOG_SHIM::OnButton( wxCommandEvent& aEvent )
|
||||||
ignore_unused( TransferDataFromWindow() );
|
ignore_unused( TransferDataFromWindow() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if( id == GetEscapeId() || (id == wxID_CANCEL && GetEscapeId() == wxID_ANY) )
|
else if( id == wxID_CANCEL )
|
||||||
{
|
{
|
||||||
EndQuasiModal( wxID_CANCEL );
|
EndQuasiModal( wxID_CANCEL );
|
||||||
}
|
}
|
||||||
|
@ -572,6 +571,17 @@ void DIALOG_SHIM::OnButton( wxCommandEvent& aEvent )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DIALOG_SHIM::onChildSetFocus( wxFocusEvent& aEvent )
|
||||||
|
{
|
||||||
|
// When setting focus to a text control reset the before-edit value.
|
||||||
|
|
||||||
|
if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( aEvent.GetEventObject() ) )
|
||||||
|
m_beforeEditValues[ textCtrl ] = textCtrl->GetValue();
|
||||||
|
else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( aEvent.GetEventObject() ) )
|
||||||
|
m_beforeEditValues[ scintilla ] = scintilla->GetText();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DIALOG_SHIM::OnCharHook( wxKeyEvent& aEvt )
|
void DIALOG_SHIM::OnCharHook( wxKeyEvent& aEvt )
|
||||||
{
|
{
|
||||||
if( aEvt.GetKeyCode() == 'U' && aEvt.GetModifiers() == wxMOD_CONTROL )
|
if( aEvt.GetKeyCode() == 'U' && aEvt.GetModifiers() == wxMOD_CONTROL )
|
||||||
|
@ -627,25 +637,36 @@ void DIALOG_SHIM::OnCharHook( wxKeyEvent& aEvt )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if( aEvt.GetKeyCode() == WXK_ESCAPE )
|
||||||
|
{
|
||||||
|
wxObject* eventSource = aEvt.GetEventObject();
|
||||||
|
|
||||||
|
if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( eventSource ) )
|
||||||
|
{
|
||||||
|
// First escape after an edit cancels edit
|
||||||
|
if( textCtrl->GetValue() != m_beforeEditValues[ textCtrl ] )
|
||||||
|
{
|
||||||
|
textCtrl->SetValue( m_beforeEditValues[ textCtrl ] );
|
||||||
|
textCtrl->SelectAll();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( eventSource ) )
|
||||||
|
{
|
||||||
|
// First escape after an edit cancels edit
|
||||||
|
if( scintilla->GetText() != m_beforeEditValues[ scintilla ] )
|
||||||
|
{
|
||||||
|
scintilla->SetText( m_beforeEditValues[ scintilla ] );
|
||||||
|
scintilla->SelectAll();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
aEvt.Skip();
|
aEvt.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DIALOG_SHIM::OnGridEditorShown( wxGridEvent& event )
|
|
||||||
{
|
|
||||||
SetEscapeId( wxID_NONE );
|
|
||||||
event.Skip();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DIALOG_SHIM::OnGridEditorHidden( wxGridEvent& event )
|
|
||||||
{
|
|
||||||
SetEscapeId( wxID_ANY );
|
|
||||||
event.Skip();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void recursiveDescent( wxSizer* aSizer, std::map<int, wxString>& aLabels )
|
static void recursiveDescent( wxSizer* aSizer, std::map<int, wxString>& aLabels )
|
||||||
{
|
{
|
||||||
wxStdDialogButtonSizer* sdbSizer = dynamic_cast<wxStdDialogButtonSizer*>( aSizer );
|
wxStdDialogButtonSizer* sdbSizer = dynamic_cast<wxStdDialogButtonSizer*>( aSizer );
|
||||||
|
|
|
@ -494,6 +494,14 @@ void GRID_TRICKS::onCharHook( wxKeyEvent& ev )
|
||||||
m_grid->ForceRefresh();
|
m_grid->ForceRefresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if( ev.GetKeyCode() == WXK_ESCAPE )
|
||||||
|
{
|
||||||
|
if( m_grid->IsCellEditControlShown() )
|
||||||
|
{
|
||||||
|
m_grid->CancelPendingChanges();
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( !handled )
|
if( !handled )
|
||||||
ev.Skip( true );
|
ev.Skip( true );
|
||||||
|
|
|
@ -420,6 +420,34 @@ void WX_GRID::DrawRowLabel( wxDC& dc, int row )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool WX_GRID::CancelPendingChanges()
|
||||||
|
{
|
||||||
|
if( !IsCellEditControlEnabled() )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
HideCellEditControl();
|
||||||
|
|
||||||
|
// do it after HideCellEditControl()
|
||||||
|
m_cellEditCtrlEnabled = false;
|
||||||
|
|
||||||
|
int row = m_currentCellCoords.GetRow();
|
||||||
|
int col = m_currentCellCoords.GetCol();
|
||||||
|
|
||||||
|
wxString oldval = GetCellValue( row, col );
|
||||||
|
wxString newval;
|
||||||
|
|
||||||
|
wxGridCellAttr* attr = GetCellAttr( row, col );
|
||||||
|
wxGridCellEditor* editor = attr->GetEditor( this, row, col );
|
||||||
|
|
||||||
|
bool changed = editor->EndEdit( row, col, this, oldval, &newval );
|
||||||
|
|
||||||
|
editor->DecRef();
|
||||||
|
attr->DecRef();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool WX_GRID::CommitPendingChanges( bool aQuietMode )
|
bool WX_GRID::CommitPendingChanges( bool aQuietMode )
|
||||||
{
|
{
|
||||||
if( !IsCellEditControlEnabled() )
|
if( !IsCellEditControlEnabled() )
|
||||||
|
|
|
@ -181,6 +181,8 @@ protected:
|
||||||
virtual void OnCharHook( wxKeyEvent& aEvt );
|
virtual void OnCharHook( wxKeyEvent& aEvt );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void selectAllInTextCtrls( wxWindowList& children );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Properly handle the wxCloseEvent when in the quasimodal mode when not calling
|
* Properly handle the wxCloseEvent when in the quasimodal mode when not calling
|
||||||
* EndQuasiModal which is possible with any dialog derived from #DIALOG_SHIM.
|
* EndQuasiModal which is possible with any dialog derived from #DIALOG_SHIM.
|
||||||
|
@ -193,8 +195,7 @@ private:
|
||||||
*/
|
*/
|
||||||
void OnButton( wxCommandEvent& aEvent );
|
void OnButton( wxCommandEvent& aEvent );
|
||||||
|
|
||||||
void OnGridEditorShown( wxGridEvent& event );
|
void onChildSetFocus( wxFocusEvent& aEvent );
|
||||||
void OnGridEditorHidden( wxGridEvent& event );
|
|
||||||
|
|
||||||
DECLARE_EVENT_TABLE();
|
DECLARE_EVENT_TABLE();
|
||||||
|
|
||||||
|
@ -223,6 +224,9 @@ protected:
|
||||||
|
|
||||||
// The size asked by the caller, used the first time the dialog is created
|
// The size asked by the caller, used the first time the dialog is created
|
||||||
wxSize m_initialSize;
|
wxSize m_initialSize;
|
||||||
|
|
||||||
|
// Used to support first-esc-cancels-edit logic
|
||||||
|
std::map<wxWindow*, wxString> m_beforeEditValues;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DIALOG_SHIM_
|
#endif // DIALOG_SHIM_
|
||||||
|
|
|
@ -86,6 +86,7 @@ public:
|
||||||
* @return false if validation failed
|
* @return false if validation failed
|
||||||
*/
|
*/
|
||||||
bool CommitPendingChanges( bool aQuietMode = false );
|
bool CommitPendingChanges( bool aQuietMode = false );
|
||||||
|
bool CancelPendingChanges();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a UNITS_PROVIDER to enable use of unit- and eval-based Getters.
|
* Set a UNITS_PROVIDER to enable use of unit- and eval-based Getters.
|
||||||
|
|
Loading…
Reference in New Issue