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, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
26
27#include <tool/picker_tool.h>
33#include <clipboard.h>
34#include <sch_actions.h>
35#include <increment.h>
36#include <pin_layout_cache.h>
37#include <string_utils.h>
38#include <symbol_edit_frame.h>
39#include <sch_commit.h>
41#include <dialogs/dialog_text_properties.h>
46#include <view/view_controls.h>
47#include <view/view.h>
48#include <richio.h>
50#include <sch_textbox.h>
52#include <wx/textdlg.h> // for wxTextEntryDialog
53#include <math/util.h> // for KiROUND
55#include <trace_helpers.h>
57#include <sch_painter.h>
58#include <sch_plotter.h>
59#include <locale_io.h>
60#include <gal/gal_print.h>
62#include <zoom_defines.h>
63#include <wx/ffile.h>
64#include <wx/mstream.h>
65#include <wx/dcmemory.h>
66
67
68namespace
69{
70constexpr double clipboardPpi = 96.0;
71constexpr int clipboardMaxBitmapSize = 4096;
72constexpr double clipboardBboxInflation = 0.02;
73
74
75void appendMimeData( std::vector<CLIPBOARD_MIME_DATA>& aMimeData, const wxString& aMimeType,
76 const wxMemoryBuffer& aBuffer )
77{
78 if( aBuffer.GetDataLen() == 0 )
79 return;
80
82 entry.m_mimeType = aMimeType;
83 entry.m_data = aBuffer;
84 aMimeData.push_back( entry );
85}
86
87
88bool loadFileToBuffer( const wxString& aFileName, wxMemoryBuffer& aBuffer )
89{
90 wxFFile file( aFileName, wxS( "rb" ) );
91
92 if( !file.IsOpened() )
93 return false;
94
95 wxFileOffset size = file.Length();
96
97 if( size <= 0 )
98 return false;
99
100 void* data = aBuffer.GetWriteBuf( size );
101
102 if( file.Read( data, size ) != static_cast<size_t>( size ) )
103 {
104 aBuffer.UngetWriteBuf( 0 );
105 return false;
106 }
107
108 aBuffer.UngetWriteBuf( size );
109 return true;
110}
111
112
113bool plotSymbolToSvg( SYMBOL_EDIT_FRAME* aFrame, LIB_SYMBOL* aSymbol, const BOX2I& aBBox,
114 int aUnit, int aBodyStyle, wxMemoryBuffer& aBuffer )
115{
116 if( !aSymbol )
117 return false;
118
119 SCH_RENDER_SETTINGS renderSettings;
120 renderSettings.LoadColors( aFrame->GetColorSettings() );
121 renderSettings.SetDefaultPenWidth( aFrame->GetRenderSettings()->GetDefaultPenWidth() );
122
123 std::unique_ptr<SVG_PLOTTER> plotter = std::make_unique<SVG_PLOTTER>();
124 plotter->SetRenderSettings( &renderSettings );
125
126 PAGE_INFO pageInfo = aFrame->GetScreen()->GetPageSettings();
127 pageInfo.SetWidthMils( schIUScale.IUToMils( aBBox.GetWidth() ) );
128 pageInfo.SetHeightMils( schIUScale.IUToMils( aBBox.GetHeight() ) );
129
130 plotter->SetPageSettings( pageInfo );
131 plotter->SetColorMode( true );
132
133 VECTOR2I plot_offset = aBBox.GetOrigin();
134 plotter->SetViewport( plot_offset, schIUScale.IU_PER_MILS / 10, 1.0, false );
135 plotter->SetCreator( wxT( "Eeschema-SVG" ) );
136
137 wxFileName tempFile( wxFileName::CreateTempFileName( wxS( "kicad_symbol_svg" ) ) );
138
139 if( !plotter->OpenFile( tempFile.GetFullPath() ) )
140 {
141 wxRemoveFile( tempFile.GetFullPath() );
142 return false;
143 }
144
145 LOCALE_IO toggle;
146 SCH_PLOT_OPTS plotOpts;
147
148 plotter->StartPlot( wxT( "1" ) );
149
150 constexpr bool background = true;
151 aSymbol->Plot( plotter.get(), background, plotOpts, aUnit, aBodyStyle, VECTOR2I( 0, 0 ), false );
152 aSymbol->Plot( plotter.get(), !background, plotOpts, aUnit, aBodyStyle, VECTOR2I( 0, 0 ), false );
153 aSymbol->PlotFields( plotter.get(), !background, plotOpts, aUnit, aBodyStyle, VECTOR2I( 0, 0 ), false );
154
155 plotter->EndPlot();
156 plotter.reset();
157
158 bool ok = loadFileToBuffer( tempFile.GetFullPath(), aBuffer );
159 wxRemoveFile( tempFile.GetFullPath() );
160 return ok;
161}
162
163
164wxImage renderSymbolToBitmap( SYMBOL_EDIT_FRAME* aFrame, LIB_SYMBOL* aSymbol, const BOX2I& aBBox,
165 int aUnit, int aBodyStyle, int aWidth, int aHeight,
166 double aViewScale, const wxColour& aBgColor )
167{
168 if( !aSymbol )
169 return wxImage();
170
171 wxBitmap bitmap( aWidth, aHeight, 24 );
172 wxMemoryDC dc;
173 dc.SelectObject( bitmap );
174 dc.SetBackground( wxBrush( aBgColor ) );
175 dc.Clear();
176
179 std::unique_ptr<KIGFX::GAL_PRINT> galPrint = KIGFX::GAL_PRINT::Create( options, &dc );
180
181 if( !galPrint )
182 return wxImage();
183
184 KIGFX::GAL* gal = galPrint->GetGAL();
185 KIGFX::PRINT_CONTEXT* printCtx = galPrint->GetPrintCtx();
186 std::unique_ptr<KIGFX::SCH_PAINTER> painter = std::make_unique<KIGFX::SCH_PAINTER>( gal );
187 std::unique_ptr<KIGFX::VIEW> view = std::make_unique<KIGFX::VIEW>();
188
189 // For symbol editor, we don't have a full schematic context
190 // but SCH_PAINTER can still work for rendering individual items
191 view->SetGAL( gal );
192 view->SetPainter( painter.get() );
193 view->SetScaleLimits( ZOOM_MAX_LIMIT_EESCHEMA, ZOOM_MIN_LIMIT_EESCHEMA );
194 view->SetScale( 1.0 );
196
197 // Clone items and add to view
198 std::vector<std::unique_ptr<SCH_ITEM>> clonedItems;
199
200 for( SCH_ITEM& item : aSymbol->GetDrawItems() )
201 {
202 if( aUnit && item.GetUnit() && item.GetUnit() != aUnit )
203 continue;
204
205 if( aBodyStyle && item.GetBodyStyle() && item.GetBodyStyle() != aBodyStyle )
206 continue;
207
208 SCH_ITEM* clone = static_cast<SCH_ITEM*>( item.Clone() );
209 clonedItems.emplace_back( clone );
210 view->Add( clone );
211 }
212
213 SCH_RENDER_SETTINGS* dstSettings = painter->GetSettings();
214 dstSettings->LoadColors( aFrame->GetColorSettings() );
215 dstSettings->SetDefaultPenWidth( aFrame->GetRenderSettings()->GetDefaultPenWidth() );
216 dstSettings->SetIsPrinting( true );
217
218 COLOR4D bgColor4D( aBgColor.Red() / 255.0, aBgColor.Green() / 255.0,
219 aBgColor.Blue() / 255.0, 1.0 );
220 dstSettings->SetBackgroundColor( bgColor4D );
221
222 for( int i = 0; i < KIGFX::VIEW::VIEW_MAX_LAYERS; ++i )
223 {
224 view->SetLayerVisible( i, true );
225 view->SetLayerTarget( i, KIGFX::TARGET_NONCACHED );
226 }
227
228 view->SetLayerVisible( LAYER_DRAWINGSHEET, false );
229
230 double ppi = clipboardPpi;
231 double inch2Iu = 1000.0 * schIUScale.IU_PER_MILS;
232 VECTOR2D pageSizeIn( (double) aWidth / ppi, (double) aHeight / ppi );
233
234 galPrint->SetSheetSize( pageSizeIn );
235 galPrint->SetNativePaperSize( pageSizeIn, printCtx->HasNativeLandscapeRotation() );
236
237 double zoomFactor = aViewScale * inch2Iu / ppi;
238
239 gal->SetLookAtPoint( aBBox.Centre() );
240 gal->SetZoomFactor( zoomFactor );
241 gal->SetClearColor( bgColor4D );
242 gal->ClearScreen();
243
244 view->UseDrawPriority( true );
245
246 {
248 view->Redraw();
249 }
250
251 dc.SelectObject( wxNullBitmap );
252 return bitmap.ConvertToImage();
253}
254
255
256bool plotSymbolToPng( SYMBOL_EDIT_FRAME* aFrame, LIB_SYMBOL* aSymbol, const BOX2I& aBBox,
257 int aUnit, int aBodyStyle, wxMemoryBuffer& aBuffer )
258{
259 if( !aSymbol )
260 return false;
261
262 VECTOR2I size = aBBox.GetSize();
263
264 if( size.x <= 0 || size.y <= 0 )
265 return false;
266
267 // Use the current view scale to match what the user sees on screen
268 double viewScale = aFrame->GetCanvas()->GetView()->GetScale();
269 int bitmapWidth = KiROUND( size.x * viewScale );
270 int bitmapHeight = KiROUND( size.y * viewScale );
271
272 // Clamp to maximum size while preserving aspect ratio
273 if( bitmapWidth > clipboardMaxBitmapSize || bitmapHeight > clipboardMaxBitmapSize )
274 {
275 double scaleDown = (double) clipboardMaxBitmapSize / std::max( bitmapWidth, bitmapHeight );
276 bitmapWidth = KiROUND( bitmapWidth * scaleDown );
277 bitmapHeight = KiROUND( bitmapHeight * scaleDown );
278 viewScale *= scaleDown;
279 }
280
281 if( bitmapWidth <= 0 || bitmapHeight <= 0 )
282 return false;
283
284 // Render twice with different backgrounds for alpha computation
285 wxImage imageOnWhite = renderSymbolToBitmap( aFrame, aSymbol, aBBox, aUnit, aBodyStyle,
286 bitmapWidth, bitmapHeight, viewScale, *wxWHITE );
287 wxImage imageOnBlack = renderSymbolToBitmap( aFrame, aSymbol, aBBox, aUnit, aBodyStyle,
288 bitmapWidth, bitmapHeight, viewScale, *wxBLACK );
289
290 if( !imageOnWhite.IsOk() || !imageOnBlack.IsOk() )
291 return false;
292
293 // Create output image with alpha channel
294 wxImage result( bitmapWidth, bitmapHeight );
295 result.InitAlpha();
296
297 unsigned char* rgbWhite = imageOnWhite.GetData();
298 unsigned char* rgbBlack = imageOnBlack.GetData();
299 unsigned char* rgbResult = result.GetData();
300 unsigned char* alphaResult = result.GetAlpha();
301
302 int pixelCount = bitmapWidth * bitmapHeight;
303
304 for( int i = 0; i < pixelCount; ++i )
305 {
306 int idx = i * 3;
307
308 int rW = rgbWhite[idx], gW = rgbWhite[idx + 1], bW = rgbWhite[idx + 2];
309 int rB = rgbBlack[idx], gB = rgbBlack[idx + 1], bB = rgbBlack[idx + 2];
310
311 // Alpha computation: α = 1 - (white - black) / 255
312 int diffR = rW - rB;
313 int diffG = gW - gB;
314 int diffB = bW - bB;
315 int avgDiff = ( diffR + diffG + diffB ) / 3;
316
317 int alpha = 255 - avgDiff;
318 alpha = std::max( 0, std::min( 255, alpha ) );
319 alphaResult[i] = static_cast<unsigned char>( alpha );
320
321 if( alpha > 0 )
322 {
323 rgbResult[idx] = static_cast<unsigned char>( std::min( 255, rB * 255 / alpha ) );
324 rgbResult[idx + 1] = static_cast<unsigned char>( std::min( 255, gB * 255 / alpha ) );
325 rgbResult[idx + 2] = static_cast<unsigned char>( std::min( 255, bB * 255 / alpha ) );
326 }
327 else
328 {
329 rgbResult[idx] = 0;
330 rgbResult[idx + 1] = 0;
331 rgbResult[idx + 2] = 0;
332 }
333 }
334
335 wxMemoryOutputStream stream;
336
337 if( !result.SaveFile( stream, wxBITMAP_TYPE_PNG ) )
338 return false;
339
340 size_t dataSize = stream.GetOutputStreamBuffer()->GetBufferSize();
341 aBuffer.AppendData( stream.GetOutputStreamBuffer()->GetBufferStart(), dataSize );
342
343 return true;
344}
345
346} // namespace
347
348
350 SCH_TOOL_BASE( "eeschema.SymbolEditTool" )
351{
352}
353
354
355const std::vector<KICAD_T> SYMBOL_EDITOR_EDIT_TOOL::SwappableItems = {
356 LIB_SYMBOL_T, // Allows swapping the anchor
357 SCH_PIN_T,
362};
363
364
366{
368
371
372 wxASSERT_MSG( drawingTools, "eeschema.SymbolDrawing tool is not available" );
373
374 auto haveSymbolCondition =
375 [&]( const SELECTION& sel )
376 {
377 return m_isSymbolEditor && m_frame->GetCurSymbol();
378 };
379
380 auto canEdit =
381 [&]( const SELECTION& sel )
382 {
383 if( !m_frame->IsSymbolEditable() )
384 return false;
385
386 if( m_frame->IsSymbolAlias() )
387 {
388 for( EDA_ITEM* item : sel )
389 {
390 if( item->Type() != SCH_FIELD_T )
391 return false;
392 }
393 }
394
395 return true;
396 };
397
398 auto swapSelectionCondition =
400
401 const auto canCopyText = SCH_CONDITIONS::OnlyTypes( {
405 SCH_PIN_T,
408 } );
409
410 const auto canConvertStackedPins =
411 [&]( const SELECTION& sel )
412 {
413 // If multiple pins are selected, check they are all at same location
414 if( sel.Size() >= 2 )
415 {
416 std::vector<SCH_PIN*> pins;
417 for( EDA_ITEM* item : sel )
418 {
419 if( item->Type() != SCH_PIN_T )
420 return false;
421 pins.push_back( static_cast<SCH_PIN*>( item ) );
422 }
423
424 // Check that all pins are at the same location
425 VECTOR2I pos = pins[0]->GetPosition();
426 for( size_t i = 1; i < pins.size(); ++i )
427 {
428 if( pins[i]->GetPosition() != pos )
429 return false;
430 }
431 return true;
432 }
433
434 // If single pin is selected, check if there are other pins at same location
435 if( sel.Size() == 1 && sel.Front()->Type() == SCH_PIN_T )
436 {
437 SCH_PIN* selectedPin = static_cast<SCH_PIN*>( sel.Front() );
438 VECTOR2I pos = selectedPin->GetPosition();
439
440 // Get the symbol and check for other pins at same location
441 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
442 if( !symbol )
443 return false;
444
445 int coLocatedCount = 0;
446
447 for( SCH_PIN* pin : symbol->GetPins() )
448 {
449 if( pin->GetPosition() == pos )
450 {
451 coLocatedCount++;
452
453 if( coLocatedCount >= 2 )
454 return true;
455 }
456 }
457 }
458
459 return false;
460 };
461
462 const auto canExplodeStackedPin =
463 [&]( const SELECTION& sel )
464 {
465 if( sel.Size() != 1 || sel.Front()->Type() != SCH_PIN_T )
466 return false;
467
468 SCH_PIN* pin = static_cast<SCH_PIN*>( sel.Front() );
469 bool isValid;
470 std::vector<wxString> stackedNumbers = pin->GetStackedPinNumbers( &isValid );
471 return isValid && stackedNumbers.size() > 1;
472 };
473
474 // clang-format off
475 // Add edit actions to the move tool menu
476 if( moveTool )
477 {
478 CONDITIONAL_MENU& moveMenu = moveTool->GetToolMenu().GetMenu();
479
480 moveMenu.AddSeparator( 200 );
481 moveMenu.AddItem( SCH_ACTIONS::rotateCCW, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
482 moveMenu.AddItem( SCH_ACTIONS::rotateCW, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
483 moveMenu.AddItem( SCH_ACTIONS::mirrorV, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
484 moveMenu.AddItem( SCH_ACTIONS::mirrorH, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
485
486 moveMenu.AddItem( SCH_ACTIONS::swap, swapSelectionCondition, 200 );
487 moveMenu.AddItem( SCH_ACTIONS::properties, canEdit && SCH_CONDITIONS::Count( 1 ), 200 );
488
489 moveMenu.AddSeparator( 300 );
492 moveMenu.AddItem( ACTIONS::copyAsText, canCopyText && SCH_CONDITIONS::IdleSelection, 300 );
493 moveMenu.AddItem( ACTIONS::duplicate, canEdit && SCH_CONDITIONS::NotEmpty, 300 );
494 moveMenu.AddItem( ACTIONS::doDelete, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
495
496 moveMenu.AddSeparator( 400 );
497 moveMenu.AddItem( ACTIONS::selectAll, haveSymbolCondition, 400 );
498 moveMenu.AddItem( ACTIONS::unselectAll, haveSymbolCondition, 400 );
499 }
500
501 // Add editing actions to the drawing tool menu
502 CONDITIONAL_MENU& drawMenu = drawingTools->GetToolMenu().GetMenu();
503
504 drawMenu.AddSeparator( 200 );
509
510 drawMenu.AddItem( SCH_ACTIONS::properties, canEdit && SCH_CONDITIONS::Count( 1 ), 200 );
511
512 // Add editing actions to the selection tool menu
513 CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
514
515 selToolMenu.AddItem( SCH_ACTIONS::rotateCCW, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
516 selToolMenu.AddItem( SCH_ACTIONS::rotateCW, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
517 selToolMenu.AddItem( SCH_ACTIONS::mirrorV, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
518 selToolMenu.AddItem( SCH_ACTIONS::mirrorH, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
519
520 selToolMenu.AddItem( SCH_ACTIONS::swap, swapSelectionCondition, 200 );
521 selToolMenu.AddItem( SCH_ACTIONS::properties, canEdit && SCH_CONDITIONS::Count( 1 ), 200 );
522
523 selToolMenu.AddSeparator( 250 );
524 selToolMenu.AddItem( SCH_ACTIONS::convertStackedPins, canEdit && canConvertStackedPins, 250 );
525 selToolMenu.AddItem( SCH_ACTIONS::explodeStackedPin, canEdit && canExplodeStackedPin, 250 );
526
527 selToolMenu.AddSeparator( 300 );
530 selToolMenu.AddItem( ACTIONS::copyAsText, canCopyText && SCH_CONDITIONS::IdleSelection, 300 );
531 selToolMenu.AddItem( ACTIONS::paste, canEdit && SCH_CONDITIONS::Idle, 300 );
532 selToolMenu.AddItem( ACTIONS::duplicate, canEdit && SCH_CONDITIONS::NotEmpty, 300 );
533 selToolMenu.AddItem( ACTIONS::doDelete, canEdit && SCH_CONDITIONS::NotEmpty, 300 );
534
535 selToolMenu.AddSeparator( 400 );
536 selToolMenu.AddItem( ACTIONS::selectAll, haveSymbolCondition, 400 );
537 selToolMenu.AddItem( ACTIONS::unselectAll, haveSymbolCondition, 400 );
538 // clang-format on
539
540 return true;
541}
542
543
545{
546 SCH_SELECTION& selection = m_selectionTool->RequestSelection();
547
548 if( selection.GetSize() == 0 )
549 return 0;
550
551 VECTOR2I rotPoint;
552 bool ccw = ( aEvent.Matches( SCH_ACTIONS::rotateCCW.MakeEvent() ) );
553 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
554 SCH_COMMIT localCommit( m_toolMgr );
555 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
556
557 if( !commit )
558 commit = &localCommit;
559
560 if( !item->IsMoving() )
561 commit->Modify( m_frame->GetCurSymbol(), m_frame->GetScreen(), RECURSE_MODE::RECURSE );
562
563 if( selection.GetSize() == 1 )
564 rotPoint = item->GetPosition();
565 else
566 rotPoint = 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 item->Rotate( rotPoint, ccw );
572 m_frame->UpdateItem( item, false, true );
573 }
574
575 if( item->IsMoving() )
576 {
578 }
579 else
580 {
581 if( selection.IsHover() )
583
584 if( !localCommit.Empty() )
585 localCommit.Push( _( "Rotate" ) );
586 }
587
588 return 0;
589}
590
591
593{
594 SCH_SELECTION& selection = m_selectionTool->RequestSelection();
595
596 if( selection.GetSize() == 0 )
597 return 0;
598
599 VECTOR2I mirrorPoint;
600 bool xAxis = ( aEvent.Matches( SCH_ACTIONS::mirrorV.MakeEvent() ) );
601 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
602
603 if( !item->IsMoving() )
605
606 if( selection.GetSize() == 1 )
607 {
608 mirrorPoint = item->GetPosition();
609
610 switch( item->Type() )
611 {
612 case SCH_FIELD_T:
613 {
614 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
615
616 if( xAxis )
618 else
620
621 break;
622 }
623
624 default:
625 if( xAxis )
626 item->MirrorVertically( mirrorPoint.y );
627 else
628 item->MirrorHorizontally( mirrorPoint.x );
629
630 break;
631 }
632
633
634 m_frame->UpdateItem( item, false, true );
635 }
636 else
637 {
638 mirrorPoint = m_frame->GetNearestHalfGridPosition( selection.GetCenter() );
639
640 for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
641 {
642 item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
643
644 if( xAxis )
645 item->MirrorVertically( mirrorPoint.y );
646 else
647 item->MirrorHorizontally( mirrorPoint.x );
648
649 m_frame->UpdateItem( item, false, true );
650 }
651 }
652
653 if( item->IsMoving() )
654 {
656 }
657 else
658 {
659 if( selection.IsHover() )
661
662 m_frame->OnModify();
663 }
664
665 return 0;
666}
668{
669 SCH_SELECTION& selection = m_selectionTool->RequestSelection( SwappableItems );
670 std::vector<EDA_ITEM*> sorted = selection.GetItemsSortedBySelectionOrder();
671
672 if( selection.Size() < 2 )
673 return 0;
674
675 EDA_ITEM* front = selection.Front();
676 bool isMoving = front->IsMoving();
677
678 // Save copy for undo if not in edit (edit command already handle the save copy)
679 if( front->GetEditFlags() == 0 )
681
682 for( size_t i = 0; i < sorted.size() - 1; i++ )
683 {
684 SCH_ITEM* a = static_cast<SCH_ITEM*>( sorted[i] );
685 SCH_ITEM* b = static_cast<SCH_ITEM*>( sorted[( i + 1 ) % sorted.size()] );
686
687 VECTOR2I aPos = a->GetPosition(), bPos = b->GetPosition();
688 std::swap( aPos, bPos );
689
690 a->SetPosition( aPos );
691 b->SetPosition( bPos );
692
693 // Special case some common swaps
694 if( a->Type() == b->Type() )
695 {
696 switch( a->Type() )
697 {
698 case SCH_PIN_T:
699 {
700 SCH_PIN* aPin = static_cast<SCH_PIN*>( a );
701 SCH_PIN* bBpin = static_cast<SCH_PIN*>( b );
702
703 PIN_ORIENTATION aOrient = aPin->GetOrientation();
704 PIN_ORIENTATION bOrient = bBpin->GetOrientation();
705
706 aPin->SetOrientation( bOrient );
707 bBpin->SetOrientation( aOrient );
708
709 break;
710 }
711 default: break;
712 }
713 }
714
715 m_frame->UpdateItem( a, false, true );
716 m_frame->UpdateItem( b, false, true );
717 }
718
719 // Update R-Tree for modified items
720 for( EDA_ITEM* selected : selection )
721 updateItem( selected, true );
722
723 if( isMoving )
724 {
725 m_toolMgr->PostAction( ACTIONS::refreshPreview );
726 }
727 else
728 {
729 if( selection.IsHover() )
731
732 m_frame->OnModify();
733 }
734
735 return 0;
736}
737
738
739static std::vector<KICAD_T> nonFields =
740{
746};
747
748
750{
751 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
752 std::deque<EDA_ITEM*> items = m_selectionTool->RequestSelection().GetItems();
753 SCH_COMMIT commit( m_frame );
754
755 if( items.empty() )
756 return 0;
757
758 // Don't leave a freed pointer in the selection
760
761 commit.Modify( symbol, m_frame->GetScreen() );
762
763 std::set<SCH_ITEM*> toDelete;
764 int fieldsHidden = 0;
765 int fieldsAlreadyHidden = 0;
766
767 for( EDA_ITEM* item : items )
768 {
769 if( item->Type() == SCH_PIN_T )
770 {
771 SCH_PIN* curr_pin = static_cast<SCH_PIN*>( item );
772 VECTOR2I pos = curr_pin->GetPosition();
773
774 toDelete.insert( curr_pin );
775
776 // when pin editing is synchronized, pins in the same position, with the same name
777 // in different units are also removed. But only one pin per unit (matching)
778 if( m_frame->SynchronizePins() )
779 {
780 std::vector<bool> got_unit( symbol->GetUnitCount() + 1 );
781
782 got_unit[curr_pin->GetUnit()] = true;
783
784 for( SCH_PIN* pin : symbol->GetPins() )
785 {
786 if( got_unit[pin->GetUnit()] )
787 continue;
788
789 if( pin->GetPosition() != pos )
790 continue;
791
792 if( pin->GetBodyStyle() != curr_pin->GetBodyStyle() )
793 continue;
794
795 if( pin->GetType() != curr_pin->GetType() )
796 continue;
797
798 if( pin->GetName() != curr_pin->GetName() )
799 continue;
800
801 toDelete.insert( pin );
802 got_unit[pin->GetUnit()] = true;
803 }
804 }
805 }
806 else if( item->Type() == SCH_FIELD_T )
807 {
808 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
809
810 // Hide "deleted" fields
811 if( field->IsVisible() )
812 {
813 field->SetVisible( false );
814 fieldsHidden++;
815 }
816 else
817 {
818 fieldsAlreadyHidden++;
819 }
820 }
821 else if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( item ) )
822 {
823 toDelete.insert( schItem );
824 }
825 }
826
827 for( SCH_ITEM* item : toDelete )
828 symbol->RemoveDrawItem( item );
829
830 if( toDelete.size() == 0 )
831 {
832 if( fieldsHidden == 1 )
833 commit.Push( _( "Hide Field" ) );
834 else if( fieldsHidden > 1 )
835 commit.Push( _( "Hide Fields" ) );
836 else if( fieldsAlreadyHidden > 0 )
837 m_frame->ShowInfoBarError( _( "Use the Symbol Properties dialog to remove fields." ) );
838 }
839 else
840 {
841 commit.Push( _( "Delete" ) );
842 }
843
844 m_frame->RebuildView();
845 return 0;
846}
847
848
850{
851 SCH_SELECTION& selection = m_selectionTool->RequestSelection();
852
853 if( selection.Empty() || aEvent.IsAction( &SCH_ACTIONS::symbolProperties ) )
854 {
855 // If called from tree context menu, edit properties without loading into canvas
857 {
858 LIB_ID treeLibId = m_frame->GetTreeLIBID();
859
860 // Check if the selected symbol in tree is different from the currently loaded one
861 if( treeLibId.IsValid() &&
862 ( !m_frame->GetCurSymbol() || m_frame->GetCurSymbol()->GetLibId() != treeLibId ) )
863 {
864 // Edit properties directly from library buffer without loading to canvas
866 return 0;
867 }
868 }
869
870 if( m_frame->GetCurSymbol() )
872 }
873 else if( selection.Size() == 1 )
874 {
875 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
876
877 // Save copy for undo if not in edit (edit command already handle the save copy)
878 if( item->GetEditFlags() == 0 )
880
881 switch( item->Type() )
882 {
883 case SCH_PIN_T:
884 {
885 SCH_PIN& pin = static_cast<SCH_PIN&>( *item );
886
887 // Mouse, not cursor, as grid points may well not be under any text
888 const VECTOR2I& mousePos = m_toolMgr->GetMousePosition();
889 PIN_LAYOUT_CACHE& layout = pin.GetLayoutCache();
890
891 bool mouseOverNumber = false;
892 if( OPT_BOX2I numberBox = layout.GetPinNumberBBox() )
893 {
894 mouseOverNumber = numberBox->Contains( mousePos );
895 }
896
897 if( SYMBOL_EDITOR_PIN_TOOL* pinTool = m_toolMgr->GetTool<SYMBOL_EDITOR_PIN_TOOL>() )
898 pinTool->EditPinProperties( &pin, mouseOverNumber );
899
900 break;
901 }
902 case SCH_SHAPE_T:
903 editShapeProperties( static_cast<SCH_SHAPE*>( item ) );
904 break;
905
906 case SCH_TEXT_T:
907 editTextProperties( item );
908 break;
909
910 case SCH_TEXTBOX_T:
911 editTextBoxProperties( item );
912 break;
913
914 case SCH_FIELD_T:
915 editFieldProperties( static_cast<SCH_FIELD*>( item ) );
916 break;
917
918 default:
919 wxFAIL_MSG( wxT( "Unhandled item <" ) + item->GetClass() + wxT( ">" ) );
920 break;
921 }
922 }
923
924 if( selection.IsHover() )
926
927 return 0;
928}
929
930
932{
933 DIALOG_SHAPE_PROPERTIES dlg( m_frame, aShape );
934
935 if( dlg.ShowModal() != wxID_OK )
936 return;
937
938 updateItem( aShape, true );
939 m_frame->GetCanvas()->Refresh();
940 m_frame->OnModify();
941
944 drawingTools->SetDrawSpecificUnit( !dlg.GetApplyToAllUnits() );
945
946 std::vector<MSG_PANEL_ITEM> items;
947 aShape->GetMsgPanelInfo( m_frame, items );
948 m_frame->SetMsgPanel( items );
949}
950
951
953{
954 if ( aItem->Type() != SCH_TEXT_T )
955 return;
956
957 DIALOG_TEXT_PROPERTIES dlg( m_frame, static_cast<SCH_TEXT*>( aItem ) );
958
959 if( dlg.ShowModal() != wxID_OK )
960 return;
961
962 updateItem( aItem, true );
963 m_frame->GetCanvas()->Refresh();
964 m_frame->OnModify( );
965}
966
967
969{
970 if ( aItem->Type() != SCH_TEXTBOX_T )
971 return;
972
973 DIALOG_TEXT_PROPERTIES dlg( m_frame, static_cast<SCH_TEXTBOX*>( aItem ) );
974
975 if( dlg.ShowModal() != wxID_OK )
976 return;
977
978 updateItem( aItem, true );
979 m_frame->GetCanvas()->Refresh();
980 m_frame->OnModify( );
981}
982
983
985{
986 if( aField == nullptr )
987 return;
988
989 wxString caption;
990
991 if( aField->IsMandatory() )
992 caption.Printf( _( "Edit %s Field" ), TitleCaps( aField->GetName() ) );
993 else
994 caption.Printf( _( "Edit '%s' Field" ), aField->GetName() );
995
996 DIALOG_FIELD_PROPERTIES dlg( m_frame, caption, aField );
997
998 // The dialog may invoke a kiway player for footprint fields
999 // so we must use a quasimodal dialog.
1000 if( dlg.ShowQuasiModal() != wxID_OK )
1001 return;
1002
1003 SCH_COMMIT commit( m_toolMgr );
1004 commit.Modify( aField, m_frame->GetScreen() );
1005
1006 dlg.UpdateField( aField );
1007
1008 commit.Push( caption );
1009
1010 m_frame->GetCanvas()->Refresh();
1011 m_frame->UpdateSymbolMsgPanelInfo();
1012}
1013
1014
1016{
1017 LIB_SYMBOL_LIBRARY_MANAGER& libMgr = m_frame->GetLibManager();
1018 wxString libName = aLibId.GetLibNickname();
1019 wxString symbolName = aLibId.GetLibItemName();
1020
1021 // Get the symbol from the library buffer (without loading it into the editor)
1022 LIB_SYMBOL* bufferedSymbol = libMgr.GetBufferedSymbol( symbolName, libName );
1023
1024 if( !bufferedSymbol )
1025 return;
1026
1027 // Create a copy to work with
1028 LIB_SYMBOL tempSymbol( *bufferedSymbol );
1029
1031 m_toolMgr->RunAction( ACTIONS::selectionClear );
1032
1033 DIALOG_LIB_SYMBOL_PROPERTIES dlg( m_frame, &tempSymbol );
1034
1035 // This dialog itself subsequently can invoke a KIWAY_PLAYER as a quasimodal
1036 // frame. Therefore this dialog as a modal frame parent, MUST be run under
1037 // quasimodal mode for the quasimodal frame support to work. So don't use
1038 // the QUASIMODAL macros here.
1039 if( dlg.ShowQuasiModal() != wxID_OK )
1040 return;
1041
1042 // Update the buffered symbol with the changes
1043 libMgr.UpdateSymbol( &tempSymbol, libName );
1044
1045 // Mark the library as modified
1046 libMgr.SetSymbolModified( symbolName, libName );
1047
1048 // Update the tree view
1049 wxDataViewItem treeItem = libMgr.GetAdapter()->FindItem( aLibId );
1050 m_frame->UpdateLibraryTree( treeItem, &tempSymbol );
1051}
1052
1053
1055{
1056 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1057 bool partLocked = symbol->UnitsLocked();
1058
1060 m_toolMgr->RunAction( ACTIONS::selectionClear );
1061
1063
1064 // This dialog itself subsequently can invoke a KIWAY_PLAYER as a quasimodal
1065 // frame. Therefore this dialog as a modal frame parent, MUST be run under
1066 // quasimodal mode for the quasimodal frame support to work. So don't use
1067 // the QUASIMODAL macros here.
1068 if( dlg.ShowQuasiModal() != wxID_OK )
1069 return;
1070
1071 m_frame->RebuildSymbolUnitAndBodyStyleLists();
1072 m_frame->OnModify();
1073
1074 // if m_UnitSelectionLocked has changed, set some edit options or defaults
1075 // to the best value
1076 if( partLocked != symbol->UnitsLocked() )
1077 {
1079
1080 // Enable synchronized pin edit mode for symbols with interchangeable units
1081 m_frame->m_SyncPinEdit = !symbol->UnitsLocked();
1082
1083 // also set default edit options to the better value
1084 // Usually if units are locked, graphic items are specific to each unit
1085 // and if units are interchangeable, graphic items are common to units
1086 tools->SetDrawSpecificUnit( symbol->UnitsLocked() );
1087 }
1088}
1089
1090
1092{
1093 SCH_COMMIT commit( m_frame );
1094 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1095
1096 if( !symbol )
1097 return 0;
1098
1099 commit.Modify( symbol, m_frame->GetScreen() );
1100
1101 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1102 wxCHECK( selTool, -1 );
1103
1104 std::vector<SCH_PIN*> selectedPins;
1105
1106 SCH_SELECTION& selection = selTool->GetSelection();
1107
1108 for( EDA_ITEM* item : selection )
1109 {
1110 if( item->Type() == SCH_PIN_T )
1111 {
1112 SCH_PIN* pinItem = static_cast<SCH_PIN*>( item );
1113 selectedPins.push_back( pinItem );
1114 }
1115 }
1116
1117 // And now clear the selection so if we change the pins we don't have dangling pointers
1118 // in the selection.
1119 m_toolMgr->RunAction( ACTIONS::selectionClear );
1120
1121 DIALOG_LIB_EDIT_PIN_TABLE dlg( m_frame, symbol, selectedPins );
1122
1123 if( dlg.ShowModal() == wxID_CANCEL )
1124 return -1;
1125
1126 commit.Push( _( "Edit Pins" ) );
1127 m_frame->RebuildView();
1128
1129 return 0;
1130}
1131
1132
1134{
1135 SCH_COMMIT commit( m_frame );
1136 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1137
1138 if( !symbol )
1139 return 0;
1140
1141 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1142 wxCHECK( selTool, -1 );
1143
1144 SCH_SELECTION& selection = selTool->GetSelection();
1145
1146 // Collect pins to convert - accept pins with any number format
1147 std::vector<SCH_PIN*> pinsToConvert;
1148
1149 if( selection.Size() == 1 && selection.Front()->Type() == SCH_PIN_T )
1150 {
1151 // Single pin selected - find all pins at the same location
1152 SCH_PIN* selectedPin = static_cast<SCH_PIN*>( selection.Front() );
1153 VECTOR2I pos = selectedPin->GetPosition();
1154
1155 for( SCH_PIN* pin : symbol->GetPins() )
1156 {
1157 if( pin->GetPosition() == pos )
1158 pinsToConvert.push_back( pin );
1159 }
1160 }
1161 else
1162 {
1163 // Multiple pins selected - use them directly, accepting any pin numbers
1164 for( EDA_ITEM* item : selection )
1165 {
1166 if( item->Type() == SCH_PIN_T )
1167 pinsToConvert.push_back( static_cast<SCH_PIN*>( item ) );
1168 }
1169 }
1170
1171 if( pinsToConvert.size() < 2 )
1172 {
1173 m_frame->ShowInfoBarError( _( "At least two pins are needed to convert to stacked pins" ) );
1174 return 0;
1175 }
1176
1177 // Check that all pins are at the same location
1178 VECTOR2I pos = pinsToConvert[0]->GetPosition();
1179 for( size_t i = 1; i < pinsToConvert.size(); ++i )
1180 {
1181 if( pinsToConvert[i]->GetPosition() != pos )
1182 {
1183 m_frame->ShowInfoBarError( _( "All pins must be at the same location" ) );
1184 return 0;
1185 }
1186 }
1187
1188 commit.Modify( symbol, m_frame->GetScreen() );
1189
1190 // Clear selection before modifying pins, like the Delete command does
1191 m_toolMgr->RunAction( ACTIONS::selectionClear );
1192
1193 // Sort pins for consistent ordering - handle arbitrary pin number formats
1194 std::sort( pinsToConvert.begin(), pinsToConvert.end(),
1195 []( SCH_PIN* a, SCH_PIN* b )
1196 {
1197 wxString numA = a->GetNumber();
1198 wxString numB = b->GetNumber();
1199
1200 // Try to convert to integers for proper numeric sorting
1201 long longA, longB;
1202 bool aIsNumeric = numA.ToLong( &longA );
1203 bool bIsNumeric = numB.ToLong( &longB );
1204
1205 // Both are purely numeric - sort numerically
1206 if( aIsNumeric && bIsNumeric )
1207 return longA < longB;
1208
1209 // Mixed numeric/non-numeric - numeric pins come first
1210 if( aIsNumeric && !bIsNumeric )
1211 return true;
1212 if( !aIsNumeric && bIsNumeric )
1213 return false;
1214
1215 // Both non-numeric or mixed alphanumeric - use lexicographic sorting
1216 return numA < numB;
1217 });
1218
1219 // Build the stacked notation string with range collapsing
1220 wxString stackedNotation = wxT("[");
1221
1222 // Helper function to collapse consecutive numbers into ranges - handles arbitrary pin formats
1223 auto collapseRanges = [&]() -> wxString
1224 {
1225 if( pinsToConvert.empty() )
1226 return wxT("");
1227
1228 wxString result;
1229
1230 // Group pins by their alphanumeric prefix for range collapsing
1231 std::map<wxString, std::vector<long>> prefixGroups;
1232 std::vector<wxString> nonNumericPins;
1233
1234 // Parse each pin number to separate prefix from numeric suffix
1235 for( SCH_PIN* pin : pinsToConvert )
1236 {
1237 wxString pinNumber = pin->GetNumber();
1238
1239 // Skip empty pin numbers (shouldn't happen, but be defensive)
1240 if( pinNumber.IsEmpty() )
1241 {
1242 nonNumericPins.push_back( wxT("(empty)") );
1243 continue;
1244 }
1245
1246 wxString prefix;
1247 wxString numericPart;
1248
1249 // Find where numeric part starts (scan from end)
1250 size_t numStart = pinNumber.length();
1251 for( int i = pinNumber.length() - 1; i >= 0; i-- )
1252 {
1253 if( !wxIsdigit( pinNumber[i] ) )
1254 {
1255 numStart = i + 1;
1256 break;
1257 }
1258 if( i == 0 ) // All digits
1259 numStart = 0;
1260 }
1261
1262 if( numStart < pinNumber.length() ) // Has numeric suffix
1263 {
1264 prefix = pinNumber.Left( numStart );
1265 numericPart = pinNumber.Mid( numStart );
1266
1267 long numValue;
1268 if( numericPart.ToLong( &numValue ) && numValue >= 0 ) // Valid non-negative number
1269 {
1270 prefixGroups[prefix].push_back( numValue );
1271 }
1272 else
1273 {
1274 // Numeric part couldn't be parsed or is negative - treat as non-numeric
1275 nonNumericPins.push_back( pinNumber );
1276 }
1277 }
1278 else // No numeric suffix - consolidate as individual value
1279 {
1280 nonNumericPins.push_back( pinNumber );
1281 }
1282 }
1283
1284 // Process each prefix group
1285 for( auto& [prefix, numbers] : prefixGroups )
1286 {
1287 if( !result.IsEmpty() )
1288 result += wxT(",");
1289
1290 // Sort numeric values for this prefix
1291 std::sort( numbers.begin(), numbers.end() );
1292
1293 // Collapse consecutive ranges within this prefix
1294 size_t i = 0;
1295 while( i < numbers.size() )
1296 {
1297 if( i > 0 ) // Not first number in this prefix group
1298 result += wxT(",");
1299
1300 long start = numbers[i];
1301 long end = start;
1302
1303 // Find the end of consecutive sequence
1304 while( i + 1 < numbers.size() && numbers[i + 1] == numbers[i] + 1 )
1305 {
1306 i++;
1307 end = numbers[i];
1308 }
1309
1310 // Add range or single number with prefix
1311 if( end > start + 1 ) // Range of 3+ numbers
1312 result += wxString::Format( wxT("%s%ld-%s%ld"), prefix, start, prefix, end );
1313 else if( end == start + 1 ) // Two consecutive numbers
1314 result += wxString::Format( wxT("%s%ld,%s%ld"), prefix, start, prefix, end );
1315 else // Single number
1316 result += wxString::Format( wxT("%s%ld"), prefix, start );
1317
1318 i++;
1319 }
1320 }
1321
1322 // Add non-numeric pin numbers as individual comma-separated values
1323 for( const wxString& nonNum : nonNumericPins )
1324 {
1325 if( !result.IsEmpty() )
1326 result += wxT(",");
1327 result += 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,
1342 wxString::Format( "Converting %zu pins to stacked notation '%s'",
1343 pinsToConvert.size(), stackedNotation ) );
1344
1345 // Remove all other pins from the symbol that were consolidated into the stacked notation
1346 // Collect pins to remove first, then remove them all at once like the Delete command
1347 std::vector<SCH_PIN*> pinsToRemove;
1348 for( size_t i = 1; i < pinsToConvert.size(); ++i )
1349 {
1350 SCH_PIN* pinToRemove = pinsToConvert[i];
1351
1352 // Log the pin before removing it
1353 wxLogTrace( traceStackedPins,
1354 wxString::Format( "Will remove pin '%s' at position (%d, %d)",
1355 pinToRemove->GetNumber(),
1356 pinToRemove->GetPosition().x,
1357 pinToRemove->GetPosition().y ) );
1358
1359 pinsToRemove.push_back( pinToRemove );
1360 }
1361
1362 // Remove all pins at once, like the Delete command does
1363 for( SCH_PIN* pin : pinsToRemove )
1364 {
1365 symbol->RemoveDrawItem( pin );
1366 }
1367
1368 commit.Push( wxString::Format( _( "Convert %zu Stacked Pins to '%s'" ),
1369 pinsToConvert.size(), stackedNotation ) );
1370 m_frame->RebuildView();
1371 return 0;
1372}
1373
1374
1376{
1377 SCH_COMMIT commit( m_frame );
1378 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1379
1380 if( !symbol )
1381 return 0;
1382
1383 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1384 wxCHECK( selTool, -1 );
1385
1386 SCH_SELECTION& selection = selTool->GetSelection();
1387
1388 if( selection.GetSize() != 1 || selection.Front()->Type() != SCH_PIN_T )
1389 {
1390 m_frame->ShowInfoBarError( _( "Select a single pin with stacked notation to explode" ) );
1391 return 0;
1392 }
1393
1394 SCH_PIN* pin = static_cast<SCH_PIN*>( selection.Front() );
1395
1396 // Check if the pin has stacked notation
1397 bool isValid;
1398 std::vector<wxString> stackedNumbers = pin->GetStackedPinNumbers( &isValid );
1399
1400 if( !isValid || stackedNumbers.size() <= 1 )
1401 {
1402 m_frame->ShowInfoBarError( _( "Selected pin does not have valid stacked notation" ) );
1403 return 0;
1404 }
1405
1406 commit.Modify( symbol, m_frame->GetScreen() );
1407
1408 // Clear selection before modifying pins
1409 m_toolMgr->RunAction( ACTIONS::selectionClear );
1410
1411 // Sort the stacked numbers to find the smallest one
1412 std::sort( stackedNumbers.begin(), stackedNumbers.end(),
1413 []( const wxString& a, const wxString& b )
1414 {
1415 // Try to convert to integers for proper numeric sorting
1416 long numA, numB;
1417 if( a.ToLong( &numA ) && b.ToLong( &numB ) )
1418 return numA < numB;
1419
1420 // Fall back to string comparison if not numeric
1421 return a < b;
1422 });
1423
1424 // Change the original pin to use the first (smallest) number and make it visible
1425 pin->SetNumber( stackedNumbers[0] );
1426 pin->SetVisible( true );
1427
1428 // Create additional pins for the remaining numbers and make them invisible
1429 for( size_t i = 1; i < stackedNumbers.size(); ++i )
1430 {
1431 SCH_PIN* newPin = new SCH_PIN( symbol );
1432
1433 // Copy all properties from the original pin
1434 newPin->SetPosition( pin->GetPosition() );
1435 newPin->SetOrientation( pin->GetOrientation() );
1436 newPin->SetShape( pin->GetShape() );
1437 newPin->SetLength( pin->GetLength() );
1438 newPin->SetType( pin->GetType() );
1439 newPin->SetName( pin->GetName() );
1440 newPin->SetNumber( stackedNumbers[i] );
1441 newPin->SetNameTextSize( pin->GetNameTextSize() );
1442 newPin->SetNumberTextSize( pin->GetNumberTextSize() );
1443 newPin->SetUnit( pin->GetUnit() );
1444 newPin->SetBodyStyle( pin->GetBodyStyle() );
1445 newPin->SetVisible( false ); // Make all other pins invisible
1446
1447 // Add the new pin to the symbol
1448 symbol->AddDrawItem( newPin );
1449 }
1450
1451 commit.Push( _( "Explode Stacked Pin" ) );
1452 m_frame->RebuildView();
1453 return 0;
1454}
1455
1456
1458{
1459 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1460
1461 if( !symbol )
1462 return 0;
1463
1464 if( !symbol->IsDerived() )
1465 {
1466 m_frame->ShowInfoBarError( _( "Symbol is not derived from another symbol." ) );
1467 }
1468 else
1469 {
1470 DIALOG_UPDATE_SYMBOL_FIELDS dlg( m_frame, symbol );
1471
1472 if( dlg.ShowModal() == wxID_CANCEL )
1473 return -1;
1474 }
1475
1476 return 0;
1477}
1478
1479
1481{
1482 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1483
1484 // Nuke the selection for later rebuilding. This does *not* clear the flags on any items;
1485 // it just clears the SELECTION's reference to them.
1486 selTool->GetSelection().Clear();
1487 {
1488 m_frame->GetSymbolFromUndoList();
1489 }
1490 selTool->RebuildSelection();
1491
1492 return 0;
1493}
1494
1495
1497{
1498 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1499
1500 // Nuke the selection for later rebuilding. This does *not* clear the flags on any items;
1501 // it just clears the SELECTION's reference to them.
1502 selTool->GetSelection().Clear();
1503 {
1504 m_frame->GetSymbolFromRedoList();
1505 }
1506 selTool->RebuildSelection();
1507
1508 return 0;
1509}
1510
1511
1513{
1514 int retVal = Copy( aEvent );
1515
1516 if( retVal == 0 )
1517 retVal = DoDelete( aEvent );
1518
1519 return retVal;
1520}
1521
1522
1524{
1525 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1526 SCH_SELECTION& selection = m_selectionTool->RequestSelection( nonFields );
1527
1528 if( !symbol || !selection.GetSize() )
1529 return 0;
1530
1531 for( SCH_ITEM& item : symbol->GetDrawItems() )
1532 {
1533 if( item.Type() == SCH_FIELD_T )
1534 continue;
1535
1536 wxASSERT( !item.HasFlag( STRUCT_DELETED ) );
1537
1538 if( !item.IsSelected() )
1539 item.SetFlags( STRUCT_DELETED );
1540 }
1541
1542 LIB_SYMBOL* partCopy = new LIB_SYMBOL( *symbol );
1543
1544 STRING_FORMATTER formatter;
1545 SCH_IO_KICAD_SEXPR::FormatLibSymbol( partCopy, formatter );
1546
1547 delete partCopy;
1548
1549 for( SCH_ITEM& item : symbol->GetDrawItems() )
1550 item.ClearFlags( STRUCT_DELETED );
1551
1552 std::string prettyData = formatter.GetString();
1553 KICAD_FORMAT::Prettify( prettyData, KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES );
1554
1555 // Generate SVG and PNG for multi-format clipboard
1556 std::vector<CLIPBOARD_MIME_DATA> mimeData;
1557
1558 // Get the bounding box for just the selected items
1559 BOX2I bbox;
1560
1561 for( EDA_ITEM* item : selection )
1562 {
1563 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item );
1564 if( bbox.GetWidth() == 0 && bbox.GetHeight() == 0 )
1565 bbox = schItem->GetBoundingBox();
1566 else
1567 bbox.Merge( schItem->GetBoundingBox() );
1568 }
1569
1570 if( bbox.GetWidth() > 0 && bbox.GetHeight() > 0 )
1571 {
1572 bbox.Inflate( bbox.GetWidth() * clipboardBboxInflation,
1573 bbox.GetHeight() * clipboardBboxInflation );
1574
1575 // Create a temporary symbol with just the selected items for plotting
1576 LIB_SYMBOL* plotSymbol = new LIB_SYMBOL( *symbol );
1577
1578 // Mark unselected items as deleted in the plot copy
1579 for( SCH_ITEM& item : plotSymbol->GetDrawItems() )
1580 {
1581 if( item.Type() == SCH_FIELD_T )
1582 continue;
1583
1584 // Find matching item in selection by position/type
1585 bool found = false;
1586
1587 for( EDA_ITEM* selItem : selection )
1588 {
1589 SCH_ITEM* selSchItem = static_cast<SCH_ITEM*>( selItem );
1590
1591 if( selSchItem->Type() == item.Type()
1592 && selSchItem->GetPosition() == item.GetPosition() )
1593 {
1594 found = true;
1595 break;
1596 }
1597 }
1598
1599 if( !found )
1600 item.SetFlags( STRUCT_DELETED );
1601 }
1602
1603 // Now copy only the non-deleted items to a clean symbol for plotting
1604 LIB_SYMBOL* cleanSymbol = new LIB_SYMBOL( *plotSymbol );
1605 delete plotSymbol;
1606
1607 int unit = m_frame->GetUnit();
1608 int bodyStyle = m_frame->GetBodyStyle();
1609
1610 wxMemoryBuffer svgBuffer;
1611
1612 if( plotSymbolToSvg( m_frame, cleanSymbol, bbox, unit, bodyStyle, svgBuffer ) )
1613 appendMimeData( mimeData, wxS( "image/svg+xml" ), svgBuffer );
1614
1615 wxMemoryBuffer pngBuffer;
1616
1617 if( plotSymbolToPng( m_frame, cleanSymbol, bbox, unit, bodyStyle, pngBuffer ) )
1618 appendMimeData( mimeData, wxS( "image/png" ), pngBuffer );
1619
1620 delete cleanSymbol;
1621 }
1622
1623 if( SaveClipboard( prettyData, mimeData ) )
1624 return 0;
1625 else
1626 return -1;
1627}
1628
1629
1631{
1632 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1633 SCH_SELECTION& selection = selTool->RequestSelection();
1634
1635 if( selection.Empty() )
1636 return 0;
1637
1638 wxString itemsAsText = GetSelectedItemsAsText( selection );
1639
1640 if( selection.IsHover() )
1641 m_toolMgr->RunAction( ACTIONS::selectionClear );
1642
1643 return SaveClipboard( itemsAsText.ToStdString() );
1644}
1645
1646
1648{
1649 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1650 LIB_SYMBOL* newPart = nullptr;
1651
1652 if( !symbol || symbol->IsDerived() )
1653 return 0;
1654
1655 std::string clipboardData = GetClipboardUTF8();
1656
1657 try
1658 {
1659 std::vector<LIB_SYMBOL*> newParts = SCH_IO_KICAD_SEXPR::ParseLibSymbols( clipboardData, "Clipboard" );
1660
1661 if( newParts.empty() || !newParts[0] )
1662 return -1;
1663
1664 newPart = newParts[0];
1665 }
1666 catch( IO_ERROR& )
1667 {
1668 // If it's not a symbol then paste as text
1669 newPart = new LIB_SYMBOL( "dummy_part" );
1670
1671 wxString pasteText( clipboardData );
1672
1673 // Limit of 5000 is totally arbitrary. Without a limit, pasting a bitmap image from
1674 // eeschema makes KiCad appear to hang.
1675 if( pasteText.Length() > 5000 )
1676 pasteText = pasteText.Left( 5000 ) + wxT( "..." );
1677
1678 SCH_TEXT* newText = new SCH_TEXT( { 0, 0 }, pasteText, LAYER_DEVICE );
1679 newPart->AddDrawItem( newText );
1680 }
1681
1682 SCH_COMMIT commit( m_toolMgr );
1683
1684 commit.Modify( symbol, m_frame->GetScreen() );
1685 m_selectionTool->ClearSelection();
1686
1687 for( SCH_ITEM& item : symbol->GetDrawItems() )
1688 item.ClearFlags( IS_NEW | IS_PASTED | SELECTED );
1689
1690 for( SCH_ITEM& item : newPart->GetDrawItems() )
1691 {
1692 if( item.Type() == SCH_FIELD_T )
1693 continue;
1694
1695 SCH_ITEM* newItem = item.Duplicate( true, &commit );
1696 newItem->SetParent( symbol );
1697 newItem->SetFlags( IS_NEW | IS_PASTED | SELECTED );
1698
1699 newItem->SetUnit( newItem->GetUnit() ? m_frame->GetUnit() : 0 );
1700 newItem->SetBodyStyle( newItem->GetBodyStyle() ? m_frame->GetBodyStyle() : 0 );
1701
1702 symbol->AddDrawItem( newItem );
1703 getView()->Add( newItem );
1704 }
1705
1706 delete newPart;
1707
1708 m_selectionTool->RebuildSelection();
1709
1710 SCH_SELECTION& selection = m_selectionTool->GetSelection();
1711
1712 if( !selection.Empty() )
1713 {
1714 selection.SetReferencePoint( getViewControls()->GetCursorPosition( true ) );
1715
1716 if( m_toolMgr->RunSynchronousAction( SCH_ACTIONS::move, &commit ) )
1717 commit.Push( _( "Paste" ) );
1718 else
1719 commit.Revert();
1720 }
1721
1722 return 0;
1723}
1724
1725
1727{
1728 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1729 SCH_SELECTION& selection = m_selectionTool->RequestSelection( nonFields );
1730 SCH_COMMIT commit( m_toolMgr );
1731
1732 if( selection.GetSize() == 0 )
1733 return 0;
1734
1735 commit.Modify( symbol, m_frame->GetScreen() );
1736
1737 std::vector<EDA_ITEM*> oldItems;
1738 std::vector<EDA_ITEM*> newItems;
1739
1740 std::copy( selection.begin(), selection.end(), std::back_inserter( oldItems ) );
1741 std::sort( oldItems.begin(), oldItems.end(), []( EDA_ITEM* a, EDA_ITEM* b )
1742 {
1743 int cmp;
1744
1745 if( a->Type() != b->Type() )
1746 return a->Type() < b->Type();
1747
1748 // Create the new pins in the same order as the old pins
1749 if( a->Type() == SCH_PIN_T )
1750 {
1751 const wxString& aNum = static_cast<SCH_PIN*>( a )->GetNumber();
1752 const wxString& bNum = static_cast<SCH_PIN*>( b )->GetNumber();
1753
1754 cmp = StrNumCmp( aNum, bNum );
1755
1756 // If the pin numbers are not numeric, then just number them by their position
1757 // on the screen.
1758 if( aNum.IsNumber() && bNum.IsNumber() && cmp != 0 )
1759 return cmp < 0;
1760 }
1761
1763
1764 if( cmp != 0 )
1765 return cmp < 0;
1766
1767 return a->m_Uuid < b->m_Uuid;
1768 } );
1769
1770 for( EDA_ITEM* item : oldItems )
1771 {
1772 SCH_ITEM* oldItem = static_cast<SCH_ITEM*>( item );
1773 SCH_ITEM* newItem = oldItem->Duplicate( true, &commit );
1774
1775 if( newItem->Type() == SCH_PIN_T )
1776 {
1777 SCH_PIN* newPin = static_cast<SCH_PIN*>( newItem );
1778
1779 if( !newPin->GetNumber().IsEmpty() )
1780 newPin->SetNumber( wxString::Format( wxT( "%i" ), symbol->GetMaxPinNumber() + 1 ) );
1781 }
1782
1783 oldItem->ClearFlags( IS_NEW | IS_PASTED | SELECTED );
1784 newItem->SetFlags( IS_NEW | IS_PASTED | SELECTED );
1785 newItem->SetParent( symbol );
1786 newItems.push_back( newItem );
1787
1788 symbol->AddDrawItem( newItem );
1789 getView()->Add( newItem );
1790 }
1791
1792 m_toolMgr->RunAction( ACTIONS::selectionClear );
1793 m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &newItems );
1794
1795 selection.SetReferencePoint( getViewControls()->GetCursorPosition( true ) );
1796
1797 if( m_toolMgr->RunSynchronousAction( SCH_ACTIONS::move, &commit ) )
1798 commit.Push( _( "Duplicate" ) );
1799 else
1800 commit.Revert();
1801
1802 return 0;
1803}
1804
1805
1807{
1808 // clang-format off
1816
1824
1830
1837 // clang-format on
1838}
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:114
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
std::optional< BOX2I > OPT_BOX2I
Definition box2.h:926
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
static TOOL_ACTION decrementPrimary
Definition actions.h:96
static TOOL_ACTION paste
Definition actions.h:80
static TOOL_ACTION cancelInteractive
Definition actions.h:72
static TOOL_ACTION unselectAll
Definition actions.h:83
static TOOL_ACTION decrementSecondary
Definition actions.h:98
static TOOL_ACTION copy
Definition actions.h:78
static TOOL_ACTION undo
Definition actions.h:75
static TOOL_ACTION incrementSecondary
Definition actions.h:97
static TOOL_ACTION duplicate
Definition actions.h:84
static TOOL_ACTION incrementPrimary
Definition actions.h:95
static TOOL_ACTION doDelete
Definition actions.h:85
static TOOL_ACTION redo
Definition actions.h:76
static TOOL_ACTION deleteTool
Definition actions.h:86
static TOOL_ACTION increment
Definition actions.h:94
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:224
static TOOL_ACTION cut
Definition actions.h:77
static TOOL_ACTION copyAsText
Definition actions.h:79
static TOOL_ACTION refreshPreview
Definition actions.h:159
static TOOL_ACTION selectAll
Definition actions.h:82
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:232
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:558
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr Vec Centre() const
Definition box2.h:97
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:658
constexpr size_type GetHeight() const
Definition box2.h:215
constexpr const Vec & GetOrigin() const
Definition box2.h:210
constexpr const SizeVec & GetSize() const
Definition box2.h:206
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
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)
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:278
virtual void SetPosition(const VECTOR2I &aPos)
Definition eda_item.h:279
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:110
EDA_ITEM_FLAGS GetEditFlags() const
Definition eda_item.h:154
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:148
const KIID m_Uuid
Definition eda_item.h:522
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:150
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.h:113
EDA_ITEM * GetParent() const
Definition eda_item.h:112
bool IsMoving() const
Definition eda_item.h:125
virtual bool IsVisible() const
Definition eda_text.h:187
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:426
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:200
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:395
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition eda_text.h:203
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:418
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:105
GAL_ANTIALIASING_MODE antialiasing_mode
The grid style to draw the grid in.
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 bool HasNativeLandscapeRotation() const =0
void SetDefaultPenWidth(int aWidth)
void SetIsPrinting(bool isPrinting)
double GetScale() const
Definition view.h:276
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:298
static constexpr int VIEW_MAX_LAYERS
Maximum number of layers that may be shown.
Definition view.h:745
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:172
const UTF8 & GetLibItemName() const
Definition lib_id.h:102
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:87
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:83
bool UnitsLocked() const
Check whether symbol units are interchangeable.
Definition lib_symbol.h:288
bool IsDerived() const
Definition lib_symbol.h:204
void Plot(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed) override
Plot the item to aPlotter.
void PlotFields(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed)
Plot symbol fields.
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:699
void RemoveDrawItem(SCH_ITEM *aItem)
Remove draw aItem from list.
std::vector< SCH_PIN * > GetPins() const override
int GetUnitCount() const override
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:41
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:79
void SetHeightMils(double aHeightInMils)
void SetWidthMils(double aWidthInMils)
A pin layout helper is a class that manages the layout of the parts of a pin on a schematic symbol:
OPT_BOX2I GetPinNumberBBox()
Get the bounding box of the pin number, if there is one.
static TOOL_ACTION rotateCCW
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_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Execute the changes.
virtual void Revert() override
Revert the commit by restoring the modified items state.
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the #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:167
SCH_ITEM * Duplicate(bool addToParentGroup, SCH_COMMIT *aCommit=nullptr, bool doClone=false) const
Routine to create a new copy of given item.
Definition sch_item.cpp:140
virtual void SetBodyStyle(int aBodyStyle)
Definition sch_item.h:246
int GetBodyStyle() const
Definition sch_item.h:247
virtual void MirrorHorizontally(int aCenter)
Mirror item horizontally about aCenter.
Definition sch_item.h:406
int GetUnit() const
Definition sch_item.h:238
virtual void Rotate(const VECTOR2I &aCenter, bool aRotateCCW)
Rotate the item around aCenter 90 degrees in the clockwise direction.
Definition sch_item.h:422
virtual void SetUnit(int aUnit)
Definition sch_item.h:237
wxString GetClass() const override
Return the class name.
Definition sch_item.h:177
virtual void MirrorVertically(int aCenter)
Mirror item vertically about aCenter.
Definition sch_item.h:414
void SetNumber(const wxString &aNumber)
Definition sch_pin.cpp:642
void SetVisible(bool aVisible)
Definition sch_pin.h:114
void SetOrientation(PIN_ORIENTATION aOrientation)
Definition sch_pin.h:93
void SetName(const wxString &aName)
Definition sch_pin.cpp:419
void SetPosition(const VECTOR2I &aPos) override
Definition sch_pin.h:251
const wxString & GetName() const
Definition sch_pin.cpp:401
void SetLength(int aLength)
Definition sch_pin.h:99
PIN_ORIENTATION GetOrientation() const
Definition sch_pin.cpp:264
void SetNumberTextSize(int aSize)
Definition sch_pin.cpp:693
void SetShape(GRAPHIC_PINSHAPE aShape)
Definition sch_pin.h:96
VECTOR2I GetPosition() const override
Definition sch_pin.cpp:256
void SetType(ELECTRICAL_PINTYPE aType)
Definition sch_pin.cpp:333
const wxString & GetNumber() const
Definition sch_pin.h:124
ELECTRICAL_PINTYPE GetType() const
Definition sch_pin.cpp:313
void SetNameTextSize(int aSize)
Definition sch_pin.cpp:669
void SetBackgroundColor(const COLOR4D &aColor) override
Set the background color.
void LoadColors(const COLOR_SETTINGS *aSettings) override
const PAGE_INFO & GetPageSettings() const
Definition sch_screen.h:140
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:80
ITER begin()
Definition selection.h:79
virtual VECTOR2I GetCenter() const
Returns the center point of the selection area bounding box.
Definition selection.cpp:92
bool IsHover() const
Definition selection.h:89
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition selection.h:105
EDA_ITEM * Front() const
Definition selection.h:177
virtual void Clear() override
Remove all the stored items from the group.
Definition selection.h:98
int Size() const
Returns the number of selected parts.
Definition selection.h:121
std::vector< EDA_ITEM * > GetItemsSortedBySelectionOrder() const
void SetReferencePoint(const VECTOR2I &aP)
bool Empty() const
Checks if there is anything selected.
Definition selection.h:115
Implement an OUTPUTFORMATTER to a memory buffer.
Definition richio.h:422
const std::string & GetString()
Definition richio.h:445
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)
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
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.
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:44
KIGFX::VIEW * getView() const
Definition tool_base.cpp:38
Generic, UI-independent tool event.
Definition tool_event.h:171
bool Matches(const TOOL_EVENT &aEvent) const
Test whether two events match in terms of category & action or command.
Definition tool_event.h:392
COMMIT * Commit() const
Definition tool_event.h:283
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:44
bool SaveClipboard(const std::string &aTextUTF8)
Store information to the system clipboard.
Definition clipboard.cpp:39
std::string GetClipboardUTF8()
Return the information currently stored in the system clipboard.
#define _(s)
@ RECURSE
Definition eda_item.h:51
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition eda_item.h:575
#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.
@ LAYER_DRAWINGSHEET
Sheet frame and title block.
Definition layer_ids.h:278
@ LAYER_DEVICE
Definition layer_ids.h:466
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:38
PIN_ORIENTATION
The symbol library pin object orientations.
Definition pin_type.h:105
Plotting engines similar to ps (PostScript, Gerber, svg)
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 m_mimeType
Definition clipboard.h:36
wxMemoryBuffer m_data
Definition clipboard.h:37
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:169
@ LIB_SYMBOL_T
Definition typeinfo.h:152
@ SCH_TABLECELL_T
Definition typeinfo.h:170
@ SCH_FIELD_T
Definition typeinfo.h:154
@ SCH_SHAPE_T
Definition typeinfo.h:153
@ SCH_TEXT_T
Definition typeinfo.h:155
@ SCH_TEXTBOX_T
Definition typeinfo.h:156
@ SCH_PIN_T
Definition typeinfo.h:157
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694
constexpr int LexicographicalCompare(const VECTOR2< T > &aA, const VECTOR2< T > &aB)
Definition vector2d.h:644
#define ZOOM_MIN_LIMIT_EESCHEMA
#define ZOOM_MAX_LIMIT_EESCHEMA