Push much of text var autocomplete down into SCINTILLA_TRICKS.

Shared code == fewer bugs.  Well, in theory anyway....
This commit is contained in:
Jeff Young 2023-05-24 23:46:48 +01:00
parent 14f004d2a5
commit 1518ddde74
11 changed files with 156 additions and 200 deletions

View File

@ -33,8 +33,8 @@
#include <confirm.h>
SCINTILLA_TRICKS::SCINTILLA_TRICKS( wxStyledTextCtrl* aScintilla, const wxString& aBraces,
bool aSingleLine, std::function<void()> aReturnCallback,
std::function<void( wxStyledTextEvent& )> aCharCallback ) :
bool aSingleLine, std::function<void()> onAcceptHandler,
std::function<void( wxStyledTextEvent& )> onCharAddedHandler ) :
m_te( aScintilla ),
m_braces( aBraces ),
m_lastCaretPos( -1 ),
@ -42,8 +42,8 @@ SCINTILLA_TRICKS::SCINTILLA_TRICKS( wxStyledTextCtrl* aScintilla, const wxString
m_lastSelEnd( -1 ),
m_suppressAutocomplete( false ),
m_singleLine( aSingleLine ),
m_returnCallback( aReturnCallback ),
m_charCallback( aCharCallback )
m_onAcceptHandler( onAcceptHandler ),
m_onCharAddedHandler( onCharAddedHandler )
{
// Always use LF as eol char, regardless the platform
m_te->SetEOLMode( wxSTC_EOL_LF );
@ -165,7 +165,7 @@ bool isCtrlSlash( wxKeyEvent& aEvent )
void SCINTILLA_TRICKS::onChar( wxStyledTextEvent& aEvent )
{
m_charCallback( aEvent );
m_onCharAddedHandler( aEvent );
}
@ -179,7 +179,7 @@ void SCINTILLA_TRICKS::onCharHook( wxKeyEvent& aEvent )
if( ( aEvent.GetKeyCode() == WXK_RETURN || aEvent.GetKeyCode() == WXK_NUMPAD_ENTER )
&& ( m_singleLine || aEvent.ShiftDown() ) )
{
m_returnCallback();
m_onAcceptHandler();
}
else if( ConvertSmartQuotesAndDashes( &c ) )
{
@ -410,6 +410,42 @@ void SCINTILLA_TRICKS::onScintillaUpdateUI( wxStyledTextEvent& aEvent )
}
void SCINTILLA_TRICKS::DoTextVarAutocomplete( std::function<void( const wxString& crossRef,
wxArrayString* tokens )> aTokenProvider )
{
wxArrayString autocompleteTokens;
int text_pos = m_te->GetCurrentPos();
int start = m_te->WordStartPosition( text_pos, true );
wxString partial;
auto textVarRef =
[&]( int pos )
{
return pos >= 2 && m_te->GetCharAt( pos-2 ) == '$' && m_te->GetCharAt( pos-1 ) == '{';
};
// Check for cross-reference
if( start > 1 && m_te->GetCharAt( start-1 ) == ':' )
{
int refStart = m_te->WordStartPosition( start-1, true );
if( textVarRef( refStart ) )
{
partial = m_te->GetRange( start, text_pos );
aTokenProvider( m_te->GetRange( refStart, start-1 ), &autocompleteTokens );
}
}
else if( textVarRef( start ) )
{
partial = m_te->GetTextRange( start, text_pos );
aTokenProvider( wxEmptyString, &autocompleteTokens );
}
DoAutocomplete( partial, autocompleteTokens );
m_te->SetFocus();
}
void SCINTILLA_TRICKS::DoAutocomplete( const wxString& aPartial, const wxArrayString& aTokens )
{
if( m_suppressAutocomplete )

View File

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

View File

@ -103,9 +103,19 @@ DIALOG_TEXT_PROPERTIES::DIALOG_TEXT_PROPERTIES( SCH_EDIT_FRAME* aParent, SCH_ITE
m_textCtrl->SetEOLMode( wxSTC_EOL_LF );
m_scintillaTricks = new SCINTILLA_TRICKS( m_textCtrl, wxT( "{}" ), false,
// onAccept handler
[this]()
{
wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
},
// onCharAdded handler
[this]( wxStyledTextEvent& aEvent )
{
m_scintillaTricks->DoTextVarAutocomplete(
[this]( const wxString& crossRef, wxArrayString* tokens )
{
getContextualTextVars( crossRef, tokens );
} );
} );
m_textEntrySizer->AddGrowableRow( 0 );
@ -169,9 +179,6 @@ DIALOG_TEXT_PROPERTIES::DIALOG_TEXT_PROPERTIES( SCH_EDIT_FRAME* aParent, SCH_ITE
SetupStandardButtons();
Layout();
m_textCtrl->Bind( wxEVT_STC_CHARADDED, &DIALOG_TEXT_PROPERTIES::onScintillaCharAdded, this );
m_textCtrl->Bind( wxEVT_STC_AUTOCOMP_CHAR_DELETED,
&DIALOG_TEXT_PROPERTIES::onScintillaCharAdded, this );
m_hAlignLeft->Bind( wxEVT_BUTTON, &DIALOG_TEXT_PROPERTIES::onHAlignButton, this );
m_hAlignCenter->Bind( wxEVT_BUTTON, &DIALOG_TEXT_PROPERTIES::onHAlignButton, this );
m_hAlignRight->Bind( wxEVT_BUTTON, &DIALOG_TEXT_PROPERTIES::onHAlignButton, this );
@ -195,6 +202,44 @@ DIALOG_TEXT_PROPERTIES::~DIALOG_TEXT_PROPERTIES()
}
void DIALOG_TEXT_PROPERTIES::getContextualTextVars( const wxString& aCrossRef,
wxArrayString* aTokens )
{
if( !aCrossRef.IsEmpty() )
{
SCH_SHEET_LIST sheets = m_frame->Schematic().GetSheets();
SCH_REFERENCE_LIST refs;
SCH_SYMBOL* refSymbol = nullptr;
sheets.GetSymbols( refs );
for( int jj = 0; jj < (int) refs.GetCount(); jj++ )
{
SCH_REFERENCE& ref = refs[jj];
if( ref.GetSymbol()->GetRef( &ref.GetSheetPath(), true ) == aCrossRef )
{
refSymbol = ref.GetSymbol();
break;
}
}
if( refSymbol )
refSymbol->GetContextualTextVars( aTokens );
}
else
{
SCHEMATIC* schematic = m_currentItem->Schematic();
if( schematic && schematic->CurrentSheet().Last() )
schematic->CurrentSheet().Last()->GetContextualTextVars( aTokens );
for( std::pair<wxString, wxString> entry : Prj().GetTextVars() )
aTokens->push_back( entry.first );
}
}
bool DIALOG_TEXT_PROPERTIES::TransferDataToWindow()
{
if( !wxDialog::TransferDataToWindow() )
@ -353,67 +398,6 @@ void DIALOG_TEXT_PROPERTIES::onHyperlinkCombo( wxCommandEvent& aEvent )
}
void DIALOG_TEXT_PROPERTIES::onScintillaCharAdded( wxStyledTextEvent &aEvent )
{
wxStyledTextCtrl* te = m_textCtrl;
wxArrayString autocompleteTokens;
int text_pos = te->GetCurrentPos();
int start = te->WordStartPosition( text_pos, true );
wxString partial;
auto textVarRef =
[&]( int pos )
{
return pos >= 2 && te->GetCharAt( pos-2 ) == '$' && te->GetCharAt( pos-1 ) == '{';
};
// Check for cross-reference
if( start > 1 && te->GetCharAt( start-1 ) == ':' )
{
int refStart = te->WordStartPosition( start-1, true );
if( textVarRef( refStart ) )
{
partial = te->GetRange( start, text_pos );
wxString ref = te->GetRange( refStart, start-1 );
SCH_SHEET_LIST sheets = m_frame->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 = te->GetTextRange( start, text_pos );
SCHEMATIC* schematic = m_currentItem->Schematic();
if( schematic && schematic->CurrentSheet().Last() )
schematic->CurrentSheet().Last()->GetContextualTextVars( &autocompleteTokens );
for( std::pair<wxString, wxString> entry : Prj().GetTextVars() )
autocompleteTokens.push_back( entry.first );
}
m_scintillaTricks->DoAutocomplete( partial, autocompleteTokens );
m_textCtrl->SetFocus();
}
void DIALOG_TEXT_PROPERTIES::onHAlignButton( wxCommandEvent& aEvent )
{
for( BITMAP_BUTTON* btn : { m_hAlignLeft, m_hAlignCenter, m_hAlignRight } )

View File

@ -42,7 +42,8 @@ public:
~DIALOG_TEXT_PROPERTIES();
private:
void onScintillaCharAdded( wxStyledTextEvent &aEvent );
void getContextualTextVars( const wxString& aCrossRef, wxArrayString* aTokens );
void onHAlignButton( wxCommandEvent &aEvent );
void onVAlignButton( wxCommandEvent &aEvent );
void onTextAngleButton( wxCommandEvent &aEvent );

View File

@ -37,15 +37,18 @@ class SCINTILLA_TRICKS : public wxEvtHandler
public:
SCINTILLA_TRICKS( wxStyledTextCtrl* aScintilla, const wxString& aBraces, bool aSingleLine,
std::function<void()> aReturnCallback =
std::function<void()> onAcceptHandler =
[]()
{ },
std::function<void( wxStyledTextEvent& )> aCharCallback =
std::function<void( wxStyledTextEvent& )> onCharAddedHandler =
[]( wxStyledTextEvent& )
{ } );
wxStyledTextCtrl* Scintilla() const { return m_te; }
void DoTextVarAutocomplete( std::function<void( const wxString& crossRef,
wxArrayString* tokens )> aTokenProvider );
void DoAutocomplete( const wxString& aPartial, const wxArrayString& aTokens );
void CancelAutocomplete();
@ -70,10 +73,10 @@ protected:
bool m_singleLine; // Treat <return> as OK, and skip special tab
// stop handling (including monospaced font).
std::function<void()> m_returnCallback; // Process <return> in singleLine, and
std::function<void()> m_onAcceptHandler; // Process <return> in singleLine, and
// <shift> + <return> irrespective.
std::function<void( wxStyledTextEvent& aEvent )> m_charCallback;
std::function<void( wxStyledTextEvent& aEvent )> m_onCharAddedHandler;
};
#endif // SCINTILLA_TRICKS_H

View File

@ -58,9 +58,19 @@ DIALOG_TEXT_PROPERTIES::DIALOG_TEXT_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent, PC
m_MultiLineText->SetEOLMode( wxSTC_EOL_LF );
m_scintillaTricks = new SCINTILLA_TRICKS( m_MultiLineText, wxT( "{}" ), false,
// onAccept handler
[this]()
{
wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
},
// onCharAdded handler
[this]( wxStyledTextEvent& aEvent )
{
m_scintillaTricks->DoTextVarAutocomplete(
[this]( const wxString& crossRef, wxArrayString* tokens )
{
m_frame->GetContextualTextVars( m_item, crossRef, tokens );
} );
} );
// A hack which causes Scintilla to auto-size the text editor canvas
@ -165,11 +175,6 @@ DIALOG_TEXT_PROPERTIES::DIALOG_TEXT_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent, PC
Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXT_PROPERTIES::OnCharHook ),
nullptr, this );
m_MultiLineText->Bind( wxEVT_STC_CHARADDED,
&DIALOG_TEXT_PROPERTIES::onScintillaCharAdded, this );
m_MultiLineText->Bind( wxEVT_STC_AUTOCOMP_CHAR_DELETED,
&DIALOG_TEXT_PROPERTIES::onScintillaCharAdded, this );
finishDialogSettings();
}
@ -212,62 +217,6 @@ void DIALOG_TEXT_PROPERTIES::OnSetFocusText( wxFocusEvent& event )
}
void DIALOG_TEXT_PROPERTIES::onScintillaCharAdded( wxStyledTextEvent &aEvent )
{
wxStyledTextCtrl* te = m_MultiLineText;
wxArrayString autocompleteTokens;
int text_pos = te->GetCurrentPos();
int start = te->WordStartPosition( text_pos, true );
wxString partial;
auto textVarRef =
[&]( int pos )
{
return pos >= 2 && te->GetCharAt( pos-2 ) == '$' && te->GetCharAt( pos-1 ) == '{';
};
// Check for cross-reference
if( start > 1 && te->GetCharAt( start-1 ) == ':' )
{
int refStart = te->WordStartPosition( start-1, true );
if( textVarRef( refStart ) )
{
partial = te->GetRange( start, text_pos );
wxString ref = te->GetRange( refStart, start-1 );
BOARD* board = m_item->GetBoard();
for( FOOTPRINT* candidate : board->Footprints() )
{
if( candidate->GetReference() == ref )
{
candidate->GetContextualTextVars( &autocompleteTokens );
break;
}
}
}
}
else if( textVarRef( start ) )
{
partial = te->GetTextRange( start, text_pos );
BOARD* board = m_item->GetBoard();
board->GetContextualTextVars( &autocompleteTokens );
if( FOOTPRINT* footprint = m_item->GetParentFootprint() )
footprint->GetContextualTextVars( &autocompleteTokens );
for( std::pair<wxString, wxString> entry : board->GetProject()->GetTextVars() )
autocompleteTokens.push_back( entry.first );
}
m_scintillaTricks->DoAutocomplete( partial, autocompleteTokens );
m_MultiLineText->SetFocus();
}
bool DIALOG_TEXT_PROPERTIES::TransferDataToWindow()
{
BOARD* board = m_frame->GetBoard();

View File

@ -56,7 +56,6 @@ private:
void onAlignButton( wxCommandEvent &aEvent ) override;
void onValignButton( wxCommandEvent &aEvent ) override;
void onThickness( wxCommandEvent &aEvent ) override;
void onScintillaCharAdded( wxStyledTextEvent &aEvent );
bool TransferDataToWindow() override;
bool TransferDataFromWindow() override;

View File

@ -50,9 +50,19 @@ DIALOG_TEXTBOX_PROPERTIES::DIALOG_TEXTBOX_PROPERTIES( PCB_BASE_EDIT_FRAME* aPare
m_MultiLineText->SetEOLMode( wxSTC_EOL_LF );
m_scintillaTricks = new SCINTILLA_TRICKS( m_MultiLineText, wxT( "{}" ), false,
// onAccept handler
[this]()
{
wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
},
// onCharAdded handler
[this]( wxStyledTextEvent& aEvent )
{
m_scintillaTricks->DoTextVarAutocomplete(
[this]( const wxString& crossRef, wxArrayString* tokens )
{
m_frame->GetContextualTextVars( m_textBox, crossRef, tokens );
} );
} );
// A hack which causes Scintilla to auto-size the text editor canvas
@ -122,11 +132,6 @@ DIALOG_TEXTBOX_PROPERTIES::DIALOG_TEXTBOX_PROPERTIES( PCB_BASE_EDIT_FRAME* aPare
Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXTBOX_PROPERTIES::OnCharHook ),
nullptr, this );
m_MultiLineText->Bind( wxEVT_STC_CHARADDED,
&DIALOG_TEXTBOX_PROPERTIES::onScintillaCharAdded, this );
m_MultiLineText->Bind( wxEVT_STC_AUTOCOMP_CHAR_DELETED,
&DIALOG_TEXTBOX_PROPERTIES::onScintillaCharAdded, this );
finishDialogSettings();
}
@ -149,62 +154,6 @@ int PCB_BASE_EDIT_FRAME::ShowTextBoxPropertiesDialog( PCB_TEXTBOX* aTextBox )
}
void DIALOG_TEXTBOX_PROPERTIES::onScintillaCharAdded( wxStyledTextEvent &aEvent )
{
wxStyledTextCtrl* te = m_MultiLineText;
wxArrayString autocompleteTokens;
int text_pos = te->GetCurrentPos();
int start = te->WordStartPosition( text_pos, true );
wxString partial;
auto textVarRef =
[&]( int pos )
{
return pos >= 2 && te->GetCharAt( pos-2 ) == '$' && te->GetCharAt( pos-1 ) == '{';
};
// Check for cross-reference
if( start > 1 && te->GetCharAt( start-1 ) == ':' )
{
int refStart = te->WordStartPosition( start-1, true );
if( textVarRef( refStart ) )
{
partial = te->GetRange( start, text_pos );
wxString ref = te->GetRange( refStart, start-1 );
BOARD* board = m_textBox->GetBoard();
for( FOOTPRINT* candidate : board->Footprints() )
{
if( candidate->GetReference() == ref )
{
candidate->GetContextualTextVars( &autocompleteTokens );
break;
}
}
}
}
else if( textVarRef( start ) )
{
partial = te->GetTextRange( start, text_pos );
BOARD* board = m_textBox->GetBoard();
board->GetContextualTextVars( &autocompleteTokens );
if( FOOTPRINT* footprint = m_textBox->GetParentFootprint() )
footprint->GetContextualTextVars( &autocompleteTokens );
for( std::pair<wxString, wxString> entry : board->GetProject()->GetTextVars() )
autocompleteTokens.push_back( entry.first );
}
m_scintillaTricks->DoAutocomplete( partial, autocompleteTokens );
m_MultiLineText->SetFocus();
}
bool DIALOG_TEXTBOX_PROPERTIES::TransferDataToWindow()
{
BOARD* board = m_frame->GetBoard();

View File

@ -47,7 +47,6 @@ private:
void onAlignButton( wxCommandEvent &aEvent ) override;
void onThickness( wxCommandEvent &aEvent ) override;
void onBorderChecked( wxCommandEvent& event ) override;
void onScintillaCharAdded( wxStyledTextEvent &aEvent );
bool TransferDataToWindow() override;
bool TransferDataFromWindow() override;

View File

@ -33,6 +33,7 @@
#include <board.h>
#include <board_design_settings.h>
#include <pcb_dimension.h>
#include <footprint.h>
#include <footprint_info_impl.h>
#include <project.h>
#include <settings/color_settings.h>
@ -41,7 +42,6 @@
#include <widgets/pcb_properties_panel.h>
#include <dialogs/eda_view_switcher.h>
#include <wildcards_and_files_ext.h>
#include <collectors.h>
#include <widgets/wx_aui_utils.h>
@ -322,3 +322,34 @@ void PCB_BASE_EDIT_FRAME::ToggleProperties()
m_auimgr.Update();
}
}
void PCB_BASE_EDIT_FRAME::GetContextualTextVars( BOARD_ITEM* aSourceItem, const wxString& aCrossRef,
wxArrayString* aTokens )
{
BOARD* board = aSourceItem->GetBoard();
if( !aCrossRef.IsEmpty() )
{
for( FOOTPRINT* candidate : board->Footprints() )
{
if( candidate->GetReference() == aCrossRef )
{
candidate->GetContextualTextVars( aTokens );
break;
}
}
}
else
{
board->GetContextualTextVars( aTokens );
if( FOOTPRINT* footprint = aSourceItem->GetParentFootprint() )
footprint->GetContextualTextVars( aTokens );
for( std::pair<wxString, wxString> entry : board->GetProject()->GetTextVars() )
aTokens->push_back( entry.first );
}
}

View File

@ -226,6 +226,9 @@ public:
void ToggleProperties();
void GetContextualTextVars( BOARD_ITEM* aSourceItem, const wxString& aCrossRef,
wxArrayString* aTokens );
protected:
/**
* Prompts a user to select global or project library tables