KiCad PCB EDA Suite
dialog_text_and_label_properties.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2013 Wayne Stambaugh <[email protected]>
6  * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include <sch_edit_frame.h>
27 #include <base_units.h>
28 #include <sch_validators.h>
29 #include <tool/tool_manager.h>
30 #include <general.h>
31 #include <gr_text.h>
32 #include <confirm.h>
33 #include <sch_symbol.h>
34 #include <sch_reference_list.h>
35 #include <schematic.h>
38 #include <string_utils.h>
39 #include <tool/actions.h>
40 #include <scintilla_tricks.h>
41 
42 class SCH_EDIT_FRAME;
43 class SCH_TEXT;
44 
45 
47  SCH_TEXT* aTextItem ) :
49  m_textSize( aParent, m_textSizeLabel, m_textSizeCtrl, m_textSizeUnits, false ),
50  m_netNameValidator( true ),
51  m_scintillaTricks( nullptr ),
52  m_helpWindow( nullptr )
53 {
54  m_Parent = aParent;
55  m_CurrentText = aTextItem;
56 
57  m_valueMultiLine->SetEOLMode( wxSTC_EOL_LF );
58 
59  m_scintillaTricks = new SCINTILLA_TRICKS( m_valueMultiLine, wxT( "{}" ), false,
60  [this]()
61  {
62  wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
63  } );
64 
66  {
68  m_activeTextEntry = nullptr;
69 
70  m_labelSingleLine->Show( false );
71  m_valueSingleLine->Show( false );
72  m_labelCombo->Show( false );
73  m_valueCombo->Show( false );
74 
75  m_textEntrySizer->AddGrowableRow( 0 );
76  }
78  {
81 
82  m_labelSingleLine->Show( false ); m_valueSingleLine->Show( false );
83  m_labelMultiLine->Show( false ); m_valueMultiLine->Show( false );
84 
85  m_valueCombo->SetValidator( m_netNameValidator );
86  }
87  else
88  {
91 
92  m_labelCombo->Show( false );
93  m_valueCombo->Show( false );
94  m_labelMultiLine->Show( false );
95  m_valueMultiLine->Show( false );
96 
97  if( m_CurrentText->Type() != SCH_TEXT_T )
98  m_valueSingleLine->SetValidator( m_netNameValidator );
99 
100  m_valueCombo->SetValidator( m_netNameValidator );
101  }
102 
103  switch( m_CurrentText->Type() )
104  {
105  case SCH_GLOBAL_LABEL_T: SetTitle( _( "Global Label Properties" ) ); break;
106  case SCH_HIER_LABEL_T: SetTitle( _( "Hierarchical Label Properties" ) ); break;
107  case SCH_LABEL_T: SetTitle( _( "Label Properties" ) ); break;
108  case SCH_SHEET_PIN_T: SetTitle( _( "Hierarchical Sheet Pin Properties" ) ); break;
109  default: SetTitle( _( "Text Properties" ) ); break;
110  }
111 
113 
116 
118  {
119  m_note1->SetFont( KIUI::GetInfoFont( this ).Italic() );
120  m_note2->SetFont( KIUI::GetInfoFont( this ).Italic() );
121  }
122  else
123  {
124  m_note1->Show( false );
125  m_note2->Show( false );
126  }
127 
128  m_sdbSizer1OK->SetDefault();
129  Layout();
130 
132 
133  // DIALOG_SHIM needs a unique hash_key because classname is not sufficient because the
134  // various versions have different controls so we want to store sizes for each version.
135  m_hash_key = TO_UTF8( GetTitle() );
136 
137 
138  // Now all widgets have the size fixed, call FinishDialogSettings
140 }
141 
142 
144 {
145  delete m_scintillaTricks;
146 
147  if( m_helpWindow )
148  m_helpWindow->Destroy();
149 }
150 
151 
152 void DIALOG_TEXT_AND_LABEL_PROPERTIES::SetTitle( const wxString& aTitle )
153 {
154  // This class is shared for numerous tasks: a couple of single line labels and
155  // multi-line text fields. Since the desired size of the multi-line text field editor
156  // is often larger, we retain separate sizes based on the dialog titles.
157  switch( m_CurrentText->Type() )
158  {
159  case SCH_GLOBAL_LABEL_T:
160  case SCH_HIER_LABEL_T:
161  case SCH_LABEL_T:
162  // labels can share retained settings probably.
163  break;
164 
165  default:
166  m_hash_key = TO_UTF8( aTitle );
167  m_hash_key += typeid(*this).name();
168  }
169 
170  DIALOG_TEXT_AND_LABEL_PROPERTIES_BASE::SetTitle( aTitle );
171 }
172 
173 
175 {
176  if( !wxDialog::TransferDataToWindow() )
177  return false;
178 
179  SCHEMATIC& schematic = m_Parent->Schematic();
180 
181  if( m_CurrentText->Type() == SCH_TEXT_T )
182  {
183  // show text variable cross-references in a human-readable format
184  m_valueMultiLine->SetValue( schematic.ConvertKIIDsToRefs( m_CurrentText->GetText() ) );
185  }
186  else
187  {
188  // show control characters in a human-readable format
189  wxString text = UnescapeString( m_CurrentText->GetText() );
190 
191  // show text variable cross-references in a human-readable format
192  text = schematic.ConvertKIIDsToRefs( text );
193 
194  m_activeTextEntry->SetValue( text );
195  }
196 
197  if( m_valueCombo->IsShown() )
198  {
199  // Load the combobox with the existing labels of the same type
200  std::set<wxString> existingLabels;
201  SCH_SCREENS allScreens( m_Parent->Schematic().Root() );
202 
203  for( SCH_SCREEN* screen = allScreens.GetFirst(); screen; screen = allScreens.GetNext() )
204  {
205  for( SCH_ITEM* item : screen->Items().OfType( m_CurrentText->Type() ) )
206  {
207  auto textItem = static_cast<const SCH_TEXT*>( item );
208  existingLabels.insert( UnescapeString( textItem->GetText() ) );
209  }
210  }
211 
212  wxArrayString existingLabelArray;
213 
214  for( const wxString& label : existingLabels )
215  existingLabelArray.push_back( label );
216 
217  // existingLabelArray.Sort();
218  m_valueCombo->Append( existingLabelArray );
219  }
220 
221  // Set text options:
222  m_TextOrient->SetSelection( static_cast<int>( m_CurrentText->GetLabelSpinStyle() ) );
223 
224  m_TextShape->SetSelection( static_cast<int>( m_CurrentText->GetShape() ) );
225 
226  int style = 0;
227 
228  if( m_CurrentText->IsItalic() )
229  style = 1;
230 
231  if( m_CurrentText->IsBold() )
232  style += 2;
233 
234  m_TextStyle->SetSelection( style );
235 
237 
238  return true;
239 }
240 
241 
245 void DIALOG_TEXT_AND_LABEL_PROPERTIES::OnEnterKey( wxCommandEvent& aEvent )
246 {
247  wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
248 }
249 
250 
252 {
253  wxStyledTextCtrl* te = m_valueMultiLine;
254  wxArrayString autocompleteTokens;
255  int text_pos = te->GetCurrentPos();
256  int start = te->WordStartPosition( text_pos, true );
257  wxString partial;
258 
259  auto textVarRef =
260  [&]( int pos )
261  {
262  return pos >= 2 && te->GetCharAt( pos-2 ) == '$' && te->GetCharAt( pos-1 ) == '{';
263  };
264 
265  // Check for cross-reference
266  if( start > 1 && te->GetCharAt( start-1 ) == ':' )
267  {
268  int refStart = te->WordStartPosition( start-1, true );
269 
270  if( textVarRef( refStart ) )
271  {
272  partial = te->GetRange( start+1, text_pos );
273 
274  wxString ref = te->GetRange( refStart, start-1 );
276  SCH_REFERENCE_LIST refs;
277  SCH_SYMBOL* refSymbol = nullptr;
278 
279  sheets.GetSymbols( refs );
280 
281  for( size_t jj = 0; jj < refs.GetCount(); jj++ )
282  {
283  if( refs[ jj ].GetSymbol()->GetRef( &refs[ jj ].GetSheetPath(), true ) == ref )
284  {
285  refSymbol = refs[ jj ].GetSymbol();
286  break;
287  }
288  }
289 
290  if( refSymbol )
291  refSymbol->GetContextualTextVars( &autocompleteTokens );
292  }
293  }
294  else if( textVarRef( start ) )
295  {
296  partial = te->GetTextRange( start, text_pos );
297 
298  m_CurrentText->GetContextualTextVars( &autocompleteTokens );
299 
300  SCHEMATIC* schematic = m_CurrentText->Schematic();
301 
302  if( schematic && schematic->CurrentSheet().Last() )
303  schematic->CurrentSheet().Last()->GetContextualTextVars( &autocompleteTokens );
304 
305  for( std::pair<wxString, wxString> entry : Prj().GetTextVars() )
306  autocompleteTokens.push_back( entry.first );
307  }
308 
309  m_scintillaTricks->DoAutocomplete( partial, autocompleteTokens );
310  m_valueMultiLine->SetFocus();
311 }
312 
313 
315 {
316  if( !wxDialog::TransferDataFromWindow() )
317  return false;
318 
319  // Don't allow text to disappear; it can be difficult to correct if you can't select it
320  if( !m_textSize.Validate( 0.01, 1000.0, EDA_UNITS::MILLIMETRES ) )
321  return false;
322 
323  SCHEMATIC& schematic = m_Parent->Schematic();
324  wxString text;
325 
326  /* save old text in undo list if not already in edit */
327  if( m_CurrentText->GetEditFlags() == 0 )
329 
330  m_Parent->GetCanvas()->Refresh();
331 
332  if( m_CurrentText->Type() == SCH_TEXT_T )
333  {
334  text = m_valueMultiLine->GetValue();
335  }
336  else
337  {
338  // labels need escaping
340  }
341 
342  // convert any text variable cross-references to their UUIDs
343  text = schematic.ConvertRefsToKIIDs( text );
344 
345  if( !text.IsEmpty() )
346  {
347 #ifdef __WXMAC__
348  // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting
349  text.Replace( wxT( "\r" ), wxT( "\n" ) );
350 #endif
352  }
353  else if( !m_CurrentText->IsNew() )
354  {
355  DisplayError( this, _( "Label requires non-empty text." ) );
356  return false;
357  }
358 
359  LABEL_SPIN_STYLE selectedSpinStyle(
360  static_cast<LABEL_SPIN_STYLE::SPIN>( m_TextOrient->GetSelection() ) );
361 
362  if( m_CurrentText->GetLabelSpinStyle() != selectedSpinStyle )
363  m_CurrentText->SetLabelSpinStyle( selectedSpinStyle );
364 
367 
368  if( m_TextShape )
370 
371  int style = m_TextStyle->GetSelection();
372  bool wantItalic = ( style & 1 ) > 0;
373  bool wantBold = (style & 2 ) > 0;
374 
375  m_CurrentText->SetItalic( wantItalic );
376 
377  if( wantBold != m_CurrentText->IsBold() )
378  {
379  if( wantBold )
380  {
381  m_CurrentText->SetBold( true );
383  }
384  else
385  {
386  m_CurrentText->SetBold( false );
387  m_CurrentText->SetTextThickness( 0 ); // Use default pen width
388  }
389  }
390 
391  m_Parent->UpdateItem( m_CurrentText, false, true );
392  m_Parent->GetCanvas()->Refresh();
393  m_Parent->OnModify();
394 
396  {
397  SCH_GLOBALLABEL* label = static_cast<SCH_GLOBALLABEL*>( m_CurrentText );
398  label->UpdateIntersheetRefProps();
399  }
400 
401  return true;
402 }
403 
404 
406 {
407  if( m_scintillaTricks )
409 
410  event.Skip();
411 }
412 
413 
415 {
417 }
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:279
Class DIALOG_TEXT_AND_LABEL_PROPERTIES_BASE.
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
bool IsBold() const
Definition: eda_text.h:204
void SetShape(PINSHEETLABEL_SHAPE aShape)
Definition: sch_text.h:163
int GetPenSizeForBold(int aTextSize)
Definition: gr_text.cpp:46
void onScintillaCharAdded(wxStyledTextEvent &aEvent)
Holds all the data relating to one schematic.
Definition: schematic.h:59
void GetSymbols(SCH_REFERENCE_LIST &aReferences, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Add a SCH_REFERENCE object to aReferences for each symbol in the list of sheets.
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
Implementation of conversion functions that require both schematic and board internal units.
This file is part of the common library.
std::string m_hash_key
Definition: dialog_shim.h:201
Add cut/copy/paste, dark theme, autocomplete and brace highlighting to a wxStyleTextCtrl instance.
void DoAutocomplete(const wxString &aPartial, const wxArrayString &aTokens)
void SetItalic(bool isItalic)
Definition: eda_text.h:200
void onMultiLineTCLostFocus(wxFocusEvent &event) override
SCHEMATIC * Schematic() const
Searches the item hierarchy to find a SCHEMATIC.
Definition: sch_item.cpp:104
wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:144
void GetContextualTextVars(wxArrayString *aVars) const
Return the list of system text vars & fields for this sheet.
Definition: sch_sheet.cpp:215
Schematic editor (Eeschema) main window.
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:258
void OnEnterKey(wxCommandEvent &aEvent) override
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:97
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
bool IsNew() const
Definition: eda_item.h:118
bool IsItalic() const
Definition: eda_text.h:201
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
void GetContextualTextVars(wxArrayString *aVars) const
Return the set of contextual text variable tokens for this text item.
Definition: sch_text.cpp:590
void GetContextualTextVars(wxArrayString *aVars) const
Return the list of system text vars & fields for this symbol.
Definition: sch_symbol.cpp:958
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:124
wxString ConvertRefsToKIIDs(const wxString &aSource) const
Definition: schematic.cpp:288
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
Definitions of control validators for schematic dialogs.
SCHEMATIC & Schematic() const
size_t GetCount() const
DIALOG_TEXT_AND_LABEL_PROPERTIES(SCH_EDIT_FRAME *parent, SCH_TEXT *aTextItem)
#define _(s)
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false, bool aUpdateRtree=false)
Mark an item for refresh.
LABEL_SPIN_STYLE GetLabelSpinStyle() const
Definition: sch_text.h:159
EDA_ITEM_FLAGS GetEditFlags() const
Definition: eda_item.h:157
void UpdateIntersheetRefProps()
Definition: sch_text.cpp:1204
wxString UnescapeString(const wxString &aSource)
bool IsMultilineAllowed() const
Definition: eda_text.h:217
wxString ConvertKIIDsToRefs(const wxString &aSource) const
Definition: schematic.cpp:344
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
SCH_SHEET_LIST GetSheets() const override
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:87
static HTML_MESSAGE_BOX * ShowSyntaxHelp(wxWindow *aParentWindow)
Definition: sch_text.cpp:1741
PINSHEETLABEL_SHAPE
Definition: sch_text.h:95
SCH_SHEET & Root() const
Definition: schematic.h:92
virtual bool Validate(double aMin, double aMax, EDA_UNITS aUnits=EDA_UNITS::UNSCALED)
Validate the control against the given range, informing the user of any errors found.
int GetTextWidth() const
Definition: eda_text.h:262
Schematic symbol object.
Definition: sch_symbol.h:78
void SaveCopyInUndoList(SCH_SCREEN *aScreen, SCH_ITEM *aItemToCopy, UNDO_REDO aTypeCommand, bool aAppend)
Create a copy of the current schematic item, and put it in the undo list.
virtual void SetValue(int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
virtual long long int GetValue()
Return the current value in Internal Units.
void OnFormattingHelp(wxHyperlinkEvent &aEvent) override
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.h:180
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current screen and u...
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
void SetTitle(const wxString &aTitle) override
virtual void SetLabelSpinStyle(LABEL_SPIN_STYLE aSpinStyle)
Set a spin or rotation angle, along with specific horizontal and vertical justification styles with e...
Definition: sch_text.cpp:330
SCH_SHEET_PATH & CurrentSheet() const override
Definition: schematic.h:121
void SetBold(bool aBold)
Definition: eda_text.h:203
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:154
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:593
PINSHEETLABEL_SHAPE GetShape() const
Definition: sch_text.h:161
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112