KiCad PCB EDA Suite
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) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2004-2019 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <fctsys.h>
26 #include <gr_basic.h>
27 #include <base_struct.h>
28 #include <gr_text.h>
29 #include <sch_draw_panel.h>
30 #include <confirm.h>
31 #include <sch_edit_frame.h>
32 #include <tool/tool_manager.h>
33 #include <tools/ee_actions.h>
34 #include <general.h>
35 #include <sch_text.h>
36 #include <sch_view.h>
37 
38 #include <wx/tokenzr.h>
39 
40 #include "invoke_sch_dialog.h"
41 
44 static bool lastTextBold = false;
45 static bool lastTextItalic = false;
46 
47 static std::deque<std::unique_ptr<SCH_TEXT>> s_queuedTexts;
48 
50 {
51  if( s_queuedTexts.empty() )
52  return nullptr;
53 
54  auto next_text = std::move( s_queuedTexts.front() );
55  s_queuedTexts.pop_front();
56 
57  return next_text.release();
58 }
59 
60 
62 {
64  SCH_TEXT* textItem = nullptr;
65 
66  s_queuedTexts.clear();
67 
68  switch( aType )
69  {
70  case LAYER_NOTES:
71  textItem = new SCH_TEXT( cursorPos );
72  break;
73 
74  case LAYER_LOCLABEL:
75  textItem = new SCH_LABEL( cursorPos );
76  break;
77 
78  case LAYER_HIERLABEL:
79  textItem = new SCH_HIERLABEL( cursorPos );
80  textItem->SetShape( lastGlobalLabelShape );
81  break;
82 
83  case LAYER_GLOBLABEL:
84  textItem = new SCH_GLOBALLABEL( cursorPos );
85  textItem->SetShape( lastGlobalLabelShape );
86  break;
87 
88  default:
89  DisplayError( this, wxT( "SCH_EDIT_FRAME::CreateNewText() Internal error" ) );
90  return nullptr;
91  }
92 
93  textItem->SetBold( lastTextBold );
94  textItem->SetItalic( lastTextItalic );
96  textItem->SetTextSize( wxSize( GetDefaultTextSize(), GetDefaultTextSize() ) );
97  textItem->SetFlags( IS_NEW | IS_MOVED );
98 
99  if( InvokeDialogLabelEditor( this, textItem ) != wxID_OK || textItem->GetText().IsEmpty() )
100  {
101  delete textItem;
102  return nullptr;
103  }
104 
105  if( aType != LAYER_NOTES )
106  {
107  UTF8 text( textItem->GetText() );
108  int brace_count = 0;
109  int bracket_count = 0;
110  bool last_space = false;
111  UTF8 token;
112 
113  for( auto chIt = text.ubegin(); chIt != text.uend(); chIt++ )
114  {
115  switch( *chIt )
116  {
117  case '{':
118  brace_count++;
119  last_space = false;
120  break;
121 
122  case '[':
123  bracket_count++;
124  last_space = false;
125  break;
126 
127  case '}':
128  brace_count = std::max( 0, brace_count - 1 );
129  last_space = false;
130  break;
131 
132  case ']':
133  bracket_count = std::max( 0, bracket_count - 1 );
134  last_space = false;
135  break;
136 
137  case ' ':
138  case '\n':
139  case '\r':
140  case '\t':
141  if( !token.empty() && bracket_count == 0 && brace_count == 0 )
142  {
143  std::unique_ptr<SCH_TEXT> nextitem( static_cast<SCH_TEXT*>( textItem->Clone() ) );
144  nextitem->SetText( token.wx_str() );
145  s_queuedTexts.push_back( std::move( nextitem ) );
146  token.clear();
147  continue;
148  }
149 
150  // Skip leading whitespace
151  if( token.empty() || last_space )
152  continue;
153 
154  last_space = true;
155  break;
156 
157  default:
158  last_space = false;
159  break;
160  }
161 
162  token += *chIt;
163  }
164 
165  if( !token.empty() )
166  {
167  std::unique_ptr<SCH_TEXT> nextitem( static_cast<SCH_TEXT*>( textItem->Clone() ) );
168  nextitem->SetText( token.wx_str() );
169  s_queuedTexts.push_back( std::move( nextitem ) );
170  }
171 
172  delete textItem;
173  textItem = GetNextNewText();
174 
175  if( !textItem )
176  return nullptr;
177  }
178 
179  lastTextBold = textItem->IsBold();
180  lastTextItalic = textItem->IsItalic();
182 
183  if( textItem->Type() == SCH_GLOBAL_LABEL_T || textItem->Type() == SCH_HIER_LABEL_T )
184  lastGlobalLabelShape = textItem->GetShape();
185 
186  return textItem;
187 }
188 
189 
191 {
192  KICAD_T oldType = aText->Type();
193  bool selected = aText->IsSelected();
194 
195  wxCHECK_RET( aText->CanIncrementLabel(), "Cannot convert text type." );
196 
197  if( oldType == aNewType )
198  return;
199 
200  SCH_TEXT* newtext = nullptr;
201  const wxPoint& position = aText->GetPosition();
202  LABEL_SPIN_STYLE orientation = aText->GetLabelSpinStyle();
203  wxString txt = UnescapeString( aText->GetText() );
204 
205  // There can be characters in a SCH_TEXT object that can break labels so we have to
206  // fix them here.
207  if( oldType == SCH_TEXT_T )
208  {
209  txt.Replace( "\n", "_" );
210  txt.Replace( "\r", "_" );
211  txt.Replace( "\t", "_" );
212  txt.Replace( " ", "_" );
213  }
214 
215  // label strings are "escaped" i.e. a '/' is replaced by "{slash}"
216  if( aNewType != SCH_TEXT_T )
217  txt = EscapeString( txt, CTX_NETNAME );
218 
219  switch( aNewType )
220  {
221  case SCH_LABEL_T: newtext = new SCH_LABEL( position, txt ); break;
222  case SCH_GLOBAL_LABEL_T: newtext = new SCH_GLOBALLABEL( position, txt ); break;
223  case SCH_HIER_LABEL_T: newtext = new SCH_HIERLABEL( position, txt ); break;
224  case SCH_TEXT_T: newtext = new SCH_TEXT( position, txt ); break;
225 
226  default:
227  wxFAIL_MSG( wxString::Format( "Invalid text type: %d.", aNewType ) );
228  return;
229  }
230 
231  // Copy the old text item settings to the new one. Justifications are not copied
232  // because they are not used in labels. Justifications will be set to default value
233  // in the new text item type.
234  //
235  newtext->SetFlags( aText->GetEditFlags() );
236  newtext->SetShape( aText->GetShape() );
237  newtext->SetLabelSpinStyle( orientation );
238  newtext->SetTextSize( aText->GetTextSize() );
239  newtext->SetThickness( aText->GetThickness() );
240  newtext->SetItalic( aText->IsItalic() );
241  newtext->SetBold( aText->IsBold() );
242  newtext->SetIsDangling( aText->IsDangling() );
243 
244  if( selected )
246 
247  if( !aText->IsNew() )
248  {
249  SaveCopyInUndoList( aText, UR_DELETED );
250  SaveCopyInUndoList( newtext, UR_NEW, true );
251 
252  RemoveFromScreen( aText );
253  AddToScreen( newtext );
254  }
255 
256  if( selected )
258 
259  // Otherwise, pointer is owned by the undo stack
260  if( aText->IsNew() )
261  delete aText;
262 
263  if( aNewType == SCH_TEXT_T )
264  {
265  if( newtext->IsDangling() )
266  {
267  newtext->SetIsDangling( false );
268  GetCanvas()->GetView()->Update( newtext, KIGFX::REPAINT );
269  }
270  }
271  else
273 
274  OnModify();
275 }
276 
277 
278 /*
279  * Function to increment bus label numbers. Adds aIncrement to labels which end in numbers.
280  */
281 void IncrementLabelMember( wxString& name, int aIncrement )
282 {
283  int ii, nn;
284  long number = 0;
285 
286  ii = name.Len() - 1; nn = 0;
287 
288  if( !wxIsdigit( name.GetChar( ii ) ) )
289  return;
290 
291  while( (ii >= 0) && wxIsdigit( name.GetChar( ii ) ) )
292  {
293  ii--; nn++;
294  }
295 
296  ii++; /* digits are starting at ii position */
297  wxString litt_number = name.Right( nn );
298 
299  if( litt_number.ToLong( &number ) )
300  {
301  number += aIncrement;
302  name.Remove( ii ); name << number;
303  }
304 }
bool IsDangling() const override
Definition: sch_text.h:302
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:236
UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to...
Definition: utf8.h:73
KIGFX::SCH_VIEW * GetView() const override
Function GetView() Returns a pointer to the VIEW instance used in the panel.
bool IsBold() const
Definition: eda_text.h:167
void SetShape(PINSHEETLABEL_SHAPE aShape)
Definition: sch_text.h:245
KIGFX::VIEW_CONTROLS * GetViewControls() const
Function GetViewControls() Returns a pointer to the VIEW_CONTROLS instance used in the panel.
SCH_TEXT * CreateNewText(int aType)
Definition: edit_label.cpp:61
bool IsSelected() const
Definition: base_struct.h:223
void AddToScreen(EDA_ITEM *aItem, SCH_SCREEN *aScreen=nullptr)
Add an item to the screen (and view) aScreen is the screen the item is located on,...
This file is part of the common library.
static PINSHEETLABEL_SHAPE lastGlobalLabelShape
Definition: edit_label.cpp:42
void SetItalic(bool isItalic)
Definition: eda_text.h:163
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:109
int GetThickness() const
Return the pen width.
Definition: eda_text.h:148
bool TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
void RemoveFromScreen(EDA_ITEM *aItem, SCH_SCREEN *aScreen=nullptr)
Remove an item from the screen (and view) aScreen is the screen the item is located on,...
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:222
bool CanIncrementLabel() const override
Definition: sch_text.h:307
static bool lastTextItalic
Definition: edit_label.cpp:45
void SetIsDangling(bool aIsDangling)
Definition: sch_text.h:303
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
bool IsNew() const
Definition: base_struct.h:218
static TOOL_ACTION removeItemFromSel
Definition: ee_actions.h:62
int InvokeDialogLabelEditor(SCH_EDIT_FRAME *aCaller, SCH_TEXT *aTextItem)
Launches the "Edit Text/Label" dialog.
bool IsItalic() const
Definition: eda_text.h:164
#define IS_NEW
New item, just created.
Definition: base_struct.h:120
static std::deque< std::unique_ptr< SCH_TEXT > > s_queuedTexts
Definition: edit_label.cpp:47
Item is being added to the view.
Definition: view_item.h:60
EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
Definition: sch_text.cpp:123
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:255
static LABEL_SPIN_STYLE lastTextOrientation
Definition: edit_label.cpp:43
static TOOL_ACTION addItemToSel
Selects an item (specified as the event parameter).
Definition: ee_actions.h:61
STATUS_FLAGS GetEditFlags() const
Definition: base_struct.h:260
const wxSize & GetTextSize() const
Definition: eda_text.h:223
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
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.
LABEL_SPIN_STYLE GetLabelSpinStyle() const
Definition: sch_text.h:238
SCH_TEXT * GetNextNewText()
Gets the next queued text item.
Definition: edit_label.cpp:49
virtual void Update(VIEW_ITEM *aItem, int aUpdateFlags)
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: view.cpp:1540
wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_text.h:315
PINSHEETLABEL_SHAPE
Definition: sch_text.h:164
void ConvertTextType(SCH_TEXT *aText, KICAD_T aNewType)
Change a text type to another one.
Definition: edit_label.cpp:190
const char * name
Definition: DXF_plotter.cpp:60
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
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
wxString wx_str() const
Definition: utf8.cpp:51
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current screen and u...
TOOL_MANAGER * m_toolManager
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:210
static bool lastTextBold
Definition: edit_label.cpp:44
void IncrementLabelMember(wxString &name, int aIncrement)
Definition: edit_label.cpp:281
void clear()
Definition: utf8.h:113
void SetBold(bool aBold)
Definition: eda_text.h:166
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:123
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.
void SetThickness(int aNewThickness)
Set the pen width.
Definition: eda_text.h:143
int GetDefaultTextSize()
Default size for text in general.
PINSHEETLABEL_SHAPE GetShape() const
Definition: sch_text.h:243
KICAD_T Type() const
Function Type()
Definition: base_struct.h:207
bool empty() const
Definition: utf8.h:108
#define IS_MOVED
Item being moved.
Definition: base_struct.h:119