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-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 <dialog_text_properties.h>
26 #include <confirm.h>
27 #include <gr_text.h>
28 #include <fctsys.h>
29 #include <widgets/tab_traversal.h>
30 #include <widgets/unit_binder.h>
31 #include <board_commit.h>
32 #include <class_board.h>
33 #include <class_dimension.h>
34 #include <class_module.h>
35 #include <class_pcb_text.h>
36 #include <class_text_mod.h>
37 #include <pcb_edit_frame.h>
38 #include <pcb_layer_box_selector.h>
39 #include <pcbnew.h>
40 #include <wx/valnum.h>
41 
42 
44  DIALOG_TEXT_PROPERTIES_BASE( aParent ),
45  m_Parent( aParent ),
46  m_item( aItem ),
47  m_edaText( nullptr ),
48  m_modText( nullptr ),
49  m_pcbText( nullptr ),
50  m_textWidth( aParent, m_SizeXLabel, m_SizeXCtrl, m_SizeXUnits, true ),
51  m_textHeight( aParent, m_SizeYLabel, m_SizeYCtrl, m_SizeYUnits, true ),
52  m_thickness( aParent, m_ThicknessLabel, m_ThicknessCtrl, m_ThicknessUnits, true ),
53  m_posX( aParent, m_PositionXLabel, m_PositionXCtrl, m_PositionXUnits ),
54  m_posY( aParent, m_PositionYLabel, m_PositionYCtrl, m_PositionYUnits ),
55  m_linesThickness( aParent, m_LineThicknessLabel, m_LineThicknessCtrl,
56  m_LineThicknessUnits, true ),
57  m_OrientValidator( 1, &m_OrientValue )
58 {
59  wxString title;
60 
62 
63  if( m_item->Type() == PCB_DIMENSION_T )
64  {
65  title = _( "Dimension Properties" );
66 
67  DIMENSION* dimension = (DIMENSION*) m_item;
68  m_edaText = &dimension->Text();
69  m_pcbText = &dimension->Text();
70 
71  // Since this is really the object properties for a dimension (rather than just the
72  // text properties), make some of the propertie labels more explicit.
73  for( wxStaticText* label : { m_SizeXLabel, m_SizeYLabel, m_ThicknessLabel,
75  {
76  label->SetLabel( label->GetToolTipText() + wxT( ":" ) );
77  }
78 
79  m_Mirrored->SetLabel( m_Mirrored->GetToolTipText() );
80 
82  m_SingleLineSizer->Show( false );
83  m_MultiLineSizer->Show( false );
84 
85  m_KeepUpright->Show( false );
86  m_statusLine->Show( false );
87  }
88  else if( m_item->Type() == PCB_MODULE_TEXT_T )
89  {
90  title = _( "Footprint Text Properties" );
91 
93  m_edaText = static_cast<EDA_TEXT*>( m_modText );
94 
95  switch( m_modText->GetType() )
96  {
97  case TEXTE_MODULE::TEXT_is_REFERENCE: m_TextLabel->SetLabel( _( "Reference:" ) ); break;
98  case TEXTE_MODULE::TEXT_is_VALUE: m_TextLabel->SetLabel( _( "Value:" ) ); break;
99  case TEXTE_MODULE::TEXT_is_DIVERS: m_TextLabel->SetLabel( _( "Text:" ) ); break;
100  }
101 
103  m_MultiLineSizer->Show( false );
104  m_DimensionTextSizer->Show( false );
105  }
106  else
107  {
108  title = _( "Text Properties" );
109 
110  m_pcbText = (TEXTE_PCB*) aItem;
111  m_edaText = static_cast<EDA_TEXT*>( m_pcbText );
112 
114  m_SingleLineSizer->Show( false );
115  m_DimensionTextSizer->Show( false );
116 
117  // This option make sense only for footprint texts,
118  // Texts on board are always visible:
119  m_Visible->SetValue( true );
120  m_Visible->Show( false );
121 
122  m_KeepUpright->Show( false );
123  m_statusLine->Show( false );
124  }
125 
126  SetTitle( title );
127  m_hash_key = title;
128 
129  // Configure the layers list selector. Note that footprints are built outside the current
130  // board and so we may need to show all layers if the text is on an unactivated layer.
133 
138 
139  m_OrientValue = 0.0;
140  m_OrientValidator.SetRange( -360.0, 360.0 );
141  m_OrientCtrl->SetValidator( m_OrientValidator );
142  m_OrientValidator.SetWindow( m_OrientCtrl );
143 
144  // Handle decimal separators in combo dropdown
145  for( size_t i = 0; i < m_OrientCtrl->GetCount(); ++i )
146  {
147  wxString item = m_OrientCtrl->GetString( i );
148  item.Replace( '.', localeconv()->decimal_point[0] );
149  m_OrientCtrl->SetString( i, item );
150  }
151 
152  // Set font sizes
153  wxFont infoFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
154  infoFont.SetSymbolicSize( wxFONTSIZE_SMALL );
155  m_statusLine->SetFont( infoFont );
156 
157  m_sdbSizerOK->SetDefault();
158 
159  // We can't set the tab order through wxWidgets due to shortcomings in their mnemonics
160  // implementation on MSW
161  m_tabOrder = {
162  m_LayerLabel,
164  m_SizeXCtrl,
165  m_SizeYCtrl,
170  m_Visible,
171  m_Italic,
173  m_OrientCtrl,
174  m_Mirrored,
176  m_sdbSizerOK,
178  };
179 
180  // wxTextCtrls fail to generate wxEVT_CHAR events when the wxTE_MULTILINE flag is set,
181  // so we have to listen to wxEVT_CHAR_HOOK events instead.
182  Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXT_PROPERTIES::OnCharHook ), NULL, this );
183 
185 }
186 
187 
189 {
190  Disconnect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXT_PROPERTIES::OnCharHook ), NULL, this );
191 }
192 
193 
198 {
199  DIALOG_TEXT_PROPERTIES dlg( this, aText );
200  dlg.ShowModal();
201 }
202 
203 
204 void DIALOG_TEXT_PROPERTIES::OnCharHook( wxKeyEvent& aEvent )
205 {
206  if( aEvent.GetKeyCode() == WXK_RETURN && aEvent.ShiftDown() )
207  {
208  if( TransferDataFromWindow() )
209  EndModal( wxID_OK );
210  }
211  else if( m_MultiLineText->IsShown() && m_MultiLineText->HasFocus() )
212  {
213  if( aEvent.GetKeyCode() == WXK_TAB && !aEvent.ControlDown() )
214  {
215  m_MultiLineText->Tab();
216  }
217  else if( IsCtrl( 'Z', aEvent ) )
218  {
219  m_MultiLineText->Undo();
220  }
221  else if( IsShiftCtrl( 'Z', aEvent ) || IsCtrl( 'Y', aEvent ) )
222  {
223  m_MultiLineText->Redo();
224  }
225  else if( IsCtrl( 'X', aEvent ) )
226  {
227  m_MultiLineText->Cut();
228  }
229  else if( IsCtrl( 'C', aEvent ) )
230  {
231  m_MultiLineText->Copy();
232  }
233  else if( IsCtrl( 'V', aEvent ) )
234  {
235  m_MultiLineText->Paste();
236  }
237  else
238  {
239  aEvent.Skip();
240  }
241  }
242  else
243  {
244  aEvent.Skip();
245  }
246 }
247 
248 
250 {
251  EDA_UNITS_T units = UNSCALED_UNITS;
252  bool useMils;
253 
254  FetchUnitsFromString( m_DimensionText->GetValue(), units, useMils );
255 
256  if( units != UNSCALED_UNITS )
257  m_DimensionUnitsOpt->SetSelection( units == MILLIMETRES ? 2 : useMils ? 1 : 0 );
258 }
259 
260 
262 {
263  DIMENSION* dimension = (DIMENSION*) m_item;
264  EDA_UNITS_T units;
265  bool useMils;
266 
267  // Get default units in case dimension text doesn't contain units.
268  dimension->GetUnits( units, useMils );
269 
270  double value = ValueFromString( units, m_DimensionText->GetValue(), useMils );
271 
272  switch( event.GetSelection() )
273  {
274  case 0: units = INCHES; useMils = false; break;
275  case 1: units = INCHES; useMils = true; break;
276  case 2: units = MILLIMETRES; useMils = false; break;
277  default: break;
278  }
279 
280  m_DimensionText->SetValue( StringFromValue( units, value, true, useMils ) );
281 }
282 
283 
285 {
286  if( m_SingleLineText->IsShown() )
287  {
288  m_SingleLineText->SetValue( m_edaText->GetText() );
289 
291  SelectReferenceNumber( static_cast<wxTextEntry*>( m_SingleLineText ) );
292  else
293  m_SingleLineText->SetSelection( -1, -1 );
294  }
295  else if( m_MultiLineText->IsShown() )
296  {
297  m_MultiLineText->SetValue( m_edaText->GetText() );
298  m_MultiLineText->SetSelection( -1, -1 );
299  }
300  else if (m_DimensionText->IsShown() )
301  {
302  m_DimensionText->SetValue( m_edaText->GetText() );
303  m_DimensionText->SetSelection( -1, -1 );
304 
305  DIMENSION* dimension = (DIMENSION*) m_item;
306  EDA_UNITS_T units;
307  bool useMils;
308  dimension->GetUnits( units, useMils );
309 
310  m_DimensionUnitsOpt->SetSelection( units == MILLIMETRES ? 2 : useMils ? 1 : 0 );
311 
312  m_linesThickness.SetValue( dimension->GetWidth() );
313  }
314 
315  if( m_item->Type() == PCB_MODULE_TEXT_T && m_modText )
316  {
317  MODULE* module = dynamic_cast<MODULE*>( m_modText->GetParent() );
318  wxString msg;
319 
320  if( module )
321  {
322  msg.Printf( _("Footprint %s (%s), %s, rotated %.1f deg"),
323  module->GetReference(),
324  module->GetValue(),
325  module->IsFlipped() ? _( "back side (mirrored)" ) : _( "front side" ),
326  module->GetOrientation() / 10.0 );
327  }
328 
329  m_statusLine->SetLabel( msg );
330  }
331  else
332  {
333  m_statusLine->Show( false );
334  }
335 
337  {
338  wxMessageBox( _( "This item was on a non-existing or forbidden layer.\n"
339  "It has been moved to the first allowed layer." ) );
340  m_LayerSelectionCtrl->SetSelection( 0 );
341  }
342 
348 
349  m_Visible->SetValue( m_edaText->IsVisible() );
350  m_Italic->SetValue( m_edaText->IsItalic() );
352  m_JustifyChoice->SetSelection( (int) hJustify + 1 );
354  m_Mirrored->SetValue( m_edaText->IsMirrored() );
355 
356  if( m_modText )
357  m_KeepUpright->SetValue( m_modText->IsKeepUpright() );
358 
359  return DIALOG_TEXT_PROPERTIES_BASE::TransferDataToWindow();
360 }
361 
362 
364 {
365  if( !DIALOG_TEXT_PROPERTIES_BASE::TransferDataFromWindow() )
366  return false;
367 
370  return false;
371 
372  BOARD_COMMIT commit( m_Parent );
373  commit.Modify( m_item );
374 
375  // If no other command in progress, prepare undo command
376  // (for a command in progress, will be made later, at the completion of command)
377  bool pushCommit = ( m_item->GetEditFlags() == 0 );
378 
379  /* set flag in edit to force undo/redo/abort proper operation,
380  * and avoid new calls to SaveCopyInUndoList for the same text
381  * this can occurs when a text is moved, and then rotated, edited ..
382  */
383  if( !pushCommit )
384  m_item->SetFlags( IN_EDIT );
385 
386  // Set the new text content
387  if( m_SingleLineText->IsShown() )
388  {
389  if( !m_SingleLineText->GetValue().IsEmpty() )
390  m_edaText->SetText( m_SingleLineText->GetValue() );
391  }
392  else if( m_MultiLineText->IsShown() )
393  {
394  if( !m_MultiLineText->GetValue().IsEmpty() )
395  {
396  // On Windows, a new line is coded as \r\n.
397  // We use only \n in kicad files and in drawing routines.
398  // so strip the \r char
399  wxString txt = m_MultiLineText->GetValue();
400 #ifdef __WINDOWS__
401  txt.Replace( "\r", "" );
402 #endif
403  m_edaText->SetText( txt );
404  }
405  }
406  else if( m_DimensionText->IsShown() )
407  {
408  if( !m_DimensionText->GetValue().IsEmpty() )
409  m_edaText->SetText( m_DimensionText->GetValue() );
410 
411  DIMENSION* dimension = (DIMENSION*) m_item;
412 
413  switch( m_DimensionUnitsOpt->GetSelection() )
414  {
415  case 0: dimension->SetUnits( INCHES, false ); break;
416  case 1: dimension->SetUnits( INCHES, true ); break;
417  case 2: dimension->SetUnits( MILLIMETRES, false ); break;
418  default: break;
419  }
420 
421  dimension->SetWidth( m_linesThickness.GetValue() );
422  }
423 
425 
428  m_edaText->SetTextPos( wxPoint( m_posX.GetValue(), m_posY.GetValue() ) );
429 
430  if( m_modText )
432 
433  // Test for acceptable values for thickness and size and clamp if fails
434  int maxthickness = Clamp_Text_PenSize( m_edaText->GetThickness(), m_edaText->GetTextSize() );
435 
436  if( m_edaText->GetThickness() > maxthickness )
437  {
438  DisplayError( this, _( "The text thickness is too large for the text size.\n"
439  "It will be clamped." ) );
440  m_edaText->SetThickness( maxthickness );
441  }
442 
443  m_edaText->SetVisible( m_Visible->GetValue() );
444  m_edaText->SetItalic( m_Italic->GetValue() );
446  m_edaText->SetMirrored( m_Mirrored->GetValue() );
447 
448  if( m_modText )
449  m_modText->SetKeepUpright( m_KeepUpright->GetValue() );
450 
451  switch( m_JustifyChoice->GetSelection() )
452  {
456  default: break;
457  }
458 
459  m_Parent->Refresh();
460 
461  if( pushCommit )
462  commit.Push( _( "Change text properties" ) );
463 
464  return true;
465 }
void SetMirrored(bool isMirrored)
Definition: eda_text.h:172
void SetTextAngle(double aAngle)
Definition: eda_text.h:150
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:236
Functions for manipulating tab traversal in forms and dialogs.
double GetOrientation() const
Definition: class_module.h:218
COMMIT & Modify(EDA_ITEM *aItem)
Modifies a given item in the model.
Definition: commit.h:103
void SetKeepUpright(bool aKeepUpright)
#define IN_EDIT
Item currently edited.
Definition: base_struct.h:118
EDA_TEXT_HJUSTIFY_T
Definition: eda_text.h:44
bool IsMirrored() const
Definition: eda_text.h:173
int GetWidth() const
DIALOG_TEXT_PROPERTIES(PCB_BASE_EDIT_FRAME *aParent, BOARD_ITEM *aItem)
TEXTE_PCB class definition.
Class DIALOG_TEXT_PROPERTIES_BASE.
bool IsFlipped() const
function IsFlipped
Definition: class_module.h:288
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
This file is part of the common library.
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
std::string m_hash_key
Definition: dialog_shim.h:186
void SetNotAllowedLayerSet(LSET aMask)
std::vector< wxWindow * > m_tabOrder
Definition: dialog_shim.h:199
void OnCharHook(wxKeyEvent &aEvent)
bool IsVisible() const
Definition: eda_text.h:170
void SetItalic(bool isItalic)
Definition: eda_text.h:163
void FinishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
void SetTextPos(const wxPoint &aPoint)
Definition: eda_text.h:231
void SetVisible(bool aVisible)
Definition: eda_text.h:169
const wxString GetValue() const
Function GetValue.
Definition: class_module.h:457
int GetThickness() const
Function GetThickness returns pen width.
Definition: eda_text.h:148
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:222
void SetBoardFrame(PCB_BASE_FRAME *aFrame)
void FetchUnitsFromString(const wxString &aTextValue, EDA_UNITS_T &aUnits, bool &aUseMils)
Function FetchUnitsFromString writes any unit info found in the string to aUnits and aUseMils.
Definition: base_units.cpp:388
void InstallTextOptionsFrame(BOARD_ITEM *aText)
Routine for main window class to launch text properties dialog.
bool IsLayerEnabled(PCB_LAYER_ID aLayer) const
Function IsLayerEnabled is a proxy function that calls the correspondent function in m_BoardSettings ...
Definition: class_board.h:438
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:118
void OnDimensionUnitsChange(wxCommandEvent &event) override
const wxString GetReference() const
Function GetReference.
Definition: class_module.h:432
bool IsItalic() const
Definition: eda_text.h:164
bool IsKeepUpright()
DIMENSION class definition.
LAYER_NUM GetLayerSelection() const
void SelectReferenceNumber(wxTextEntry *aTextEntry)
Select the number (or "?") in a reference for ease of editing.
Definition: common.cpp:159
void Show(bool aShow, bool aResize=false)
Function Show Shows/hides the label, widget and units label.
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:64
Footprint text class description.
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:265
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:184
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:126
STATUS_FLAGS GetEditFlags() const
Definition: base_struct.h:270
void ShowNonActivatedLayers(bool aShow)
const wxSize & GetTextSize() const
Definition: eda_text.h:223
Definition: common.h:134
TEXT_TYPE GetType() const
int SetLayerSelection(LAYER_NUM layer)
#define TEXTS_MAX_SIZE
Maximum text size in internal units (10 inches)
Definition: pcbnew.h:39
void SetUnits(EDA_UNITS_T aUnits, bool aUseMils)
virtual bool Validate(long long int aMin, long long int aMax, bool setFocusOnError=true)
Function Validate Validates the control against the given range, informing the user of any errors fou...
bool SetLayersHotkeys(bool value)
class DIMENSION, a dimension (graphic item)
Definition: typeinfo.h:99
#define _(s)
PCB_BASE_EDIT_FRAME * m_Parent
#define TEXTS_MIN_SIZE
Minimum text size in internal units (1 mil)
Definition: pcbnew.h:38
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
void SetLocalCoord()
Set relative coordinates.
double GetTextAngleDegrees() const
Definition: eda_text.h:160
PCB_LAYER_BOX_SELECTOR * m_LayerSelectionCtrl
Common, abstract interface for edit frames.
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:187
static bool IsShiftCtrl(int aChar, const wxKeyEvent &e)
Definition: dialog_shim.h:142
virtual void SetValue(int aValue)
Function SetValue Sets new value (in Internal Units) for the text field, taking care of units convers...
TEXTE_PCB & Text()
size_t i
Definition: json11.cpp:649
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Executes the changes.
void GetUnits(EDA_UNITS_T &aUnits, bool &aUseMils) const
virtual long long int GetValue()
Function GetValue Returns the current value in Internal Units.
const wxPoint & GetTextPos() const
Definition: eda_text.h:232
static LSET ForbiddenTextLayers()
Function ForbiddenTextLayers Layers which are now allowed to have text on them.
Definition: lset.cpp:796
Module description (excepted pads)
BOARD * GetBoard() const
void SetWidth(int aWidth)
static bool IsCtrl(int aChar, const wxKeyEvent &e)
Definition: dialog_shim.h:137
BOARD_ITEM_CONTAINER * GetParent() const
void OnDimensionTextChange(wxCommandEvent &event) override
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
virtual const wxString & GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:124
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:813
wxFloatingPointValidator< double > m_OrientValidator
EDA_UNITS_T
Definition: common.h:133
Class DIMENSION.
void SetThickness(int aNewThickness)
Function SetThickness sets pen width.
Definition: eda_text.h:142
long long int ValueFromString(EDA_UNITS_T aUnits, const wxString &aTextValue, bool aUseMils)
Function ValueFromString converts aTextValue in aUnits to internal units used by the application.
Definition: base_units.cpp:427
wxString StringFromValue(EDA_UNITS_T aUnits, double aValue, bool aAddUnitSymbol, bool aUseMils)
Function StringFromValue returns the string from aValue according to units (inch, mm ....
Definition: base_units.cpp:217
KICAD_T Type() const
Function Type()
Definition: base_struct.h:210
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:114