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-2021 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 <string_utils.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 #include <scintilla_tricks.h>
40 
41 
43  DIALOG_TEXT_PROPERTIES_BASE( aParent ),
44  m_Parent( aParent ),
45  m_item( aItem ),
46  m_edaText( nullptr ),
47  m_fpText( nullptr ),
48  m_pcbText( nullptr ),
49  m_textWidth( aParent, m_SizeXLabel, m_SizeXCtrl, m_SizeXUnits ),
50  m_textHeight( aParent, m_SizeYLabel, m_SizeYCtrl, m_SizeYUnits ),
51  m_thickness( aParent, m_ThicknessLabel, m_ThicknessCtrl, m_ThicknessUnits ),
52  m_posX( aParent, m_PositionXLabel, m_PositionXCtrl, m_PositionXUnits ),
53  m_posY( aParent, m_PositionYLabel, m_PositionYCtrl, m_PositionYUnits ),
54  m_orientation( aParent, m_OrientLabel, m_OrientCtrl, nullptr )
55 {
56  wxString title;
57 
58  // Configure display origin transforms
61 
62  m_MultiLineText->SetEOLMode( wxSTC_EOL_LF );
63 
64  m_scintillaTricks = new SCINTILLA_TRICKS( m_MultiLineText, wxT( "{}" ), false,
65  [this]()
66  {
67  wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
68  } );
69 
70  // A hack which causes Scintilla to auto-size the text editor canvas
71  // See: https://github.com/jacobslusser/ScintillaNET/issues/216
72  m_MultiLineText->SetScrollWidth( 1 );
73  m_MultiLineText->SetScrollWidthTracking( true );
74 
75  if( m_item->Type() == PCB_FP_TEXT_T )
76  {
77  m_fpText = (FP_TEXT*) m_item;
78  m_edaText = static_cast<EDA_TEXT*>( m_fpText );
79 
80  switch( m_fpText->GetType() )
81  {
82  case FP_TEXT::TEXT_is_REFERENCE: title = _( "Footprint Reference Properties" ); break;
83  case FP_TEXT::TEXT_is_VALUE: title = _( "Footprint Value Properties" ); break;
84  case FP_TEXT::TEXT_is_DIVERS: title = _( "Footprint Text Properties" ); break;
85  }
86 
87  switch( m_fpText->GetType() )
88  {
89  case FP_TEXT::TEXT_is_REFERENCE: m_TextLabel->SetLabel( _( "Reference:" ) ); break;
90  case FP_TEXT::TEXT_is_VALUE: m_TextLabel->SetLabel( _( "Value:" ) ); break;
91  case FP_TEXT::TEXT_is_DIVERS: m_TextLabel->SetLabel( _( "Text:" ) ); break;
92  }
93 
95  m_MultiLineSizer->Show( false );
96 
97  // Do not allow locking items in the footprint editor
98  m_cbLocked->Show( false );
99  }
100  else
101  {
102  title = _( "Text Properties" );
103 
104  m_pcbText = (PCB_TEXT*) aItem;
105  m_edaText = static_cast<EDA_TEXT*>( m_pcbText );
106 
108  m_SingleLineSizer->Show( false );
109 
110  // This option makes sense only for footprint texts; texts on board are always visible.
111  m_Visible->SetValue( true );
112  m_Visible->Show( false );
113 
114  m_KeepUpright->Show( false );
115  m_statusLine->Show( false );
116  }
117 
118  SetTitle( title );
119  m_hash_key = title;
120 
121  // Configure the layers list selector. Note that footprints are built outside the current
122  // board and so we may need to show all layers if the text is on an unactivated layer.
125 
129 
130  m_OrientValue = 0.0;
133 
134  // Set predefined rotations in combo dropdown, according to the locale floating point
135  // separator notation
136  double rot_list[] = { 0.0, 90.0, -90.0, 180.0 };
137 
138  for( size_t ii = 0; ii < m_OrientCtrl->GetCount() && ii < 4; ++ii )
139  m_OrientCtrl->SetString( ii, wxString::Format( wxT( "%.1f" ), rot_list[ii] ) );
140 
141  // Set font sizes
142  m_statusLine->SetFont( KIUI::GetInfoFont( this ) );
143 
144  m_sdbSizerOK->SetDefault();
145 
146  // We can't set the tab order through wxWidgets due to shortcomings in their mnemonics
147  // implementation on MSW
148  m_tabOrder = {
149  m_LayerLabel,
151  m_SizeXCtrl,
152  m_SizeYCtrl,
156  m_Visible,
157  m_Italic,
159  m_OrientCtrl,
160  m_Mirrored,
162  m_sdbSizerOK,
164  };
165 
166  // wxTextCtrls fail to generate wxEVT_CHAR events when the wxTE_MULTILINE flag is set,
167  // so we have to listen to wxEVT_CHAR_HOOK events instead.
168  Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXT_PROPERTIES::OnCharHook ),
169  nullptr, this );
170 
172 }
173 
174 
176 {
177  Disconnect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXT_PROPERTIES::OnCharHook ),
178  nullptr, this );
179 
180  delete m_scintillaTricks;
181 }
182 
183 
185 {
186  DIALOG_TEXT_PROPERTIES dlg( this, aText );
187  dlg.ShowQuasiModal();
188 }
189 
190 
191 void DIALOG_TEXT_PROPERTIES::OnSetFocusText( wxFocusEvent& event )
192 {
193 #ifdef __WXGTK__
194  // Force an update of the text control before setting the text selection
195  // This is needed because GTK seems to ignore the selection on first update
196  //
197  // Note that we can't do this on OSX as it tends to provoke Apple's
198  // "[NSAlert runModal] may not be invoked inside of transaction begin/commit pair"
199  // bug. See: https://bugs.launchpad.net/kicad/+bug/1837225
201  m_SingleLineText->Update();
202 #endif
203 
205  KIUI::SelectReferenceNumber( static_cast<wxTextEntry*>( m_SingleLineText ) );
206  else
207  m_SingleLineText->SetSelection( -1, -1 );
208 
209  event.Skip();
210 }
211 
212 
214 {
215  if( m_SingleLineText->IsShown() )
216  {
217  m_SingleLineText->SetValue( m_edaText->GetText() );
218 
220  KIUI::SelectReferenceNumber( static_cast<wxTextEntry*>( m_SingleLineText ) );
221  else
222  m_SingleLineText->SetSelection( -1, -1 );
223  }
224  else if( m_MultiLineText->IsShown() )
225  {
226  BOARD* board = m_Parent->GetBoard();
227  wxString converted = board->ConvertKIIDsToCrossReferences(
229 
230  m_MultiLineText->SetValue( converted );
231  m_MultiLineText->SetSelection( -1, -1 );
232  }
233 
234  if( m_item->Type() == PCB_FP_TEXT_T && m_fpText )
235  {
236  FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( m_fpText->GetParent() );
237  wxString msg;
238 
239  if( footprint )
240  {
241  msg.Printf( _( "Footprint %s (%s), %s, rotated %.1f deg"),
242  footprint->GetReference(),
243  footprint->GetValue(),
244  footprint->IsFlipped() ? _( "back side (mirrored)" ) : _( "front side" ),
245  footprint->GetOrientation() / 10.0 );
246  }
247 
248  m_statusLine->SetLabel( msg );
249  }
250  else
251  {
252  m_statusLine->Show( false );
253  }
254 
255  m_cbLocked->SetValue( m_item->IsLocked() );
256 
258 
264 
265  m_Visible->SetValue( m_edaText->IsVisible() );
266  m_Italic->SetValue( m_edaText->IsItalic() );
268  m_JustifyChoice->SetSelection( (int) hJustify + 1 );
271  m_Mirrored->SetValue( m_edaText->IsMirrored() );
272 
273  if( m_fpText )
274  m_KeepUpright->SetValue( m_fpText->IsKeepUpright() );
275 
276  return DIALOG_TEXT_PROPERTIES_BASE::TransferDataToWindow();
277 }
278 
279 
281 {
282  if( !DIALOG_TEXT_PROPERTIES_BASE::TransferDataFromWindow() )
283  return false;
284 
287  {
288  return false;
289  }
290 
291  BOARD_COMMIT commit( m_Parent );
292  commit.Modify( m_item );
293 
294  // If no other command in progress, prepare undo command
295  // (for a command in progress, will be made later, at the completion of command)
296  bool pushCommit = ( m_item->GetEditFlags() == 0 );
297 
298  // Set IN_EDIT flag to force undo/redo/abort proper operation and avoid new calls to
299  // SaveCopyInUndoList for the same text if is moved, and then rotated, edited, etc....
300  if( !pushCommit )
301  m_item->SetFlags( IN_EDIT );
302 
303  // Set the new text content
304  if( m_SingleLineText->IsShown() )
305  {
306  if( !m_SingleLineText->GetValue().IsEmpty() )
307  m_edaText->SetText( m_SingleLineText->GetValue() );
308  }
309  else if( m_MultiLineText->IsShown() )
310  {
311  if( !m_MultiLineText->GetValue().IsEmpty() )
312  {
313  BOARD* board = m_Parent->GetBoard();
314  wxString txt = board->ConvertCrossReferencesToKIIDs( m_MultiLineText->GetValue() );
315 
316 #ifdef __WXMAC__
317  // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting.
318  // Replace it now.
319  txt.Replace( wxT( "\r" ), wxT( "\n" ) );
320 #elif defined( __WINDOWS__ )
321  // On Windows, a new line is coded as \r\n. We use only \n in kicad files and in
322  // drawing routines so strip the \r char.
323  txt.Replace( wxT( "\r" ), wxEmptyString );
324 #endif
326  }
327  }
328 
329  m_item->SetLocked( m_cbLocked->GetValue() );
330 
332 
335  m_edaText->SetTextPos( wxPoint( m_posX.GetValue(), m_posY.GetValue() ) );
336 
337  if( m_fpText )
339 
340  // Test for acceptable values for thickness and size and clamp if fails
342 
343  if( m_edaText->GetTextThickness() > maxPenWidth )
344  {
345  DisplayError( this, _( "The text thickness is too large for the text size.\n"
346  "It will be clamped." ) );
347  m_edaText->SetTextThickness( maxPenWidth );
348  }
349 
350  m_edaText->SetVisible( m_Visible->GetValue() );
351  m_edaText->SetItalic( m_Italic->GetValue() );
354  m_edaText->SetMirrored( m_Mirrored->GetValue() );
355 
356  if( m_fpText )
357  m_fpText->SetKeepUpright( m_KeepUpright->GetValue() );
358 
359  switch( m_JustifyChoice->GetSelection() )
360  {
364  default: break;
365  }
366 
367  if( pushCommit )
368  commit.Push( _( "Change text properties" ) );
369 
370  return true;
371 }
372 
373 
375 {
376  if( m_scintillaTricks )
378 
379  event.Skip();
380 }
void SetMirrored(bool isMirrored)
Definition: eda_text.h:209
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:279
void SelectReferenceNumber(wxTextEntry *aTextEntry)
Select the number (or "?") in a reference for ease of editing.
Definition: ui_common.cpp:185
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:82
bool IsMirrored() const
Definition: eda_text.h:210
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:488
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:164
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:49
std::string m_hash_key
Definition: dialog_shim.h:201
Add cut/copy/paste, dark theme, autocomplete and brace highlighting to a wxStyleTextCtrl instance.
std::vector< wxWindow * > m_tabOrder
Definition: dialog_shim.h:220
void SetItalic(bool isItalic)
Definition: eda_text.h:200
void SetTextPos(const wxPoint &aPoint)
Definition: eda_text.h:267
wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:144
double GetOrientation() const
Definition: footprint.h:191
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:152
double GetTextAngle() const
Definition: eda_text.h:195
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:258
virtual void SetLocked(bool aLocked)
Modify the 'lock' status for of the item.
Definition: board_item.h:218
void SetBoardFrame(PCB_BASE_FRAME *aFrame)
int GetTextThickness() const
Definition: eda_text.h:181
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:493
virtual bool IsLocked() const
Definition: board_item.cpp:64
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:201
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 (...
virtual void SetVisible(bool aVisible)
Definition: eda_text.h:206
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:67
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:219
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:124
TEXT_TYPE GetType() const
Definition: fp_text.h:141
virtual bool IsVisible() const
Definition: eda_text.h:207
int ShowQuasiModal()
void ShowNonActivatedLayers(bool aShow)
const wxSize & GetTextSize() const
Definition: eda_text.h:259
const wxString & GetReference() const
Definition: footprint.h:466
#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:157
bool SetLayersHotkeys(bool value)
PCB_BASE_EDIT_FRAME * m_Parent
wxString UnescapeString(const wxString &aSource)
#define TEXTS_MIN_SIZE
Minimum text size in internal units (1 mil)
Definition: pcbnew.h:31
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:281
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
virtual void OnCharHook(wxKeyEvent &aEvt)
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: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.
PCB_LAYER_BOX_SELECTOR * m_LayerSelectionCtrl
Common, abstract interface for edit frames.
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:191
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:222
wxString ConvertCrossReferencesToKIIDs(const wxString &aSource) const
Convert cross-references back and forth between ${refDes:field} and ${kiid:field}.
Definition: board.cpp:960
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 void SetValue(long long int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
virtual long long int GetValue()
Return the current value in Internal Units.
wxString ConvertKIIDsToCrossReferences(const wxString &aSource) const
Definition: board.cpp:1014
const wxPoint & GetTextPos() const
Definition: eda_text.h:268
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.h:180
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:177
#define IN_EDIT
Item currently edited.
virtual void SetTextAngle(double aAngle)
Definition: eda_text.h:188
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
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.
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:136
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:143
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:154
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:914
SCINTILLA_TRICKS * m_scintillaTricks
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112
void onMultiLineTCLostFocus(wxFocusEvent &event) override