KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_label_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) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2013 Wayne Stambaugh <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.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
27#include <widgets/font_choice.h>
32#include <sch_edit_frame.h>
33#include <tool/tool_manager.h>
34#include <gr_text.h>
35#include <confirm.h>
36#include <schematic.h>
39#include <string_utils.h>
40#include <kiface_base.h>
41#include <sch_label.h>
42#include <sch_commit.h>
43
44
47 m_Parent( aParent ),
48 m_currentLabel( aLabel ),
49 m_activeTextEntry( nullptr ),
50 m_netNameValidator( true ),
51 m_fields( nullptr ),
53 m_helpWindow( nullptr ),
54 m_labelList( nullptr )
55{
56 COLOR_SETTINGS* colorSettings = m_Parent->GetColorSettings();
57 COLOR4D schematicBackground = colorSettings->GetColor( LAYER_SCHEMATIC_BACKGROUND );
58
59 m_fields = new FIELDS_GRID_TABLE( this, aParent, m_grid, m_currentLabel );
62
63 if( m_currentLabel->Type() == SCH_GLOBAL_LABEL_T || m_currentLabel->Type() == SCH_LABEL_T )
64 {
66 SetInitialFocus( m_valueCombo->GetTextCtrl() );
67
68 m_labelSingleLine->Show( false );
69 m_valueSingleLine->Show( false );
70 }
71 else if( m_currentLabel->Type() == SCH_HIER_LABEL_T )
72 {
75
76 m_labelCombo->Show( false );
77 m_valueCombo->Show( false );
78 }
79 else if( m_currentLabel->Type() == SCH_DIRECTIVE_LABEL_T )
80 {
83
84 m_labelSingleLine->Show( false );
85 m_valueSingleLine->Show( false );
86 m_labelCombo->Show( false );
87 m_valueCombo->Show( false );
88 m_syntaxHelp->Show( false );
89 m_textEntrySizer->Show( false );
90 m_labelCombo->Show( false );
91 m_valueCombo->Show( false );
92 m_cbMultiLine->Show( false );
93
94 m_textSizeLabel->SetLabel( _( "Pin length:" ) );
95 }
96
97 if( !aNew )
98 m_cbMultiLine->Show( false );
99
100 // multiline set of labels can be used only to create new labels
101 m_multilineAllowed = aNew && m_cbMultiLine->IsShown();
102
103 switch( m_currentLabel->Type() )
104 {
105 case SCH_GLOBAL_LABEL_T: SetTitle( _( "Global Label Properties" ) ); break;
106 case SCH_HIER_LABEL_T: SetTitle( _( "Hierarchical Label Properties" ) ); break;
107 case SCH_LABEL_T: SetTitle( _( "Label Properties" ) ); break;
108 case SCH_DIRECTIVE_LABEL_T: SetTitle( _( "Directive Label Properties" ) ); break;
109 case SCH_SHEET_PIN_T: SetTitle( _( "Hierarchical Sheet Pin Properties" ) ); break;
110 default: UNIMPLEMENTED_FOR( m_currentLabel->GetClass() ); break;
111 }
112
113 m_grid->SetTable( m_fields );
114 m_grid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this, {},
115 [&]( wxCommandEvent& aEvent )
116 {
117 OnAddField( aEvent );
118 } ) );
119 m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
120 m_grid->ShowHideColumns( "0 1 2 3 4 5 6 7" );
121 m_shownColumns = m_grid->GetShownColumns();
122
123 // Configure button logos
128
129 m_separator1->SetIsSeparator();
130
131 m_bold->SetIsCheckButton();
133 m_italic->SetIsCheckButton();
135
136 m_separator2->SetIsSeparator();
137
138 m_spin0->SetIsRadioButton();
139 m_spin1->SetIsRadioButton();
140 m_spin2->SetIsRadioButton();
141 m_spin3->SetIsRadioButton();
142
143 m_separator3->SetIsSeparator();
144
145 m_textColorSwatch->SetDefaultColor( COLOR4D::UNSPECIFIED );
146 m_textColorSwatch->SetSwatchBackground( schematicBackground );
147
148 // Show/hide relevant controls
150 {
151 m_dot->Hide();
152 m_circle->Hide();
153 m_diamond->Hide();
154 m_rectangle->Hide();
155
160 }
161 else if( m_currentLabel->Type() == SCH_DIRECTIVE_LABEL_T )
162 {
163 m_input->Hide();
164 m_output->Hide();
165 m_bidirectional->Hide();
166 m_triState->Hide();
167 m_passive->Hide();
168
169 m_fontLabel->SetLabel( _( "Orientation:" ) );
170 m_fontCtrl->Hide();
171 m_separator1->Hide();
172 m_bold->Hide();
173 m_italic->Hide();
174 m_separator2->Hide();
179 m_separator3->Hide();
180
181 m_formattingGB->Detach( m_fontCtrl );
182 m_formattingGB->Detach( m_iconBar );
183 m_formattingGB->Add( m_iconBar, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxEXPAND | wxRIGHT, 5 );
184 }
185 else
186 {
187 m_shapeSizer->Show( false );
188
193 }
194
195 if( !m_currentLabel->AutoRotateOnPlacementSupported() )
196 {
197 m_autoRotate->Hide();
198 wxSizer* parentSizer = m_autoRotate->GetContainingSizer();
199 parentSizer->Detach( m_autoRotate );
200 parentSizer->Layout();
201 }
202
204
205 // DIALOG_SHIM needs a unique hash_key because classname is not sufficient because the
206 // various versions have different controls so we want to store sizes for each version.
207 m_hash_key = TO_UTF8( GetTitle() );
208
209 m_spin0->Bind( wxEVT_BUTTON, &DIALOG_LABEL_PROPERTIES::onSpinButton, this );
210 m_spin1->Bind( wxEVT_BUTTON, &DIALOG_LABEL_PROPERTIES::onSpinButton, this );
211 m_spin2->Bind( wxEVT_BUTTON, &DIALOG_LABEL_PROPERTIES::onSpinButton, this );
212 m_spin3->Bind( wxEVT_BUTTON, &DIALOG_LABEL_PROPERTIES::onSpinButton, this );
213
214 // wxFormBuilder doesn't include this event...
215 m_grid->Connect( wxEVT_GRID_CELL_CHANGING,
216 wxGridEventHandler( DIALOG_LABEL_PROPERTIES::OnGridCellChanging ), nullptr,
217 this );
218
219 // Now all widgets have the size fixed, call FinishDialogSettings
221}
222
223
225{
226 // Prevents crash bug in wxGrid's d'tor
227 m_grid->DestroyTable( m_fields );
228
229 m_grid->Disconnect( wxEVT_GRID_CELL_CHANGING,
230 wxGridEventHandler( DIALOG_LABEL_PROPERTIES::OnGridCellChanging ), nullptr,
231 this );
232
233 // Delete the GRID_TRICKS.
234 m_grid->PopEventHandler( true );
235
236 if( m_helpWindow )
237 m_helpWindow->Destroy();
238}
239
240
242{
243 if( !wxDialog::TransferDataToWindow() )
244 return false;
245
246 // Respond to previously-saved state of multilable checkbox
247 wxCommandEvent dummy;
249
250 wxString text;
251
253 {
254 // show control characters in a human-readable format
255 text = UnescapeString( m_currentLabel->GetText() );
256
257 // show text variable cross-references in a human-readable format
258 text = m_currentLabel->Schematic()->ConvertKIIDsToRefs( text );
259 }
260
261 if( m_currentLabel->Type() == SCH_GLOBAL_LABEL_T || m_currentLabel->Type() == SCH_LABEL_T )
262 {
263 // Load the combobox with the existing labels of the same type
264 std::set<wxString> existingLabels;
265 SCH_SCREENS allScreens( m_Parent->Schematic().Root() );
266
267 for( SCH_SCREEN* screen = allScreens.GetFirst(); screen; screen = allScreens.GetNext() )
268 {
269 for( SCH_ITEM* item : screen->Items().OfType( m_currentLabel->Type() ) )
270 {
271 const SCH_LABEL_BASE* label = static_cast<const SCH_LABEL_BASE*>( item );
272 existingLabels.insert( UnescapeString( label->GetText() ) );
273 }
274
275 // Add global power labels from power symbols
276 if( m_currentLabel->Type() == SCH_GLOBAL_LABEL_T )
277 {
278 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_LOCATE_POWER_T ) )
279 {
280 const SCH_SYMBOL* power = static_cast<const SCH_SYMBOL*>( item );
281
282 // Ensure the symbol has the Power (i.e. equivalent to a global label
283 // before adding its value in list
284 if( power->IsSymbolLikePowerGlobalLabel() )
285 {
286 const SCH_FIELD* valueField = power->GetField( FIELD_T::VALUE );
287 existingLabels.insert( UnescapeString( valueField->GetText() ) );
288 }
289 }
290 }
291
292 // Add local power labels from power symbols
293 if( m_currentLabel->Type() == SCH_LABEL_T )
294 {
295 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_LOCATE_POWER_T ) )
296 {
297 const SCH_SYMBOL* power = static_cast<const SCH_SYMBOL*>( item );
298
299 // Ensure the symbol has the Power (i.e. equivalent to a local label
300 // before adding its value in list
301 if( power->IsSymbolLikePowerLocalLabel() )
302 {
303 const SCH_FIELD* valueField = power->GetField( FIELD_T::VALUE );
304 existingLabels.insert( UnescapeString( valueField->GetText() ) );
305 }
306 }
307 }
308 }
309
310 // Add bus aliases to label list
311 for( const std::shared_ptr<BUS_ALIAS>& busAlias : m_Parent->Schematic().GetAllBusAliases() )
312 existingLabels.insert( wxT( "{" ) + busAlias->GetName() + wxT( "}" ) );
313
314 for( const wxString& label : existingLabels )
315 m_existingLabelArray.push_back( label );
316
317 m_valueCombo->SetStringList( m_existingLabelArray );
318 m_valueCombo->SetSelectedString( text );
319 }
320 else if( m_activeTextEntry )
321 {
322 m_activeTextEntry->SetValue( text );
323 }
324
325 // Push a copy of each field into m_updateFields
326 for( SCH_FIELD& field : m_currentLabel->GetFields() )
327 {
328 SCH_FIELD field_copy( field );
329
330 // change offset to be symbol-relative
331 field_copy.Offset( -m_currentLabel->GetPosition() );
332
333 m_fields->push_back( field_copy );
334 }
335
336 // notify the grid
337 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, (int) m_fields->size() );
338 m_grid->ProcessTableMessage( msg );
339
340 if( m_shapeSizer->AreAnyItemsShown() )
341 {
342 switch( m_currentLabel->GetShape() )
343 {
344 case LABEL_FLAG_SHAPE::L_INPUT: m_input->SetValue( true ); break;
345 case LABEL_FLAG_SHAPE::L_OUTPUT: m_output->SetValue( true ); break;
346 case LABEL_FLAG_SHAPE::L_BIDI: m_bidirectional->SetValue( true ); break;
347 case LABEL_FLAG_SHAPE::L_TRISTATE: m_triState->SetValue( true ); break;
348 case LABEL_FLAG_SHAPE::L_UNSPECIFIED: m_passive->SetValue( true ); break;
349 case LABEL_FLAG_SHAPE::F_DOT: m_dot->SetValue( true ); break;
350 case LABEL_FLAG_SHAPE::F_ROUND: m_circle->SetValue( true ); break;
351 case LABEL_FLAG_SHAPE::F_DIAMOND: m_diamond->SetValue( true ); break;
352 case LABEL_FLAG_SHAPE::F_RECTANGLE: m_rectangle->SetValue( true ); break;
353 }
354 }
355
356 m_fontCtrl->SetFontSelection( m_currentLabel->GetFont() );
357
359 m_textSize.SetValue( static_cast<SCH_DIRECTIVE_LABEL*>( m_currentLabel )->GetPinLength() );
360 else
361 m_textSize.SetValue( m_currentLabel->GetTextWidth() );
362
363 m_bold->Check( m_currentLabel->IsBold() );
364 m_italic->Check( m_currentLabel->IsItalic() );
365 m_textColorSwatch->SetSwatchColor( m_currentLabel->GetTextColor(), false );
366
367 switch( m_currentLabel->GetSpinStyle() )
368 {
369 case SPIN_STYLE::RIGHT: m_spin0->Check( true ); break;
370 case SPIN_STYLE::LEFT: m_spin1->Check( true ); break;
371 case SPIN_STYLE::UP: m_spin2->Check( true ); break;
372 case SPIN_STYLE::BOTTOM: m_spin3->Check( true ); break;
373 }
374
375 if( m_currentLabel->AutoRotateOnPlacementSupported() )
376 m_autoRotate->SetValue( m_currentLabel->AutoRotateOnPlacement() );
377
378 return true;
379}
380
381
382void DIALOG_LABEL_PROPERTIES::OnEnterKey( wxCommandEvent& aEvent )
383{
384 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
385}
386
387
389{
390 // If the key is WXK_RETURN/WXK_NUMPAD_ENTER because m_valueCombo is the source event, we do not skip
391 // the key event because the default action is to show the m_valueCombo dropdown list,
392 // and we only want to accept the entered string.
393 if(( aEvent.GetKeyCode() == WXK_RETURN ) || (aEvent.GetKeyCode() == WXK_NUMPAD_ENTER))
394 {
395 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
396 }
397 else if( aEvent.GetKeyCode() == WXK_SPACE )
398 {
399 // our FILTER_COMBOBOX uses the space as special command, not wanted here,
400 // to open the dropdown list of labels.
401 // So just add the space char to the current text, at current insertion point,
402 // and do not skip this event
403 m_activeTextEntry->WriteText( wxT(" " ) );
404 }
405 else
406 {
407 aEvent.Skip();
408 }
409}
410
411
413{
414 if( aEvent.GetKeyCode() == WXK_TAB )
415 {
416 if( aEvent.ShiftDown() )
417 {
418 m_textSizeCtrl->SetFocusFromKbd();
419 }
420 else if( !m_fields->empty() )
421 {
422 m_grid->SetFocusFromKbd();
423 m_grid->MakeCellVisible( 0, 0 );
424 m_grid->SetGridCursor( 0, 0 );
425 }
426 else
427 {
428 m_textSizeCtrl->SetFocusFromKbd();
429 }
430 }
431 else
432 {
433 aEvent.Skip();
434 }
435}
436
437
438static bool positioningChanged( const SCH_FIELD& a, const SCH_FIELD& b )
439{
440 return a.GetPosition() != b.GetPosition()
441 || a.GetHorizJustify() != b.GetHorizJustify()
442 || a.GetVertJustify() != b.GetVertJustify()
443 || a.GetTextAngle() != b.GetTextAngle();
444}
445
446
447static bool positioningChanged( FIELDS_GRID_TABLE* a, std::vector<SCH_FIELD>& b )
448{
449 for( size_t i = 0; i < a->size() && i < b.size(); ++i )
450 {
451 if( positioningChanged( a->at( i ), b.at( i ) ) )
452 return true;
453 }
454
455 return false;
456}
457
458
460{
461 if( !m_grid->CommitPendingChanges() )
462 return false;
463
464 if( !wxDialog::TransferDataFromWindow() )
465 return false;
466
467 // Don't allow text to disappear; it can be difficult to correct if you can't select it
468 if( !m_textSize.Validate( 0.01, 1000.0, EDA_UNITS::MM ) )
469 return false;
470
471 SCH_COMMIT commit( m_Parent );
472 wxString text;
473
474 /* save old text in undo list if not already in edit */
475 if( m_currentLabel->GetEditFlags() == 0 )
476 commit.Modify( m_currentLabel, m_Parent->GetScreen() );
477
478 m_Parent->GetCanvas()->Refresh();
479
481 {
482 // labels need escaping
484
485 // convert any text variable cross-references to their UUIDs
486 text = m_currentLabel->Schematic()->ConvertRefsToKIIDs( text );
487
488#ifdef __WXMAC__
489 // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting
490 text.Replace( wxS( "\r" ), wxS( "\n" ) );
491#endif
492
493 if( text.IsEmpty() && !m_currentLabel->IsNew() )
494 {
495 DisplayError( this, _( "Label can not be empty." ) );
496 return false;
497 }
498
499 m_currentLabel->SetText( text );
500 }
501
502 // change all field positions from relative to absolute
503 for( SCH_FIELD& field : *m_fields )
504 {
505 field.Offset( m_currentLabel->GetPosition() );
506
507 if( field.GetCanonicalName() == wxT( "Netclass" ) )
508 {
509 field.SetLayer( LAYER_NETCLASS_REFS );
510 }
511 else if( field.GetId() == FIELD_T::INTERSHEET_REFS )
512 {
513 if( field.IsVisible() != m_Parent->Schematic().Settings().m_IntersheetRefsShow )
514 {
515 DisplayInfoMessage( this, _( "Intersheet reference visibility is controlled globally from "
516 "Schematic Setup > General > Formatting" ) );
517 }
518
519 field.SetLayer( LAYER_INTERSHEET_REFS );
520 }
521 else
522 {
523 field.SetLayer( LAYER_FIELDS );
524 }
525 }
526
527 if( positioningChanged( m_fields, m_currentLabel->GetFields() ) )
528 m_currentLabel->SetFieldsAutoplaced( AUTOPLACE_NONE );
529
530 for( int ii = m_fields->GetNumberRows() - 1; ii >= 0; ii-- )
531 {
532 SCH_FIELD& field = m_fields->at( ii );
533 const wxString& fieldName = field.GetCanonicalName();
534 const wxString& fieldText = field.GetText();
535
536 if( fieldName.IsEmpty() && fieldText.IsEmpty() )
537 {
538 // delete empty, unnamed fields
539 m_fields->erase( m_fields->begin() + ii );
540 }
541 else if( fieldName == wxT( "Netclass" ) && fieldText.IsEmpty() )
542 {
543 // delete empty Netclass fields if there are other Netclass fields present
544 int netclassFieldCount = 0;
545
546 for( int jj = 0; jj < m_fields->GetNumberRows(); ++jj )
547 {
548 if( m_fields->at( jj ).GetCanonicalName() == wxT( "Netclass" ) )
549 netclassFieldCount++;
550 }
551
552 if( netclassFieldCount > 1 )
553 m_fields->erase( m_fields->begin() + ii );
554 }
555 else if( fieldName.IsEmpty() )
556 {
557 // give non-empty, unnamed fields a name
558 field.SetName( _( "untitled" ) );
559 }
560 }
561
562 int ordinal = 42; // Arbitrarily larger than any mandatory FIELD_T ids.
563
564 for( SCH_FIELD& field : *m_fields )
565 {
566 if( !field.IsMandatory() )
567 field.SetOrdinal( ordinal++ );
568 }
569
570 m_currentLabel->SetFields( *m_fields );
571
572 if( m_shapeSizer->AreAnyItemsShown() )
573 {
574 if( m_bidirectional->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
575 else if( m_input->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
576 else if( m_output->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
577 else if( m_triState->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::L_TRISTATE );
578 else if( m_passive->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
579 else if( m_dot->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::F_DOT );
580 else if( m_circle->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::F_ROUND );
581 else if( m_diamond->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::F_DIAMOND );
582 else if( m_rectangle->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::F_RECTANGLE );
583 }
584
585 if( m_fontCtrl->HaveFontSelection() )
586 m_currentLabel->SetFont( m_fontCtrl->GetFontSelection( m_bold->IsChecked(), m_italic->IsChecked() ) );
587
589 static_cast<SCH_DIRECTIVE_LABEL*>( m_currentLabel )->SetPinLength( m_textSize.GetIntValue() );
590 else if( m_currentLabel->GetTextWidth() != m_textSize.GetIntValue() )
591 m_currentLabel->SetTextSize( VECTOR2I( m_textSize.GetIntValue(), m_textSize.GetIntValue() ) );
592
593 // Must come after SetTextSize()
594 m_currentLabel->SetBold( m_bold->IsChecked() );
595 m_currentLabel->SetItalic( m_italic->IsChecked() );
596
597 m_currentLabel->SetTextColor( m_textColorSwatch->GetSwatchColor() );
598
599 SPIN_STYLE selectedSpinStyle= SPIN_STYLE::LEFT;
600
601 if( m_spin0->IsChecked() ) selectedSpinStyle = SPIN_STYLE::RIGHT;
602 else if( m_spin1->IsChecked() ) selectedSpinStyle = SPIN_STYLE::LEFT;
603 else if( m_spin2->IsChecked() ) selectedSpinStyle = SPIN_STYLE::UP;
604 else if( m_spin3->IsChecked() ) selectedSpinStyle = SPIN_STYLE::BOTTOM;
605
606 if( m_currentLabel->AutoRotateOnPlacementSupported() )
607 {
608 SCH_EDIT_FRAME* frame = static_cast<SCH_EDIT_FRAME*>( m_parentFrame );
609 m_currentLabel->SetAutoRotateOnPlacement( m_autoRotate->IsChecked() );
610 frame->AutoRotateItem( frame->GetScreen(), m_currentLabel );
611 }
612 else
613 {
614 m_currentLabel->SetAutoRotateOnPlacement( false );
615 }
616
617 if( !m_currentLabel->AutoRotateOnPlacement() && m_currentLabel->GetSpinStyle() != selectedSpinStyle )
618 m_currentLabel->SetSpinStyle( selectedSpinStyle );
619
620 AUTOPLACE_ALGO fieldsAutoplaced = m_currentLabel->GetFieldsAutoplaced();
621
622 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
623 m_currentLabel->AutoplaceFields( m_Parent->GetScreen(), fieldsAutoplaced );
624
625 if( !commit.Empty() )
626 {
627 commit.Push( _( "Edit Label Properties" ) );
628 }
629 else if( m_activeTextEntry && m_labelList )
630 {
631 text = m_activeTextEntry->GetValue();
632 // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting
633 text.Replace( wxS( "\r" ), wxS( "\n" ) );
634 wxArrayString lines = wxSplit( text, '\n' );
635
636 for( const wxString& line : lines )
637 {
638 text = EscapeString( line, CTX_NETNAME );
639 text.Trim( false ).Trim( true );
640
641 if( text.empty() )
642 continue;
643
644 // convert any text variable cross-references to their UUIDs
645 text = m_currentLabel->Schematic()->ConvertRefsToKIIDs( text );
646
647 switch ( m_currentLabel->Type() )
648 {
650 {
651 SCH_GLOBALLABEL* label = new SCH_GLOBALLABEL( *static_cast<SCH_GLOBALLABEL*>( m_currentLabel ) );
652 const_cast<KIID&>( label->m_Uuid ) = KIID(); // Gives a new UUID to the copy
653 label->SetText( text );
654 m_labelList->push_back( std::unique_ptr<SCH_LABEL_BASE>( label ) );
655 break;
656 }
657 case SCH_HIER_LABEL_T:
658 {
659 SCH_HIERLABEL* label = new SCH_HIERLABEL( *static_cast<SCH_HIERLABEL*>( m_currentLabel ) );
660 const_cast<KIID&>( label->m_Uuid ) = KIID();
661 label->SetText( text );
662 m_labelList->push_back( std::unique_ptr<SCH_LABEL_BASE>( label ) );
663 break;
664 }
665 case SCH_LABEL_T:
666 {
667 SCH_LABEL* label = new SCH_LABEL( *static_cast<SCH_LABEL*>( m_currentLabel ) );
668 const_cast<KIID&>( label->m_Uuid ) = KIID();
669 label->SetText( text );
670 m_labelList->push_back( std::unique_ptr<SCH_LABEL_BASE>( label ) );
671 break;
672 }
673 default:
674 break;
675 }
676 }
677 }
678 else if( m_labelList && m_currentLabel->Type() == SCH_DIRECTIVE_LABEL_T )
679 {
681 m_labelList->push_back( std::unique_ptr<SCH_LABEL_BASE>( label ) );
682 }
683
684 return true;
685}
686
687
688void DIALOG_LABEL_PROPERTIES::onSpinButton( wxCommandEvent& aEvent )
689{
690 for( BITMAP_BUTTON* btn : { m_spin0, m_spin1, m_spin2, m_spin3 } )
691 {
692 if( btn->IsChecked() && btn != aEvent.GetEventObject() )
693 btn->Check( false );
694 }
695}
696
697
698void DIALOG_LABEL_PROPERTIES::OnFormattingHelp( wxHyperlinkEvent& aEvent )
699{
701}
702
703
705{
706 wxGridCellEditor* editor = m_grid->GetCellEditor( event.GetRow(), event.GetCol() );
707 wxControl* control = editor->GetControl();
708
709 if( control && control->GetValidator() && !control->GetValidator()->Validate( control ) )
710 {
711 event.Veto();
712 m_delayedFocusRow = event.GetRow();
713 m_delayedFocusColumn = event.GetCol();
714 }
715 else if( event.GetCol() == FDC_NAME )
716 {
717 wxString newName = event.GetString();
718
719 for( int i = 0; i < m_grid->GetNumberRows(); ++i )
720 {
721 if( i == event.GetRow() )
722 continue;
723
724 if( newName.CmpNoCase( m_grid->GetCellValue( i, FDC_NAME ) ) == 0 )
725 {
726 DisplayError( this, wxString::Format( _( "Field name '%s' already in use." ),
727 newName ) );
728 event.Veto();
729 m_delayedFocusRow = event.GetRow();
730 m_delayedFocusColumn = event.GetCol();
731 break;
732 }
733 }
734 }
735
736 editor->DecRef();
737}
738
739
740void DIALOG_LABEL_PROPERTIES::OnAddField( wxCommandEvent& event )
741{
742 m_grid->OnAddRow(
743 [&]() -> std::pair<int, int>
744 {
745 wxString fieldName = wxT( "Netclass" );
746
747 for( SCH_FIELD& field : *m_fields )
748 {
749 if( field.GetId() != FIELD_T::INTERSHEET_REFS && field.GetName() != wxT( "Netclass" ) )
750 {
751 fieldName = wxEmptyString;
752 break;
753 }
754 }
755
756 fieldName = SCH_LABEL_BASE::GetDefaultFieldName( fieldName, true );
757
758 SCH_FIELD newField( m_currentLabel, FIELD_T::USER, fieldName );
759
760 if( m_fields->size() > 0 )
761 {
762 // SetAttributes() also covers text angle, size, italic and bold
763 newField.SetAttributes( m_fields->at( m_fields->size() - 1 ) );
764 newField.SetVisible( m_fields->at( m_fields->size() - 1 ).IsVisible() );
765 }
766 else
767 {
768 newField.SetVisible( true );
769 newField.SetItalic( true );
770 }
771
772 m_fields->push_back( newField );
773
774 // notify the grid
775 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
776 m_grid->ProcessTableMessage( msg );
777 return { m_fields->size() - 1, FDC_NAME };
778 } );
779}
780
781
782void DIALOG_LABEL_PROPERTIES::OnDeleteField( wxCommandEvent& event )
783{
784 m_grid->OnDeleteRows(
785 [&]( int row )
786 {
787 if( row < m_currentLabel->GetMandatoryFieldCount() )
788 {
789 DisplayError( this, _( "The first field is mandatory." ) );
790 return false;
791 }
792
793 return true;
794 },
795 [&]( int row )
796 {
797 m_fields->erase( m_fields->begin() + row );
798
799 // notify the grid
800 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
801 m_grid->ProcessTableMessage( msg );
802 } );
803}
804
805
806void DIALOG_LABEL_PROPERTIES::OnMoveUp( wxCommandEvent& event )
807{
808 m_grid->OnMoveRowUp(
809 [&]( int row )
810 {
811 return row > m_currentLabel->GetMandatoryFieldCount();
812 },
813 [&]( int row )
814 {
815 std::swap( *( m_fields->begin() + row ), *( m_fields->begin() + row - 1 ) );
816 m_grid->ForceRefresh();
817 } );
818}
819
820
821void DIALOG_LABEL_PROPERTIES::OnMoveDown( wxCommandEvent& event )
822{
823 m_grid->OnMoveRowUp(
824 [&]( int row )
825 {
826 return row >= m_currentLabel->GetMandatoryFieldCount();
827 },
828 [&]( int row )
829 {
830 std::swap( *( m_fields->begin() + row ), *( m_fields->begin() + row + 1 ) );
831 m_grid->ForceRefresh();
832 } );
833}
834
835
836void DIALOG_LABEL_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
837{
838 std::bitset<64> shownColumns = m_grid->GetShownColumns();
839
840 if( shownColumns != m_shownColumns )
841 {
842 m_shownColumns = shownColumns;
843
844 if( !m_grid->IsCellEditControlShown() )
845 m_grid->SetGridWidthsDirty();
846 }
847
848 // Handle a delayed focus
849 if( m_delayedFocusRow >= 0 && m_delayedFocusRow < m_grid->GetNumberRows() )
850 {
851 m_grid->SetFocus();
852 m_grid->MakeCellVisible( m_delayedFocusRow, m_delayedFocusColumn );
854 }
855
858}
859
860
862{
863 bool multiLine = m_multilineAllowed && m_cbMultiLine->IsChecked();
864
865 if( m_currentLabel->Type() == SCH_GLOBAL_LABEL_T || m_currentLabel->Type() == SCH_LABEL_T )
866 {
867 m_labelCombo->Show( !multiLine );
868 m_valueCombo->Show( !multiLine );
869 m_labelMultiLine->Show( multiLine );
870 m_valueMultiLine->Show( multiLine );
871
872 if( multiLine )
873 {
874 m_valueMultiLine->SetValue( m_valueCombo->GetValue() );
877 }
878 else
879 {
880 wxString multiText = m_valueMultiLine->GetValue();
881 m_valueCombo->SetValue( multiText.BeforeFirst( '\n' ) );
883 SetInitialFocus( m_valueCombo->GetTextCtrl() );
884 }
885 }
886 else if( m_currentLabel->Type() == SCH_HIER_LABEL_T )
887 {
888 m_labelSingleLine->Show( !multiLine );
889 m_valueSingleLine->Show( !multiLine );
890 m_labelMultiLine->Show( multiLine );
891 m_valueMultiLine->Show( multiLine );
892
893 if( multiLine )
894 {
895 m_valueMultiLine->SetValue( m_valueSingleLine->GetValue() );
898 }
899 else
900 {
901 wxString multiText = m_valueMultiLine->GetValue();
902 m_valueSingleLine->SetValue( multiText.BeforeFirst( '\n' ) );
905 }
906 }
907
908 Layout();
909}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
@ text_align_right
@ label_align_bottom
@ text_align_left
@ label_align_right
@ label_align_top
@ pinorient_right
@ label_align_left
@ text_align_bottom
A bitmap button widget that behaves like an AUI toolbar item's button when it is drawn.
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:402
Color settings are a bit different than most of the settings objects in that there can be more than o...
COLOR4D GetColor(int aLayer) const
bool Empty() const
Definition commit.h:137
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:106
DIALOG_LABEL_PROPERTIES_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Label Properties"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
std::list< std::unique_ptr< SCH_LABEL_BASE > > * m_labelList
void OnMoveUp(wxCommandEvent &event) override
void OnMoveDown(wxCommandEvent &event) override
DIALOG_LABEL_PROPERTIES(SCH_EDIT_FRAME *parent, SCH_LABEL_BASE *aLabel, bool aNew)
void OnEnterKey(wxCommandEvent &aEvent) override
wxEVT_COMMAND_ENTER event handler for single-line control.
void OnAddField(wxCommandEvent &event) override
SCH_NETNAME_VALIDATOR m_netNameValidator
void OnFormattingHelp(wxHyperlinkEvent &aEvent) override
void OnCBValueCharHook(wxKeyEvent &aEvent) override
void OnUpdateUI(wxUpdateUIEvent &event) override
void onSpinButton(wxCommandEvent &aEvent)
void onMultiLabelCheck(wxCommandEvent &aEvent) override
void OnDeleteField(wxCommandEvent &event) override
void OnGridCellChanging(wxGridEvent &event)
void OnValueCharHook(wxKeyEvent &aEvent) override
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition dialog_shim.h:82
void SetupStandardButtons(std::map< int, wxString > aLabels={})
std::string m_hash_key
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
EDA_BASE_FRAME * m_parentFrame
const KIID m_Uuid
Definition eda_item.h:521
const EDA_ANGLE & GetTextAngle() const
Definition eda_text.h:147
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:98
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
Definition eda_text.cpp:445
void Offset(const VECTOR2I &aOffset)
Definition eda_text.cpp:606
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:200
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:398
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition eda_text.h:203
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:282
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition eda_text.cpp:319
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
Definition kiid.h:49
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Execute the changes.
Schematic editor (Eeschema) main window.
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
void AutoRotateItem(SCH_SCREEN *aScreen, SCH_ITEM *aItem)
Automatically set the rotation of an item (if the item supports it).
VECTOR2I GetPosition() const override
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:116
wxString GetCanonicalName() const
Get a non-language-specific name for a field which can be used for storage, variable look-up,...
void SetName(const wxString &aName)
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
static const wxString GetDefaultFieldName(const wxString &aName, bool aUseDefaultName)
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:747
SCH_SCREEN * GetNext()
SCH_SCREEN * GetFirst()
Schematic symbol object.
Definition sch_symbol.h:76
bool IsSymbolLikePowerGlobalLabel() const
bool IsSymbolLikePowerLocalLabel() const
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
static HTML_MESSAGE_BOX * ShowSyntaxHelp(wxWindow *aParentWindow)
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition confirm.cpp:230
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:177
This file is part of the common library.
static bool positioningChanged(const SCH_FIELD &a, const SCH_FIELD &b)
#define _(s)
@ FDC_NAME
@ FDC_VALUE
@ LAYER_FIELDS
Definition layer_ids.h:462
@ LAYER_NETCLASS_REFS
Definition layer_ids.h:464
@ LAYER_SCHEMATIC_BACKGROUND
Definition layer_ids.h:488
@ LAYER_INTERSHEET_REFS
Definition layer_ids.h:463
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:96
AUTOPLACE_ALGO
Definition sch_item.h:68
@ AUTOPLACE_MANUAL
Definition sch_item.h:71
@ AUTOPLACE_NONE
Definition sch_item.h:69
@ AUTOPLACE_AUTO
Definition sch_item.h:70
@ L_BIDI
Definition sch_label.h:102
@ L_TRISTATE
Definition sch_label.h:103
@ L_UNSPECIFIED
Definition sch_label.h:104
@ F_DOT
Definition sch_label.h:107
@ F_ROUND
Definition sch_label.h:108
@ L_OUTPUT
Definition sch_label.h:101
@ F_DIAMOND
Definition sch_label.h:109
@ L_INPUT
Definition sch_label.h:100
@ F_RECTANGLE
Definition sch_label.h:110
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
@ CTX_NETNAME
@ USER
The field ID hasn't been set yet; field is invalid.
@ INTERSHEET_REFS
Global label cross-reference page numbers.
@ VALUE
Field Value of part, i.e. "3.3K".
@ SCH_DIRECTIVE_LABEL_T
Definition typeinfo.h:175
@ SCH_LABEL_T
Definition typeinfo.h:171
@ SCH_HIER_LABEL_T
Definition typeinfo.h:173
@ SCH_SHEET_PIN_T
Definition typeinfo.h:178
@ SCH_SYMBOL_LOCATE_POWER_T
Definition typeinfo.h:200
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:172
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695