KiCad PCB EDA Suite
dialog_edit_label.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 <stambaughw@verizon.net>
6  * Copyright (C) 1992-2020 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 <fctsys.h>
27 #include <sch_edit_frame.h>
28 #include <base_units.h>
29 #include <sch_validators.h>
30 #include <tool/tool_manager.h>
31 #include <general.h>
32 #include <gr_text.h>
33 #include <confirm.h>
34 #include <sch_component.h>
35 #include <sch_reference_list.h>
36 #include <schematic.h>
37 #include <widgets/unit_binder.h>
38 #include <dialog_edit_label.h>
39 #include <kicad_string.h>
40 #include <tool/actions.h>
41 #include <scintilla_tricks.h>
42 
43 class SCH_EDIT_FRAME;
44 class SCH_TEXT;
45 
46 
48  DIALOG_LABEL_EDITOR_BASE( aParent ),
49  m_textSize( aParent, m_textSizeLabel, m_textSizeCtrl, m_textSizeUnits, false ),
50  m_netNameValidator( true ),
51  m_scintillaTricks( nullptr )
52 {
53  m_Parent = aParent;
54  m_CurrentText = aTextItem;
55 
56  switch( m_CurrentText->Type() )
57  {
58  case SCH_GLOBAL_LABEL_T: SetTitle( _( "Global Label Properties" ) ); break;
59  case SCH_HIER_LABEL_T: SetTitle( _( "Hierarchical Label Properties" ) ); break;
60  case SCH_LABEL_T: SetTitle( _( "Label Properties" ) ); break;
61  case SCH_SHEET_PIN_T: SetTitle( _( "Hierarchical Sheet Pin Properties" ) ); break;
62  default: SetTitle( _( "Text Properties" ) ); break;
63  }
64 
65  m_valueMultiLine->SetEOLMode( wxSTC_EOL_LF );
66 
68 
70  {
72  m_activeTextEntry = nullptr;
73 
74  m_labelSingleLine->Show( false );
75  m_valueSingleLine->Show( false );
76  m_labelCombo->Show( false );
77  m_valueCombo->Show( false );
78 
79  m_textEntrySizer->AddGrowableRow( 0 );
80  }
82  {
85 
86  m_labelSingleLine->Show( false ); m_valueSingleLine->Show( false );
87  m_labelMultiLine->Show( false ); m_valueMultiLine->Show( false );
88 
89  m_valueCombo->SetValidator( m_netNameValidator );
90  }
91  else
92  {
95 
96  m_labelCombo->Show( false );
97  m_valueCombo->Show( false );
98  m_labelMultiLine->Show( false );
99  m_valueMultiLine->Show( false );
100 
101  if( m_CurrentText->Type() != SCH_TEXT_T )
102  m_valueSingleLine->SetValidator( m_netNameValidator );
103 
104  m_valueCombo->SetValidator( m_netNameValidator );
105  }
106 
108 
111 
113  {
114  wxFont infoFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
115  infoFont.SetSymbolicSize( wxFONTSIZE_X_SMALL );
116  m_note1->SetFont( infoFont );
117  m_note2->SetFont( infoFont );
118  }
119  else
120  {
121  m_note1->Show( false );
122  m_note2->Show( false );
123  }
124 
125  m_sdbSizer1OK->SetDefault();
126  Layout();
127 
128  m_valueMultiLine->Bind( wxEVT_STC_CHARADDED, &DIALOG_LABEL_EDITOR::onScintillaCharAdded, this );
129 
130  // DIALOG_SHIM needs a unique hash_key because classname is not sufficient because the
131  // various versions have different controls so we want to store sizes for each version.
132  m_hash_key = TO_UTF8( GetTitle() );
133 
134 
135  // Now all widgets have the size fixed, call FinishDialogSettings
137 }
138 
139 
141 {
142  delete m_scintillaTricks;
143 }
144 
145 
146 wxString DIALOG_LABEL_EDITOR::convertKIIDsToReferences( const wxString& aSource ) const
147 {
148  wxString newbuf;
149  size_t sourceLen = aSource.length();
150 
151  for( size_t i = 0; i < sourceLen; ++i )
152  {
153  if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i+1] == '{' )
154  {
155  wxString token;
156  bool isCrossRef = false;
157 
158  for( i = i + 2; i < sourceLen; ++i )
159  {
160  if( aSource[i] == '}' )
161  break;
162 
163  if( aSource[i] == ':' )
164  isCrossRef = true;
165 
166  token.append( aSource[i] );
167  }
168 
169  if( isCrossRef )
170  {
171  SCH_SHEET_LIST sheetList = m_Parent->Schematic().GetSheets();
172  wxString remainder;
173  wxString ref = token.BeforeFirst( ':', &remainder );
174 
175  SCH_SHEET_PATH refSheetPath;
176  SCH_ITEM* refItem = sheetList.GetItem( KIID( ref ), &refSheetPath );
177 
178  if( refItem && refItem->Type() == SCH_COMPONENT_T )
179  {
180  SCH_COMPONENT* refComponent = static_cast<SCH_COMPONENT*>( refItem );
181  token = refComponent->GetRef( &refSheetPath, true ) + ":" + remainder;
182  }
183  }
184 
185  newbuf.append( "${" + token + "}" );
186  }
187  else
188  {
189  newbuf.append( aSource[i] );
190  }
191  }
192 
193  return newbuf;
194 }
195 
196 
197 wxString DIALOG_LABEL_EDITOR::convertReferencesToKIIDs( const wxString& aSource ) const
198 {
199  wxString newbuf;
200  size_t sourceLen = aSource.length();
201 
202  for( size_t i = 0; i < sourceLen; ++i )
203  {
204  if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i+1] == '{' )
205  {
206  wxString token;
207  bool isCrossRef = false;
208 
209  for( i = i + 2; i < sourceLen; ++i )
210  {
211  if( aSource[i] == '}' )
212  break;
213 
214  if( aSource[i] == ':' )
215  isCrossRef = true;
216 
217  token.append( aSource[i] );
218  }
219 
220  if( isCrossRef )
221  {
223  wxString remainder;
224  wxString ref = token.BeforeFirst( ':', &remainder );
225  SCH_REFERENCE_LIST references;
226 
227  sheets.GetComponents( references );
228 
229  for( size_t jj = 0; jj < references.GetCount(); jj++ )
230  {
231  SCH_COMPONENT* refComponent = references[ jj ].GetComp();
232 
233  if( ref == refComponent->GetRef( &references[ jj ].GetSheetPath(), true ) )
234  {
235  wxString test( remainder );
236 
237  if( refComponent->ResolveTextVar( &test ) )
238  token = refComponent->m_Uuid.AsString() + ":" + remainder;
239 
240  break;
241  }
242  }
243  }
244 
245  newbuf.append( "${" + token + "}" );
246  }
247  else
248  {
249  newbuf.append( aSource[i] );
250  }
251  }
252 
253  return newbuf;
254 }
255 
256 
258 {
259  if( !wxDialog::TransferDataToWindow() )
260  return false;
261 
262  if( m_CurrentText->Type() == SCH_TEXT_T )
263  {
264  // show text variable cross-references in a human-readable format
266  }
267  else
268  {
269  // show control characters in a human-readable format
271  }
272 
273  if( m_valueCombo->IsShown() )
274  {
275  // Load the combobox with the existing labels of the same type
276  std::set<wxString> existingLabels;
277  SCH_SCREENS allScreens( m_Parent->Schematic().Root() );
278 
279  for( SCH_SCREEN* screen = allScreens.GetFirst(); screen; screen = allScreens.GetNext() )
280  {
281  for( SCH_ITEM* item : screen->Items().OfType( m_CurrentText->Type() ) )
282  {
283  auto textItem = static_cast<const SCH_TEXT*>( item );
284  existingLabels.insert( UnescapeString( textItem->GetText() ) );
285  }
286  }
287 
288  wxArrayString existingLabelArray;
289 
290  for( const wxString& label : existingLabels )
291  existingLabelArray.push_back( label );
292 
293  // existingLabelArray.Sort();
294  m_valueCombo->Append( existingLabelArray );
295  }
296 
297  // Set text options:
298  m_TextOrient->SetSelection( static_cast<int>( m_CurrentText->GetLabelSpinStyle() ) );
299 
300  m_TextShape->SetSelection( static_cast<int>( m_CurrentText->GetShape() ) );
301 
302  int style = 0;
303 
304  if( m_CurrentText->IsItalic() )
305  style = 1;
306 
307  if( m_CurrentText->IsBold() )
308  style += 2;
309 
310  m_TextStyle->SetSelection( style );
311 
313 
314  return true;
315 }
316 
317 
321 void DIALOG_LABEL_EDITOR::OnEnterKey( wxCommandEvent& aEvent )
322 {
323  wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
324 }
325 
326 
327 void DIALOG_LABEL_EDITOR::onScintillaCharAdded( wxStyledTextEvent &aEvent )
328 {
329  wxStyledTextCtrl* te = m_valueMultiLine;
330  wxArrayString autocompleteTokens;
331  int text_pos = te->GetCurrentPos();
332  int start = te->WordStartPosition( text_pos, true );
333  wxString partial;
334 
335  auto textVarRef =
336  [&]( int pos )
337  {
338  return pos >= 2 && te->GetCharAt( pos-2 ) == '$' && te->GetCharAt( pos-1 ) == '{';
339  };
340 
341  // Check for cross-reference
342  if( start > 1 && te->GetCharAt( start-1 ) == ':' )
343  {
344  int refStart = te->WordStartPosition( start-1, true );
345 
346  if( textVarRef( refStart ) )
347  {
348  partial = te->GetRange( start+1, text_pos );
349 
350  wxString ref = te->GetRange( refStart, start-1 );
352  SCH_REFERENCE_LIST refs;
353  SCH_COMPONENT* refComponent = nullptr;
354 
355  sheets.GetComponents( refs );
356 
357  for( size_t jj = 0; jj < refs.GetCount(); jj++ )
358  {
359  if( refs[ jj ].GetComp()->GetRef( &refs[ jj ].GetSheetPath(), true ) == ref )
360  {
361  refComponent = refs[ jj ].GetComp();
362  break;
363  }
364  }
365 
366  if( refComponent )
367  refComponent->GetContextualTextVars( &autocompleteTokens );
368  }
369  }
370  else if( textVarRef( start ) )
371  {
372  partial = te->GetTextRange( start, text_pos );
373 
374  m_CurrentText->GetContextualTextVars( &autocompleteTokens );
375 
376  for( std::pair<wxString, wxString> entry : Prj().GetTextVars() )
377  autocompleteTokens.push_back( entry.first );
378  }
379 
380  m_scintillaTricks->DoAutocomplete( partial, autocompleteTokens );
381  m_valueMultiLine->SetFocus();
382 }
383 
384 
386 {
387  if( !wxDialog::TransferDataFromWindow() )
388  return false;
389 
390  // Don't allow text to disappear; it can be difficult to correct if you can't select it
391  if( !m_textSize.Validate( 0.01, 1000.0, EDA_UNITS::MILLIMETRES ) )
392  return false;
393 
394  wxString text;
395 
396  /* save old text in undo list if not already in edit */
397  if( m_CurrentText->GetEditFlags() == 0 )
399 
400  m_Parent->GetCanvas()->Refresh();
401 
402  if( m_CurrentText->Type() == SCH_TEXT_T )
403  {
404  // convert any text variable cross-references to their UUIDs
405  text = convertReferencesToKIIDs( m_valueMultiLine->GetValue() );
406  }
407  else
408  {
409  // labels need escaping
410  text = EscapeString( m_activeTextEntry->GetValue(), CTX_NETNAME );
411  }
412 
413  if( !text.IsEmpty() )
414  m_CurrentText->SetText( text );
415  else if( !m_CurrentText->IsNew() )
416  {
417  DisplayError( this, _( "Empty Text!" ) );
418  return false;
419  }
420 
422 
424 
425  if( m_TextShape )
427 
428  int style = m_TextStyle->GetSelection();
429 
430  m_CurrentText->SetItalic( ( style & 1 ) );
431 
432  if( ( style & 2 ) )
433  {
434  m_CurrentText->SetBold( true );
436  }
437  else
438  {
439  m_CurrentText->SetBold( false );
440  m_CurrentText->SetTextThickness( 0 ); // Use default pen width
441  }
442 
444  m_Parent->GetCanvas()->Refresh();
445  m_Parent->OnModify();
446 
447  return true;
448 }
449 
450 
451 void DIALOG_LABEL_EDITOR::OnFormattingHelp( wxHyperlinkEvent& aEvent )
452 {
453  SCH_TEXT::ShowSyntaxHelp( this );
454 }
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:239
SCH_SHEET_LIST.
bool IsBold() const
Definition: eda_text.h:182
void SetTitle(const wxString &aTitle) override
void SetShape(PINSHEETLABEL_SHAPE aShape)
Definition: sch_text.h:239
SCH_SHEET_LIST GetSheets() const
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:92
bool ResolveTextVar(wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the component.
wxTextEntry * m_activeTextEntry
SCH_ITEM * GetItem(const KIID &aID, SCH_SHEET_PATH *aPathOut=nullptr)
Fetch a SCH_ITEM by ID.
int GetPenSizeForBold(int aTextSize)
Function GetPensizeForBold.
Definition: gr_text.cpp:51
wxString convertKIIDsToReferences(const wxString &aSource) const
Implementation of conversion functions that require both schematic and board internal units.
This file is part of the common library.
void onScintillaCharAdded(wxStyledTextEvent &aEvent)
std::string m_hash_key
Definition: dialog_shim.h:198
SCINTILLA_TRICKS is used to add cut/copy/paste, autocomplete and brace highlighting to a wxStyleTextC...
void DoAutocomplete(const wxString &aPartial, const wxArrayString &aTokens)
void SetItalic(bool isItalic)
Definition: eda_text.h:178
void OnEnterKey(wxCommandEvent &aEvent) override
bool TransferDataToWindow() override
void FinishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
wxString AsString() const
Definition: common.cpp:165
Schematic editor (Eeschema) main window.
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:237
static void ShowSyntaxHelp(wxWindow *aParentWindow)
Definition: sch_text.cpp:1283
wxString convertReferencesToKIIDs(const wxString &aSource) const
Class DIALOG_LABEL_EDITOR_BASE.
SCH_EDIT_FRAME * m_Parent
wxFlexGridSizer * m_textEntrySizer
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:114
DIALOG_LABEL_EDITOR(SCH_EDIT_FRAME *parent, SCH_TEXT *aTextItem)
SCH_REFERENCE_LIST is used to create a flattened list of components because in a complex hierarchy,...
bool IsNew() const
Definition: base_struct.h:199
bool IsItalic() const
Definition: eda_text.h:179
void GetContextualTextVars(wxArrayString *aVars) const
Returns the set of contextual text variable tokens for this text item.
Definition: sch_text.cpp:474
Definition: common.h:68
void OnFormattingHelp(wxHyperlinkEvent &aEvent) override
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:116
void GetComponents(SCH_REFERENCE_LIST &aReferences, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanComponents=false) const
Function GetComponents adds a SCH_REFERENCE() object to aReferences for each component in the list of...
STATUS_FLAGS GetEditFlags() const
Definition: base_struct.h:237
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
SCH_NETNAME_VALIDATOR m_netNameValidator
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.
void SaveCopyInUndoList(SCH_ITEM *aItemToCopy, UNDO_REDO_T aTypeCommand, bool aAppend=false, const wxPoint &aTransformPoint=wxPoint(0, 0))
Create a copy of the current schematic item, and put it in the undo list.
SCHEMATIC & Schematic() const
LABEL_SPIN_STYLE GetLabelSpinStyle() const
Definition: sch_text.h:232
SCINTILLA_TRICKS * m_scintillaTricks
SCH_SHEET_PATH.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false)
Return the reference for the given sheet path.
void GetContextualTextVars(wxArrayString *aVars) const
Return the list of system text vars & fields for this symbol.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=NULL) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
bool IsMultilineAllowed() const
Definition: eda_text.h:196
bool TransferDataFromWindow() override
const KIID m_Uuid
Definition: base_struct.h:162
unsigned GetCount() const
Function GetCount.
virtual bool Validate(double aMin, double aMax, EDA_UNITS aUnits=EDA_UNITS::UNSCALED, bool aUseMils=false)
Function Validate Validates the control against the given range, informing the user of any errors fou...
PINSHEETLABEL_SHAPE
Definition: sch_text.h:150
SCH_SHEET & Root() const
Definition: schematic.h:97
int GetTextWidth() const
Definition: eda_text.h:241
void RefreshItem(EDA_ITEM *aItem, bool isAddOrDelete=false)
Mark an item for refresh.
#define _(s)
Definition: 3d_actions.cpp:33
wxString UnescapeString(const wxString &aSource)
Definition: string.cpp:131
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
These Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which ar...
Definition: string.cpp:50
virtual void SetValue(int aValue)
Function SetValue Sets new value (in Internal Units) for the text field, taking care of units convers...
Schematic symbol object.
Definition: sch_component.h:88
#define TO_UTF8(wxstring)
virtual long long int GetValue()
Function GetValue Returns the current value in Internal Units.
wxStyledTextCtrl * m_valueMultiLine
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.h:157
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current screen and u...
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:230
void SetBold(bool aBold)
Definition: eda_text.h:181
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:187
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:126
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:546
PINSHEETLABEL_SHAPE GetShape() const
Definition: sch_text.h:237
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193