Hook up text variable auto-complete for PCBNew.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/14777
This commit is contained in:
Jeff Young 2023-05-24 12:08:52 +01:00
parent 5a9ed66cfd
commit 14f004d2a5
9 changed files with 152 additions and 11 deletions

View File

@ -1003,7 +1003,7 @@ SCH_TEXT* SCH_DRAWING_TOOLS::createNewText( const VECTOR2I& aPosition, int aType
{ {
DIALOG_TEXT_PROPERTIES dlg( m_frame, textItem ); DIALOG_TEXT_PROPERTIES dlg( m_frame, textItem );
// Must be quasi modal for syntax help // QuasiModal required for syntax help and Scintilla auto-complete
if( dlg.ShowQuasiModal() != wxID_OK ) if( dlg.ShowQuasiModal() != wxID_OK )
{ {
delete textItem; delete textItem;
@ -1648,7 +1648,7 @@ int SCH_DRAWING_TOOLS::DrawShape( const TOOL_EVENT& aEvent )
getViewControls()->SetAutoPan( false ); getViewControls()->SetAutoPan( false );
getViewControls()->CaptureCursor( false ); getViewControls()->CaptureCursor( false );
// Must be quasi modal for syntax help // QuasiModal required for syntax help and Scintilla auto-complete
if( dlg.ShowQuasiModal() != wxID_OK ) if( dlg.ShowQuasiModal() != wxID_OK )
{ {
cleanup(); cleanup();

View File

@ -1873,7 +1873,7 @@ int SCH_EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
{ {
DIALOG_TEXT_PROPERTIES dlg( m_frame, static_cast<SCH_ITEM*>( curr_item ) ); DIALOG_TEXT_PROPERTIES dlg( m_frame, static_cast<SCH_ITEM*>( curr_item ) );
// Must be quasi modal for syntax help // QuasiModal required for syntax help and Scintilla auto-complete
if( dlg.ShowQuasiModal() == wxID_OK ) if( dlg.ShowQuasiModal() == wxID_OK )
{ {
m_toolMgr->PostEvent( EVENTS::SelectedItemsModified ); m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );

View File

@ -352,6 +352,24 @@ std::vector<PCB_MARKER*> BOARD::ResolveDRCExclusions( bool aCreateMarkers )
} }
void BOARD::GetContextualTextVars( wxArrayString* aVars ) const
{
auto add =
[&]( const wxString& aVar )
{
if( !alg::contains( *aVars, aVar ) )
aVars->push_back( aVar );
};
add( wxT( "LAYER" ) );
GetTitleBlock().GetContextualTextVars( aVars );
for( std::pair<wxString, wxString> entry : GetProject()->GetTextVars() )
add( entry.first );
}
bool BOARD::ResolveTextVar( wxString* token, int aDepth ) const bool BOARD::ResolveTextVar( wxString* token, int aDepth ) const
{ {
if( token->Contains( ':' ) ) if( token->Contains( ':' ) )

View File

@ -339,6 +339,7 @@ public:
const std::map<wxString, wxString>& GetProperties() const { return m_properties; } const std::map<wxString, wxString>& GetProperties() const { return m_properties; }
void SetProperties( const std::map<wxString, wxString>& aProps ) { m_properties = aProps; } void SetProperties( const std::map<wxString, wxString>& aProps ) { m_properties = aProps; }
void GetContextualTextVars( wxArrayString* aVars ) const;
bool ResolveTextVar( wxString* token, int aDepth ) const; bool ResolveTextVar( wxString* token, int aDepth ) const;
/// Visibility settings stored in board prior to 6.0, only used for loading legacy files /// Visibility settings stored in board prior to 6.0, only used for loading legacy files

View File

@ -26,17 +26,15 @@
#include <widgets/font_choice.h> #include <widgets/font_choice.h>
#include <dialog_text_properties.h> #include <dialog_text_properties.h>
#include <confirm.h> #include <confirm.h>
#include <widgets/unit_binder.h>
#include <board_commit.h> #include <board_commit.h>
#include <board.h> #include <board.h>
#include <footprint.h> #include <footprint.h>
#include <string_utils.h>
#include <pcb_text.h> #include <pcb_text.h>
#include <pcbnew.h> #include <pcbnew.h>
#include <project.h>
#include <pcb_edit_frame.h> #include <pcb_edit_frame.h>
#include <pcb_layer_box_selector.h> #include <pcb_layer_box_selector.h>
#include <wx/valnum.h> #include <wx/valnum.h>
#include <math/util.h> // for KiROUND
#include <scintilla_tricks.h> #include <scintilla_tricks.h>
@ -167,6 +165,11 @@ DIALOG_TEXT_PROPERTIES::DIALOG_TEXT_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent, PC
Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXT_PROPERTIES::OnCharHook ), Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXT_PROPERTIES::OnCharHook ),
nullptr, this ); 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(); finishDialogSettings();
} }
@ -209,6 +212,62 @@ 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() bool DIALOG_TEXT_PROPERTIES::TransferDataToWindow()
{ {
BOARD* board = m_frame->GetBoard(); BOARD* board = m_frame->GetBoard();

View File

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

View File

@ -25,19 +25,16 @@
#include <widgets/font_choice.h> #include <widgets/font_choice.h>
#include <dialog_textbox_properties.h> #include <dialog_textbox_properties.h>
#include <confirm.h> #include <confirm.h>
#include <widgets/unit_binder.h>
#include <board_commit.h> #include <board_commit.h>
#include <board_design_settings.h> #include <board_design_settings.h>
#include <board.h> #include <board.h>
#include <footprint.h> #include <footprint.h>
#include <string_utils.h>
#include <pcb_textbox.h> #include <pcb_textbox.h>
#include <pcbnew.h> #include <pcbnew.h>
#include <project.h>
#include <pcb_edit_frame.h> #include <pcb_edit_frame.h>
#include <pcb_layer_box_selector.h> #include <pcb_layer_box_selector.h>
#include <math/util.h> // for KiROUND
#include <scintilla_tricks.h> #include <scintilla_tricks.h>
#include "macros.h"
DIALOG_TEXTBOX_PROPERTIES::DIALOG_TEXTBOX_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent, DIALOG_TEXTBOX_PROPERTIES::DIALOG_TEXTBOX_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent,
PCB_TEXTBOX* aTextBox ) : PCB_TEXTBOX* aTextBox ) :
@ -125,6 +122,11 @@ DIALOG_TEXTBOX_PROPERTIES::DIALOG_TEXTBOX_PROPERTIES( PCB_BASE_EDIT_FRAME* aPare
Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXTBOX_PROPERTIES::OnCharHook ), Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXTBOX_PROPERTIES::OnCharHook ),
nullptr, this ); 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(); finishDialogSettings();
} }
@ -141,10 +143,68 @@ DIALOG_TEXTBOX_PROPERTIES::~DIALOG_TEXTBOX_PROPERTIES()
int PCB_BASE_EDIT_FRAME::ShowTextBoxPropertiesDialog( PCB_TEXTBOX* aTextBox ) int PCB_BASE_EDIT_FRAME::ShowTextBoxPropertiesDialog( PCB_TEXTBOX* aTextBox )
{ {
DIALOG_TEXTBOX_PROPERTIES dlg( this, aTextBox ); DIALOG_TEXTBOX_PROPERTIES dlg( this, aTextBox );
// QuasiModal required for Scintilla auto-complete
return dlg.ShowQuasiModal(); return dlg.ShowQuasiModal();
} }
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() bool DIALOG_TEXTBOX_PROPERTIES::TransferDataToWindow()
{ {
BOARD* board = m_frame->GetBoard(); BOARD* board = m_frame->GetBoard();

View File

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

View File

@ -888,7 +888,8 @@ int DRAWING_TOOL::PlaceText( const TOOL_EVENT& aEvent )
RunMainStack( [&]() RunMainStack( [&]()
{ {
cancelled = !textDialog.ShowModal(); // QuasiModal required for Scintilla auto-complete
cancelled = !textDialog.ShowQuasiModal();
} ); } );
if( cancelled || NoPrintableChars( text->GetText() ) ) if( cancelled || NoPrintableChars( text->GetText() ) )