KiCad PCB EDA Suite
dialog_text_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) 2004-2018 Jean-Pierre Charras jp.charras at wanadoo.fr
5  * Copyright (C) 2010-2020 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 <dialog_text_properties.h>
26 #include <confirm.h>
27 #include <widgets/unit_binder.h>
28 #include <board_commit.h>
29 #include <board.h>
30 #include <footprint.h>
31 #include <kicad_string.h>
32 #include <pcb_text.h>
33 #include <fp_text.h>
34 #include <pcbnew.h>
35 #include <pcb_edit_frame.h>
36 #include <pcb_layer_box_selector.h>
37 #include <wx/valnum.h>
38 #include <math/util.h> // for KiROUND
39 
40 
42  DIALOG_TEXT_PROPERTIES_BASE( aParent ),
43  m_Parent( aParent ),
44  m_item( aItem ),
45  m_edaText( nullptr ),
46  m_fpText( nullptr ),
47  m_pcbText( nullptr ),
48  m_textWidth( aParent, m_SizeXLabel, m_SizeXCtrl, m_SizeXUnits ),
49  m_textHeight( aParent, m_SizeYLabel, m_SizeYCtrl, m_SizeYUnits ),
50  m_thickness( aParent, m_ThicknessLabel, m_ThicknessCtrl, m_ThicknessUnits ),
51  m_posX( aParent, m_PositionXLabel, m_PositionXCtrl, m_PositionXUnits ),
52  m_posY( aParent, m_PositionYLabel, m_PositionYCtrl, m_PositionYUnits ),
53  m_orientation( aParent, m_OrientLabel, m_OrientCtrl, nullptr )
54 {
55  wxString title;
56 
57  // Configure display origin transforms
60 
61  m_MultiLineText->SetEOLMode( wxSTC_EOL_LF );
62 
63  // A hack which causes Scintilla to auto-size the text editor canvas
64  // See: https://github.com/jacobslusser/ScintillaNET/issues/216
65  m_MultiLineText->SetScrollWidth( 1 );
66  m_MultiLineText->SetScrollWidthTracking( true );
67 
68  if( m_item->Type() == PCB_FP_TEXT_T )
69  {
70  title = _( "Footprint Text Properties" );
71 
72  m_fpText = (FP_TEXT*) m_item;
73  m_edaText = static_cast<EDA_TEXT*>( m_fpText );
74 
75  switch( m_fpText->GetType() )
76  {
77  case FP_TEXT::TEXT_is_REFERENCE: m_TextLabel->SetLabel( _( "Reference:" ) ); break;
78  case FP_TEXT::TEXT_is_VALUE: m_TextLabel->SetLabel( _( "Value:" ) ); break;
79  case FP_TEXT::TEXT_is_DIVERS: m_TextLabel->SetLabel( _( "Text:" ) ); break;
80  }
81 
83  m_MultiLineSizer->Show( false );
84  }
85  else
86  {
87  title = _( "Text Properties" );
88 
89  m_pcbText = (PCB_TEXT*) aItem;
90  m_edaText = static_cast<EDA_TEXT*>( m_pcbText );
91 
93  m_SingleLineSizer->Show( false );
94 
95  int size = wxNORMAL_FONT->GetPointSize();
96  wxFont fixedFont( size, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL );
97 
98  for( size_t i = 0; i < wxSTC_STYLE_MAX; ++i )
99  m_MultiLineText->StyleSetFont( i, fixedFont );
100 
101  // Addresses a bug in wx3.0 where styles are not correctly set
102  m_MultiLineText->StyleClearAll();
103 
104  // This option makes sense only for footprint texts; texts on board are always visible.
105  m_Visible->SetValue( true );
106  m_Visible->Enable( false );
107 
108  m_KeepUpright->Show( false );
109  m_statusLine->Show( false );
110  }
111 
112  SetTitle( title );
113  m_hash_key = title;
114 
115  // Configure the layers list selector. Note that footprints are built outside the current
116  // board and so we may need to show all layers if the text is on an unactivated layer.
119 
123 
124  m_OrientValue = 0.0;
127 
128  // Set predefined rotations in combo dropdown, according to the locale floating point
129  // separator notation
130  double rot_list[] = { 0.0, 90.0, -90.0, 180.0 };
131 
132  for( size_t ii = 0; ii < m_OrientCtrl->GetCount() && ii < 4; ++ii )
133  m_OrientCtrl->SetString( ii, wxString::Format( "%.1f", rot_list[ii] ) );
134 
135  // Set font sizes
136  wxFont infoFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
137  infoFont.SetSymbolicSize( wxFONTSIZE_X_SMALL );
138  m_statusLine->SetFont( infoFont );
139 
140  m_sdbSizerOK->SetDefault();
141 
142  // We can't set the tab order through wxWidgets due to shortcomings in their mnemonics
143  // implementation on MSW
144  m_tabOrder = {
145  m_LayerLabel,
147  m_SizeXCtrl,
148  m_SizeYCtrl,
152  m_Visible,
153  m_Italic,
155  m_OrientCtrl,
156  m_Mirrored,
158  m_sdbSizerOK,
160  };
161 
162  // wxTextCtrls fail to generate wxEVT_CHAR events when the wxTE_MULTILINE flag is set,
163  // so we have to listen to wxEVT_CHAR_HOOK events instead.
164  Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXT_PROPERTIES::OnCharHook ), NULL, this );
165 
167 }
168 
169 
171 {
172  Disconnect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXT_PROPERTIES::OnCharHook ), NULL, this );
173 }
174 
175 
176 // Launch the text properties dialog in quasi modal mode.
178 {
179  DIALOG_TEXT_PROPERTIES dlg( this, aText );
180  dlg.ShowQuasiModal();
181 }
182 
183 
184 void DIALOG_TEXT_PROPERTIES::OnCharHook( wxKeyEvent& aEvent )
185 {
186  if( aEvent.GetKeyCode() == WXK_RETURN && aEvent.ShiftDown() )
187  {
188  if( TransferDataFromWindow() )
189  {
190  // Do not use EndModal to close the dialog that can be opened
191  // in quasi modal mode
192  SetReturnCode( wxID_OK );
193  Close();
194  }
195  }
196  else if( m_MultiLineText->IsShown() && m_MultiLineText->HasFocus() )
197  {
198  if( aEvent.GetKeyCode() == WXK_TAB && !aEvent.ControlDown() )
199  {
200  m_MultiLineText->Tab();
201  }
202  else if( IsCtrl( 'Z', aEvent ) )
203  {
204  m_MultiLineText->Undo();
205  }
206  else if( IsShiftCtrl( 'Z', aEvent ) || IsCtrl( 'Y', aEvent ) )
207  {
208  m_MultiLineText->Redo();
209  }
210  else if( IsCtrl( 'X', aEvent ) )
211  {
212  m_MultiLineText->Cut();
213  }
214  else if( IsCtrl( 'C', aEvent ) )
215  {
216  m_MultiLineText->Copy();
217  }
218  else if( IsCtrl( 'V', aEvent ) )
219  {
220  m_MultiLineText->Paste();
221  }
222  else if( IsCtrl( 'A', aEvent ) )
223  {
224  m_MultiLineText->SelectAll();
225  }
226  else
227  {
228  aEvent.Skip();
229  }
230  }
231  else
232  {
233  aEvent.Skip();
234  }
235 }
236 
237 
238 void DIALOG_TEXT_PROPERTIES::OnSetFocusText( wxFocusEvent& event )
239 {
240 #ifdef __WXGTK__
241  // Force an update of the text control before setting the text selection
242  // This is needed because GTK seems to ignore the selection on first update
243  //
244  // Note that we can't do this on OSX as it tends to provoke Apple's
245  // "[NSAlert runModal] may not be invoked inside of transaction begin/commit pair"
246  // bug. See: https://bugs.launchpad.net/kicad/+bug/1837225
248  m_SingleLineText->Update();
249 #endif
250 
252  KIUI::SelectReferenceNumber( static_cast<wxTextEntry*>( m_SingleLineText ) );
253  else
254  m_SingleLineText->SetSelection( -1, -1 );
255 
256  event.Skip();
257 }
258 
259 
261 {
262  if( m_SingleLineText->IsShown() )
263  {
264  m_SingleLineText->SetValue( m_edaText->GetText() );
265 
267  KIUI::SelectReferenceNumber( static_cast<wxTextEntry*>( m_SingleLineText ) );
268  else
269  m_SingleLineText->SetSelection( -1, -1 );
270  }
271  else if( m_MultiLineText->IsShown() )
272  {
273  BOARD* board = m_Parent->GetBoard();
274  wxString converted = board->ConvertKIIDsToCrossReferences( m_edaText->GetText() );
275 
276  m_MultiLineText->SetValue( converted );
277  m_MultiLineText->SetSelection( -1, -1 );
278  }
279 
280  if( m_item->Type() == PCB_FP_TEXT_T && m_fpText )
281  {
282  FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( m_fpText->GetParent() );
283  wxString msg;
284 
285  if( footprint )
286  {
287  msg.Printf( _( "Footprint %s (%s), %s, rotated %.1f deg"),
288  footprint->GetReference(),
289  footprint->GetValue(),
290  footprint->IsFlipped() ? _( "back side (mirrored)" ) : _( "front side" ),
291  footprint->GetOrientation() / 10.0 );
292  }
293 
294  m_statusLine->SetLabel( msg );
295  }
296  else
297  {
298  m_statusLine->Show( false );
299  }
300 
301  m_cbLocked->SetValue( m_item->IsLocked() );
302 
304 
310 
311  m_Visible->SetValue( m_edaText->IsVisible() );
312  m_Italic->SetValue( m_edaText->IsItalic() );
314  m_JustifyChoice->SetSelection( (int) hJustify + 1 );
317  m_Mirrored->SetValue( m_edaText->IsMirrored() );
318 
319  if( m_fpText )
320  m_KeepUpright->SetValue( m_fpText->IsKeepUpright() );
321 
322  return DIALOG_TEXT_PROPERTIES_BASE::TransferDataToWindow();
323 }
324 
325 
327 {
328  if( !DIALOG_TEXT_PROPERTIES_BASE::TransferDataFromWindow() )
329  return false;
330 
333  {
334  return false;
335  }
336 
337  BOARD_COMMIT commit( m_Parent );
338  commit.Modify( m_item );
339 
340  // If no other command in progress, prepare undo command
341  // (for a command in progress, will be made later, at the completion of command)
342  bool pushCommit = ( m_item->GetEditFlags() == 0 );
343 
344  // Set IN_EDIT flag to force undo/redo/abort proper operation and avoid new calls to
345  // SaveCopyInUndoList for the same text if is moved, and then rotated, edited, etc....
346  if( !pushCommit )
347  m_item->SetFlags( IN_EDIT );
348 
349  // Set the new text content
350  if( m_SingleLineText->IsShown() )
351  {
352  if( !m_SingleLineText->GetValue().IsEmpty() )
353  m_edaText->SetText( m_SingleLineText->GetValue() );
354  }
355  else if( m_MultiLineText->IsShown() )
356  {
357  if( !m_MultiLineText->GetValue().IsEmpty() )
358  {
359  BOARD* board = m_Parent->GetBoard();
360  wxString txt = board->ConvertCrossReferencesToKIIDs( m_MultiLineText->GetValue() );
361 
362 #ifdef __WXMAC__
363  // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting.
364  // Replace it now.
365  txt.Replace( "\r", "\n" );
366 #elif defined( __WINDOWS__ )
367  // On Windows, a new line is coded as \r\n. We use only \n in kicad files and in
368  // drawing routines so strip the \r char.
369  txt.Replace( "\r", "" );
370 #endif
372  }
373  }
374 
375  m_item->SetLocked( m_cbLocked->GetValue() );
376 
378 
381  m_edaText->SetTextPos( wxPoint( m_posX.GetValue(), m_posY.GetValue() ) );
382 
383  if( m_fpText )
385 
386  // Test for acceptable values for thickness and size and clamp if fails
388 
389  if( m_edaText->GetTextThickness() > maxPenWidth )
390  {
391  DisplayError( this, _( "The text thickness is too large for the text size.\n"
392  "It will be clamped." ) );
393  m_edaText->SetTextThickness( maxPenWidth );
394  }
395 
396  m_edaText->SetVisible( m_Visible->GetValue() );
397  m_edaText->SetItalic( m_Italic->GetValue() );
400  m_edaText->SetMirrored( m_Mirrored->GetValue() );
401 
402  if( m_fpText )
403  m_fpText->SetKeepUpright( m_KeepUpright->GetValue() );
404 
405  switch( m_JustifyChoice->GetSelection() )
406  {
410  default: break;
411  }
412 
413  if( pushCommit )
414  commit.Push( _( "Change text properties" ) );
415 
416  return true;
417 }
void SetMirrored(bool isMirrored)
Definition: eda_text.h:195
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:252
void SelectReferenceNumber(wxTextEntry *aTextEntry)
Select the number (or "?") in a reference for ease of editing.
Definition: ui_common.cpp:103
COMMIT & Modify(EDA_ITEM *aItem)
Create an undo entry for an item that has been already modified.
Definition: commit.h:103
EDA_TEXT_HJUSTIFY_T
Definition: eda_text.h:61
bool IsMirrored() const
Definition: eda_text.h:196
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
DIALOG_TEXT_PROPERTIES(PCB_BASE_EDIT_FRAME *aParent, BOARD_ITEM *aItem)
Class DIALOG_TEXT_PROPERTIES_BASE.
const wxString & GetValue() const
Definition: footprint.h:443
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:192
This file is part of the common library.
bool IsKeepUpright() const
Definition: fp_text.h:110
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:80
std::string m_hash_key
Definition: dialog_shim.h:199
std::vector< wxWindow * > m_tabOrder
Definition: dialog_shim.h:218
bool IsVisible() const
Definition: eda_text.h:193
void SetItalic(bool isItalic)
Definition: eda_text.h:186
void SetTextPos(const wxPoint &aPoint)
Definition: eda_text.h:253
void SetVisible(bool aVisible)
Definition: eda_text.h:192
double GetOrientation() const
Definition: footprint.h:181
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:153
double GetTextAngle() const
Definition: eda_text.h:181
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:244
virtual void SetLocked(bool aLocked)
Modify the 'lock' status for of the item.
Definition: board_item.h:255
void SetBoardFrame(PCB_BASE_FRAME *aFrame)
int GetTextThickness() const
Definition: eda_text.h:167
bool IsLayerEnabled(PCB_LAYER_ID aLayer) const
A proxy function that calls the correspondent function in m_BoardSettings tests whether a given layer...
Definition: board.cpp:491
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:97
void ShowTextPropertiesDialog(BOARD_ITEM *aText)
bool IsItalic() const
Definition: eda_text.h:187
LAYER_NUM GetLayerSelection() const
virtual void SetPrecision(int aLength)
Normally not needed, but can be used to set the precision when using internal units that are floats (...
Definition: unit_binder.cpp:90
int Clamp_Text_PenSize(int aPenSize, int aSize, bool aBold)
Don't allow text to become cluttered up in its own fatness.
Definition: gr_text.cpp:68
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:205
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:114
#define NULL
TEXT_TYPE GetType() const
Definition: fp_text.h:141
int ShowQuasiModal()
void ShowNonActivatedLayers(bool aShow)
const wxSize & GetTextSize() const
Definition: eda_text.h:245
const wxString & GetReference() const
Definition: footprint.h:421
#define _(s)
int SetLayerSelection(LAYER_NUM layer)
#define TEXTS_MAX_SIZE
Maximum text size in internal units (10 inches)
Definition: pcbnew.h:32
EDA_ITEM_FLAGS GetEditFlags() const
Definition: eda_item.h:158
bool SetLayersHotkeys(bool value)
PCB_BASE_EDIT_FRAME * m_Parent
#define TEXTS_MIN_SIZE
Minimum text size in internal units (1 mil)
Definition: pcbnew.h:31
void OnCharHook(wxKeyEvent &aEvent) override
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
bool IsFlipped() const
Definition: footprint.h:261
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
void SetKeepUpright(bool aKeepUpright)
Definition: fp_text.h:115
virtual void SetUnits(EDA_UNITS aUnits)
Normally not needed (as the UNIT_BINDER inherits from the parent frame), but can be used to set to DE...
Definition: unit_binder.cpp:81
virtual bool IsLocked() const
Definition: board_item.h:247
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.
PCB_LAYER_BOX_SELECTOR * m_LayerSelectionCtrl
Common, abstract interface for edit frames.
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:190
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:208
static bool IsShiftCtrl(int aChar, const wxKeyEvent &e)
Definition: dialog_shim.h:130
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
Definition: string.cpp:141
virtual void SetValue(int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
wxString ConvertCrossReferencesToKIIDs(const wxString &aSource) const
Convert cross-references back and forth between ${refDes:field} and ${kiid:field}.
Definition: board.cpp:982
void SetLocalCoord()
Definition: fp_text.cpp:209
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Revert the commit by restoring the modified items state.
virtual long long int GetValue()
Return the current value in Internal Units.
wxString ConvertKIIDsToCrossReferences(const wxString &aSource) const
Definition: board.cpp:1036
const wxPoint & GetTextPos() const
Definition: eda_text.h:254
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.h:166
virtual void OnSetFocusText(wxFocusEvent &event) override
Used to select the variant part of some text fields (for instance, the question mark or number in a r...
void SetCoordType(ORIGIN_TRANSFORMS::COORD_TYPES_T aCoordType)
Set the current origin transform mode.
Definition: unit_binder.h:173
#define IN_EDIT
Item currently edited.
virtual void SetTextAngle(double aAngle)
Definition: eda_text.h:174
BOARD * GetBoard() const
virtual void SetDoubleValue(double aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
virtual double GetDoubleValue()
Return the current value in Internal Units.
static bool IsCtrl(int aChar, const wxKeyEvent &e)
Definition: dialog_shim.h:124
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:166
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:171
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:133
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:905
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113