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 <pcb_edit_frame.h>
35 #include <pcb_layer_box_selector.h>
36 #include <wx/valnum.h>
37 #include <math/util.h> // for KiROUND
38 
39 
41  DIALOG_TEXT_PROPERTIES_BASE( aParent ),
42  m_Parent( aParent ),
43  m_item( aItem ),
44  m_edaText( nullptr ),
45  m_fpText( nullptr ),
46  m_pcbText( nullptr ),
47  m_textWidth( aParent, m_SizeXLabel, m_SizeXCtrl, m_SizeXUnits, true ),
48  m_textHeight( aParent, m_SizeYLabel, m_SizeYCtrl, m_SizeYUnits, true ),
49  m_thickness( aParent, m_ThicknessLabel, m_ThicknessCtrl, m_ThicknessUnits, true ),
50  m_posX( aParent, m_PositionXLabel, m_PositionXCtrl, m_PositionXUnits ),
51  m_posY( aParent, m_PositionYLabel, m_PositionYCtrl, m_PositionYUnits ),
52  m_orientation( aParent, m_OrientLabel, m_OrientCtrl, nullptr, false )
53 {
54  wxString title;
55 
56  // Configure display origin transforms
59 
60  m_MultiLineText->SetEOLMode( wxSTC_EOL_LF );
61 
62  // A hack which causes Scintilla to auto-size the text editor canvas
63  // See: https://github.com/jacobslusser/ScintillaNET/issues/216
64  m_MultiLineText->SetScrollWidth( 1 );
65  m_MultiLineText->SetScrollWidthTracking( true );
66 
67  if( m_item->Type() == PCB_FP_TEXT_T )
68  {
69  title = _( "Footprint Text Properties" );
70 
71  m_fpText = (FP_TEXT*) m_item;
72  m_edaText = static_cast<EDA_TEXT*>( m_fpText );
73 
74  switch( m_fpText->GetType() )
75  {
76  case FP_TEXT::TEXT_is_REFERENCE: m_TextLabel->SetLabel( _( "Reference:" ) ); break;
77  case FP_TEXT::TEXT_is_VALUE: m_TextLabel->SetLabel( _( "Value:" ) ); break;
78  case FP_TEXT::TEXT_is_DIVERS: m_TextLabel->SetLabel( _( "Text:" ) ); break;
79  }
80 
82  m_MultiLineSizer->Show( false );
83  }
84  else
85  {
86  title = _( "Text Properties" );
87 
88  m_pcbText = (PCB_TEXT*) aItem;
89  m_edaText = static_cast<EDA_TEXT*>( m_pcbText );
90 
92  m_SingleLineSizer->Show( false );
93 
94  int size = wxNORMAL_FONT->GetPointSize();
95  wxFont fixedFont( size, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL );
96 
97  for( size_t i = 0; i < wxSTC_STYLE_MAX; ++i )
98  m_MultiLineText->StyleSetFont( i, fixedFont );
99 
100  // Addresses a bug in wx3.0 where styles are not correctly set
101  m_MultiLineText->StyleClearAll();
102 
103  // This option makes sense only for footprint texts; texts on board are always visible.
104  m_Visible->SetValue( true );
105  m_Visible->Enable( false );
106 
107  m_KeepUpright->Show( false );
108  m_statusLine->Show( false );
109  }
110 
111  SetTitle( title );
112  m_hash_key = title;
113 
114  // Configure the layers list selector. Note that footprints are built outside the current
115  // board and so we may need to show all layers if the text is on an unactivated layer.
118 
122 
123  m_OrientValue = 0.0;
126 
127  // Set predefined rotations in combo dropdown, according to the locale floating point
128  // separator notation
129  double rot_list[] = { 0.0, 90.0, -90.0, 180.0 };
130 
131  for( size_t ii = 0; ii < m_OrientCtrl->GetCount() && ii < 4; ++ii )
132  m_OrientCtrl->SetString( ii, wxString::Format( "%.1f", rot_list[ii] ) );
133 
134  // Set font sizes
135  wxFont infoFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
136  infoFont.SetSymbolicSize( wxFONTSIZE_X_SMALL );
137  m_statusLine->SetFont( infoFont );
138 
139  m_sdbSizerOK->SetDefault();
140 
141  // We can't set the tab order through wxWidgets due to shortcomings in their mnemonics
142  // implementation on MSW
143  m_tabOrder = {
144  m_LayerLabel,
146  m_SizeXCtrl,
147  m_SizeYCtrl,
151  m_Visible,
152  m_Italic,
154  m_OrientCtrl,
155  m_Mirrored,
157  m_sdbSizerOK,
159  };
160 
161  // wxTextCtrls fail to generate wxEVT_CHAR events when the wxTE_MULTILINE flag is set,
162  // so we have to listen to wxEVT_CHAR_HOOK events instead.
163  Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXT_PROPERTIES::OnCharHook ), NULL, this );
164 
166 }
167 
168 
170 {
171  Disconnect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXT_PROPERTIES::OnCharHook ), NULL, this );
172 }
173 
174 
175 // Launch the text properties dialog in quasi modal mode.
177 {
178  DIALOG_TEXT_PROPERTIES dlg( this, aText );
179  dlg.ShowQuasiModal();
180 }
181 
182 
183 void DIALOG_TEXT_PROPERTIES::OnCharHook( wxKeyEvent& aEvent )
184 {
185  if( aEvent.GetKeyCode() == WXK_RETURN && aEvent.ShiftDown() )
186  {
187  if( TransferDataFromWindow() )
188  {
189  // Do not use EndModal to close the dialog that can be opened
190  // in quasi modal mode
191  SetReturnCode( wxID_OK );
192  Close();
193  }
194  }
195  else if( m_MultiLineText->IsShown() && m_MultiLineText->HasFocus() )
196  {
197  if( aEvent.GetKeyCode() == WXK_TAB && !aEvent.ControlDown() )
198  {
199  m_MultiLineText->Tab();
200  }
201  else if( IsCtrl( 'Z', aEvent ) )
202  {
203  m_MultiLineText->Undo();
204  }
205  else if( IsShiftCtrl( 'Z', aEvent ) || IsCtrl( 'Y', aEvent ) )
206  {
207  m_MultiLineText->Redo();
208  }
209  else if( IsCtrl( 'X', aEvent ) )
210  {
211  m_MultiLineText->Cut();
212  }
213  else if( IsCtrl( 'C', aEvent ) )
214  {
215  m_MultiLineText->Copy();
216  }
217  else if( IsCtrl( 'V', aEvent ) )
218  {
219  m_MultiLineText->Paste();
220  }
221  else if( IsCtrl( 'A', aEvent ) )
222  {
223  m_MultiLineText->SelectAll();
224  }
225  else
226  {
227  aEvent.Skip();
228  }
229  }
230  else
231  {
232  aEvent.Skip();
233  }
234 }
235 
236 
237 void DIALOG_TEXT_PROPERTIES::OnSetFocusText( wxFocusEvent& event )
238 {
239 #ifdef __WXGTK__
240  // Force an update of the text control before setting the text selection
241  // This is needed because GTK seems to ignore the selection on first update
242  //
243  // Note that we can't do this on OSX as it tends to provoke Apple's
244  // "[NSAlert runModal] may not be invoked inside of transaction begin/commit pair"
245  // bug. See: https://bugs.launchpad.net/kicad/+bug/1837225
247  m_SingleLineText->Update();
248 #endif
249 
251  KIUI::SelectReferenceNumber( static_cast<wxTextEntry*>( m_SingleLineText ) );
252  else
253  m_SingleLineText->SetSelection( -1, -1 );
254 
255  event.Skip();
256 }
257 
258 
260 {
261  if( m_SingleLineText->IsShown() )
262  {
263  m_SingleLineText->SetValue( m_edaText->GetText() );
264 
266  KIUI::SelectReferenceNumber( static_cast<wxTextEntry*>( m_SingleLineText ) );
267  else
268  m_SingleLineText->SetSelection( -1, -1 );
269  }
270  else if( m_MultiLineText->IsShown() )
271  {
272  BOARD* board = m_Parent->GetBoard();
273  wxString converted = board->ConvertKIIDsToCrossReferences( m_edaText->GetText() );
274 
275  m_MultiLineText->SetValue( converted );
276  m_MultiLineText->SetSelection( -1, -1 );
277  }
278 
279  if( m_item->Type() == PCB_FP_TEXT_T && m_fpText )
280  {
281  FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( m_fpText->GetParent() );
282  wxString msg;
283 
284  if( footprint )
285  {
286  msg.Printf( _( "Footprint %s (%s), %s, rotated %.1f deg"),
287  footprint->GetReference(),
288  footprint->GetValue(),
289  footprint->IsFlipped() ? _( "back side (mirrored)" ) : _( "front side" ),
290  footprint->GetOrientation() / 10.0 );
291  }
292 
293  m_statusLine->SetLabel( msg );
294  }
295  else
296  {
297  m_statusLine->Show( false );
298  }
299 
300  m_cbLocked->SetValue( m_item->IsLocked() );
301 
303 
309 
310  m_Visible->SetValue( m_edaText->IsVisible() );
311  m_Italic->SetValue( m_edaText->IsItalic() );
313  m_JustifyChoice->SetSelection( (int) hJustify + 1 );
316  m_Mirrored->SetValue( m_edaText->IsMirrored() );
317 
318  if( m_fpText )
319  m_KeepUpright->SetValue( m_fpText->IsKeepUpright() );
320 
321  return DIALOG_TEXT_PROPERTIES_BASE::TransferDataToWindow();
322 }
323 
324 
326 {
327  if( !DIALOG_TEXT_PROPERTIES_BASE::TransferDataFromWindow() )
328  return false;
329 
332  {
333  return false;
334  }
335 
336  BOARD_COMMIT commit( m_Parent );
337  commit.Modify( m_item );
338 
339  // If no other command in progress, prepare undo command
340  // (for a command in progress, will be made later, at the completion of command)
341  bool pushCommit = ( m_item->GetEditFlags() == 0 );
342 
343  // Set IN_EDIT flag to force undo/redo/abort proper operation and avoid new calls to
344  // SaveCopyInUndoList for the same text if is moved, and then rotated, edited, etc....
345  if( !pushCommit )
346  m_item->SetFlags( IN_EDIT );
347 
348  // Set the new text content
349  if( m_SingleLineText->IsShown() )
350  {
351  if( !m_SingleLineText->GetValue().IsEmpty() )
352  m_edaText->SetText( m_SingleLineText->GetValue() );
353  }
354  else if( m_MultiLineText->IsShown() )
355  {
356  if( !m_MultiLineText->GetValue().IsEmpty() )
357  {
358  BOARD* board = m_Parent->GetBoard();
359  wxString txt = board->ConvertCrossReferencesToKIIDs( m_MultiLineText->GetValue() );
360 
361 #ifdef __WINDOWS__
362  // On Windows, a new line is coded as \r\n. We use only \n in kicad files and in
363  // drawing routines so strip the \r char.
364  txt.Replace( "\r", "" );
365 #endif
367  }
368  }
369 
370  m_item->SetLocked( m_cbLocked->GetValue() );
371 
373 
376  m_edaText->SetTextPos( wxPoint( m_posX.GetValue(), m_posY.GetValue() ) );
377 
378  if( m_fpText )
380 
381  // Test for acceptable values for thickness and size and clamp if fails
383 
384  if( m_edaText->GetTextThickness() > maxPenWidth )
385  {
386  DisplayError( this, _( "The text thickness is too large for the text size.\n"
387  "It will be clamped." ) );
388  m_edaText->SetTextThickness( maxPenWidth );
389  }
390 
391  m_edaText->SetVisible( m_Visible->GetValue() );
392  m_edaText->SetItalic( m_Italic->GetValue() );
395  m_edaText->SetMirrored( m_Mirrored->GetValue() );
396 
397  if( m_fpText )
398  m_fpText->SetKeepUpright( m_KeepUpright->GetValue() );
399 
400  switch( m_JustifyChoice->GetSelection() )
401  {
405  default: break;
406  }
407 
408  if( pushCommit )
409  commit.Push( _( "Change text properties" ) );
410 
411  return true;
412 }
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:102
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:445
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:194
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:82
std::string m_hash_key
Definition: dialog_shim.h:200
std::vector< wxWindow * > m_tabOrder
Definition: dialog_shim.h:219
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:186
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:257
void SetBoardFrame(PCB_BASE_FRAME *aFrame)
int GetTextThickness() const
Definition: eda_text.h:167
wxString ConvertKIIDsToCrossReferences(const wxString &aSource)
Definition: board.cpp:961
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.h:513
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:98
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)
Function Clamp_Text_PenSize Don't allow text to become cluttered up in its own fatness.
Definition: gr_text.cpp:69
void SetFlags(STATUS_FLAGS aMask)
Definition: eda_item.h:202
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:205
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:121
#define NULL
STATUS_FLAGS GetEditFlags() const
Definition: eda_item.h:207
TEXT_TYPE GetType() const
Definition: fp_text.h:141
int ShowQuasiModal()
void ShowNonActivatedLayers(bool aShow)
const wxSize & GetTextSize() const
Definition: eda_text.h:245
#define IN_EDIT
Item currently edited.
Definition: eda_item.h:104
const wxString & GetReference() const
Definition: footprint.h:423
int SetLayerSelection(LAYER_NUM layer)
#define TEXTS_MAX_SIZE
Maximum text size in internal units (10 inches)
Definition: pcbnew.h:32
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:263
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:249
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
#define _(s)
Definition: 3d_actions.cpp:33
static bool IsShiftCtrl(int aChar, const wxKeyEvent &e)
Definition: dialog_shim.h: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:77
virtual void SetValue(int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
void SetLocalCoord()
Definition: fp_text.cpp:218
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.
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
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:125
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:168
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:173
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:133
wxString ConvertCrossReferencesToKIIDs(const wxString &aSource)
Convert cross-references back and forth between ${refDes:field} and ${kiid:field}.
Definition: board.cpp:907
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:905
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:162