You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

759 lines
26 KiB

5 years ago
2 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.com
  5. * Copyright (C) 2016 Wayne Stambaugh, stambaughw@gmail.com
  6. * Copyright The KiCad Developers, see AITHORS.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. #include <widgets/bitmap_button.h>
  26. #include <widgets/std_bitmap_button.h>
  27. #include <widgets/font_choice.h>
  28. #include <widgets/color_swatch.h>
  29. #include <settings/color_settings.h>
  30. #include <bitmaps.h>
  31. #include <kiway.h>
  32. #include <kiway_mail.h>
  33. #include <confirm.h>
  34. #include <common.h>
  35. #include <string_utils.h>
  36. #include <sch_edit_frame.h>
  37. #include <sch_collectors.h>
  38. #include <sch_symbol.h>
  39. #include <template_fieldnames.h>
  40. #include <sch_validators.h>
  41. #include <schematic.h>
  42. #include <sch_commit.h>
  43. #include <dialog_field_properties.h>
  44. #include <sch_text.h>
  45. #include <scintilla_tricks.h>
  46. #include <wildcards_and_files_ext.h>
  47. DIALOG_FIELD_PROPERTIES::DIALOG_FIELD_PROPERTIES( SCH_BASE_FRAME* aParent, const wxString& aTitle,
  48. const SCH_FIELD* aField ) :
  49. DIALOG_FIELD_PROPERTIES_BASE( aParent, wxID_ANY, aTitle ),
  50. m_posX( aParent, m_xPosLabel, m_xPosCtrl, m_xPosUnits, true ),
  51. m_posY( aParent, m_yPosLabel, m_yPosCtrl, m_yPosUnits, true ),
  52. m_textSize( aParent, m_textSizeLabel, m_textSizeCtrl, m_textSizeUnits, true ),
  53. m_font( nullptr ),
  54. m_firstFocus( true ),
  55. m_scintillaTricks( nullptr ),
  56. m_field( aField )
  57. {
  58. COLOR_SETTINGS* colorSettings = aParent->GetColorSettings();
  59. COLOR4D schematicBackground = colorSettings->GetColor( LAYER_SCHEMATIC_BACKGROUND );
  60. wxASSERT( m_field );
  61. m_note->SetFont( KIUI::GetInfoFont( this ).Italic() );
  62. m_note->Show( false );
  63. m_scintillaTricks = new SCINTILLA_TRICKS( m_StyledTextCtrl, wxT( "{}" ), true,
  64. // onAcceptFn
  65. [this]( wxKeyEvent& aEvent )
  66. {
  67. wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
  68. } );
  69. m_StyledTextCtrl->SetEOLMode( wxSTC_EOL_LF ); // Normalize EOL across platforms
  70. #ifdef __WXGTK__
  71. m_StyledTextCtrl->SetExtraAscent( 6 );
  72. m_StyledTextCtrl->SetExtraDescent( 6 );
  73. #elif defined ( __WXMSW__ )
  74. // Do nothing: SetExtraAscent() + SetExtraDescent(), when set to a value not 0
  75. // Generate a strange bug: the text is not always shown (Perhaps a wxMSW bug)
  76. // and this call is not needed on WXMSW
  77. #else
  78. m_StyledTextCtrl->SetExtraAscent( 1 );
  79. m_StyledTextCtrl->SetExtraDescent( 2 );
  80. #endif
  81. #ifdef _WIN32
  82. // Without this setting, on Windows, some esoteric unicode chars create display issue
  83. // in a wxStyledTextCtrl.
  84. // for SetTechnology() info, see https://www.scintilla.org/ScintillaDoc.html#SCI_SETTECHNOLOGY
  85. m_StyledTextCtrl->SetTechnology(wxSTC_TECHNOLOGY_DIRECTWRITE);
  86. #endif
  87. m_textColorSwatch->SetDefaultColor( COLOR4D::UNSPECIFIED );
  88. m_textColorSwatch->SetSwatchBackground( schematicBackground );
  89. m_separator1->SetIsSeparator();
  90. m_horizontal->SetIsRadioButton();
  91. m_horizontal->SetBitmap( KiBitmapBundle( BITMAPS::text_horizontal ) );
  92. m_vertical->SetIsRadioButton();
  93. m_vertical->SetBitmap( KiBitmapBundle( BITMAPS::text_vertical ) );
  94. m_separator2->SetIsSeparator();
  95. m_bold->SetIsCheckButton();
  96. m_bold->SetBitmap( KiBitmapBundle( BITMAPS::text_bold ) );
  97. m_italic->SetIsCheckButton();
  98. m_italic->SetBitmap( KiBitmapBundle( BITMAPS::text_italic ) );
  99. m_separator3->SetIsSeparator();
  100. m_hAlignLeft->SetIsRadioButton();
  101. m_hAlignLeft->SetBitmap( KiBitmapBundle( BITMAPS::text_align_left ) );
  102. m_hAlignCenter->SetIsRadioButton();
  103. m_hAlignCenter->SetBitmap( KiBitmapBundle( BITMAPS::text_align_center ) );
  104. m_hAlignRight->SetIsRadioButton();
  105. m_hAlignRight->SetBitmap( KiBitmapBundle( BITMAPS::text_align_right ) );
  106. m_separator4->SetIsSeparator();
  107. m_vAlignTop->SetIsRadioButton();
  108. m_vAlignTop->SetBitmap( KiBitmapBundle( BITMAPS::text_valign_top ) );
  109. m_vAlignCenter->SetIsRadioButton();
  110. m_vAlignCenter->SetBitmap( KiBitmapBundle( BITMAPS::text_valign_center ) );
  111. m_vAlignBottom->SetIsRadioButton();
  112. m_vAlignBottom->SetBitmap( KiBitmapBundle( BITMAPS::text_valign_bottom ) );
  113. m_separator5->SetIsSeparator();
  114. m_horizontal->Bind( wxEVT_BUTTON, &DIALOG_FIELD_PROPERTIES::onOrientButton, this );
  115. m_vertical->Bind( wxEVT_BUTTON, &DIALOG_FIELD_PROPERTIES::onOrientButton, this );
  116. m_hAlignLeft->Bind( wxEVT_BUTTON, &DIALOG_FIELD_PROPERTIES::onHAlignButton, this );
  117. m_hAlignCenter->Bind( wxEVT_BUTTON, &DIALOG_FIELD_PROPERTIES::onHAlignButton, this );
  118. m_hAlignRight->Bind( wxEVT_BUTTON, &DIALOG_FIELD_PROPERTIES::onHAlignButton, this );
  119. m_vAlignTop->Bind( wxEVT_BUTTON, &DIALOG_FIELD_PROPERTIES::onVAlignButton, this );
  120. m_vAlignCenter->Bind( wxEVT_BUTTON, &DIALOG_FIELD_PROPERTIES::onVAlignButton, this );
  121. m_vAlignBottom->Bind( wxEVT_BUTTON, &DIALOG_FIELD_PROPERTIES::onVAlignButton, this );
  122. // show text variable cross-references in a human-readable format
  123. if( aField->Schematic() )
  124. {
  125. const SCH_SHEET_PATH& sheetPath = aField->Schematic()->CurrentSheet();
  126. wxString variant = aField->Schematic()->GetCurrentVariant();
  127. m_text = aField->Schematic()->ConvertKIIDsToRefs( aField->GetText( &sheetPath, variant ) );
  128. }
  129. else
  130. {
  131. m_text = aField->GetText();
  132. }
  133. m_font = m_field->GetFont();
  134. m_isItalic = aField->IsItalic();
  135. m_isBold = aField->IsBold();
  136. m_color = aField->GetTextColor();
  137. m_position = aField->GetTextPos();
  138. m_size = aField->GetTextWidth();
  139. m_isVertical = aField->GetTextAngle().IsVertical();
  140. m_verticalJustification = aField->GetVertJustify();
  141. m_horizontalJustification = aField->GetHorizJustify();
  142. m_isVisible = aField->IsVisible();
  143. m_isSheetFilename = false;
  144. m_fieldId = aField->GetId();
  145. if( aField->GetParent() && aField->GetParent()->Type() == LIB_SYMBOL_T )
  146. {
  147. const LIB_SYMBOL* symbol = static_cast<const LIB_SYMBOL*>( aField->GetParentSymbol() );
  148. /*
  149. * Symbol netlist format:
  150. * pinNumber pinName <tab> pinNumber pinName...
  151. * fpFilter fpFilter...
  152. */
  153. wxString netlist;
  154. wxArrayString pins;
  155. for( const SCH_PIN* pin : symbol->GetGraphicalPins( 0 /* all units */, 1 /* single bodyStyle */ ) )
  156. {
  157. bool valid = false;
  158. auto expanded = pin->GetStackedPinNumbers( &valid );
  159. if( valid && !expanded.empty() )
  160. {
  161. for( const wxString& num : expanded )
  162. pins.push_back( num + ' ' + pin->GetShownName() );
  163. }
  164. else
  165. {
  166. pins.push_back( pin->GetNumber() + ' ' + pin->GetShownName() );
  167. }
  168. }
  169. if( !pins.IsEmpty() )
  170. {
  171. wxString dbg = wxJoin( pins, '\t' );
  172. wxLogTrace( "FOOTPRINT_CHOOSER", wxS( "Chooser payload pins (LIB_SYMBOL): %s" ), dbg );
  173. netlist << EscapeString( dbg, CTX_LINE );
  174. }
  175. netlist << wxS( "\r" );
  176. wxArrayString fpFilters = symbol->GetFPFilters();
  177. if( !fpFilters.IsEmpty() )
  178. netlist << EscapeString( wxJoin( fpFilters, ' ' ), CTX_LINE );
  179. netlist << wxS( "\r" );
  180. m_netlist = netlist;
  181. }
  182. else if( aField->GetParent() && aField->GetParent()->Type() == SCH_SYMBOL_T )
  183. {
  184. const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( aField->GetParentSymbol() );
  185. SCH_SHEET_PATH sheetPath = static_cast<SCH_EDIT_FRAME*>( aParent )->GetCurrentSheet();
  186. /*
  187. * Symbol netlist format:
  188. * pinNumber pinName <tab> pinNumber pinName...
  189. * fpFilter fpFilter...
  190. */
  191. wxString netlist;
  192. // We need the list of pins of the lib symbol, not just the pins of the current
  193. // sch symbol, that can be just an unit of a multi-unit symbol, to be able to
  194. // select/filter right footprints
  195. wxArrayString pins;
  196. const std::unique_ptr< LIB_SYMBOL >& lib_symbol = symbol->GetLibSymbolRef();
  197. if( lib_symbol )
  198. {
  199. for( SCH_PIN* pin : lib_symbol->GetGraphicalPins( 0 /* all units */, 1 /* single bodyStyle */ ) )
  200. {
  201. bool valid = false;
  202. auto expanded = pin->GetStackedPinNumbers( &valid );
  203. if( valid && !expanded.empty() )
  204. {
  205. for( const wxString& num : expanded )
  206. pins.push_back( num + ' ' + pin->GetShownName() );
  207. }
  208. else
  209. {
  210. pins.push_back( pin->GetNumber() + ' ' + pin->GetShownName() );
  211. }
  212. }
  213. }
  214. if( !pins.IsEmpty() )
  215. {
  216. wxString dbg = wxJoin( pins, '\t' );
  217. wxLogTrace( "FOOTPRINT_CHOOSER", wxS( "Chooser payload pins (SCH_SYMBOL): %s" ), dbg );
  218. netlist << EscapeString( dbg, CTX_LINE );
  219. }
  220. netlist << wxS( "\r" );
  221. wxArrayString fpFilters;
  222. if( symbol->GetLibSymbolRef() ) // can be null with very old schematic
  223. fpFilters = symbol->GetLibSymbolRef()->GetFPFilters();
  224. if( !fpFilters.IsEmpty() )
  225. netlist << EscapeString( wxJoin( fpFilters, ' ' ), CTX_LINE );
  226. netlist << wxS( "\r" );
  227. m_netlist = netlist;
  228. }
  229. if( aField->GetId() == FIELD_T::SHEET_FILENAME )
  230. {
  231. m_isSheetFilename = true;
  232. m_note->Show( true );
  233. }
  234. m_textLabel->SetLabel( aField->GetName() + wxS( ":" ) );
  235. m_position = m_field->GetPosition();
  236. m_isNameVisible = m_field->IsNameShown();
  237. m_allowAutoplace = m_field->CanAutoplace();
  238. m_horizontalJustification = m_field->GetEffectiveHorizJustify();
  239. m_verticalJustification = m_field->GetEffectiveVertJustify();
  240. m_StyledTextCtrl->Bind( wxEVT_STC_CHARADDED,
  241. &DIALOG_FIELD_PROPERTIES::onScintillaCharAdded, this );
  242. m_StyledTextCtrl->Bind( wxEVT_STC_AUTOCOMP_CHAR_DELETED,
  243. &DIALOG_FIELD_PROPERTIES::onScintillaCharAdded, this );
  244. m_nameVisible->Show();
  245. m_cbAllowAutoPlace->Show();
  246. init();
  247. if( m_isSheetFilename || m_field->IsGeneratedField() )
  248. {
  249. m_StyledTextCtrl->Enable( false );
  250. m_TextCtrl->Enable( false );
  251. }
  252. }
  253. DIALOG_FIELD_PROPERTIES::~DIALOG_FIELD_PROPERTIES()
  254. {
  255. delete m_scintillaTricks;
  256. m_scintillaTricks = nullptr;
  257. }
  258. void DIALOG_FIELD_PROPERTIES::init()
  259. {
  260. // Disable options for graphic text editing which are not needed for fields.
  261. m_commonToAllBodyStyles->Show( false );
  262. m_commonToAllUnits->Show( false );
  263. // Predefined fields cannot contain some chars and cannot be empty, so they need a
  264. // SCH_FIELD_VALIDATOR (m_StyledTextCtrl cannot use a SCH_FIELD_VALIDATOR).
  265. if( m_fieldId == FIELD_T::REFERENCE
  266. || m_fieldId == FIELD_T::FOOTPRINT
  267. || m_fieldId == FIELD_T::DATASHEET
  268. || m_fieldId == FIELD_T::SHEET_NAME
  269. || m_fieldId == FIELD_T::SHEET_FILENAME )
  270. {
  271. m_TextCtrl->SetValidator( FIELD_VALIDATOR( m_fieldId, &m_text ) );
  272. SetInitialFocus( m_TextCtrl );
  273. m_StyledTextCtrl->Show( false );
  274. m_StyledTextCtrlBorder->Show( false );
  275. }
  276. else
  277. {
  278. SetInitialFocus( m_StyledTextCtrl );
  279. m_TextCtrl->Show( false );
  280. }
  281. // Show the unit selector for reference fields on multi-unit schematic symbols
  282. bool showUnitSelector = m_fieldId == FIELD_T::REFERENCE
  283. && m_field->GetParentSymbol()
  284. && m_field->GetParentSymbol()->Type() == SCH_SYMBOL_T
  285. && m_field->GetParentSymbol()->IsMultiUnit();
  286. m_unitLabel->Show( showUnitSelector );
  287. m_unitChoice->Show( showUnitSelector );
  288. // Show the footprint selection dialog if this is the footprint field.
  289. m_TextValueSelectButton->SetBitmap( KiBitmapBundle( BITMAPS::small_library ) );
  290. m_TextValueSelectButton->Show( m_fieldId == FIELD_T::FOOTPRINT );
  291. m_TextCtrl->Enable( true );
  292. GetSizer()->SetSizeHints( this );
  293. // Adjust the height of the scintilla editor after the first layout to show a single line
  294. // (multiline text is not supported in fields and will be removed)
  295. if( m_StyledTextCtrl->IsShown() )
  296. {
  297. wxSize maxSize;
  298. maxSize.x = -1; // Do not fix the max width
  299. maxSize.y = m_StyledTextCtrl->TextHeight( 0 );
  300. m_StyledTextCtrl->SetMaxSize( maxSize );
  301. m_StyledTextCtrl->SetUseVerticalScrollBar( false );
  302. m_StyledTextCtrl->SetUseHorizontalScrollBar( false );
  303. }
  304. SetupStandardButtons();
  305. // Now all widgets have the size fixed, call FinishDialogSettings
  306. finishDialogSettings();
  307. }
  308. void DIALOG_FIELD_PROPERTIES::OnTextValueSelectButtonClick( wxCommandEvent& aEvent )
  309. {
  310. // pick a footprint using the footprint picker.
  311. wxString fpid;
  312. if( m_StyledTextCtrl->IsShown() )
  313. fpid = m_StyledTextCtrl->GetValue();
  314. else
  315. fpid = m_TextCtrl->GetValue();
  316. if( KIWAY_PLAYER* frame = Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, this ) )
  317. {
  318. KIWAY_MAIL_EVENT event( FRAME_FOOTPRINT_CHOOSER, MAIL_SYMBOL_NETLIST, m_netlist );
  319. frame->KiwayMailIn( event );
  320. if( frame->ShowModal( &fpid, this ) )
  321. {
  322. if( m_StyledTextCtrl->IsShown() )
  323. m_StyledTextCtrl->SetValue( fpid );
  324. else
  325. m_TextCtrl->SetValue( fpid );
  326. }
  327. frame->Destroy();
  328. }
  329. }
  330. void DIALOG_FIELD_PROPERTIES::OnSetFocusText( wxFocusEvent& event )
  331. {
  332. if( m_firstFocus )
  333. {
  334. #ifdef __WXGTK__
  335. // Force an update of the text control before setting the text selection
  336. // This is needed because GTK seems to ignore the selection on first update
  337. //
  338. // Note that we can't do this on OSX as it tends to provoke Apple's
  339. // "[NSAlert runModal] may not be invoked inside of transaction begin/commit pair"
  340. // bug. See: https://bugs.launchpad.net/kicad/+bug/1837225
  341. if( m_fieldId == FIELD_T::REFERENCE || m_fieldId == FIELD_T::VALUE || m_fieldId == FIELD_T::SHEET_NAME )
  342. m_TextCtrl->Update();
  343. #endif
  344. if( m_fieldId == FIELD_T::REFERENCE )
  345. KIUI::SelectReferenceNumber( static_cast<wxTextEntry*>( m_TextCtrl ) );
  346. else if( m_fieldId == FIELD_T::VALUE || m_fieldId == FIELD_T::SHEET_NAME )
  347. m_TextCtrl->SetSelection( -1, -1 );
  348. m_firstFocus = false;
  349. }
  350. event.Skip();
  351. }
  352. void DIALOG_FIELD_PROPERTIES::onOrientButton( wxCommandEvent& aEvent )
  353. {
  354. for( BITMAP_BUTTON* btn : { m_horizontal, m_vertical } )
  355. {
  356. if( btn->IsChecked() && btn != aEvent.GetEventObject() )
  357. btn->Check( false );
  358. }
  359. }
  360. void DIALOG_FIELD_PROPERTIES::onHAlignButton( wxCommandEvent& aEvent )
  361. {
  362. for( BITMAP_BUTTON* btn : { m_hAlignLeft, m_hAlignCenter, m_hAlignRight } )
  363. {
  364. if( btn->IsChecked() && btn != aEvent.GetEventObject() )
  365. btn->Check( false );
  366. }
  367. }
  368. void DIALOG_FIELD_PROPERTIES::onVAlignButton( wxCommandEvent& aEvent )
  369. {
  370. for( BITMAP_BUTTON* btn : { m_vAlignTop, m_vAlignCenter, m_vAlignBottom } )
  371. {
  372. if( btn->IsChecked() && btn != aEvent.GetEventObject() )
  373. btn->Check( false );
  374. }
  375. }
  376. bool DIALOG_FIELD_PROPERTIES::TransferDataToWindow()
  377. {
  378. if( m_TextCtrl->IsShown() )
  379. {
  380. m_TextCtrl->SetValue( EscapeString( m_text, CTX_LINE ) );
  381. }
  382. else if( m_StyledTextCtrl->IsShown() )
  383. {
  384. m_StyledTextCtrl->SetValue( EscapeString( m_text, CTX_LINE ) );
  385. m_StyledTextCtrl->EmptyUndoBuffer();
  386. }
  387. if( m_unitChoice->IsShown() )
  388. {
  389. const SYMBOL* parent = m_field->GetParentSymbol();
  390. // Control shouldn't be shown for non-schematic symbols
  391. wxCHECK( parent->Type() == SCH_SYMBOL_T, true );
  392. const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( parent );
  393. for( int ii = 1; ii <= symbol->GetUnitCount(); ii++ )
  394. m_unitChoice->Append( symbol->GetUnitDisplayName( ii, false ) );
  395. if( symbol->GetUnit() <= (int) m_unitChoice->GetCount() )
  396. m_unitChoice->SetSelection( symbol->GetUnit() - 1 );
  397. }
  398. m_fontCtrl->SetFontSelection( m_font );
  399. m_posX.SetValue( m_position.x );
  400. m_posY.SetValue( m_position.y );
  401. m_textSize.SetValue( m_size );
  402. m_horizontal->Check( !m_isVertical );
  403. m_vertical->Check( m_isVertical );
  404. m_italic->Check( m_isItalic );
  405. m_bold->Check( m_isBold );
  406. m_textColorSwatch->SetSwatchColor( m_color, false );
  407. switch ( m_horizontalJustification )
  408. {
  409. case GR_TEXT_H_ALIGN_LEFT: m_hAlignLeft->Check( true ); break;
  410. case GR_TEXT_H_ALIGN_CENTER: m_hAlignCenter->Check( true ); break;
  411. case GR_TEXT_H_ALIGN_RIGHT: m_hAlignRight->Check( true ); break;
  412. case GR_TEXT_H_ALIGN_INDETERMINATE: break;
  413. }
  414. switch ( m_verticalJustification )
  415. {
  416. case GR_TEXT_V_ALIGN_TOP: m_vAlignTop->Check( true ); break;
  417. case GR_TEXT_V_ALIGN_CENTER: m_vAlignCenter->Check( true ); break;
  418. case GR_TEXT_V_ALIGN_BOTTOM: m_vAlignBottom->Check( true ); break;
  419. case GR_TEXT_V_ALIGN_INDETERMINATE: break;
  420. }
  421. m_visible->SetValue( m_isVisible );
  422. m_nameVisible->SetValue( m_isNameVisible );
  423. m_cbAllowAutoPlace->SetValue( m_allowAutoplace );
  424. return true;
  425. }
  426. bool DIALOG_FIELD_PROPERTIES::TransferDataFromWindow()
  427. {
  428. if( m_TextCtrl->IsShown() )
  429. m_text = UnescapeString( m_TextCtrl->GetValue() );
  430. else if( m_StyledTextCtrl->IsShown() )
  431. m_text = UnescapeString( m_StyledTextCtrl->GetValue() );
  432. if( m_fieldId == FIELD_T::SHEET_FILENAME )
  433. m_text = EnsureFileExtension( m_text, FILEEXT::KiCadSchematicFileExtension );
  434. m_position = VECTOR2I( m_posX.GetIntValue(), m_posY.GetIntValue() );
  435. m_size = m_textSize.GetIntValue();
  436. if( m_fontCtrl->HaveFontSelection() )
  437. m_font = m_fontCtrl->GetFontSelection( m_bold->IsChecked(), m_italic->IsChecked() );
  438. m_isVertical = m_vertical->IsChecked();
  439. m_isBold = m_bold->IsChecked();
  440. m_isItalic = m_italic->IsChecked();
  441. m_color = m_textColorSwatch->GetSwatchColor();
  442. if( m_hAlignLeft->IsChecked() )
  443. m_horizontalJustification = GR_TEXT_H_ALIGN_LEFT;
  444. else if( m_hAlignCenter->IsChecked() )
  445. m_horizontalJustification = GR_TEXT_H_ALIGN_CENTER;
  446. else
  447. m_horizontalJustification = GR_TEXT_H_ALIGN_RIGHT;
  448. if( m_vAlignTop->IsChecked() )
  449. m_verticalJustification = GR_TEXT_V_ALIGN_TOP;
  450. else if( m_vAlignCenter->IsChecked() )
  451. m_verticalJustification = GR_TEXT_V_ALIGN_CENTER;
  452. else
  453. m_verticalJustification = GR_TEXT_V_ALIGN_BOTTOM;
  454. m_isVisible = m_visible->GetValue();
  455. m_isNameVisible = m_nameVisible->GetValue();
  456. m_allowAutoplace = m_cbAllowAutoPlace->GetValue();
  457. return true;
  458. }
  459. void DIALOG_FIELD_PROPERTIES::updateText( SCH_FIELD* aField )
  460. {
  461. if( aField->GetTextWidth() != m_size )
  462. aField->SetTextSize( VECTOR2I( m_size, m_size ) );
  463. aField->SetFont( m_font );
  464. aField->SetVisible( m_isVisible );
  465. aField->SetTextAngle( m_isVertical ? ANGLE_VERTICAL : ANGLE_HORIZONTAL );
  466. aField->SetItalic( m_isItalic );
  467. aField->SetBold( m_isBold );
  468. aField->SetTextColor( m_color );
  469. }
  470. void DIALOG_FIELD_PROPERTIES::UpdateField( SCH_FIELD* aField )
  471. {
  472. if( aField->Schematic() )
  473. {
  474. const SCH_SHEET_PATH& sheetPath = aField->Schematic()->CurrentSheet();
  475. wxString variant = aField->Schematic()->GetCurrentVariant();
  476. aField->SetText( m_text, &sheetPath, variant );
  477. }
  478. else
  479. {
  480. aField->SetText( m_text );
  481. }
  482. updateText( aField );
  483. aField->SetNameShown( m_isNameVisible );
  484. aField->SetCanAutoplace( m_allowAutoplace );
  485. aField->SetHorizJustify( EDA_TEXT::MapHorizJustify( m_horizontalJustification ) );
  486. aField->SetVertJustify( EDA_TEXT::MapVertJustify( m_verticalJustification ) );
  487. aField->SetTextPos( m_position );
  488. }
  489. void DIALOG_FIELD_PROPERTIES::onScintillaCharAdded( wxStyledTextEvent &aEvent )
  490. {
  491. m_field->OnScintillaCharAdded( m_scintillaTricks, aEvent );
  492. }
  493. void DIALOG_FIELD_PROPERTIES::UpdateField( SCH_COMMIT* aCommit, SCH_FIELD* aField,
  494. SCH_SHEET_PATH* aSheetPath )
  495. {
  496. SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
  497. SCH_ITEM* parent = dynamic_cast<SCH_ITEM*>( aField->GetParent() );
  498. bool fieldTextSet = false;
  499. SCH_SHEET_PATH sheetPath;
  500. wxString variantName;
  501. // convert any text variable cross-references to their UUIDs
  502. m_text = aField->Schematic()->ConvertRefsToKIIDs( m_text );
  503. if( aField->Schematic() )
  504. {
  505. sheetPath = aField->Schematic()->CurrentSheet();
  506. variantName = aField->Schematic()->GetCurrentVariant();
  507. }
  508. if( parent && parent->Type() == SCH_SYMBOL_T )
  509. {
  510. SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( parent );
  511. if( m_fieldId == FIELD_T::REFERENCE )
  512. symbol->SetRef( aSheetPath, m_text );
  513. else
  514. symbol->SetFieldText( aField->GetName(), m_text, &sheetPath, variantName );
  515. fieldTextSet = true;
  516. // Set the unit selection in multiple units per package
  517. if( m_unitChoice->IsShown() )
  518. {
  519. int unit_selection = m_unitChoice->IsEnabled() ? m_unitChoice->GetSelection() + 1 : 1;
  520. symbol->SetUnitSelection( aSheetPath, unit_selection );
  521. symbol->SetUnit( unit_selection );
  522. }
  523. }
  524. else if( parent && parent->Type() == SCH_SHEET_T )
  525. {
  526. SCH_SHEET* sheet = static_cast<SCH_SHEET*>( parent );
  527. if( !aField->IsMandatory() )
  528. {
  529. sheet->SetFieldText( aField->GetName(), m_text, &sheetPath, variantName );
  530. fieldTextSet = true;
  531. }
  532. }
  533. else if( parent && parent->Type() == SCH_GLOBAL_LABEL_T )
  534. {
  535. if( m_fieldId == FIELD_T::INTERSHEET_REFS )
  536. {
  537. if( m_visible->GetValue() != parent->Schematic()->Settings().m_IntersheetRefsShow )
  538. {
  539. DisplayInfoMessage( this, _( "Intersheet reference visibility is "
  540. "controlled globally from "
  541. "Schematic Setup > General > Formatting" ) );
  542. }
  543. }
  544. }
  545. bool positioningModified = false;
  546. if( aField->GetPosition() != m_position )
  547. positioningModified = true;
  548. if( aField->GetTextAngle().IsVertical() != m_isVertical )
  549. positioningModified = true;
  550. if( aField->GetEffectiveHorizJustify() != m_horizontalJustification )
  551. positioningModified = true;
  552. if( aField->GetEffectiveVertJustify() != m_verticalJustification )
  553. positioningModified = true;
  554. // Changing a sheetname need to update the hierarchy navigator
  555. bool needUpdateHierNav = false;
  556. if( m_fieldId == FIELD_T::SHEET_NAME )
  557. needUpdateHierNav = m_text != aField->GetText();
  558. if( !fieldTextSet )
  559. aField->SetText( m_text );
  560. updateText( aField );
  561. aField->SetPosition( m_position );
  562. aField->SetNameShown( m_isNameVisible );
  563. aField->SetCanAutoplace( m_allowAutoplace );
  564. // Note that we must set justifications before we can ask if they're flipped. If the old
  565. // justification is center then it won't know (whereas if the new justification is center
  566. // the we don't care).
  567. aField->SetHorizJustify( m_horizontalJustification );
  568. aField->SetVertJustify( m_verticalJustification );
  569. if( aField->IsHorizJustifyFlipped() )
  570. aField->SetHorizJustify( EDA_TEXT::MapHorizJustify( -m_horizontalJustification ) );
  571. if( aField->IsVertJustifyFlipped() )
  572. aField->SetVertJustify( EDA_TEXT::MapVertJustify( -m_verticalJustification ) );
  573. // The value, footprint and datasheet fields should be kept in sync in multi-unit parts.
  574. // Of course the symbol must be annotated to collect other units.
  575. if( editFrame && parent && parent->Type() == SCH_SYMBOL_T )
  576. {
  577. SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( parent );
  578. if( symbol->IsAnnotated( aSheetPath ) && ( m_fieldId == FIELD_T::VALUE
  579. || m_fieldId == FIELD_T::FOOTPRINT
  580. || m_fieldId == FIELD_T::DATASHEET ) )
  581. {
  582. wxString ref = symbol->GetRef( aSheetPath );
  583. int unit = symbol->GetUnit();
  584. LIB_ID libId = symbol->GetLibId();
  585. for( SCH_SHEET_PATH& sheet : editFrame->Schematic().Hierarchy() )
  586. {
  587. SCH_SCREEN* screen = sheet.LastScreen();
  588. std::vector<SCH_SYMBOL*> otherUnits;
  589. CollectOtherUnits( ref, unit, libId, sheet, &otherUnits );
  590. for( SCH_SYMBOL* otherUnit : otherUnits )
  591. {
  592. aCommit->Modify( otherUnit, screen );
  593. otherUnit->GetField( m_fieldId )->SetText( m_text );
  594. editFrame->UpdateItem( otherUnit, false, true );
  595. }
  596. }
  597. }
  598. }
  599. if( positioningModified && parent )
  600. parent->SetFieldsAutoplaced( AUTOPLACE_NONE );
  601. // Update the hierarchy navigator labels if needed.
  602. if( editFrame && needUpdateHierNav )
  603. editFrame->UpdateLabelsHierarchyNavigator();
  604. }