ADDED autocomplete for value field in Symbol Properties dialog.

This commit is contained in:
Jeff Young 2023-08-02 20:11:59 +01:00
parent 3428bd8e83
commit 686dfba77a
13 changed files with 164 additions and 132 deletions

View File

@ -33,7 +33,8 @@
#include <confirm.h>
SCINTILLA_TRICKS::SCINTILLA_TRICKS( wxStyledTextCtrl* aScintilla, const wxString& aBraces,
bool aSingleLine, std::function<void()> onAcceptHandler,
bool aSingleLine,
std::function<void( wxKeyEvent& )> onAcceptHandler,
std::function<void( wxStyledTextEvent& )> onCharAddedHandler ) :
m_te( aScintilla ),
m_braces( aBraces ),
@ -180,6 +181,10 @@ void SCINTILLA_TRICKS::onCharHook( wxKeyEvent& aEvent )
m_te->AutoCompCancel();
m_suppressAutocomplete = true; // Don't run autocomplete again on the next char...
}
else if( aEvent.GetKeyCode() == WXK_RETURN || aEvent.GetKeyCode() == WXK_NUMPAD_ENTER )
{
m_te->AutoCompComplete();
}
else
{
aEvent.Skip();
@ -194,7 +199,7 @@ void SCINTILLA_TRICKS::onCharHook( wxKeyEvent& aEvent )
if( ( aEvent.GetKeyCode() == WXK_RETURN || aEvent.GetKeyCode() == WXK_NUMPAD_ENTER )
&& ( m_singleLine || aEvent.ShiftDown() ) )
{
m_onAcceptHandler();
m_onAcceptHandler( aEvent );
}
else if( ConvertSmartQuotesAndDashes( &c ) )
{

View File

@ -93,9 +93,9 @@ void GRID_CELL_STC_EDITOR::Create( wxWindow* aParent, wxWindowID aId, wxEvtHandl
m_scintillaTricks = new SCINTILLA_TRICKS(
stc_ctrl(), wxEmptyString, true,
// onAccept handler
[this]()
[this]( wxKeyEvent& aEvent )
{
stc_ctrl()->AutoCompComplete();
HandleReturn( aEvent );
},
// onCharAdded handler
[this]( wxStyledTextEvent& aEvent )

View File

@ -72,7 +72,7 @@ DIALOG_FIELD_PROPERTIES::DIALOG_FIELD_PROPERTIES( SCH_BASE_FRAME* aParent, const
m_fieldId = VALUE_FIELD;
m_scintillaTricks = new SCINTILLA_TRICKS( m_StyledTextCtrl, wxT( "{}" ), true,
[this]()
[this]( wxKeyEvent& aEvent )
{
wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
} );
@ -513,119 +513,7 @@ DIALOG_SCH_FIELD_PROPERTIES::DIALOG_SCH_FIELD_PROPERTIES( SCH_BASE_FRAME* aParen
void DIALOG_SCH_FIELD_PROPERTIES::onScintillaCharAdded( wxStyledTextEvent &aEvent )
{
int key = aEvent.GetKey();
SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( GetParent() );
wxArrayString autocompleteTokens;
int pos = m_StyledTextCtrl->GetCurrentPos();
int start = m_StyledTextCtrl->WordStartPosition( pos, true );
wxString partial;
// Currently, '\n' is not allowed in fields. So remove it when entered
// TODO: see if we must close the dialog. However this is not obvious, as
// if a \n is typed (and removed) when a text is selected, this text is deleted
// (in fact replaced by \n, that is removed by the filter)
if( key == '\n' )
{
wxString text = m_StyledTextCtrl->GetText();
int currpos = m_StyledTextCtrl->GetCurrentPos();
text.Replace( wxS( "\n" ), wxS( "" ) );
m_StyledTextCtrl->SetText( text );
m_StyledTextCtrl->GotoPos( currpos-1 );
return;
}
auto textVarRef =
[&]( int pt )
{
return pt >= 2
&& m_StyledTextCtrl->GetCharAt( pt - 2 ) == '$'
&& m_StyledTextCtrl->GetCharAt( pt - 1 ) == '{';
};
// Check for cross-reference
if( start > 1 && m_StyledTextCtrl->GetCharAt( start - 1 ) == ':' )
{
int refStart = m_StyledTextCtrl->WordStartPosition( start - 1, true );
if( textVarRef( refStart ) )
{
partial = m_StyledTextCtrl->GetRange( start, pos );
wxString ref = m_StyledTextCtrl->GetRange( refStart, start - 1 );
if( ref == wxS( "OP" ) )
{
// SPICE operating points use ':' syntax for ports
SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( m_field->GetParent() );
SCH_SHEET_PATH& sheet = editFrame->Schematic().CurrentSheet();
if( symbol )
{
SIM_LIB_MGR mgr( &Prj() );
SIM_MODEL& model = mgr.CreateModel( &sheet, *symbol ).model;
for( wxString pin : model.GetPinNames() )
{
if( pin.StartsWith( '<' ) && pin.EndsWith( '>' ) )
autocompleteTokens.push_back( pin.Mid( 1, pin.Length() - 2 ) );
else
autocompleteTokens.push_back( pin );
}
}
}
else
{
SCH_SHEET_LIST sheets = editFrame->Schematic().GetSheets();
SCH_REFERENCE_LIST refs;
SCH_SYMBOL* refSymbol = nullptr;
sheets.GetSymbols( refs );
for( size_t jj = 0; jj < refs.GetCount(); jj++ )
{
if( refs[ jj ].GetSymbol()->GetRef( &refs[ jj ].GetSheetPath(), true ) == ref )
{
refSymbol = refs[ jj ].GetSymbol();
break;
}
}
if( refSymbol )
refSymbol->GetContextualTextVars( &autocompleteTokens );
}
}
}
else if( textVarRef( start ) )
{
partial = m_StyledTextCtrl->GetTextRange( start, pos );
SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( m_field->GetParent() );
SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( m_field->GetParent() );
SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( m_field->GetParent() );
if( symbol )
{
symbol->GetContextualTextVars( &autocompleteTokens );
SCHEMATIC* schematic = symbol->Schematic();
if( schematic && schematic->CurrentSheet().Last() )
schematic->CurrentSheet().Last()->GetContextualTextVars( &autocompleteTokens );
}
if( sheet )
sheet->GetContextualTextVars( &autocompleteTokens );
if( label )
label->GetContextualTextVars( &autocompleteTokens );
for( std::pair<wxString, wxString> entry : Prj().GetTextVars() )
autocompleteTokens.push_back( entry.first );
}
m_scintillaTricks->DoAutocomplete( partial, autocompleteTokens );
m_StyledTextCtrl->SetFocus();
m_field->OnScintillaCharAdded( m_scintillaTricks, aEvent );
}

View File

@ -45,7 +45,7 @@ DIALOG_LIB_TEXT_PROPERTIES::DIALOG_LIB_TEXT_PROPERTIES( SYMBOL_EDIT_FRAME* aPare
COLOR4D schematicBackground = colorSettings->GetColor( LAYER_SCHEMATIC_BACKGROUND );
m_scintillaTricks = new SCINTILLA_TRICKS( m_StyledTextCtrl, wxT( "{}" ), false,
[this]()
[this]( wxKeyEvent& aEvent )
{
wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
} );

View File

@ -65,7 +65,7 @@ DIALOG_LIB_TEXTBOX_PROPERTIES::DIALOG_LIB_TEXTBOX_PROPERTIES( SYMBOL_EDIT_FRAME*
m_textCtrl->SetEOLMode( wxSTC_EOL_LF );
m_scintillaTricks = new SCINTILLA_TRICKS( m_textCtrl, wxT( "{}" ), false,
[this]()
[this]( wxKeyEvent& aEvent )
{
wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
} );

View File

@ -101,7 +101,7 @@ DIALOG_TEXT_PROPERTIES::DIALOG_TEXT_PROPERTIES( SCH_EDIT_FRAME* aParent, SCH_ITE
m_scintillaTricks = new SCINTILLA_TRICKS( m_textCtrl, wxT( "{}" ), false,
// onAccept handler
[this]()
[this]( wxKeyEvent& aEvent )
{
wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
},

View File

@ -42,6 +42,7 @@
#include "widgets/grid_color_swatch_helpers.h"
#include "font/fontconfig.h"
#include "font/kicad_font_name.h"
#include "widgets/grid_text_helpers.h"
#include <wx/settings.h>
#include <string_utils.h>
#include <widgets/grid_combobox.h>
@ -190,9 +191,23 @@ void FIELDS_GRID_TABLE<T>::initGrid( WX_GRID* aGrid )
m_referenceAttr->SetEditor( referenceEditor );
m_valueAttr = new wxGridCellAttr;
GRID_CELL_TEXT_EDITOR* valueEditor = new GRID_CELL_TEXT_EDITOR();
valueEditor->SetValidator( m_valueValidator );
m_valueAttr->SetEditor( valueEditor );
if constexpr ( std::is_same_v<T, SCH_FIELD> )
{
GRID_CELL_STC_EDITOR* valueEditor = new GRID_CELL_STC_EDITOR( true,
[this]( wxStyledTextEvent& aEvent, SCINTILLA_TRICKS* aScintillaTricks )
{
SCH_FIELD& valueField = static_cast<SCH_FIELD&>( this->at( VALUE_FIELD ) );
valueField.OnScintillaCharAdded( aScintillaTricks, aEvent );
} );
m_valueAttr->SetEditor( valueEditor );
}
else
{
GRID_CELL_TEXT_EDITOR* valueEditor = new GRID_CELL_TEXT_EDITOR();
valueEditor->SetValidator( m_valueValidator );
m_valueAttr->SetEditor( valueEditor );
}
m_footprintAttr = new wxGridCellAttr;
GRID_CELL_FPID_EDITOR* fpIdEditor = new GRID_CELL_FPID_EDITOR( m_dialog, m_symbolNetlist );

View File

@ -55,6 +55,7 @@
#include <tool/tool_manager.h>
#include <tools/sch_navigate_tool.h>
#include <font/outline_font.h>
#include "sim/sim_lib_mgr.h"
SCH_FIELD::SCH_FIELD( const VECTOR2I& aPos, int aFieldId, SCH_ITEM* aParent,
const wxString& aName ) :
@ -654,6 +655,127 @@ bool SCH_FIELD::Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) co
}
void SCH_FIELD::OnScintillaCharAdded( SCINTILLA_TRICKS* aScintillaTricks,
wxStyledTextEvent &aEvent ) const
{
SCH_ITEM* parent = dynamic_cast<SCH_ITEM*>( GetParent() );
SCHEMATIC* schematic = parent ? parent->Schematic() : nullptr;
if( !schematic )
return;
wxStyledTextCtrl* scintilla = aScintillaTricks->Scintilla();
int key = aEvent.GetKey();
wxArrayString autocompleteTokens;
int pos = scintilla->GetCurrentPos();
int start = scintilla->WordStartPosition( pos, true );
wxString partial;
// Currently, '\n' is not allowed in fields. So remove it when entered
// TODO: see if we must close the dialog. However this is not obvious, as
// if a \n is typed (and removed) when a text is selected, this text is deleted
// (in fact replaced by \n, that is removed by the filter)
if( key == '\n' )
{
wxString text = scintilla->GetText();
int currpos = scintilla->GetCurrentPos();
text.Replace( wxS( "\n" ), wxS( "" ) );
scintilla->SetText( text );
scintilla->GotoPos( currpos-1 );
return;
}
auto textVarRef =
[&]( int pt )
{
return pt >= 2
&& scintilla->GetCharAt( pt - 2 ) == '$'
&& scintilla->GetCharAt( pt - 1 ) == '{';
};
// Check for cross-reference
if( start > 1 && scintilla->GetCharAt( start - 1 ) == ':' )
{
int refStart = scintilla->WordStartPosition( start - 1, true );
if( textVarRef( refStart ) )
{
partial = scintilla->GetRange( start, pos );
wxString ref = scintilla->GetRange( refStart, start - 1 );
if( ref == wxS( "OP" ) )
{
// SPICE operating points use ':' syntax for ports
if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( parent ) )
{
SCH_SHEET_PATH& sheet = schematic->CurrentSheet();
SIM_LIB_MGR mgr( &schematic->Prj() );
SIM_MODEL& model = mgr.CreateModel( &sheet, *symbol ).model;
for( wxString pin : model.GetPinNames() )
{
if( pin.StartsWith( '<' ) && pin.EndsWith( '>' ) )
autocompleteTokens.push_back( pin.Mid( 1, pin.Length() - 2 ) );
else
autocompleteTokens.push_back( pin );
}
}
}
else
{
SCH_SHEET_LIST sheets = schematic->GetSheets();
SCH_REFERENCE_LIST refs;
SCH_SYMBOL* refSymbol = nullptr;
sheets.GetSymbols( refs );
for( size_t jj = 0; jj < refs.GetCount(); jj++ )
{
if( refs[ jj ].GetSymbol()->GetRef( &refs[ jj ].GetSheetPath(), true ) == ref )
{
refSymbol = refs[ jj ].GetSymbol();
break;
}
}
if( refSymbol )
refSymbol->GetContextualTextVars( &autocompleteTokens );
}
}
}
else if( textVarRef( start ) )
{
partial = scintilla->GetTextRange( start, pos );
SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( parent );
SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( parent );
SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( parent );
if( symbol )
{
symbol->GetContextualTextVars( &autocompleteTokens );
if( schematic->CurrentSheet().Last() )
schematic->CurrentSheet().Last()->GetContextualTextVars( &autocompleteTokens );
}
if( sheet )
sheet->GetContextualTextVars( &autocompleteTokens );
if( label )
label->GetContextualTextVars( &autocompleteTokens );
for( std::pair<wxString, wxString> entry : schematic->Prj().GetTextVars() )
autocompleteTokens.push_back( entry.first );
}
aScintillaTricks->DoAutocomplete( partial, autocompleteTokens );
scintilla->SetFocus();
}
bool SCH_FIELD::IsReplaceable() const
{
if( m_parent && m_parent->Type() == SCH_SHEET_T )

View File

@ -31,6 +31,7 @@
#include <sch_item.h>
#include <template_fieldnames.h>
#include <general.h>
#include "scintilla_tricks.h"
class SCH_EDIT_FRAME;
class LIB_FIELD;
@ -233,6 +234,8 @@ public:
{
}
void OnScintillaCharAdded( SCINTILLA_TRICKS* aScintillaTricks, wxStyledTextEvent &aEvent ) const;
bool Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const override;
bool Replace( const EDA_SEARCH_DATA& aSearchData, void* aAuxData = nullptr ) override;

View File

@ -37,8 +37,8 @@ class SCINTILLA_TRICKS : public wxEvtHandler
public:
SCINTILLA_TRICKS( wxStyledTextCtrl* aScintilla, const wxString& aBraces, bool aSingleLine,
std::function<void()> onAcceptHandler =
[]()
std::function<void( wxKeyEvent& )> onAcceptHandler =
[]( wxKeyEvent& aEvent )
{ },
std::function<void( wxStyledTextEvent& )> onCharAddedHandler =
[]( wxStyledTextEvent& )
@ -73,9 +73,8 @@ protected:
bool m_singleLine; // Treat <return> as OK, and skip special tab
// stop handling (including monospaced font).
std::function<void()> m_onAcceptHandler; // Process <return> in singleLine, and
// <shift> + <return> irrespective.
// Process <return> in singleLine, and <shift> + <return> irrespective.
std::function<void( wxKeyEvent& aEvent )> m_onAcceptHandler;
std::function<void( wxStyledTextEvent& aEvent )> m_onCharAddedHandler;
};

View File

@ -58,7 +58,7 @@ DIALOG_TEXT_PROPERTIES::DIALOG_TEXT_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent, PC
m_scintillaTricks = new SCINTILLA_TRICKS( m_MultiLineText, wxT( "{}" ), false,
// onAccept handler
[this]()
[this]( wxKeyEvent& aEvent )
{
wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
},

View File

@ -50,7 +50,7 @@ DIALOG_TEXTBOX_PROPERTIES::DIALOG_TEXTBOX_PROPERTIES( PCB_BASE_EDIT_FRAME* aPare
m_scintillaTricks = new SCINTILLA_TRICKS( m_MultiLineText, wxT( "{}" ), false,
// onAccept handler
[this]()
[this]( wxKeyEvent& aEvent )
{
wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
},

View File

@ -46,7 +46,7 @@ PANEL_SETUP_RULES::PANEL_SETUP_RULES( wxWindow* aParentWindow, PCB_EDIT_FRAME* a
m_helpWindow( nullptr )
{
m_scintillaTricks = new SCINTILLA_TRICKS( m_textEditor, wxT( "()" ), false,
[this]()
[this]( wxKeyEvent& aEvent )
{
wxPostEvent( PAGED_DIALOG::GetDialog( this ),
wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );