KiCad PCB EDA Suite
Loading...
Searching...
No Matches
symbol_editor_edit_tool.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) 2019 CERN
5 * Copyright The 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, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <tool/tool_manager.h>
23#include "tl/expected.hpp"
24
25#include <optional>
26#include <wx/buffer.h>
27#include <wx/debug.h>
28#include <wx/mstream.h>
29#include <wx/dcmemory.h>
30
31#include <tool/picker_tool.h>
37#include <clipboard.h>
38#include <sch_actions.h>
39#include <increment.h>
40#include <pin_layout_cache.h>
41#include <render_utils.h>
42#include <string_utils.h>
43#include <symbol_edit_frame.h>
44#include <sch_commit.h>
51#include <view/view_controls.h>
52#include <view/view.h>
53#include <richio.h>
55#include <sch_textbox.h>
57#include <widgets/lib_tree.h>
58#include <widgets/wx_infobar.h>
60#include <math/util.h> // for KiROUND
62#include <trace_helpers.h>
63#include <sch_painter.h>
64#include <sch_plotter.h>
65#include <gal/gal_print.h>
67#include <zoom_defines.h>
68
69
70namespace
71{
72constexpr int clipboardMaxBitmapSize = 4096;
73constexpr double clipboardBboxInflation = 0.02;
74
75
76void appendMimeData( std::vector<CLIPBOARD_MIME_DATA>& aMimeData, const wxString& aMimeType,
77 const wxMemoryBuffer& aBuffer )
78{
79 if( aBuffer.GetDataLen() == 0 )
80 return;
81
83 entry.m_mimeType = aMimeType;
84 entry.m_data = aBuffer;
85 aMimeData.push_back( entry );
86}
87
88
89void appendMimeData( std::vector<CLIPBOARD_MIME_DATA>& aMimeData, const wxString& aMimeType,
90 wxImage&& aImage )
91{
92 if( !aImage.IsOk() )
93 return;
94
96 entry.m_mimeType = aMimeType;
97 entry.m_image = std::move( aImage );
98 aMimeData.push_back( std::move( entry ) );
99}
100
101
102bool plotSymbolToSvg( SYMBOL_EDIT_FRAME& aFrame, LIB_SYMBOL& aSymbol, const BOX2I& aBBox,
103 int aUnit, int aBodyStyle, wxMemoryBuffer& aBuffer )
104{
105 SCH_RENDER_SETTINGS renderSettings;
106 renderSettings.LoadColors( aFrame.GetColorSettings() );
107 renderSettings.SetDefaultPenWidth( aFrame.GetRenderSettings()->GetDefaultPenWidth() );
108
109 wxFileName tempFile( wxFileName::CreateTempFileName( wxS( "kicad_symbol_svg" ) ) );
110
111 // The bbox is the bounding box of the selected items only, so it is passed in rather than
112 // computed from the whole (partial) symbol.
113 if( !PlotSymbolToSVG( aSymbol, aSymbol, aUnit, aBodyStyle, aBBox, renderSettings, false,
114 tempFile.GetFullPath() ) )
115 {
116 wxRemoveFile( tempFile.GetFullPath() );
117 return false;
118 }
119
120 bool ok = LoadFileToMemory( tempFile.GetFullPath(), aBuffer );
121 wxRemoveFile( tempFile.GetFullPath() );
122 return ok;
123}
124
125
126wxImage renderSymbolToBitmap( SYMBOL_EDIT_FRAME& aFrame, LIB_SYMBOL& aSymbol, const BOX2I& aBBox,
127 int aUnit, int aBodyStyle, int aWidth, int aHeight,
128 double aViewScale, const wxColour& aBgColor )
129{
130 wxBitmap bitmap( aWidth, aHeight, 24 );
131 wxMemoryDC dc;
132 dc.SelectObject( bitmap );
133 dc.SetBackground( wxBrush( aBgColor ) );
134 dc.Clear();
135
138 std::unique_ptr<KIGFX::GAL_PRINT> galPrint = KIGFX::GAL_PRINT::Create( options, &dc );
139
140 if( !galPrint )
141 return wxImage();
142
143 KIGFX::GAL* gal = galPrint->GetGAL();
144 KIGFX::PRINT_CONTEXT* printCtx = galPrint->GetPrintCtx();
145 std::unique_ptr<KIGFX::SCH_PAINTER> painter = std::make_unique<KIGFX::SCH_PAINTER>( gal );
146 std::unique_ptr<KIGFX::VIEW> view = std::make_unique<KIGFX::VIEW>();
147
148 // For symbol editor, we don't have a full schematic context
149 // but SCH_PAINTER can still work for rendering individual items
150 view->SetGAL( gal );
151 view->SetPainter( painter.get() );
152 view->SetScaleLimits( ZOOM_MAX_LIMIT_EESCHEMA, ZOOM_MIN_LIMIT_EESCHEMA );
153 view->SetScale( 1.0 );
155
156 // Clone items and add to view
157 std::vector<std::unique_ptr<SCH_ITEM>> clonedItems;
158
159 for( SCH_ITEM& item : aSymbol.GetDrawItems() )
160 {
161 if( aUnit != ALL_UNITS
162 && item.GetUnit() != ALL_UNITS
163 && item.GetUnit() != aUnit )
164 {
165 continue;
166 }
167
168 if( aBodyStyle != ALL_BODY_STYLES
169 && item.GetBodyStyle() != ALL_BODY_STYLES
170 && item.GetBodyStyle() != aBodyStyle )
171 {
172 continue;
173 }
174
175 SCH_ITEM* clone = static_cast<SCH_ITEM*>( item.Clone() );
176 clonedItems.emplace_back( clone );
177 view->Add( clone );
178 }
179
180 SCH_RENDER_SETTINGS* dstSettings = painter->GetSettings();
181 dstSettings->LoadColors( aFrame.GetColorSettings() );
182 dstSettings->SetDefaultPenWidth( aFrame.GetRenderSettings()->GetDefaultPenWidth() );
183 dstSettings->SetIsPrinting( true );
184
185 COLOR4D bgColor4D( aBgColor.Red() / 255.0, aBgColor.Green() / 255.0,
186 aBgColor.Blue() / 255.0, 1.0 );
187 dstSettings->SetBackgroundColor( bgColor4D );
188
189 for( int i = 0; i < KIGFX::VIEW::VIEW_MAX_LAYERS; ++i )
190 {
191 view->SetLayerVisible( i, true );
192 view->SetLayerTarget( i, KIGFX::TARGET_NONCACHED );
193 }
194
195 view->SetLayerVisible( LAYER_DRAWINGSHEET, false );
196
197 // Calculate effective output DPI for the print context.
198 // On GTK, Cairo uses device scale 72/4800 and SetSheetSize doubles internal resolution.
199 // On Windows/macOS, there's no device scale, so effective DPI = native DPI * 2.
200#ifdef __WXGTK__
201 double ppi = 144.0;
202#else
203 double ppi = printCtx->GetNativeDPI() * 2.0;
204#endif
205 double inch2Iu = 1000.0 * schIUScale.IU_PER_MILS;
206 VECTOR2D pageSizeIn( (double) aWidth / ppi, (double) aHeight / ppi );
207
208 galPrint->SetSheetSize( pageSizeIn );
209 galPrint->SetNativePaperSize( pageSizeIn, printCtx->HasNativeLandscapeRotation() );
210
211 // SetSheetSize creates an internal canvas at 2× the nominal page size for quality.
212 // The × 2 multiplier ensures content fills this internal canvas.
213 double zoomFactor = 2.0 * aViewScale * inch2Iu / ppi;
214
215 // Set up both the GAL and VIEW to center on the bbox.
216 view->SetCenter( aBBox.Centre() );
217 view->SetScale( aViewScale * zoomFactor );
218
219 gal->SetLookAtPoint( aBBox.Centre() );
220 gal->SetZoomFactor( zoomFactor );
221 gal->SetClearColor( bgColor4D );
222 gal->ClearScreen();
223
224 view->UseDrawPriority( true );
225
226 {
228 view->Redraw();
229 }
230
231 dc.SelectObject( wxNullBitmap );
232 return bitmap.ConvertToImage();
233}
234
235
236tl::expected<wxImage, std::string> renderSymbolToImageWithAlpha( SYMBOL_EDIT_FRAME& aFrame, LIB_SYMBOL aSymbol,
237 const BOX2I& aBBox, int aUnit, int aBodyStyle )
238{
239 VECTOR2I size = aBBox.GetSize();
240
241 if( size.x <= 0 || size.y <= 0 )
242 return tl::make_unexpected( "Invalid image size" + std::to_string( size.x ) + "x" + std::to_string( size.y ) );
243
244 // Use the current view scale to match what the user sees on screen
245 double viewScale = aFrame.GetCanvas()->GetView()->GetScale();
246 int bitmapWidth = KiROUND( size.x * viewScale );
247 int bitmapHeight = KiROUND( size.y * viewScale );
248
249 // Clamp to maximum size while preserving aspect ratio
250 if( bitmapWidth > clipboardMaxBitmapSize || bitmapHeight > clipboardMaxBitmapSize )
251 {
252 double scaleDown = (double) clipboardMaxBitmapSize / std::max( bitmapWidth, bitmapHeight );
253 bitmapWidth = KiROUND( bitmapWidth * scaleDown );
254 bitmapHeight = KiROUND( bitmapHeight * scaleDown );
255 viewScale *= scaleDown;
256 }
257
258 if( bitmapWidth <= 0 || bitmapHeight <= 0 )
259 return tl::make_unexpected( "Invalid image size" + std::to_string( bitmapWidth ) + "x"
260 + std::to_string( bitmapHeight ) );
261
262 // Render twice with different backgrounds for alpha computation
263 wxImage imageOnWhite = renderSymbolToBitmap( aFrame, aSymbol, aBBox, aUnit, aBodyStyle, bitmapWidth, bitmapHeight,
264 viewScale, *wxWHITE );
265 wxImage imageOnBlack = renderSymbolToBitmap( aFrame, aSymbol, aBBox, aUnit, aBodyStyle, bitmapWidth, bitmapHeight,
266 viewScale, *wxBLACK );
267
268 if( !imageOnWhite.IsOk() || !imageOnBlack.IsOk() )
269 return tl::make_unexpected( "Failed to render symbol to white/black bitmaps" );
270
271 return CreateAlphaImageFromTwoRenders( imageOnWhite, imageOnBlack );
272}
273
274} // namespace
275
276
278 SCH_TOOL_BASE( "eeschema.SymbolEditTool" )
279{
280}
281
282
283const std::vector<KICAD_T> SYMBOL_EDITOR_EDIT_TOOL::SwappableItems = {
284 LIB_SYMBOL_T, // Allows swapping the anchor
285 SCH_PIN_T,
290};
291
292
294{
296
299
300 wxASSERT_MSG( drawingTools, "eeschema.SymbolDrawing tool is not available" );
301
302 auto haveSymbolCondition =
303 [&]( const SELECTION& sel )
304 {
305 return m_isSymbolEditor && m_frame->GetCurSymbol();
306 };
307
308 auto canEdit =
309 [&]( const SELECTION& sel )
310 {
311 if( !m_frame->IsSymbolEditable() )
312 return false;
313
314 if( m_frame->IsSymbolAlias() )
315 {
316 for( EDA_ITEM* item : sel )
317 {
318 if( item->Type() != SCH_FIELD_T )
319 return false;
320 }
321 }
322
323 return true;
324 };
325
326 auto swapSelectionCondition =
328
329 const auto canCopyText = SCH_CONDITIONS::OnlyTypes( {
333 SCH_PIN_T,
336 } );
337
338 const auto canConvertStackedPins =
339 [&]( const SELECTION& sel )
340 {
341 // If multiple pins are selected, check they are all at same location
342 if( sel.Size() >= 2 )
343 {
344 std::vector<SCH_PIN*> pins;
345 for( EDA_ITEM* item : sel )
346 {
347 if( item->Type() != SCH_PIN_T )
348 return false;
349 pins.push_back( static_cast<SCH_PIN*>( item ) );
350 }
351
352 // Check that all pins are at the same location
353 VECTOR2I pos = pins[0]->GetPosition();
354 for( size_t i = 1; i < pins.size(); ++i )
355 {
356 if( pins[i]->GetPosition() != pos )
357 return false;
358 }
359 return true;
360 }
361
362 // If single pin is selected, check if there are other pins at same location
363 if( sel.Size() == 1 && sel.Front()->Type() == SCH_PIN_T )
364 {
365 SCH_PIN* selectedPin = static_cast<SCH_PIN*>( sel.Front() );
366 VECTOR2I pos = selectedPin->GetPosition();
367
368 // Get the symbol and check for other pins at same location
369 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
370 if( !symbol )
371 return false;
372
373 int coLocatedCount = 0;
374
376 {
377 if( pin->GetPosition() == pos )
378 {
379 coLocatedCount++;
380
381 if( coLocatedCount >= 2 )
382 return true;
383 }
384 }
385 }
386
387 return false;
388 };
389
390 const auto canExplodeStackedPin =
391 [&]( const SELECTION& sel )
392 {
393 if( sel.Size() != 1 || sel.Front()->Type() != SCH_PIN_T )
394 return false;
395
396 SCH_PIN* pin = static_cast<SCH_PIN*>( sel.Front() );
397 bool isValid;
398 std::vector<wxString> stackedNumbers = pin->GetStackedPinNumbers( &isValid );
399 return isValid && stackedNumbers.size() > 1;
400 };
401
402 // clang-format off
403 // Add edit actions to the move tool menu
404 if( moveTool )
405 {
406 CONDITIONAL_MENU& moveMenu = moveTool->GetToolMenu().GetMenu();
407
408 moveMenu.AddSeparator( 200 );
409 moveMenu.AddItem( SCH_ACTIONS::rotateCCW, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
410 moveMenu.AddItem( SCH_ACTIONS::rotateCW, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
411 moveMenu.AddItem( SCH_ACTIONS::mirrorV, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
412 moveMenu.AddItem( SCH_ACTIONS::mirrorH, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
413
414 moveMenu.AddItem( SCH_ACTIONS::swap, swapSelectionCondition, 200 );
415 moveMenu.AddItem( SCH_ACTIONS::properties, canEdit && SCH_CONDITIONS::Count( 1 ), 200 );
416
417 moveMenu.AddSeparator( 300 );
420 moveMenu.AddItem( ACTIONS::copyAsText, canCopyText && SCH_CONDITIONS::IdleSelection, 300 );
421 moveMenu.AddItem( ACTIONS::duplicate, canEdit && SCH_CONDITIONS::NotEmpty, 300 );
422 moveMenu.AddItem( ACTIONS::doDelete, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
423
424 moveMenu.AddSeparator( 400 );
425 moveMenu.AddItem( ACTIONS::selectAll, haveSymbolCondition, 400 );
426 moveMenu.AddItem( ACTIONS::unselectAll, haveSymbolCondition, 400 );
427 }
428
429 // Add editing actions to the drawing tool menu
430 CONDITIONAL_MENU& drawMenu = drawingTools->GetToolMenu().GetMenu();
431
432 drawMenu.AddSeparator( 200 );
437
438 drawMenu.AddItem( SCH_ACTIONS::properties, canEdit && SCH_CONDITIONS::Count( 1 ), 200 );
439
440 // Add editing actions to the selection tool menu
441 CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
442
443 selToolMenu.AddItem( SCH_ACTIONS::rotateCCW, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
444 selToolMenu.AddItem( SCH_ACTIONS::rotateCW, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
445 selToolMenu.AddItem( SCH_ACTIONS::mirrorV, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
446 selToolMenu.AddItem( SCH_ACTIONS::mirrorH, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
447
448 selToolMenu.AddItem( SCH_ACTIONS::swap, swapSelectionCondition, 200 );
449 selToolMenu.AddItem( SCH_ACTIONS::properties, canEdit && SCH_CONDITIONS::Count( 1 ), 200 );
450
451 selToolMenu.AddSeparator( 250 );
452 selToolMenu.AddItem( SCH_ACTIONS::convertStackedPins, canEdit && canConvertStackedPins, 250 );
453 selToolMenu.AddItem( SCH_ACTIONS::explodeStackedPin, canEdit && canExplodeStackedPin, 250 );
454
455 selToolMenu.AddSeparator( 300 );
458 selToolMenu.AddItem( ACTIONS::copyAsText, canCopyText && SCH_CONDITIONS::IdleSelection, 300 );
459 selToolMenu.AddItem( ACTIONS::paste, canEdit && SCH_CONDITIONS::Idle, 300 );
460 selToolMenu.AddItem( ACTIONS::duplicate, canEdit && SCH_CONDITIONS::NotEmpty, 300 );
461 selToolMenu.AddItem( ACTIONS::doDelete, canEdit && SCH_CONDITIONS::NotEmpty, 300 );
462
463 selToolMenu.AddSeparator( 400 );
464 selToolMenu.AddItem( ACTIONS::selectAll, haveSymbolCondition, 400 );
465 selToolMenu.AddItem( ACTIONS::unselectAll, haveSymbolCondition, 400 );
466 // clang-format on
467
468 return true;
469}
470
471
473{
474 SCH_SELECTION& selection = m_selectionTool->RequestSelection();
475
476 if( selection.GetSize() == 0 )
477 return 0;
478
479 VECTOR2I rotPoint;
480 bool ccw = ( aEvent.Matches( SCH_ACTIONS::rotateCCW.MakeEvent() ) );
481 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
482 SCH_COMMIT localCommit( m_toolMgr );
483 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
484
485 if( !commit )
486 commit = &localCommit;
487
488 if( !item->IsMoving() )
489 commit->Modify( m_frame->GetCurSymbol(), m_frame->GetScreen(), RECURSE_MODE::RECURSE );
490
491 if( selection.GetSize() == 1 )
492 rotPoint = item->GetPosition();
493 else
494 rotPoint = m_frame->GetNearestHalfGridPosition( selection.GetCenter() );
495
496 for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
497 {
498 item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
499 item->Rotate( rotPoint, ccw );
500 m_frame->UpdateItem( item, false, true );
501 }
502
503 if( item->IsMoving() )
504 {
506 }
507 else
508 {
509 if( selection.IsHover() )
511
512 if( !localCommit.Empty() )
513 localCommit.Push( _( "Rotate" ) );
514 }
515
516 return 0;
517}
518
519
521{
522 SCH_SELECTION& selection = m_selectionTool->RequestSelection();
523
524 if( selection.GetSize() == 0 )
525 return 0;
526
527 VECTOR2I mirrorPoint;
528 bool xAxis = ( aEvent.Matches( SCH_ACTIONS::mirrorV.MakeEvent() ) );
529 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
530
531 if( !item->IsMoving() )
533
534 if( selection.GetSize() == 1 )
535 {
536 mirrorPoint = item->GetPosition();
537
538 switch( item->Type() )
539 {
540 case SCH_FIELD_T:
541 {
542 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
543
544 if( xAxis )
546 else
548
549 break;
550 }
551
552 default:
553 if( xAxis )
554 item->MirrorVertically( mirrorPoint.y );
555 else
556 item->MirrorHorizontally( mirrorPoint.x );
557
558 break;
559 }
560
561
562 m_frame->UpdateItem( item, false, true );
563 }
564 else
565 {
566 mirrorPoint = m_frame->GetNearestHalfGridPosition( selection.GetCenter() );
567
568 for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
569 {
570 item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
571
572 if( xAxis )
573 item->MirrorVertically( mirrorPoint.y );
574 else
575 item->MirrorHorizontally( mirrorPoint.x );
576
577 m_frame->UpdateItem( item, false, true );
578 }
579 }
580
581 if( item->IsMoving() )
582 {
584 }
585 else
586 {
587 if( selection.IsHover() )
589
590 m_frame->OnModify();
591 }
592
593 return 0;
594}
596{
597 SCH_SELECTION& selection = m_selectionTool->RequestSelection( SwappableItems );
598 std::vector<EDA_ITEM*> sorted = selection.GetItemsSortedBySelectionOrder();
599
600 if( selection.Size() < 2 )
601 return 0;
602
603 EDA_ITEM* front = selection.Front();
604 bool isMoving = front->IsMoving();
605
606 // Save copy for undo if not in edit (edit command already handle the save copy)
607 if( front->GetEditFlags() == 0 )
609
610 for( size_t i = 0; i < sorted.size() - 1; i++ )
611 {
612 SCH_ITEM* a = static_cast<SCH_ITEM*>( sorted[i] );
613 SCH_ITEM* b = static_cast<SCH_ITEM*>( sorted[( i + 1 ) % sorted.size()] );
614
615 VECTOR2I aPos = a->GetPosition(), bPos = b->GetPosition();
616 std::swap( aPos, bPos );
617
618 a->SetPosition( aPos );
619 b->SetPosition( bPos );
620
621 // Special case some common swaps
622 if( a->Type() == b->Type() )
623 {
624 switch( a->Type() )
625 {
626 case SCH_PIN_T:
627 {
628 SCH_PIN* aPin = static_cast<SCH_PIN*>( a );
629 SCH_PIN* bBpin = static_cast<SCH_PIN*>( b );
630
631 PIN_ORIENTATION aOrient = aPin->GetOrientation();
632 PIN_ORIENTATION bOrient = bBpin->GetOrientation();
633
634 aPin->SetOrientation( bOrient );
635 bBpin->SetOrientation( aOrient );
636
637 break;
638 }
639 default: break;
640 }
641 }
642
643 m_frame->UpdateItem( a, false, true );
644 m_frame->UpdateItem( b, false, true );
645 }
646
647 // Update R-Tree for modified items
648 for( EDA_ITEM* selected : selection )
649 updateItem( selected, true );
650
651 if( isMoving )
652 {
653 m_toolMgr->PostAction( ACTIONS::refreshPreview );
654 }
655 else
656 {
657 if( selection.IsHover() )
659
660 m_frame->OnModify();
661 }
662
663 return 0;
664}
665
666
667static std::vector<KICAD_T> nonFields =
668{
674};
675
676
678{
679 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
680 std::deque<EDA_ITEM*> items = m_selectionTool->RequestSelection().GetItems();
681 SCH_COMMIT commit( m_frame );
682
683 if( items.empty() )
684 return 0;
685
686 // Don't leave a freed pointer in the selection
688
689 commit.Modify( symbol, m_frame->GetScreen() );
690
691 std::set<SCH_ITEM*> toDelete;
692 int fieldsHidden = 0;
693 int fieldsAlreadyHidden = 0;
694
695 for( EDA_ITEM* item : items )
696 {
697 if( item->Type() == SCH_PIN_T )
698 {
699 SCH_PIN* curr_pin = static_cast<SCH_PIN*>( item );
700 VECTOR2I pos = curr_pin->GetPosition();
701
702 toDelete.insert( curr_pin );
703
704 // when pin editing is synchronized, pins in the same position, with the same name
705 // in different units are also removed. But only one pin per unit (matching)
706 if( m_frame->SynchronizePins() )
707 {
708 std::vector<bool> got_unit( symbol->GetUnitCount() + 1 );
709
710 got_unit[curr_pin->GetUnit()] = true;
711
713 {
714 if( got_unit[pin->GetUnit()] )
715 continue;
716
717 if( pin->GetPosition() != pos )
718 continue;
719
720 if( pin->GetBodyStyle() != curr_pin->GetBodyStyle() )
721 continue;
722
723 if( pin->GetType() != curr_pin->GetType() )
724 continue;
725
726 if( pin->GetName() != curr_pin->GetName() )
727 continue;
728
729 toDelete.insert( pin );
730 got_unit[pin->GetUnit()] = true;
731 }
732 }
733 }
734 else if( item->Type() == SCH_FIELD_T )
735 {
736 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
737
738 // Hide "deleted" fields
739 if( field->IsVisible() )
740 {
741 field->SetVisible( false );
742 fieldsHidden++;
743 }
744 else
745 {
746 fieldsAlreadyHidden++;
747 }
748 }
749 else if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( item ) )
750 {
751 toDelete.insert( schItem );
752 }
753 }
754
755 for( SCH_ITEM* item : toDelete )
756 symbol->RemoveDrawItem( item );
757
758 if( toDelete.size() == 0 )
759 {
760 if( fieldsHidden == 1 )
761 commit.Push( _( "Hide Field" ) );
762 else if( fieldsHidden > 1 )
763 commit.Push( _( "Hide Fields" ) );
764 else if( fieldsAlreadyHidden > 0 )
765 m_frame->ShowInfoBarError( _( "Use the Symbol Properties dialog to remove fields." ) );
766 }
767 else
768 {
769 commit.Push( _( "Delete" ) );
770 }
771
772 m_frame->RebuildView();
773 return 0;
774}
775
776
778 bool aCursorMovedByKeyboard )
779{
780 if( aCursorMovedByKeyboard )
781 return false;
782
783 // Mouse, not cursor, as grid points may well not be under any text
784 if( OPT_BOX2I numberBox = aPin.GetLayoutCache().GetPinNumberBBox() )
785 return numberBox->Contains( aMousePos );
786
787 return false;
788}
789
790
792{
793 SCH_SELECTION& selection = m_selectionTool->RequestSelection();
794
795 if( selection.Empty() || aEvent.IsAction( &SCH_ACTIONS::symbolProperties ) )
796 {
797 // If called from tree context menu, edit properties without loading into canvas
799 {
800 LIB_ID treeLibId = m_frame->GetTreeLIBID();
801
802 // Check if the selected symbol in tree is different from the currently loaded one
803 if( treeLibId.IsValid() &&
804 ( !m_frame->GetCurSymbol() || m_frame->GetCurSymbol()->GetLibId() != treeLibId ) )
805 {
806 // Edit properties directly from library buffer without loading to canvas
808 return 0;
809 }
810 }
811
812 if( m_frame->GetCurSymbol() )
814 }
815 else if( selection.Size() == 1 )
816 {
817 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
818
819 // Save copy for undo if not in edit (edit command already handle the save copy)
820 if( item->GetEditFlags() == 0 )
822
823 switch( item->Type() )
824 {
825 case SCH_PIN_T:
826 {
827 SCH_PIN& pin = static_cast<SCH_PIN&>( *item );
828
829 const VECTOR2I& mousePos = m_toolMgr->GetMousePosition();
830 const bool keyboardCursor =
832
833 if( SYMBOL_EDITOR_PIN_TOOL* pinTool = m_toolMgr->GetTool<SYMBOL_EDITOR_PIN_TOOL>() )
834 pinTool->EditPinProperties( &pin, ShouldFocusPinNumber( pin, mousePos, keyboardCursor ) );
835
836 break;
837 }
838 case SCH_SHAPE_T:
839 editShapeProperties( static_cast<SCH_SHAPE*>( item ) );
840 break;
841
842 case SCH_TEXT_T:
843 editTextProperties( item );
844 break;
845
846 case SCH_TEXTBOX_T:
847 editTextBoxProperties( item );
848 break;
849
850 case SCH_FIELD_T:
851 editFieldProperties( static_cast<SCH_FIELD*>( item ) );
852 break;
853
854 default:
855 wxFAIL_MSG( wxT( "Unhandled item <" ) + item->GetClass() + wxT( ">" ) );
856 break;
857 }
858 }
859 else if( selection.Size() > 1 )
860 {
861 WX_INFOBAR* infobar = frame()->GetInfoBar();
862
863 infobar->RemoveAllButtons();
864
865 if( !frame()->GetPropertiesPanel()->IsShownOnScreen() )
866 {
867 infobar->AddLink( _( "Show Properties panel" ),
868 [this]( wxHyperlinkEvent& )
869 {
870 frame()->ToggleProperties();
871 } );
872 }
873
874 infobar->AddCloseButton();
875 infobar->ShowMessageFor( _( "Use Properties panel to edit properties common to selected items." ),
876 8000, wxICON_INFORMATION );
877 }
878
879 if( selection.IsHover() )
881
882 return 0;
883}
884
885
887{
888 DIALOG_SHAPE_PROPERTIES dlg( m_frame, aShape );
889
890 if( dlg.ShowModal() != wxID_OK )
891 return;
892
893 updateItem( aShape, true );
894 m_frame->GetCanvas()->Refresh();
895 m_frame->OnModify();
896
897 m_frame->SetDrawSpecificBodyStyle( !dlg.GetApplyToAllConversions() );
898 m_frame->SetDrawSpecificUnit( !dlg.GetApplyToAllUnits() );
899
900 std::vector<MSG_PANEL_ITEM> items;
901 aShape->GetMsgPanelInfo( m_frame, items );
902 m_frame->SetMsgPanel( items );
903}
904
905
907{
908 if ( aItem->Type() != SCH_TEXT_T )
909 return;
910
911 DIALOG_TEXT_PROPERTIES dlg( m_frame, static_cast<SCH_TEXT*>( aItem ) );
912
913 if( dlg.ShowModal() != wxID_OK )
914 return;
915
916 updateItem( aItem, true );
917 m_frame->GetCanvas()->Refresh();
918 m_frame->OnModify( );
919}
920
921
923{
924 if ( aItem->Type() != SCH_TEXTBOX_T )
925 return;
926
927 DIALOG_TEXT_PROPERTIES dlg( m_frame, static_cast<SCH_TEXTBOX*>( aItem ) );
928
929 if( dlg.ShowModal() != wxID_OK )
930 return;
931
932 updateItem( aItem, true );
933 m_frame->GetCanvas()->Refresh();
934 m_frame->OnModify( );
935}
936
937
939{
940 if( aField == nullptr )
941 return;
942
943 wxString caption;
944
945 if( aField->IsMandatory() )
946 caption.Printf( _( "Edit %s Field" ), TitleCaps( aField->GetName() ) );
947 else
948 caption.Printf( _( "Edit '%s' Field" ), aField->GetName() );
949
950 DIALOG_FIELD_PROPERTIES dlg( m_frame, caption, aField );
951
952 // The dialog may invoke a kiway player for footprint fields
953 // so we must use a quasimodal dialog.
954 if( dlg.ShowQuasiModal() != wxID_OK )
955 return;
956
957 SCH_COMMIT commit( m_toolMgr );
958 commit.Modify( aField, m_frame->GetScreen() );
959
960 dlg.UpdateField( aField );
961
962 commit.Push( caption );
963
964 m_frame->GetCanvas()->Refresh();
965 m_frame->UpdateSymbolMsgPanelInfo();
966}
967
968
970{
971 LIB_SYMBOL_LIBRARY_MANAGER& libMgr = m_frame->GetLibManager();
972 wxString libName = aLibId.GetLibNickname();
973 wxString symbolName = aLibId.GetLibItemName();
974
975 // Get the symbol from the library buffer (without loading it into the editor)
976 LIB_SYMBOL* bufferedSymbol = libMgr.GetBufferedSymbol( symbolName, libName );
977
978 if( !bufferedSymbol )
979 return;
980
981 // Create a copy to work with
982 LIB_SYMBOL tempSymbol( *bufferedSymbol );
983
986
987 DIALOG_LIB_SYMBOL_PROPERTIES dlg( m_frame, &tempSymbol );
988
989 // This dialog itself subsequently can invoke a KIWAY_PLAYER as a quasimodal
990 // frame. Therefore this dialog as a modal frame parent, MUST be run under
991 // quasimodal mode for the quasimodal frame support to work. So don't use
992 // the QUASIMODAL macros here.
993 if( dlg.ShowQuasiModal() != wxID_OK )
994 return;
995
996 wxString newName = tempSymbol.GetName();
997
998 // Update the buffered symbol with the changes. A rename has to be keyed on the old name so
999 // the existing buffer is renamed in place rather than a duplicate being created under the new
1000 // name.
1001 if( newName != symbolName )
1002 libMgr.UpdateSymbolAfterRename( &tempSymbol, symbolName, libName );
1003 else
1004 libMgr.UpdateSymbol( &tempSymbol, libName );
1005
1006 // Mark the library as modified
1007 libMgr.SetSymbolModified( newName, libName );
1008
1009 // Update the tree view
1010 LIB_ID newLibId( libName, newName );
1011 wxDataViewItem treeItem = libMgr.GetAdapter()->FindItem( newLibId );
1012 m_frame->UpdateLibraryTree( treeItem, &tempSymbol );
1013 m_frame->GetLibTree()->SelectLibId( newLibId );
1014}
1015
1016
1018{
1019 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1020 bool partLocked = symbol->UnitsLocked();
1021
1023 m_toolMgr->RunAction( ACTIONS::selectionClear );
1024
1026
1027 // This dialog itself subsequently can invoke a KIWAY_PLAYER as a quasimodal
1028 // frame. Therefore this dialog as a modal frame parent, MUST be run under
1029 // quasimodal mode for the quasimodal frame support to work. So don't use
1030 // the QUASIMODAL macros here.
1031 if( dlg.ShowQuasiModal() != wxID_OK )
1032 return;
1033
1034 m_frame->RebuildSymbolUnitAndBodyStyleLists();
1035 m_frame->OnModify();
1036
1037 // Update the library tree node so the description and other metadata reflect the changes
1038 // immediately without requiring the editor to be reopened.
1039 LIB_SYMBOL_LIBRARY_MANAGER& libMgr = m_frame->GetLibManager();
1040 wxDataViewItem treeItem = libMgr.GetAdapter()->FindItem( symbol->GetLibId() );
1041 m_frame->UpdateLibraryTree( treeItem, symbol );
1042
1043 // if m_UnitSelectionLocked has changed, set some edit options or defaults
1044 // to the best value
1045 if( partLocked != symbol->UnitsLocked() )
1046 {
1047 // Usually if units are locked, graphic items are specific to each unit
1048 // and if units are interchangeable, graphic items are common to units
1049 m_frame->SetDrawSpecificUnit( symbol->UnitsLocked() );
1050 }
1051}
1052
1053
1055{
1056 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1057
1058 if( !symbol )
1059 {
1060 wxBell();
1061 return 0;
1062 }
1063
1065 m_toolMgr->RunAction( ACTIONS::selectionClear );
1066
1068 dlg.SelectPinMapPage();
1069
1070 // This dialog can subsequently invoke a KIWAY_PLAYER as a quasimodal frame, so it must be run
1071 // quasimodally to keep that support working.
1072 if( dlg.ShowQuasiModal() != wxID_OK )
1073 return 0;
1074
1075 m_frame->RebuildSymbolUnitAndBodyStyleLists();
1076 m_frame->OnModify();
1077
1078 return 0;
1079}
1080
1081
1083{
1084 SCH_COMMIT commit( m_frame );
1085 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1086
1087 if( !symbol )
1088 return 0;
1089
1090 commit.Modify( symbol, m_frame->GetScreen() );
1091
1092 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1093 wxCHECK( selTool, -1 );
1094
1095 std::vector<SCH_PIN*> selectedPins;
1096
1097 SCH_SELECTION& selection = selTool->GetSelection();
1098
1099 for( EDA_ITEM* item : selection )
1100 {
1101 if( item->Type() == SCH_PIN_T )
1102 {
1103 SCH_PIN* pinItem = static_cast<SCH_PIN*>( item );
1104 selectedPins.push_back( pinItem );
1105 }
1106 }
1107
1108 // And now clear the selection so if we change the pins we don't have dangling pointers
1109 // in the selection.
1110 m_toolMgr->RunAction( ACTIONS::selectionClear );
1111
1112 DIALOG_LIB_EDIT_PIN_TABLE dlg( m_frame, symbol, selectedPins );
1113
1114 if( dlg.ShowModal() == wxID_CANCEL )
1115 return -1;
1116
1117 commit.Push( _( "Edit Pins" ) );
1118 m_frame->RebuildView();
1119
1120 return 0;
1121}
1122
1123
1125{
1126 SCH_COMMIT commit( m_frame );
1127 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1128
1129 if( !symbol )
1130 return 0;
1131
1132 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1133 wxCHECK( selTool, -1 );
1134
1135 SCH_SELECTION& selection = selTool->GetSelection();
1136
1137 // Collect pins to convert - accept pins with any number format
1138 std::vector<SCH_PIN*> pinsToConvert;
1139
1140 if( selection.Size() == 1 && selection.Front()->Type() == SCH_PIN_T )
1141 {
1142 // Single pin selected - find all pins at the same location
1143 SCH_PIN* selectedPin = static_cast<SCH_PIN*>( selection.Front() );
1144 VECTOR2I pos = selectedPin->GetPosition();
1145
1147 {
1148 if( pin->GetPosition() == pos )
1149 pinsToConvert.push_back( pin );
1150 }
1151 }
1152 else
1153 {
1154 // Multiple pins selected - use them directly, accepting any pin numbers
1155 for( EDA_ITEM* item : selection )
1156 {
1157 if( item->Type() == SCH_PIN_T )
1158 pinsToConvert.push_back( static_cast<SCH_PIN*>( item ) );
1159 }
1160 }
1161
1162 if( pinsToConvert.size() < 2 )
1163 {
1164 m_frame->ShowInfoBarError( _( "At least two pins are needed to convert to stacked pins" ) );
1165 return 0;
1166 }
1167
1168 // Check that all pins are at the same location
1169 VECTOR2I pos = pinsToConvert[0]->GetPosition();
1170 for( size_t i = 1; i < pinsToConvert.size(); ++i )
1171 {
1172 if( pinsToConvert[i]->GetPosition() != pos )
1173 {
1174 m_frame->ShowInfoBarError( _( "All pins must be at the same location" ) );
1175 return 0;
1176 }
1177 }
1178
1179 commit.Modify( symbol, m_frame->GetScreen() );
1180
1181 // Clear selection before modifying pins, like the Delete command does
1182 m_toolMgr->RunAction( ACTIONS::selectionClear );
1183
1184 // Sort pins for consistent ordering - handle arbitrary pin number formats
1185 std::sort( pinsToConvert.begin(), pinsToConvert.end(),
1186 []( SCH_PIN* a, SCH_PIN* b )
1187 {
1188 wxString numA = a->GetNumber();
1189 wxString numB = b->GetNumber();
1190
1191 // Try to convert to integers for proper numeric sorting
1192 long longA, longB;
1193 bool aIsNumeric = numA.ToLong( &longA );
1194 bool bIsNumeric = numB.ToLong( &longB );
1195
1196 // Both are purely numeric - sort numerically
1197 if( aIsNumeric && bIsNumeric )
1198 return longA < longB;
1199
1200 // Mixed numeric/non-numeric - numeric pins come first
1201 if( aIsNumeric && !bIsNumeric )
1202 return true;
1203 if( !aIsNumeric && bIsNumeric )
1204 return false;
1205
1206 // Both non-numeric or mixed alphanumeric - use lexicographic sorting
1207 return numA < numB;
1208 });
1209
1210 // Build the stacked notation string with range collapsing
1211 wxString stackedNotation = wxT("[");
1212
1213 // Helper function to collapse consecutive numbers into ranges - handles arbitrary pin formats
1214 auto collapseRanges =
1215 [&]() -> wxString
1216 {
1217 if( pinsToConvert.empty() )
1218 return wxT("");
1219
1220 wxString result;
1221
1222 // Group pins by their alphanumeric prefix for range collapsing
1223 std::map<wxString, std::vector<long>> prefixGroups;
1224 std::vector<wxString> nonNumericPins;
1225
1226 // Parse each pin number to separate prefix from numeric suffix
1227 for( SCH_PIN* pin : pinsToConvert )
1228 {
1229 wxString pinNumber = pin->GetNumber();
1230
1231 // Skip empty pin numbers (shouldn't happen, but be defensive)
1232 if( pinNumber.IsEmpty() )
1233 {
1234 nonNumericPins.push_back( wxT("(empty)") );
1235 continue;
1236 }
1237
1238 wxString prefix;
1239 wxString numericPart;
1240
1241 // Find where numeric part starts (scan from end)
1242 size_t numStart = pinNumber.length();
1243 for( int i = pinNumber.length() - 1; i >= 0; i-- )
1244 {
1245 if( !wxIsdigit( pinNumber[i] ) )
1246 {
1247 numStart = i + 1;
1248 break;
1249 }
1250
1251 if( i == 0 ) // All digits
1252 numStart = 0;
1253 }
1254
1255 if( numStart < pinNumber.length() ) // Has numeric suffix
1256 {
1257 prefix = pinNumber.Left( numStart );
1258 numericPart = pinNumber.Mid( numStart );
1259
1260 long numValue;
1261
1262 if( numericPart.ToLong( &numValue ) && numValue >= 0 ) // Valid non-negative number
1263 {
1264 prefixGroups[prefix].push_back( numValue );
1265 }
1266 else
1267 {
1268 // Numeric part couldn't be parsed or is negative - treat as non-numeric
1269 nonNumericPins.push_back( pinNumber );
1270 }
1271 }
1272 else // No numeric suffix - consolidate as individual value
1273 {
1274 nonNumericPins.push_back( pinNumber );
1275 }
1276 }
1277
1278 // Process each prefix group
1279 for( auto& [prefix, numbers] : prefixGroups )
1280 {
1281 if( !result.IsEmpty() )
1282 result += wxT(",");
1283
1284 // The prefix may contain characters that are structural in stacked notation (e.g. a pin
1285 // numbered "foo,bar3"); escape it so it round-trips as a single pin number.
1286 wxString escPrefix = EscapeStackedPinItem( prefix );
1287
1288 // Sort numeric values for this prefix
1289 std::sort( numbers.begin(), numbers.end() );
1290
1291 // Collapse consecutive ranges within this prefix
1292 size_t i = 0;
1293
1294 while( i < numbers.size() )
1295 {
1296 if( i > 0 ) // Not first number in this prefix group
1297 result += wxT(",");
1298
1299 long start = numbers[i];
1300 long end = start;
1301
1302 // Find the end of consecutive sequence
1303 while( i + 1 < numbers.size() && numbers[i + 1] == numbers[i] + 1 )
1304 {
1305 i++;
1306 end = numbers[i];
1307 }
1308
1309 // Add range or single number with prefix
1310 if( end > start + 1 ) // Range of 3+ numbers
1311 result += wxString::Format( wxT("%s%ld-%s%ld"), escPrefix, start, escPrefix, end );
1312 else if( end == start + 1 ) // Two consecutive numbers
1313 result += wxString::Format( wxT("%s%ld,%s%ld"), escPrefix, start, escPrefix, end );
1314 else // Single number
1315 result += wxString::Format( wxT("%s%ld"), escPrefix, start );
1316
1317 i++;
1318 }
1319 }
1320
1321 // Add non-numeric pin numbers as individual comma-separated values
1322 for( const wxString& nonNum : nonNumericPins )
1323 {
1324 if( !result.IsEmpty() )
1325 result += wxT(",");
1326
1327 result += EscapeStackedPinItem( nonNum );
1328 }
1329
1330 return result;
1331 };
1332
1333 stackedNotation += collapseRanges();
1334 stackedNotation += wxT("]");
1335
1336 // Keep the first pin and give it the stacked notation
1337 SCH_PIN* masterPin = pinsToConvert[0];
1338 masterPin->SetNumber( stackedNotation );
1339
1340 // Log information about pins being removed before we remove them
1341 wxLogTrace( traceStackedPins, wxString::Format( wxT( "Converting %zu pins to stacked notation '%s'" ),
1342 pinsToConvert.size(), stackedNotation ) );
1343
1344 // Remove all other pins from the symbol that were consolidated into the stacked notation
1345 // Collect pins to remove first, then remove them all at once like the Delete command
1346 std::vector<SCH_PIN*> pinsToRemove;
1347 for( size_t i = 1; i < pinsToConvert.size(); ++i )
1348 {
1349 SCH_PIN* pinToRemove = pinsToConvert[i];
1350
1351 // Log the pin before removing it
1352 wxLogTrace( traceStackedPins, wxString::Format( wxT( "Will remove pin '%s' at position (%d, %d)" ),
1353 pinToRemove->GetNumber(),
1354 pinToRemove->GetPosition().x,
1355 pinToRemove->GetPosition().y ) );
1356
1357 pinsToRemove.push_back( pinToRemove );
1358 }
1359
1360 // Remove all pins at once, like the Delete command does
1361 for( SCH_PIN* pin : pinsToRemove )
1362 {
1363 symbol->RemoveDrawItem( pin );
1364 }
1365
1366 commit.Push( _( "Convert Stacked Pins" ) );
1367 m_frame->RebuildView();
1368 return 0;
1369}
1370
1371
1373{
1374 SCH_COMMIT commit( m_frame );
1375 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1376
1377 if( !symbol )
1378 return 0;
1379
1380 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1381 wxCHECK( selTool, -1 );
1382
1383 SCH_SELECTION& selection = selTool->GetSelection();
1384
1385 if( selection.GetSize() != 1 || selection.Front()->Type() != SCH_PIN_T )
1386 {
1387 m_frame->ShowInfoBarError( _( "Select a single pin with stacked notation to explode" ) );
1388 return 0;
1389 }
1390
1391 SCH_PIN* pin = static_cast<SCH_PIN*>( selection.Front() );
1392
1393 // Check if the pin has stacked notation
1394 bool isValid;
1395 std::vector<wxString> stackedNumbers = pin->GetStackedPinNumbers( &isValid );
1396
1397 if( !isValid || stackedNumbers.size() <= 1 )
1398 {
1399 m_frame->ShowInfoBarError( _( "Selected pin does not have valid stacked notation" ) );
1400 return 0;
1401 }
1402
1403 commit.Modify( symbol, m_frame->GetScreen() );
1404
1405 // Clear selection before modifying pins
1406 m_toolMgr->RunAction( ACTIONS::selectionClear );
1407
1408 // Sort the stacked numbers to find the smallest one
1409 std::sort( stackedNumbers.begin(), stackedNumbers.end(),
1410 []( const wxString& a, const wxString& b )
1411 {
1412 // Try to convert to integers for proper numeric sorting
1413 long numA, numB;
1414 if( a.ToLong( &numA ) && b.ToLong( &numB ) )
1415 return numA < numB;
1416
1417 // Fall back to string comparison if not numeric
1418 return a < b;
1419 });
1420
1421 // Change the original pin to use the first (smallest) number and make it visible
1422 pin->SetNumber( stackedNumbers[0] );
1423 pin->SetVisible( true );
1424
1425 // Create additional pins for the remaining numbers and make them invisible
1426 for( size_t i = 1; i < stackedNumbers.size(); ++i )
1427 {
1428 SCH_PIN* newPin = new SCH_PIN( symbol );
1429
1430 // Copy all properties from the original pin
1431 newPin->SetPosition( pin->GetPosition() );
1432 newPin->SetOrientation( pin->GetOrientation() );
1433 newPin->SetShape( pin->GetShape() );
1434 newPin->SetLength( pin->GetLength() );
1435 // Hidden power input pins act as global labels, so demote them to passive
1436 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN )
1438 else
1439 newPin->SetType( pin->GetType() );
1440
1441 newPin->SetName( pin->GetName() );
1442 newPin->SetNumber( stackedNumbers[i] );
1443 newPin->SetNameTextSize( pin->GetNameTextSize() );
1444 newPin->SetNumberTextSize( pin->GetNumberTextSize() );
1445 newPin->SetUnit( pin->GetUnit() );
1446 newPin->SetBodyStyle( pin->GetBodyStyle() );
1447 newPin->SetVisible( false );
1448
1449 // Add the new pin to the symbol
1450 symbol->AddDrawItem( newPin );
1451 }
1452
1453 commit.Push( _( "Explode Stacked Pin" ) );
1454 m_frame->RebuildView();
1455 return 0;
1456}
1457
1458
1460{
1461 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1462
1463 if( !symbol )
1464 return 0;
1465
1466 if( !symbol->CanUpdateFieldsFromParent() )
1467 {
1468 m_frame->ShowInfoBarError( _( "Symbol is not derived from another symbol." ) );
1469 }
1470 else
1471 {
1472 DIALOG_UPDATE_SYMBOL_FIELDS dlg( m_frame, symbol );
1473
1474 if( dlg.ShowModal() == wxID_CANCEL )
1475 return -1;
1476 }
1477
1478 return 0;
1479}
1480
1481
1483{
1484 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1485
1486 // Nuke the selection for later rebuilding. This does *not* clear the flags on any items;
1487 // it just clears the SELECTION's reference to them.
1488 selTool->GetSelection().Clear();
1489 {
1490 m_frame->GetSymbolFromUndoList();
1491 }
1492 selTool->RebuildSelection();
1493
1494 return 0;
1495}
1496
1497
1499{
1500 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1501
1502 // Nuke the selection for later rebuilding. This does *not* clear the flags on any items;
1503 // it just clears the SELECTION's reference to them.
1504 selTool->GetSelection().Clear();
1505 {
1506 m_frame->GetSymbolFromRedoList();
1507 }
1508 selTool->RebuildSelection();
1509
1510 return 0;
1511}
1512
1513
1515{
1516 int retVal = Copy( aEvent );
1517
1518 if( retVal == 0 )
1519 retVal = DoDelete( aEvent );
1520
1521 return retVal;
1522}
1523
1524
1526{
1527 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1528 SCH_SELECTION& selection = m_selectionTool->RequestSelection( nonFields );
1529
1530 if( !symbol || !selection.GetSize() )
1531 return 0;
1532
1533 for( SCH_ITEM& item : symbol->GetDrawItems() )
1534 {
1535 if( item.Type() == SCH_FIELD_T )
1536 continue;
1537
1538 wxASSERT( !item.HasFlag( STRUCT_DELETED ) );
1539
1540 if( !item.IsSelected() )
1541 item.SetFlags( STRUCT_DELETED );
1542 }
1543
1544 LIB_SYMBOL* partCopy = new LIB_SYMBOL( *symbol );
1545
1546 STRING_FORMATTER formatter;
1547 SCH_IO_KICAD_SEXPR::FormatLibSymbol( partCopy, formatter );
1548
1549 delete partCopy;
1550
1551 for( SCH_ITEM& item : symbol->GetDrawItems() )
1552 item.ClearFlags( STRUCT_DELETED );
1553
1554 std::string prettyData = formatter.GetString();
1555 KICAD_FORMAT::Prettify( prettyData, KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES );
1556
1557 // Generate SVG and PNG for multi-format clipboard
1558 std::vector<CLIPBOARD_MIME_DATA> mimeData;
1559
1560 // Get the bounding box for just the selected items
1561 BOX2I bbox;
1562
1563 for( EDA_ITEM* item : selection )
1564 {
1565 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item );
1566 if( bbox.GetWidth() == 0 && bbox.GetHeight() == 0 )
1567 bbox = schItem->GetBoundingBox();
1568 else
1569 bbox.Merge( schItem->GetBoundingBox() );
1570 }
1571
1572 if( bbox.GetWidth() > 0 && bbox.GetHeight() > 0 )
1573 {
1574 bbox.Inflate( bbox.GetWidth() * clipboardBboxInflation,
1575 bbox.GetHeight() * clipboardBboxInflation );
1576
1577 // Create a temporary symbol with just the selected items for plotting
1578 std::unique_ptr<LIB_SYMBOL> plotSymbol = std::make_unique<LIB_SYMBOL>( *symbol );
1579
1580 // Mark unselected items as deleted in the plot copy
1581 for( SCH_ITEM& item : plotSymbol->GetDrawItems() )
1582 {
1583 if( item.Type() == SCH_FIELD_T )
1584 continue;
1585
1586 // Find matching item in selection by position/type
1587 bool found = false;
1588
1589 for( EDA_ITEM* selItem : selection )
1590 {
1591 SCH_ITEM* selSchItem = static_cast<SCH_ITEM*>( selItem );
1592
1593 if( selSchItem->Type() == item.Type()
1594 && selSchItem->GetPosition() == item.GetPosition() )
1595 {
1596 found = true;
1597 break;
1598 }
1599 }
1600
1601 if( !found )
1602 item.SetFlags( STRUCT_DELETED );
1603 }
1604
1605 // Now copy only the non-deleted items to a clean symbol for plotting
1606 std::unique_ptr<LIB_SYMBOL> cleanSymbol = std::make_unique<LIB_SYMBOL>( *plotSymbol );
1607 plotSymbol.reset();
1608
1609 int unit = m_frame->GetUnit();
1610 int bodyStyle = m_frame->GetBodyStyle();
1611
1612 wxMemoryBuffer svgBuffer;
1613
1614 if( plotSymbolToSvg( *m_frame, *cleanSymbol, bbox, unit, bodyStyle, svgBuffer ) )
1615 appendMimeData( mimeData, wxS( "image/svg+xml" ), svgBuffer );
1616
1617 tl::expected<wxImage, std::string> pngImage =
1618 renderSymbolToImageWithAlpha( *m_frame, *cleanSymbol, bbox, unit, bodyStyle );
1619
1620 if( pngImage )
1621 {
1622 wxASSERT( pngImage->IsOk() );
1623 appendMimeData( mimeData, wxS( "image/png" ), std::move( *pngImage ) );
1624 }
1625 else
1626 {
1627 wxLogWarning( wxS( "Failed to render symbol to PNG: " ) + wxString::FromUTF8( pngImage.error() ) );
1628 }
1629 }
1630
1631 if( SaveClipboard( prettyData, mimeData ) )
1632 return 0;
1633 else
1634 return -1;
1635}
1636
1637
1639{
1640 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1641 SCH_SELECTION& selection = selTool->RequestSelection();
1642
1643 if( selection.Empty() )
1644 return 0;
1645
1646 wxString itemsAsText = GetSelectedItemsAsText( selection );
1647
1648 if( selection.IsHover() )
1649 m_toolMgr->RunAction( ACTIONS::selectionClear );
1650
1651 return SaveClipboard( itemsAsText.ToStdString() );
1652}
1653
1654
1656{
1657 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1658 LIB_SYMBOL* newPart = nullptr;
1659
1660 if( !symbol || symbol->IsDerived() )
1661 return 0;
1662
1663 std::string clipboardData = GetClipboardUTF8();
1664
1665 try
1666 {
1667 std::vector<LIB_SYMBOL*> newParts = SCH_IO_KICAD_SEXPR::ParseLibSymbols( clipboardData, "Clipboard" );
1668
1669 if( newParts.empty() || !newParts[0] )
1670 return -1;
1671
1672 newPart = newParts[0];
1673 }
1674 catch( IO_ERROR& )
1675 {
1676 // If it's not a symbol then paste as text
1677 newPart = new LIB_SYMBOL( "dummy_part" );
1678
1679 wxString pasteText( clipboardData );
1680
1681 // Limit of 5000 is totally arbitrary. Without a limit, pasting a bitmap image from
1682 // eeschema makes KiCad appear to hang.
1683 if( pasteText.Length() > 5000 )
1684 pasteText = pasteText.Left( 5000 ) + wxT( "..." );
1685
1686 SCH_TEXT* newText = new SCH_TEXT( { 0, 0 }, pasteText, LAYER_DEVICE );
1687 newPart->AddDrawItem( newText );
1688 }
1689
1690 SCH_COMMIT commit( m_toolMgr );
1691
1692 commit.Modify( symbol, m_frame->GetScreen() );
1693 m_selectionTool->ClearSelection();
1694
1695 for( SCH_ITEM& item : symbol->GetDrawItems() )
1696 item.ClearFlags( IS_NEW | IS_PASTED | SELECTED );
1697
1698 for( SCH_ITEM& item : newPart->GetDrawItems() )
1699 {
1700 if( item.Type() == SCH_FIELD_T )
1701 continue;
1702
1703 SCH_ITEM* newItem = item.Duplicate( true, &commit );
1704 newItem->SetParent( symbol );
1705 newItem->SetFlags( IS_NEW | IS_PASTED | SELECTED );
1706
1707 newItem->SetUnit( newItem->GetUnit() ? m_frame->GetUnit() : ALL_UNITS );
1708 newItem->SetBodyStyle( newItem->GetBodyStyle() ? m_frame->GetBodyStyle() : ALL_BODY_STYLES );
1709
1710 symbol->AddDrawItem( newItem );
1711 getView()->Add( newItem );
1712 }
1713
1714 delete newPart;
1715
1716 m_selectionTool->RebuildSelection();
1717
1718 SCH_SELECTION& selection = m_selectionTool->GetSelection();
1719
1720 if( !selection.Empty() )
1721 {
1722 selection.SetReferencePoint( getViewControls()->GetCursorPosition( true ) );
1723
1724 if( m_toolMgr->RunSynchronousAction( SCH_ACTIONS::move, &commit ) )
1725 commit.Push( _( "Paste" ) );
1726 else
1727 commit.Revert();
1728 }
1729
1730 return 0;
1731}
1732
1733
1735{
1736 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1737 SCH_SELECTION& selection = m_selectionTool->RequestSelection( nonFields );
1738 SCH_COMMIT commit( m_toolMgr );
1739
1740 if( selection.GetSize() == 0 )
1741 return 0;
1742
1743 commit.Modify( symbol, m_frame->GetScreen() );
1744
1745 std::vector<EDA_ITEM*> oldItems;
1746 std::vector<EDA_ITEM*> newItems;
1747
1748 std::copy( selection.begin(), selection.end(), std::back_inserter( oldItems ) );
1749 std::sort( oldItems.begin(), oldItems.end(), []( EDA_ITEM* a, EDA_ITEM* b )
1750 {
1751 int cmp;
1752
1753 if( a->Type() != b->Type() )
1754 return a->Type() < b->Type();
1755
1756 // Create the new pins in the same order as the old pins
1757 if( a->Type() == SCH_PIN_T )
1758 {
1759 const wxString& aNum = static_cast<SCH_PIN*>( a )->GetNumber();
1760 const wxString& bNum = static_cast<SCH_PIN*>( b )->GetNumber();
1761
1762 cmp = StrNumCmp( aNum, bNum );
1763
1764 // If the pin numbers are not numeric, then just number them by their position
1765 // on the screen.
1766 if( aNum.IsNumber() && bNum.IsNumber() && cmp != 0 )
1767 return cmp < 0;
1768 }
1769
1771
1772 if( cmp != 0 )
1773 return cmp < 0;
1774
1775 return a->m_Uuid < b->m_Uuid;
1776 } );
1777
1778 for( EDA_ITEM* item : oldItems )
1779 {
1780 SCH_ITEM* oldItem = static_cast<SCH_ITEM*>( item );
1781 SCH_ITEM* newItem = oldItem->Duplicate( true, &commit );
1782
1783 if( newItem->Type() == SCH_PIN_T )
1784 {
1785 SCH_PIN* newPin = static_cast<SCH_PIN*>( newItem );
1786
1787 if( !newPin->GetNumber().IsEmpty() )
1788 newPin->SetNumber( wxString::Format( wxT( "%i" ), symbol->GetMaxPinNumber() + 1 ) );
1789 }
1790
1791 oldItem->ClearFlags( IS_NEW | IS_PASTED | SELECTED );
1792 newItem->SetFlags( IS_NEW | IS_PASTED | SELECTED );
1793 newItem->SetParent( symbol );
1794 newItems.push_back( newItem );
1795
1796 symbol->AddDrawItem( newItem );
1797 getView()->Add( newItem );
1798 }
1799
1800 m_toolMgr->RunAction( ACTIONS::selectionClear );
1801 m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &newItems );
1802
1803 selection.SetReferencePoint( getViewControls()->GetCursorPosition( true ) );
1804
1805 if( m_toolMgr->RunSynchronousAction( SCH_ACTIONS::move, &commit ) )
1806 commit.Push( _( "Duplicate" ) );
1807 else
1808 commit.Revert();
1809
1810 return 0;
1811}
1812
1813
1815{
1816 // clang-format off
1824
1832
1838
1846 // clang-format on
1847}
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:130
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
std::optional< BOX2I > OPT_BOX2I
Definition box2.h:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
static TOOL_ACTION decrementPrimary
Definition actions.h:92
static TOOL_ACTION paste
Definition actions.h:76
static TOOL_ACTION cancelInteractive
Definition actions.h:68
static TOOL_ACTION unselectAll
Definition actions.h:79
static TOOL_ACTION decrementSecondary
Definition actions.h:94
static TOOL_ACTION copy
Definition actions.h:74
static TOOL_ACTION undo
Definition actions.h:71
static TOOL_ACTION incrementSecondary
Definition actions.h:93
static TOOL_ACTION duplicate
Definition actions.h:80
static TOOL_ACTION incrementPrimary
Definition actions.h:91
static TOOL_ACTION doDelete
Definition actions.h:81
static TOOL_ACTION redo
Definition actions.h:72
static TOOL_ACTION deleteTool
Definition actions.h:82
static TOOL_ACTION increment
Definition actions.h:90
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
static TOOL_ACTION cut
Definition actions.h:73
static TOOL_ACTION copyAsText
Definition actions.h:75
static TOOL_ACTION refreshPreview
Definition actions.h:155
static TOOL_ACTION selectAll
Definition actions.h:78
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:228
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr size_type GetWidth() const
Definition box2.h:211
constexpr Vec Centre() const
Definition box2.h:94
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:594
constexpr size_type GetHeight() const
Definition box2.h:212
constexpr const SizeVec & GetSize() const
Definition box2.h:203
bool Empty() const
Definition commit.h:145
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:102
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
void AddSeparator(int aOrder=ANY_ORDER)
Add a separator to the menu.
This class is setup in expectation of its children possibly using Kiway player so DIALOG_SHIM::ShowQu...
void UpdateField(SCH_FIELD *aField)
void SelectPinMapPage()
Switch the notebook to the Pin Map page (issue #2282).
int ShowModal() override
Dialog to update or change schematic library symbols.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
virtual VECTOR2I GetPosition() const
Definition eda_item.h:348
virtual void SetPosition(const VECTOR2I &aPos)
Definition eda_item.h:349
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:270
EDA_ITEM_FLAGS GetEditFlags() const
Definition eda_item.h:170
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:158
const KIID m_Uuid
Definition eda_item.h:599
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:160
EDA_ITEM * GetParent() const
Definition eda_item.h:112
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:153
bool IsMoving() const
Definition eda_item.h:132
virtual bool IsVisible() const
Definition eda_text.h:226
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:378
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:239
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:347
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition eda_text.h:242
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:370
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
GAL_ANTIALIASING_MODE antialiasing_mode
static std::unique_ptr< GAL_PRINT > Create(GAL_DISPLAY_OPTIONS &aOptions, wxDC *aDC)
Abstract interface for drawing on a 2D-surface.
void SetZoomFactor(double aZoomFactor)
void SetLookAtPoint(const VECTOR2D &aPoint)
Get/set the Point in world space to look at.
virtual void ClearScreen()
Clear the screen.
void SetWorldUnitLength(double aWorldUnitLength)
Set the unit length.
void SetClearColor(const COLOR4D &aColor)
virtual double GetNativeDPI() const =0
virtual bool HasNativeLandscapeRotation() const =0
void SetDefaultPenWidth(int aWidth)
void SetIsPrinting(bool isPrinting)
const VC_SETTINGS & GetSettings() const
Return the current VIEW_CONTROLS settings.
double GetScale() const
Definition view.h:283
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:297
static constexpr int VIEW_MAX_LAYERS
Maximum number of layers that may be shown.
Definition view.h:775
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:168
const UTF8 & GetLibItemName() const
Definition lib_id.h:98
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:83
Symbol library management helper that is specific to the symbol library editor frame.
wxObjectDataPtr< LIB_TREE_MODEL_ADAPTER > & GetAdapter()
Return the adapter object that provides the stored data.
Define a library symbol object.
Definition lib_symbol.h:114
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:190
bool UnitsLocked() const
Check whether symbol units are interchangeable.
bool IsDerived() const
Definition lib_symbol.h:241
bool CanUpdateFieldsFromParent() const
Definition lib_symbol.h:420
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:843
wxString GetName() const override
Definition lib_symbol.h:183
void RemoveDrawItem(SCH_ITEM *aItem)
Remove draw aItem from list.
int GetUnitCount() const override
std::vector< SCH_PIN * > GetGraphicalPins(int aUnit=0, int aBodyStyle=0) const override
Graphical pins: Return schematic pin objects as drawn (unexpanded), filtered by unit/body.
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
OPT_BOX2I GetPinNumberBBox()
Get the bounding box of the pin number, if there is one.
static TOOL_ACTION rotateCCW
static TOOL_ACTION editSymbolPinMaps
static TOOL_ACTION mirrorV
static TOOL_ACTION swap
static TOOL_ACTION convertStackedPins
static TOOL_ACTION pinTable
static TOOL_ACTION properties
static TOOL_ACTION rotateCW
static TOOL_ACTION mirrorH
static TOOL_ACTION symbolProperties
static TOOL_ACTION explodeStackedPin
static TOOL_ACTION updateSymbolFields
static TOOL_ACTION move
SCH_RENDER_SETTINGS * GetRenderSettings()
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
Commit for the schematic and symbol editors.
Definition sch_commit.h:54
void Revert() override
Revert the commit by restoring the modified items state.
void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the KIGFX::VIEW instance used in the panel.
bool IsMandatory() const
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
static void FormatLibSymbol(LIB_SYMBOL *aPart, OUTPUTFORMATTER &aFormatter)
static std::vector< LIB_SYMBOL * > ParseLibSymbols(std::string &aSymbolText, std::string aSource, int aFileVersion=SEXPR_SCHEMATIC_FILE_VERSION)
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
SCH_ITEM * Duplicate(bool addToParentGroup, SCH_COMMIT *aCommit=nullptr, bool aDoClone=false) const
Routine to create a new copy of given item.
Definition sch_item.cpp:191
virtual void SetBodyStyle(int aBodyStyle)
Definition sch_item.h:252
int GetBodyStyle() const
Definition sch_item.h:253
virtual void MirrorHorizontally(int aCenter)
Mirror item horizontally about aCenter.
Definition sch_item.h:425
int GetUnit() const
Definition sch_item.h:243
virtual void Rotate(const VECTOR2I &aCenter, bool aRotateCCW)
Rotate the item around aCenter 90 degrees in the clockwise direction.
Definition sch_item.h:441
virtual void SetUnit(int aUnit)
Definition sch_item.h:242
wxString GetClass() const override
Return the class name.
Definition sch_item.h:180
virtual void MirrorVertically(int aCenter)
Mirror item vertically about aCenter.
Definition sch_item.h:433
void SetNumber(const wxString &aNumber)
Definition sch_pin.cpp:842
void SetVisible(bool aVisible)
Definition sch_pin.h:134
void SetOrientation(PIN_ORIENTATION aOrientation)
Definition sch_pin.h:113
void SetName(const wxString &aName)
Definition sch_pin.cpp:545
void SetPosition(const VECTOR2I &aPos) override
Definition sch_pin.h:318
const wxString & GetName() const
Definition sch_pin.cpp:527
void SetLength(int aLength)
Definition sch_pin.h:119
PIN_ORIENTATION GetOrientation() const
Definition sch_pin.cpp:386
void SetNumberTextSize(int aSize)
Definition sch_pin.cpp:896
void SetShape(GRAPHIC_PINSHAPE aShape)
Definition sch_pin.h:116
VECTOR2I GetPosition() const override
Definition sch_pin.cpp:378
PIN_LAYOUT_CACHE & GetLayoutCache() const
Get the layout cache associated with this pin.
Definition sch_pin.cpp:1799
void SetType(ELECTRICAL_PINTYPE aType)
Definition sch_pin.cpp:455
const wxString & GetNumber() const
Definition sch_pin.h:144
ELECTRICAL_PINTYPE GetType() const
Definition sch_pin.cpp:435
void SetNameTextSize(int aSize)
Definition sch_pin.cpp:870
void SetBackgroundColor(const COLOR4D &aColor) override
Set the background color.
void LoadColors(const COLOR_SETTINGS *aSettings) override
void RebuildSelection()
Rebuild the selection from the EDA_ITEMs' selection flags.
SCH_SELECTION & GetSelection()
SCH_SELECTION & RequestSelection(const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T }, bool aPromoteCellSelections=false, bool aPromoteGroups=false)
Return either an existing selection (filtered), or the selection at the current cursor position if th...
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
void updateItem(EDA_ITEM *aItem, bool aUpdateRTree) const
int Increment(const TOOL_EVENT &aEvent)
void saveCopyInUndoList(EDA_ITEM *aItem, UNDO_REDO aType, bool aAppend=false, bool aDirtyConnectivity=true)
int InteractiveDelete(const TOOL_EVENT &aEvent)
bool Init() override
Init() is called once upon a registration of the tool.
SCH_TOOL_BASE(const std::string &aName)
SCH_SELECTION_TOOL * m_selectionTool
static bool NotEmpty(const SELECTION &aSelection)
Test if there are any items selected.
static SELECTION_CONDITION MoreThan(int aNumber)
Create a functor that tests if the number of selected items is greater than the value given as parame...
static bool Idle(const SELECTION &aSelection)
Test if there no items selected or being edited.
static bool IdleSelection(const SELECTION &aSelection)
Test if all selected items are not being edited.
static SELECTION_CONDITION Count(int aNumber)
Create a functor that tests if the number of selected items is equal to the value given as parameter.
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition selection.cpp:75
ITER end()
Definition selection.h:76
ITER begin()
Definition selection.h:75
virtual VECTOR2I GetCenter() const
Returns the center point of the selection area bounding box.
Definition selection.cpp:92
bool IsHover() const
Definition selection.h:85
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition selection.h:104
EDA_ITEM * Front() const
Definition selection.h:176
virtual void Clear() override
Remove all the stored items from the group.
Definition selection.h:97
int Size() const
Returns the number of selected parts.
Definition selection.h:120
std::vector< EDA_ITEM * > GetItemsSortedBySelectionOrder() const
void SetReferencePoint(const VECTOR2I &aP)
bool Empty() const
Checks if there is anything selected.
Definition selection.h:114
Implement an OUTPUTFORMATTER to a memory buffer.
Definition richio.h:430
const std::string & GetString()
Definition richio.h:453
int Undo(const TOOL_EVENT &aEvent)
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
void editTextBoxProperties(SCH_ITEM *aItem)
int PinTable(const TOOL_EVENT &aEvent)
int Copy(const TOOL_EVENT &aEvent)
int CopyAsText(const TOOL_EVENT &aEvent)
int Paste(const TOOL_EVENT &aEvent)
int Cut(const TOOL_EVENT &aEvent)
bool Init() override
Init() is called once upon a registration of the tool.
int Redo(const TOOL_EVENT &aEvent)
void editTextProperties(SCH_ITEM *aItem)
int Swap(const TOOL_EVENT &aEvent)
void editFieldProperties(SCH_FIELD *aField)
void editShapeProperties(SCH_SHAPE *aShape)
int Duplicate(const TOOL_EVENT &aEvent)
int Mirror(const TOOL_EVENT &aEvent)
int Rotate(const TOOL_EVENT &aEvent)
int Properties(const TOOL_EVENT &aEvent)
int ExplodeStackedPin(const TOOL_EVENT &aEvent)
int EditSymbolPinMaps(const TOOL_EVENT &aEvent)
Open the symbol properties dialog directly on its Pin Map page (issue #2282).
void editSymbolPropertiesFromLibrary(const LIB_ID &aLibId)
Set up handlers for various events.
int ConvertStackedPins(const TOOL_EVENT &aEvent)
int UpdateSymbolFields(const TOOL_EVENT &aEvent)
int DoDelete(const TOOL_EVENT &aEvent)
Delete the selected items, or the item under the cursor.
static const std::vector< KICAD_T > SwappableItems
static bool ShouldFocusPinNumber(SCH_PIN &aPin, const VECTOR2I &aMousePos, bool aCursorMovedByKeyboard)
The pointer only says what the user is aiming at while the pointer is the device being steered.
The symbol library editor main window.
COLOR_SETTINGS * GetColorSettings(bool aForceRefresh=false) const override
Returns a pointer to the active color theme settings.
LIB_SYMBOL * GetBufferedSymbol(const wxString &aSymbolName, const wxString &aLibrary)
Return the symbol copy from the buffer.
bool UpdateSymbolAfterRename(LIB_SYMBOL *aSymbol, const wxString &aOldSymbolName, const wxString &aLibrary)
Update the symbol buffer with a new version of the symbol when the name has changed.
void SetSymbolModified(const wxString &aSymbolName, const wxString &aLibrary)
bool UpdateSymbol(LIB_SYMBOL *aSymbol, const wxString &aLibrary)
Update the symbol buffer with a new version of the symbol.
KIGFX::VIEW_CONTROLS * getViewControls() const
Definition tool_base.cpp:40
KIGFX::VIEW * getView() const
Definition tool_base.cpp:34
Generic, UI-independent tool event.
Definition tool_event.h:167
bool Matches(const TOOL_EVENT &aEvent) const
Test whether two events match in terms of category & action or command.
Definition tool_event.h:388
COMMIT * Commit() const
Definition tool_event.h:279
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
void Go(int(SYMBOL_EDIT_FRAME::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
TOOL_MENU & GetToolMenu()
CONDITIONAL_MENU & GetMenu()
Definition tool_menu.cpp:40
A modified version of the wxInfoBar class that allows us to:
Definition wx_infobar.h:76
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
void ShowMessageFor(const wxString &aMessage, int aTime, int aFlags=wxICON_INFORMATION, MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the infobar with the provided message and icon for a specific period of time.
void AddLink(const wxString &aLinkText, const std::function< void(wxHyperlinkEvent &)> &aFn)
Add a hypertext link to the infobar.
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
bool SaveClipboard(const std::string &aTextUTF8)
Store information to the system clipboard.
Definition clipboard.cpp:32
std::string GetClipboardUTF8()
Return the information currently stored in the system clipboard.
#define _(s)
@ RECURSE
Definition eda_item.h:51
#define IS_PASTED
Modifier on IS_NEW which indicates it came from clipboard.
#define IS_NEW
New item, just created.
#define SELECTED
Item was manually selected by the user.
#define STRUCT_DELETED
flag indication structures to be erased
const wxChar *const traceStackedPins
Flag to enable debug output for stacked pins handling in symbol/pin code.
bool LoadFileToMemory(const wxString &aFileName, wxMemoryBuffer &aBuffer)
Load the contents of a file into a memory buffer.
@ LAYER_DRAWINGSHEET
Sheet frame and title block.
Definition layer_ids.h:274
@ LAYER_DEVICE
Definition layer_ids.h:488
void Prettify(std::string &aSource, FORMAT_MODE aMode)
Pretty-prints s-expression text according to KiCad format rules.
@ TARGET_NONCACHED
Auxiliary rendering target (noncached)
Definition definitions.h:34
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
Definition pin_type.h:42
@ PT_PASSIVE
pin for passive symbols: must be connected, and can be connected to any pin.
Definition pin_type.h:39
PIN_ORIENTATION
The symbol library pin object orientations.
Definition pin_type.h:101
tl::expected< wxImage, std::string > CreateAlphaImageFromTwoRenders(const wxImage &aOnWhite, const wxImage &aOnBlack)
Combine two opaque renders of the same content into a single image with an alpha channel.
std::vector< EDA_ITEM * > EDA_ITEMS
bool PlotSymbolToSVG(LIB_SYMBOL &aDrawSymbol, LIB_SYMBOL &aFieldsSymbol, int aUnit, int aBodyStyle, const BOX2I &aBBox, SCH_RENDER_SETTINGS &aRenderSettings, bool aBlackAndWhite, const wxString &aFileName, REPORTER *aReporter)
Plot a single symbol variant (unit and body style) to an SVG file.
wxString GetSelectedItemsAsText(const SELECTION &aSel)
constexpr double SCH_WORLD_UNIT(1e-7/0.0254)
wxString TitleCaps(const wxString &aString)
Capitalize the first letter in each word.
wxString EscapeStackedPinItem(const wxString &aPinNumber)
Escape the characters that carry structural meaning inside stacked pin notation ('[',...
wxString m_mimeType
Definition clipboard.h:35
wxMemoryBuffer m_data
Definition clipboard.h:36
std::optional< wxBitmap > m_image
Optional bitmap image to add to clipboard via wxBitmapDataObject.
Definition clipboard.h:41
bool m_lastKeyboardCursorPositionValid
Is last cursor motion event coming from keyboard arrow cursor motion action.
#define ALL_UNITS
Definition symbol.h:150
#define ALL_BODY_STYLES
Definition symbol.h:151
static std::vector< KICAD_T > nonFields
KIBIS_PIN * pin
VECTOR2I end
wxString result
Test unit parsing edge cases and error handling.
constexpr GR_TEXT_H_ALIGN_T GetFlippedAlignment(GR_TEXT_H_ALIGN_T aAlign)
Get the reverse alignment: left-right are swapped, others are unchanged.
wxLogTrace helper definitions.
@ SCH_TABLE_T
Definition typeinfo.h:161
@ LIB_SYMBOL_T
Definition typeinfo.h:144
@ SCH_TABLECELL_T
Definition typeinfo.h:162
@ SCH_FIELD_T
Definition typeinfo.h:146
@ SCH_SHAPE_T
Definition typeinfo.h:145
@ SCH_TEXT_T
Definition typeinfo.h:147
@ SCH_TEXTBOX_T
Definition typeinfo.h:148
@ SCH_PIN_T
Definition typeinfo.h:149
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707
constexpr int LexicographicalCompare(const VECTOR2< T > &aA, const VECTOR2< T > &aB)
Definition vector2d.h:657
#define ZOOM_MIN_LIMIT_EESCHEMA
#define ZOOM_MAX_LIMIT_EESCHEMA