diff --git a/common/env_vars.cpp b/common/env_vars.cpp index 06f4d67578..1971acc677 100644 --- a/common/env_vars.cpp +++ b/common/env_vars.cpp @@ -20,6 +20,7 @@ #include <build_version.h> #include <env_vars.h> #include <settings/environment.h> +#include <core/kicad_algo.h> #include <map> @@ -27,15 +28,13 @@ #include <wx/translation.h> #include <wx/utils.h> -using STRING_MAP = std::map<wxString, wxString>; - /** * List of pre-defined environment variables. * * @todo Instead of defining these values here, extract them from elsewhere in the program * (where they are originally defined). */ -static const ENV_VAR::ENV_VAR_LIST predefinedEnvVars = { +static const std::vector<wxString> predefinedEnvVars = { wxS( "KIPRJMOD" ), ENV_VAR::GetVersionedEnvVarName( wxS( "SYMBOL_DIR" ) ), ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ), @@ -65,12 +64,22 @@ bool ENV_VAR::IsEnvVarImmutable( const wxString& aEnvVar ) } -const ENV_VAR::ENV_VAR_LIST& ENV_VAR::GetPredefinedEnvVars() +const std::vector<wxString>& ENV_VAR::GetPredefinedEnvVars() { return predefinedEnvVars; } +void ENV_VAR::GetEnvVarAutocompleteTokens( wxArrayString* aVars ) +{ + for( const wxString& var : ENV_VAR::GetPredefinedEnvVars() ) + { + if( !alg::contains( *aVars, var ) ) + aVars->push_back( var ); + } +} + + wxString ENV_VAR::GetVersionedEnvVarName( const wxString& aBaseName ) { int version = 0; @@ -100,43 +109,46 @@ std::optional<wxString> ENV_VAR::GetVersionedEnvVarValue( const ENV_VAR_MAP& aMa } -static void initialiseEnvVarHelp( STRING_MAP& aMap ) +static void initialiseEnvVarHelp( std::map<wxString, wxString>& aMap ) { // Set up dynamically, as we want to be able to use _() translations, // which can't be done statically aMap[ENV_VAR::GetVersionedEnvVarName( wxS( "FOOTPRINT_DIR" ) )] = - _( "The base path of locally installed system " - "footprint libraries (.pretty folders)."); + _( "The base path of locally installed system footprint libraries (.pretty folders)." ); + aMap[ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) )] = - _( "The base path of system footprint 3D shapes (.3Dshapes folders)."); + _( "The base path of system footprint 3D shapes (.3Dshapes folders)." ); + aMap[ENV_VAR::GetVersionedEnvVarName( wxS( "SYMBOL_DIR" ) )] = - _( "The base path of the locally installed symbol libraries."); + _( "The base path of the locally installed symbol libraries." ); + aMap[ENV_VAR::GetVersionedEnvVarName( wxS( "TEMPLATE_DIR" ) )] = - _( "A directory containing project templates installed with KiCad."); + _( "A directory containing project templates installed with KiCad." ); + aMap[wxS( "KICAD_USER_TEMPLATE_DIR" )] = - _( "Optional. Can be defined if you want to create your own project " - "templates folder."); + _( "Optional. Can be defined if you want to create your own project templates folder." ); + aMap[ENV_VAR::GetVersionedEnvVarName( wxS( "3RD_PARTY" ) )] = - _( "A directory containing 3rd party plugins, libraries and other " - "downloadable content."); + _( "A directory containing 3rd party plugins, libraries and other downloadable content." ); + aMap[wxS( "KIPRJMOD" )] = - _("Internally defined by KiCad (cannot be edited) and is set " - "to the absolute path of the currently loaded project file. This environment " - "variable can be used to define files and paths relative to the currently loaded " - "project. For instance, ${KIPRJMOD}/libs/footprints.pretty can be defined as a " - "folder containing a project specific footprint library named footprints.pretty." ); + _( "Internally defined by KiCad (cannot be edited) and is set to the absolute path of the currently " + "loaded project file. This environment variable can be used to define files and paths relative " + "to the currently loaded project. For instance, ${KIPRJMOD}/libs/footprints.pretty can be " + "defined as a folder containing a project specific footprint library named footprints.pretty." ); + aMap[ENV_VAR::GetVersionedEnvVarName( wxS( "SCRIPTING_DIR" ) )] = - _( "A directory containing system-wide scripts installed with KiCad" ); + _( "A directory containing system-wide scripts installed with KiCad." ); + aMap[ENV_VAR::GetVersionedEnvVarName( wxS( "USER_SCRIPTING_DIR" ) )] = - _( "A directory containing user-specific scripts installed with KiCad" ); + _( "A directory containing user-specific scripts installed with KiCad." ); // Deprecated vars #define DEP( var ) wxString::Format( _( "Deprecated version of %s." ), var ) - aMap[wxS( "KICAD_PTEMPLATES" )] = - DEP( ENV_VAR::GetVersionedEnvVarName( wxS( "TEMPLATE_DIR" ) ) ); - aMap[wxS( "KISYS3DMOD" )] = DEP( ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ) ); - aMap[wxS( "KISYSMOD" )] = DEP( ENV_VAR::GetVersionedEnvVarName( wxS( "FOOTPRINT_DIR" ) ) ); + aMap[wxS( "KICAD_PTEMPLATES" )] = DEP( ENV_VAR::GetVersionedEnvVarName( wxS( "TEMPLATE_DIR" ) ) ); + aMap[wxS( "KISYS3DMOD" )] = DEP( ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ) ); + aMap[wxS( "KISYSMOD" )] = DEP( ENV_VAR::GetVersionedEnvVarName( wxS( "FOOTPRINT_DIR" ) ) ); aMap[wxS( "KICAD_SYMBOL_DIR" )] = DEP( ENV_VAR::GetVersionedEnvVarName( wxS( "SYMBOL_DIR" ) ) ); #undef DEP @@ -145,7 +157,7 @@ static void initialiseEnvVarHelp( STRING_MAP& aMap ) wxString ENV_VAR::LookUpEnvVarHelp( const wxString& aEnvVar ) { - static STRING_MAP envVarHelpText; + static std::map<wxString, wxString> envVarHelpText; if( envVarHelpText.size() == 0 ) initialiseEnvVarHelp( envVarHelpText ); @@ -175,13 +187,10 @@ template<> std::optional<wxString> ENV_VAR::GetEnvVar( const wxString& aEnvVarName ) { std::optional<wxString> optValue; - - wxString env; + wxString env; if( wxGetEnv( aEnvVarName, &env ) ) - { optValue = env; - } return optValue; } diff --git a/common/scintilla_tricks.cpp b/common/scintilla_tricks.cpp index 67c2b0111a..08614ca0b6 100644 --- a/common/scintilla_tricks.cpp +++ b/common/scintilla_tricks.cpp @@ -572,8 +572,8 @@ void SCINTILLA_TRICKS::onScintillaUpdateUI( wxStyledTextEvent& aEvent ) } -void SCINTILLA_TRICKS::DoTextVarAutocomplete( - const std::function<void( const wxString& xRef, wxArrayString* tokens )>& getTokensFn ) +void SCINTILLA_TRICKS::DoTextVarAutocomplete( const std::function<void( const wxString& xRef, + wxArrayString* tokens )>& getTokensFn ) { wxArrayString autocompleteTokens; int text_pos = m_te->GetCurrentPos(); diff --git a/include/env_vars.h b/include/env_vars.h index 68e4a6fc88..0a302ca163 100644 --- a/include/env_vars.h +++ b/include/env_vars.h @@ -28,6 +28,7 @@ #include <kicommon.h> #include <wx/string.h> +#include <wx/arrstr.h> #include <map> #include <vector> #include <optional> @@ -36,8 +37,6 @@ class ENV_VAR_ITEM; namespace ENV_VAR { - using ENV_VAR_LIST = std::vector<wxString>; - /** * Determine if an environment variable is "predefined", i.e. if the * name of the variable is special to KiCad, and isn't just a user-specified @@ -51,7 +50,12 @@ namespace ENV_VAR /** * Get the list of pre-defined environment variables. */ - KICOMMON_API const ENV_VAR_LIST& GetPredefinedEnvVars(); + KICOMMON_API const std::vector<wxString>& GetPredefinedEnvVars(); + + /** + * Return autocomplete tokens for environment variables for Scintilla. + */ + KICOMMON_API void GetEnvVarAutocompleteTokens( wxArrayString* aVars ); /** * Construct a versioned environment variable based on this KiCad major version. diff --git a/kicad/dialogs/dialog_executecommand_job_settings.cpp b/kicad/dialogs/dialog_executecommand_job_settings.cpp index aaf6855cfc..79e0a10494 100644 --- a/kicad/dialogs/dialog_executecommand_job_settings.cpp +++ b/kicad/dialogs/dialog_executecommand_job_settings.cpp @@ -20,18 +20,46 @@ #include <dialogs/dialog_executecommand_job_settings.h> #include <jobs/job_special_execute.h> +#include <scintilla_tricks.h> +#include <env_vars.h> + DIALOG_EXECUTECOMMAND_JOB_SETTINGS::DIALOG_EXECUTECOMMAND_JOB_SETTINGS( wxWindow* aParent, JOB_SPECIAL_EXECUTE* aJob ) : DIALOG_EXECUTECOMMAND_JOB_SETTINGS_BASE( aParent ), - m_job( aJob ) + m_job( aJob ), + m_scintillaTricks( nullptr ) { + m_scintillaTricks = new SCINTILLA_TRICKS( m_textCtrlCommand, wxT( "{}" ), false, + // onAcceptFn + [this]( wxKeyEvent& aEvent ) + { + wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) ); + }, + + // onCharFn + [this]( wxStyledTextEvent& aEvent ) + { + m_scintillaTricks->DoTextVarAutocomplete( + // getTokensFn + []( const wxString& xRef, wxArrayString* tokens ) + { + ENV_VAR::GetEnvVarAutocompleteTokens( tokens ); + } ); + } ); + SetupStandardButtons(); finishDialogSettings(); } +DIALOG_EXECUTECOMMAND_JOB_SETTINGS::~DIALOG_EXECUTECOMMAND_JOB_SETTINGS() +{ + delete m_scintillaTricks; +} + + bool DIALOG_EXECUTECOMMAND_JOB_SETTINGS::TransferDataFromWindow() { m_job->m_command = m_textCtrlCommand->GetValue(); diff --git a/kicad/dialogs/dialog_executecommand_job_settings.h b/kicad/dialogs/dialog_executecommand_job_settings.h index 90f534f2a6..f696b8755e 100644 --- a/kicad/dialogs/dialog_executecommand_job_settings.h +++ b/kicad/dialogs/dialog_executecommand_job_settings.h @@ -21,17 +21,23 @@ #include <dialogs/dialog_executecommand_job_settings_base.h> class JOB_SPECIAL_EXECUTE; +class SCINTILLA_TRICKS; + class DIALOG_EXECUTECOMMAND_JOB_SETTINGS: public DIALOG_EXECUTECOMMAND_JOB_SETTINGS_BASE { public: DIALOG_EXECUTECOMMAND_JOB_SETTINGS( wxWindow* aParent, JOB_SPECIAL_EXECUTE* aJob ); + ~DIALOG_EXECUTECOMMAND_JOB_SETTINGS(); bool TransferDataFromWindow() override; bool TransferDataToWindow() override; +private: + void OnRecordOutputClicked( wxCommandEvent& event ) override; + private: JOB_SPECIAL_EXECUTE* m_job; - void OnRecordOutputClicked( wxCommandEvent& event ) override; + SCINTILLA_TRICKS* m_scintillaTricks; }; \ No newline at end of file diff --git a/kicad/dialogs/dialog_executecommand_job_settings_base.cpp b/kicad/dialogs/dialog_executecommand_job_settings_base.cpp index 4657ab6993..a397dc1295 100644 --- a/kicad/dialogs/dialog_executecommand_job_settings_base.cpp +++ b/kicad/dialogs/dialog_executecommand_job_settings_base.cpp @@ -25,13 +25,39 @@ DIALOG_EXECUTECOMMAND_JOB_SETTINGS_BASE::DIALOG_EXECUTECOMMAND_JOB_SETTINGS_BASE m_textCommand = new wxStaticText( this, wxID_ANY, _("Command:"), wxDefaultPosition, wxDefaultSize, 0 ); m_textCommand->Wrap( -1 ); - fgSizer1->Add( m_textCommand, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + fgSizer1->Add( m_textCommand, 0, wxALL, 5 ); - m_textCtrlCommand = new wxTextCtrl( this, wxID_ANY, _("Enter the command line to run SPICE\nUsually '<path to SPICE binary> \"%I\"'\n%I will be replaced by the netlist filepath"), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE ); - m_textCtrlCommand->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) ); - m_textCtrlCommand->SetMinSize( wxSize( 400,-1 ) ); - - fgSizer1->Add( m_textCtrlCommand, 1, wxEXPAND|wxRIGHT, 5 ); + m_textCtrlCommand = new wxStyledTextCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, wxEmptyString ); + m_textCtrlCommand->SetUseTabs( false ); + m_textCtrlCommand->SetTabWidth( 4 ); + m_textCtrlCommand->SetIndent( 4 ); + m_textCtrlCommand->SetTabIndents( false ); + m_textCtrlCommand->SetBackSpaceUnIndents( false ); + m_textCtrlCommand->SetViewEOL( false ); + m_textCtrlCommand->SetViewWhiteSpace( false ); + m_textCtrlCommand->SetMarginWidth( 2, 0 ); + m_textCtrlCommand->SetIndentationGuides( false ); + m_textCtrlCommand->SetReadOnly( false ); + m_textCtrlCommand->SetMarginWidth( 1, 0 ); + m_textCtrlCommand->SetMarginWidth( 0, 0 ); + m_textCtrlCommand->MarkerDefine( wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS ); + m_textCtrlCommand->MarkerSetBackground( wxSTC_MARKNUM_FOLDER, wxColour( wxT("BLACK") ) ); + m_textCtrlCommand->MarkerSetForeground( wxSTC_MARKNUM_FOLDER, wxColour( wxT("WHITE") ) ); + m_textCtrlCommand->MarkerDefine( wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS ); + m_textCtrlCommand->MarkerSetBackground( wxSTC_MARKNUM_FOLDEROPEN, wxColour( wxT("BLACK") ) ); + m_textCtrlCommand->MarkerSetForeground( wxSTC_MARKNUM_FOLDEROPEN, wxColour( wxT("WHITE") ) ); + m_textCtrlCommand->MarkerDefine( wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_EMPTY ); + m_textCtrlCommand->MarkerDefine( wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_BOXPLUS ); + m_textCtrlCommand->MarkerSetBackground( wxSTC_MARKNUM_FOLDEREND, wxColour( wxT("BLACK") ) ); + m_textCtrlCommand->MarkerSetForeground( wxSTC_MARKNUM_FOLDEREND, wxColour( wxT("WHITE") ) ); + m_textCtrlCommand->MarkerDefine( wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BOXMINUS ); + m_textCtrlCommand->MarkerSetBackground( wxSTC_MARKNUM_FOLDEROPENMID, wxColour( wxT("BLACK") ) ); + m_textCtrlCommand->MarkerSetForeground( wxSTC_MARKNUM_FOLDEROPENMID, wxColour( wxT("WHITE") ) ); + m_textCtrlCommand->MarkerDefine( wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_EMPTY ); + m_textCtrlCommand->MarkerDefine( wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_EMPTY ); + m_textCtrlCommand->SetSelBackground( true, wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) ); + m_textCtrlCommand->SetSelForeground( true, wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT ) ); + fgSizer1->Add( m_textCtrlCommand, 1, wxEXPAND|wxTOP|wxBOTTOM|wxRIGHT, 5 ); m_textOutputPath = new wxStaticText( this, wxID_ANY, _("Output path:"), wxDefaultPosition, wxDefaultSize, 0 ); m_textOutputPath->Wrap( -1 ); diff --git a/kicad/dialogs/dialog_executecommand_job_settings_base.fbp b/kicad/dialogs/dialog_executecommand_job_settings_base.fbp index 272bf0fdfd..cafdf167f0 100644 --- a/kicad/dialogs/dialog_executecommand_job_settings_base.fbp +++ b/kicad/dialogs/dialog_executecommand_job_settings_base.fbp @@ -82,7 +82,7 @@ <property name="vgap">5</property> <object class="sizeritem" expanded="false"> <property name="border">5</property> - <property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property> + <property name="flag">wxALL</property> <property name="proportion">0</property> <object class="wxStaticText" expanded="false"> <property name="BottomDockable">1</property> @@ -142,11 +142,11 @@ <property name="wrap">-1</property> </object> </object> - <object class="sizeritem" expanded="false"> + <object class="sizeritem" expanded="true"> <property name="border">5</property> - <property name="flag">wxEXPAND|wxRIGHT</property> + <property name="flag">wxEXPAND|wxTOP|wxBOTTOM|wxRIGHT</property> <property name="proportion">1</property> - <object class="wxTextCtrl" expanded="false"> + <object class="wxStyledTextCtrl" expanded="true"> <property name="BottomDockable">1</property> <property name="LeftDockable">1</property> <property name="RightDockable">1</property> @@ -155,6 +155,7 @@ <property name="aui_name"></property> <property name="aui_position">0</property> <property name="aui_row">0</property> + <property name="backspace_unindents">0</property> <property name="best_size"></property> <property name="bg"></property> <property name="caption"></property> @@ -171,17 +172,19 @@ <property name="enabled">1</property> <property name="fg"></property> <property name="floatable">1</property> - <property name="font">,90,400,-1,70,0</property> + <property name="folding">0</property> + <property name="font"></property> <property name="gripper">0</property> <property name="hidden">0</property> <property name="id">wxID_ANY</property> + <property name="indentation_guides">0</property> + <property name="line_numbers">0</property> <property name="max_size"></property> <property name="maximize_button">0</property> <property name="maximum_size"></property> - <property name="maxlength">0</property> <property name="min_size"></property> <property name="minimize_button">0</property> - <property name="minimum_size">400,-1</property> + <property name="minimum_size"></property> <property name="moveable">1</property> <property name="name">m_textCtrlCommand</property> <property name="pane_border">1</property> @@ -190,18 +193,18 @@ <property name="permission">protected</property> <property name="pin_button">1</property> <property name="pos"></property> + <property name="read_only">0</property> <property name="resize">Resizable</property> <property name="show">1</property> <property name="size"></property> - <property name="style">wxTE_MULTILINE</property> <property name="subclass">; ; forward_declare</property> + <property name="tab_indents">0</property> + <property name="tab_width">4</property> <property name="toolbar_pane">0</property> <property name="tooltip"></property> - <property name="validator_data_type"></property> - <property name="validator_style">wxFILTER_NONE</property> - <property name="validator_type">wxDefaultValidator</property> - <property name="validator_variable"></property> - <property name="value">Enter the command line to run SPICE
Usually '<path to SPICE binary> "%I"'
%I will be replaced by the netlist filepath</property> + <property name="use_tabs">0</property> + <property name="view_eol">0</property> + <property name="view_whitespace">0</property> <property name="window_extra_style"></property> <property name="window_name"></property> <property name="window_style"></property> diff --git a/kicad/dialogs/dialog_executecommand_job_settings_base.h b/kicad/dialogs/dialog_executecommand_job_settings_base.h index 9979ae7abc..accf922c5c 100644 --- a/kicad/dialogs/dialog_executecommand_job_settings_base.h +++ b/kicad/dialogs/dialog_executecommand_job_settings_base.h @@ -17,6 +17,7 @@ #include <wx/font.h> #include <wx/colour.h> #include <wx/settings.h> +#include <wx/stc/stc.h> #include <wx/textctrl.h> #include <wx/sizer.h> #include <wx/checkbox.h> @@ -34,7 +35,7 @@ class DIALOG_EXECUTECOMMAND_JOB_SETTINGS_BASE : public DIALOG_SHIM protected: wxStaticText* m_textCommand; - wxTextCtrl* m_textCtrlCommand; + wxStyledTextCtrl* m_textCtrlCommand; wxStaticText* m_textOutputPath; wxTextCtrl* m_textCtrlOutputPath; wxCheckBox* m_cbRecordOutput; diff --git a/kicad/dialogs/panel_jobset.cpp b/kicad/dialogs/panel_jobset.cpp index c86588a60d..8917c15a06 100644 --- a/kicad/dialogs/panel_jobset.cpp +++ b/kicad/dialogs/panel_jobset.cpp @@ -389,12 +389,9 @@ void JOBS_GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent ) menu.Append( JOB_DESCRIPTION, _( "Edit Job Description" ) ); menu.Append( JOB_PROPERTIES, _( "Edit Job Settings..." ) ); menu.AppendSeparator(); - menu.Append( GRIDTRICKS_ID_COPY, _( "Copy" ) + "\tCtrl+C", - _( "Copy selected cells to clipboard" ) ); - menu.Append( GRIDTRICKS_ID_DELETE, _( "Delete" ) + "\tDel", - _( "Delete selected jobs" ) ); - menu.Append( GRIDTRICKS_ID_SELECT, _( "Select All" ) + "\tCtrl+A", - _( "Select all jobs" ) ); + menu.Append( GRIDTRICKS_ID_COPY, _( "Copy" ) + "\tCtrl+C", _( "Copy selected cells to clipboard" ) ); + menu.Append( GRIDTRICKS_ID_DELETE, _( "Delete" ) + "\tDel", _( "Delete selected jobs" ) ); + menu.Append( GRIDTRICKS_ID_SELECT, _( "Select All" ) + "\tCtrl+A", _( "Select all jobs" ) ); menu.Enable( JOB_DESCRIPTION, selectedRows.size() == 1 ); menu.Enable( JOB_PROPERTIES, selectedRows.size() == 1 ); @@ -632,13 +629,13 @@ bool PANEL_JOBSET::OpenJobOptionsForListItem( size_t aItemIndex ) DIALOG_EXECUTECOMMAND_JOB_SETTINGS dialog( m_frame, specialJob ); - if( dialog.ShowModal() == wxID_OK ) + // QuasiModal for Scintilla autocomplete + if( dialog.ShowQuasiModal() == wxID_OK ) success = true; } else if( job.m_job->GetType() == "special_copyfiles" ) { - JOB_SPECIAL_COPYFILES* specialJob = - static_cast<JOB_SPECIAL_COPYFILES*>( job.m_job.get() ); + JOB_SPECIAL_COPYFILES* specialJob = static_cast<JOB_SPECIAL_COPYFILES*>( job.m_job.get() ); DIALOG_COPYFILES_JOB_SETTINGS dialog( m_frame, specialJob ); if( dialog.ShowModal() == wxID_OK )