KiCad PCB EDA Suite
Loading...
Searching...
No Matches
ee_graphic_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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <wx/msgdlg.h>
23
24#include <default_values.h>
25#include <scoped_set_reset.h>
26
28#include <eeschema_settings.h>
31#include <sch_actions.h>
32#include <sch_commit.h>
33#include <sch_edit_frame.h>
34#include <sch_shape.h>
35#include <sch_textbox.h>
36#include <schematic.h>
37#include <symbol_edit_frame.h>
44#include <view/view_controls.h>
45#include <view/view.h>
46
47
49
50
68
69
71{
73
74 const auto inDrawingArc =
75 [this]( const SELECTION& aSel )
76 {
77 return m_mode == MODE::ARC;
78 };
79
80 const auto inManagedShape = [this]( const SELECTION& aSel )
81 {
83 };
84
85 CONDITIONAL_MENU& ctxMenu = m_menu->GetMenu();
86
87 // clang-format off
88 ctxMenu.AddItem( ACTIONS::arcPosture, inDrawingArc, 200 );
89 ctxMenu.AddItem( ACTIONS::deleteLastPoint, inManagedShape, 200 );
90 ctxMenu.AddItem( ACTIONS::finishInteractive, inManagedShape, 200 );
91 // clang-format on
92
93 return true;
94}
95
96
101
102
104{
105 if( IsSymbolEditor() )
106 {
107 const SYMBOL_EDITOR_SETTINGS* cfg = frame<SYMBOL_EDIT_FRAME>()->libeditconfig();
108
109 return schIUScale.MilsToIU( cfg ? cfg->m_Defaults.text_size : DEFAULT_TEXT_SIZE );
110 }
111
112 return getModel<SCHEMATIC>()->Settings().m_DefaultTextSize;
113}
114
115
117{
118 if( !IsSymbolEditor() )
119 return;
120
122
123 if( symFrame->GetDrawSpecificUnit() )
124 aItem.SetUnit( symFrame->GetUnit() );
125
126 if( symFrame->GetDrawSpecificBodyStyle() )
127 aItem.SetBodyStyle( symFrame->GetBodyStyle() );
128}
129
130
131void EE_GRAPHIC_TOOL::commitItem( SCH_COMMIT& aCommit, std::unique_ptr<SCH_ITEM> aItem, const wxString& aDescription )
132{
133 aItem->ClearEditFlags();
134
135 if( IsSymbolEditor() )
136 {
138 LIB_SYMBOL* symbol = symFrame->GetCurSymbol();
139
140 aCommit.Modify( symbol, frame()->GetScreen() );
141 symbol->AddDrawItem( aItem.release() );
142 aCommit.Push( aDescription );
143 symFrame->RebuildView();
144 }
145 else
146 {
147 aCommit.Add( aItem.release(), frame()->GetScreen() );
148 aCommit.Push( aDescription );
149 }
150}
151
152
154{
155 EDA_ITEM* parent = getDrawParent();
156
157 if( !parent )
158 return 0;
159
160 int defaultTextSize = getDefaultTextSize();
161 bool isTextBox = aEvent.IsAction( &SCH_ACTIONS::drawTextBox )
163 SHAPE_T type = isTextBox ? SHAPE_T::RECTANGLE : aEvent.Parameter<SHAPE_T>();
164
165 if( m_inDrawingTool )
166 return 0;
167
169
172 VECTOR2I cursorPos;
173
174 std::unique_ptr<SCH_SHAPE> item;
175
176 // We might be running as the same shape in another co-routine. Make sure that one
177 // gets whacked.
178 m_toolMgr->DeactivateTool();
179
181
182 TOOL_EVENT originalEvent = aEvent;
183 SCOPED_TOOL_PUSHER raii( frame(), originalEvent );
184
185 auto setCursor =
186 [&]()
187 {
188 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
189 };
190
191 auto cleanup =
192 [&] ()
193 {
195 m_view->ClearPreview();
196 item.reset();
197 };
198
199 Activate();
200
201 // Must be done after Activate() so that it gets set into the correct context
202 getViewControls()->ShowCursor( true );
203
204 // Set initial cursor
205 setCursor();
206
207 if( aEvent.HasPosition() )
208 m_toolMgr->PrimeTool( aEvent.Position() );
209
210 SCH_LAYER_ID shapeLayer = getShapeLayer();
211
212 // Main loop: keep receiving events
213 while( TOOL_EVENT* evt = Wait() )
214 {
215 setCursor();
216 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
217 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
218
219 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
220 controls->ForceCursorPosition( true, cursorPos );
221
222 // The tool hotkey is interpreted as a click when drawing
223 bool isSyntheticClick = item && evt->IsActivate() && evt->HasPosition() && evt->Matches( aEvent );
224
225 if( evt->IsCancelInteractive() || ( item && evt->IsAction( &ACTIONS::undo ) ) )
226 {
227 if( item )
228 cleanup();
229 else
230 break;
231 }
232 else if( evt->IsActivate() && !isSyntheticClick )
233 {
234 if( item && evt->IsMoveTool() )
235 {
236 // we're already drawing our own item; ignore the move tool
237 evt->SetPassEvent( false );
238 continue;
239 }
240
241 if( item )
242 cleanup();
243
244 if( evt->IsPointEditor() )
245 {
246 // don't exit (the point editor runs in the background)
247 continue;
248 }
249
250 if( evt->IsMoveTool() )
251 {
252 // Make sure we come back after the move tool runs
253 frame()->PushTool( originalEvent );
254 }
255
256 break;
257 }
258 else if( !item && ( evt->IsClick( BUT_LEFT )
259 || evt->IsAction( &ACTIONS::cursorClick ) ) )
260 {
262
263 if( isTextBox )
264 {
265 auto textbox = std::make_unique<SCH_TEXTBOX>( shapeLayer, 0, m_lastTextboxFillStyle );
266
267 textbox->SetTextSize( VECTOR2I( defaultTextSize, defaultTextSize ) );
268
269 // Must come after SetTextSize()
270 textbox->SetBold( m_lastTextBold );
271 textbox->SetItalic( m_lastTextItalic );
272
273 textbox->SetTextAngle( m_lastTextboxAngle );
274 textbox->SetHorizJustify( m_lastTextboxHJustify );
275 textbox->SetVertJustify( m_lastTextboxVJustify );
276 textbox->SetStroke( m_lastTextboxStroke );
277 textbox->SetFillColor( m_lastTextboxFillColor );
278 textbox->SetParent( parent );
279
280 item = std::move( textbox );
281 }
282 else
283 {
284 item = std::make_unique<SCH_SHAPE>( type, shapeLayer, 0, m_lastFillStyle );
285
286 item->SetStroke( m_lastStroke );
287 item->SetFillColor( m_lastFillColor );
288 item->SetParent( parent );
289 }
290
291 item->SetFlags( IS_NEW );
292
293 applySymbolEditorFlags( *item );
294
295 item->BeginEdit( cursorPos );
296
297 m_view->ClearPreview();
298 m_view->AddToPreview( item->Clone() );
299 }
300 else if( item && ( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
301 || isSyntheticClick
302 || evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick )
303 || evt->IsAction( &ACTIONS::finishInteractive ) ) )
304 {
305 bool finished = false;
306
307 if( evt->IsDblClick( BUT_LEFT )
308 || evt->IsAction( &ACTIONS::cursorDblClick )
309 || evt->IsAction( &ACTIONS::finishInteractive ) )
310 {
311 finished = true;
312 }
313 else
314 {
315 finished = !item->ContinueEdit( cursorPos );
316 }
317
318 if( finished )
319 {
320 item->EndEdit();
321 item->SetFlags( IS_NEW );
322
323 if( isTextBox )
324 {
325 SCH_TEXTBOX* textbox = static_cast<SCH_TEXTBOX*>( item.get() );
326 DIALOG_TEXT_PROPERTIES dlg( frame(), textbox );
327
328 getViewControls()->SetAutoPan( false );
329 getViewControls()->CaptureCursor( false );
330
331 // QuasiModal required for syntax help and Scintilla auto-complete
332 if( dlg.ShowQuasiModal() != wxID_OK )
333 {
334 cleanup();
335 continue;
336 }
337
338 m_lastTextBold = textbox->IsBold();
339 m_lastTextItalic = textbox->IsItalic();
340 m_lastTextboxAngle = textbox->GetTextAngle();
343 m_lastTextboxStroke = textbox->GetStroke();
346 }
347 else
348 {
349 m_lastStroke = item->GetStroke();
350 m_lastFillStyle = item->GetFillMode();
351 m_lastFillColor = item->GetFillColor();
352 }
353
354 m_selectionTool->AddItemToSel( item.get() );
355
356 SCH_COMMIT commit( m_toolMgr );
357 wxString msg = wxString::Format( _( "Draw %s" ), item->GetClass() );
358
359 commitItem( commit, std::move( item ), msg );
360 item = nullptr;
361
362 m_view->ClearPreview();
364 }
365 }
366 else if( evt->IsAction( &ACTIONS::duplicate )
367 || evt->IsAction( &SCH_ACTIONS::repeatDrawItem )
368 || evt->IsAction( &ACTIONS::paste ) )
369 {
370 if( item )
371 {
372 wxBell();
373 continue;
374 }
375
376 // Exit. The duplicate/repeat/paste will run in its own loop.
377 evt->SetPassEvent();
378 break;
379 }
380 else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
381 {
382 item->CalcEdit( cursorPos );
383 m_view->ClearPreview();
384 m_view->AddToPreview( item->Clone() );
385
386 frame()->SetMsgPanel( item.get() );
387 }
388 else if( evt->IsDblClick( BUT_LEFT ) && !item )
389 {
391 }
392 else if( evt->IsClick( BUT_RIGHT ) )
393 {
394 // Warp after context menu only if dragging...
395 if( !item )
396 m_toolMgr->VetoContextMenuMouseWarp();
397
398 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
399 }
400 else if( item && evt->IsAction( &ACTIONS::redo ) )
401 {
402 wxBell();
403 }
404 else
405 {
406 evt->SetPassEvent();
407 }
408
409 // Enable autopanning and cursor capture only when there is a shape being drawn
410 getViewControls()->SetAutoPan( item != nullptr );
411 getViewControls()->CaptureCursor( item != nullptr );
412 }
413
414 getViewControls()->SetAutoPan( false );
415 getViewControls()->CaptureCursor( false );
416 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
417 return 0;
418}
419
420
422{
423 if( m_inDrawingTool )
424 return 0;
425
426 EDA_ITEM* parent = getDrawParent();
427
428 if( !parent )
429 return 0;
430
432 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::ARC );
433
434 SCH_LAYER_ID shapeLayer = getShapeLayer();
435 std::vector<VECTOR2D> initialPts;
436
437 const auto makeNewArc =
438 [&]()
439 {
440 std::unique_ptr<SCH_SHAPE> arc = std::make_unique<SCH_SHAPE>( SHAPE_T::ARC, shapeLayer, 0, m_lastFillStyle );
441 arc->SetStroke( m_lastStroke );
442 arc->SetFillColor( m_lastFillColor );
443 arc->SetParent( parent );
444 arc->SetFlags( IS_NEW );
445
447
448 return arc;
449 };
450
451 std::unique_ptr<SCH_SHAPE> arc = makeNewArc();
452
453 arc->SetFlags( IS_NEW );
454
455 TOOL_EVENT originalEvent = aEvent;
456 SCOPED_TOOL_PUSHER raii( m_frame, originalEvent );
457 Activate();
458
459 if( aEvent.HasPosition() )
460 initialPts.push_back( aEvent.Position() );
461
462 ARC_DRAW_BEHAVIOR arcBehavior( schIUScale, frame()->GetUserUnits() );
463
465
467 {
468 result = drawManagedShape( originalEvent, arc, arcBehavior, initialPts );
469
470 if( arc )
471 {
472 m_lastStroke = arc->GetStroke();
473 m_lastFillStyle = arc->GetFillMode();
474 m_lastFillColor = arc->GetFillColor();
475
476 m_selectionTool->AddItemToSel( arc.get() );
477
478 SCH_COMMIT commit( m_toolMgr );
479 commitItem( commit, std::move( arc ), _( "Draw Arc" ) );
480
482 }
483
484 arc = makeNewArc();
485 initialPts.clear();
486 }
487
488 return 0;
489}
490
491
493{
494 if( m_inDrawingTool )
495 return 0;
496
497 EDA_ITEM* parent = getDrawParent();
498
499 if( !parent )
500 return 0;
501
503 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::ELLIPSE_ARC );
504
505 SCH_LAYER_ID shapeLayer = getShapeLayer();
506 std::vector<VECTOR2D> initialPts;
507
508 const auto makeNewEllipseArc =
509 [&]()
510 {
511 std::unique_ptr<SCH_SHAPE> arc = std::make_unique<SCH_SHAPE>( SHAPE_T::ELLIPSE_ARC, shapeLayer,
512 0, m_lastFillStyle );
513 arc->SetStroke( m_lastStroke );
514 arc->SetFillColor( m_lastFillColor );
515 arc->SetParent( parent );
516 arc->SetFlags( IS_NEW );
517
519
520 return arc;
521 };
522
523 std::unique_ptr<SCH_SHAPE> arc = makeNewEllipseArc();
524
525 TOOL_EVENT originalEvent = aEvent; // This can change out from under us when the event loop runs
526 SCOPED_TOOL_PUSHER raii( m_frame, originalEvent );
527 Activate();
528
529 if( aEvent.HasPosition() )
530 initialPts.push_back( aEvent.Position() );
531
532 ELLIPSE_ARC_DRAW_BEHAVIOR ellipseBehavior( schIUScale, frame()->GetUserUnits() );
533
535
537 {
538 result = drawManagedShape( originalEvent, arc, ellipseBehavior, initialPts );
539
540 if( arc )
541 {
542 m_lastStroke = arc->GetStroke();
543 m_lastFillStyle = arc->GetFillMode();
544 m_lastFillColor = arc->GetFillColor();
545
546 m_selectionTool->AddItemToSel( arc.get() );
547
548 SCH_COMMIT commit( m_toolMgr );
549 commitItem( commit, std::move( arc ), _( "Draw Elliptical Arc" ) );
550
552 }
553
554 arc = makeNewEllipseArc();
555 initialPts.clear();
556 }
557
558 return 0;
559}
560
561
563{
564 if( m_inDrawingTool )
565 return 0;
566
567 EDA_ITEM* parent = getDrawParent();
568
569 if( !parent )
570 return 0;
571
573 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::BEZIER );
574
575 SCH_LAYER_ID shapeLayer = getShapeLayer();
576 std::vector<VECTOR2D> initialPts;
577
578 const auto makeNewBezier =
579 [&]()
580 {
581 std::unique_ptr<SCH_SHAPE> bezier = std::make_unique<SCH_SHAPE>(
582 SHAPE_T::BEZIER, shapeLayer, 0, m_lastFillStyle );
583 bezier->SetStroke( m_lastStroke );
584 bezier->SetFillColor( m_lastFillColor );
585 bezier->SetParent( parent );
586 bezier->SetFlags( IS_NEW );
587
588 applySymbolEditorFlags( *bezier );
589
590 return bezier;
591 };
592
593 std::unique_ptr<SCH_SHAPE> bezier = makeNewBezier();
594
595 TOOL_EVENT originalEvent = aEvent; // This can change out from under us when the event loop runs
596 SCOPED_TOOL_PUSHER raii( m_frame, originalEvent );
597 Activate();
598
599 if( aEvent.HasPosition() )
600 initialPts.push_back( aEvent.Position() );
601
602 BEZIER_DRAW_BEHAVIOR bezierBehavior( schIUScale, frame()->GetUserUnits() );
603
605
607 {
608 result = drawManagedShape( originalEvent, bezier, bezierBehavior, initialPts );
609
610 if( bezier )
611 {
612 m_lastStroke = bezier->GetStroke();
613 m_lastFillStyle = bezier->GetFillMode();
614 m_lastFillColor = bezier->GetFillColor();
615
616 // Chain: next bezier starts at the end of this one
617 initialPts.clear();
618 initialPts.push_back( bezier->GetEnd() );
619
620 // If the last control arm is non-zero, mirror it for tangent continuity
621 if( bezier->GetEnd() != bezier->GetBezierC2() )
622 {
623 VECTOR2D mirroredC1 = bezier->GetEnd() - ( bezier->GetBezierC2() - bezier->GetEnd() );
624 initialPts.push_back( mirroredC1 );
625 }
626
627 m_selectionTool->AddItemToSel( bezier.get() );
628
629 SCH_COMMIT commit( m_toolMgr );
630 commitItem( commit, std::move( bezier ), _( "Draw Bezier" ) );
631
633 }
634 else
635 {
636 initialPts.clear();
637 }
638
639 bezier = makeNewBezier();
640 }
641
642 return 0;
643}
644
645
647 std::unique_ptr<SCH_SHAPE>& aShape,
648 SHAPE_DRAW_BEHAVIOR& aBehavior,
649 const std::vector<VECTOR2D>& aInitialPts )
650{
651 if( !aShape )
653
654 aBehavior.Reset();
655
656 SELECTION preview;
659 VECTOR2I cursorPos;
660 EDA_ITEM* parent = getDrawParent();
661
662 m_view->Add( &preview );
663 m_view->Add( &aBehavior.GetAssistant() );
664
665 auto setCursor =
666 [&]()
667 {
668 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
669 };
670
671 auto cleanup =
672 [&]()
673 {
675 preview.Clear();
676 aShape.reset();
677 };
678
679 controls->ShowCursor( true );
680 setCursor();
681
682 bool started = false;
683 bool cancelled = false;
684 bool finished = false;
685
686 m_toolMgr->PostAction( ACTIONS::refreshPreview );
687
688 // Pre-load any initial points into the behaviour, advancing the construction
689 // state machine so that the next user click adds the subsequent point.
690 // The user can still undo these points if they want to change them.
691 for( const VECTOR2D& pt : aInitialPts )
692 aBehavior.AddPoint( pt );
693
694 if( !aInitialPts.empty() )
695 {
697
698 controls->SetAutoPan( true );
699 controls->CaptureCursor( true );
700
701 preview.Add( aShape.get() );
702 frame()->SetMsgPanel( aShape.get() );
703
704 started = true;
705 }
706
707 while( TOOL_EVENT* evt = Wait() )
708 {
709 setCursor();
710 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
711 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
712
713 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
714 controls->ForceCursorPosition( true, cursorPos );
715
716 if( evt->IsCancelInteractive() )
717 {
718 cleanup();
719
720 if( !started )
721 {
722 evt->SetPassEvent( false );
723 cancelled = true;
724 }
725
726 break;
727 }
728 else if( started && evt->IsAction( &ACTIONS::undo ) )
729 {
730 cleanup();
731 break;
732 }
733 else if( evt->IsActivate() )
734 {
735 if( evt->IsPointEditor() )
736 {
737 // don't exit (the point editor runs in the background)
738 continue;
739 }
740
741 if( evt->IsMoveTool() )
742 {
743 // Make sure we come back after the move tool runs
744 m_frame->PushTool( aTool );
745 }
746
747 cleanup();
748 cancelled = true;
749 break;
750 }
751 else if( evt->IsClick( BUT_LEFT ) )
752 {
753 if( !started )
754 {
756
757 controls->SetAutoPan( true );
758 controls->CaptureCursor( true );
759
760 preview.Add( aShape.get() );
761 frame()->SetMsgPanel( aShape.get() );
762 started = true;
763 }
764
765 aBehavior.AddPoint( cursorPos );
766 }
767 else if( evt->IsDblClick( BUT_LEFT )
768 || evt->IsAction( &ACTIONS::cursorDblClick )
769 || evt->IsAction( &ACTIONS::finishInteractive ) )
770 {
771 // Keep whatever we have so far, and report that we're finished.
772 if( !started )
773 cleanup();
774
775 finished = true;
776 break;
777 }
778 else if( evt->IsAction( &ACTIONS::arcPosture ) )
779 {
780 aBehavior.ToggleClockwise();
781 }
782 else if( evt->IsAction( &ACTIONS::deleteLastPoint ) )
783 {
784 aBehavior.RemoveLastPoint();
785 grid.FullReset();
786 }
787 else if( evt->IsMotion() )
788 {
789 aBehavior.SetCursorPosition( cursorPos );
790 }
791 else if( evt->IsClick( BUT_RIGHT ) )
792 {
793 if( !aShape )
794 m_toolMgr->VetoContextMenuMouseWarp();
795
796 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
797 }
798 else if( evt->IsAction( &ACTIONS::updateUnits ) )
799 {
800 aBehavior.SetUnits( frame()->GetUserUnits() );
801 m_view->Update( &aBehavior.GetAssistant() );
802 evt->SetPassEvent();
803 }
804 else if( started && evt->IsAction( &ACTIONS::redo ) )
805 {
806 wxBell();
807 }
808 else
809 {
810 evt->SetPassEvent();
811 }
812
813 if( aBehavior.IsComplete() )
814 {
815 break;
816 }
817 else if( aBehavior.HasGeometryChanged() )
818 {
819 aBehavior.ApplyToShape( *aShape );
820 m_view->Update( &preview );
821 m_view->Update( &aBehavior.GetAssistant() );
822 aBehavior.ClearGeometryChanged();
823
824 if( started )
825 frame()->SetMsgPanel( aShape.get() );
826 else
827 frame()->SetMsgPanel( parent );
828 }
829 }
830
831 preview.Remove( aShape.get() );
832 m_view->Remove( &aBehavior.GetAssistant() );
833 m_view->Remove( &preview );
834
835 if( !started )
836 frame()->SetMsgPanel( parent );
837
838 controls->SetAutoPan( false );
839 controls->CaptureCursor( false );
840 controls->ForceCursorPosition( false );
841 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
842
843 if( cancelled )
844 {
845 aShape.reset();
847 }
848
850}
851
852
854{
855 if( m_inDrawingTool )
856 return 0;
857
858 EDA_ITEM* parent = getDrawParent();
859
860 if( !parent )
861 return 0;
862
863 if( IsSymbolEditor() )
864 {
866
867 if( !symFrame->IsSymbolGraphicallyEditable() )
868 return 0;
869 }
870
872
874
875 // Set filename on drag-and-drop
876 if( aEvent.HasParameter() )
877 dlg.SetFilenameOverride( *aEvent.Parameter<wxString*>() );
878
879 int dlgResult = dlg.ShowModal();
880
881 std::list<std::unique_ptr<EDA_ITEM>>& list = dlg.GetImportedItems();
882
883 if( dlgResult != wxID_OK )
884 return 0;
885
886 // Ensure the list is not empty:
887 if( list.empty() )
888 {
889 wxMessageBox( _( "No graphic items found in file." ) );
890 return 0;
891 }
892
894
896 std::vector<SCH_ITEM*> newItems;
897 std::vector<SCH_ITEM*> selectedItems;
898 SCH_SELECTION preview;
899 SCH_COMMIT commit( m_toolMgr );
900
901 auto commitImport =
902 [&]( const std::vector<SCH_ITEM*>& aItems )
903 {
904 if( IsSymbolEditor() )
905 {
906 LIB_SYMBOL* symbol = static_cast<LIB_SYMBOL*>( parent );
907 commit.Modify( symbol, frame()->GetScreen() );
908
909 for( SCH_ITEM* item : aItems )
910 {
911 symbol->AddDrawItem( item );
912 item->ClearEditFlags();
913 }
914 }
915 else
916 {
917 for( SCH_ITEM* item : aItems )
918 commit.Add( item, frame()->GetScreen() );
919 }
920
921 commit.Push( _( "Import Graphic" ) );
922
923 if( IsSymbolEditor() )
924 frame<SYMBOL_EDIT_FRAME>()->RebuildView();
925 };
926
927 for( std::unique_ptr<EDA_ITEM>& ptr : list )
928 {
929 EDA_ITEM* eda_item = ptr.release();
930 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( eda_item );
931
932 wxCHECK2_MSG( item, continue, wxString::Format( "Bad item type: ", eda_item->Type() ) );
933
934 newItems.push_back( item );
935 selectedItems.push_back( item );
936 preview.Add( item );
937 }
938
939 if( !dlg.IsPlacementInteractive() )
940 {
941 commitImport( newItems );
942 return 0;
943 }
944
945 m_view->Add( &preview );
946
948
949 EDA_ITEMS selItems( selectedItems.begin(), selectedItems.end() );
950 m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &selItems );
951
952 SCOPED_TOOL_PUSHER raii( frame(), aEvent );
953
954 auto setCursor =
955 [&]()
956 {
957 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
958 };
959
960 Activate();
961 controls->ShowCursor( true );
962 controls->ForceCursorPosition( false );
963 setCursor();
964
966
967 VECTOR2I cursorPos = controls->GetCursorPosition( !aEvent.DisableGridSnapping() );
968 VECTOR2I delta = cursorPos;
969 VECTOR2I currentOffset;
970
971 for( SCH_ITEM* item : selectedItems )
972 item->Move( delta );
973
974 currentOffset += delta;
975 m_view->Update( &preview );
976
977 // Main loop: keep receiving events
978 while( TOOL_EVENT* evt = Wait() )
979 {
980 setCursor();
981
982 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
983 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
984
985 cursorPos = grid.Align( controls->GetMousePosition(), GRID_GRAPHICS );
986 controls->ForceCursorPosition( true, cursorPos );
987
988 if( evt->IsCancelInteractive() || evt->IsActivate() )
989 {
991
992 for( SCH_ITEM* item : newItems )
993 delete item;
994
995 break;
996 }
997 else if( evt->IsMotion() )
998 {
999 delta = cursorPos - currentOffset;
1000
1001 for( SCH_ITEM* item : selectedItems )
1002 item->Move( delta );
1003
1004 currentOffset += delta;
1005 m_view->Update( &preview );
1006 }
1007 else if( evt->IsClick( BUT_RIGHT ) )
1008 {
1009 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
1010 }
1011 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
1012 || evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick ) )
1013 {
1014 commitImport( newItems );
1015 break;
1016 }
1017 else
1018 {
1019 evt->SetPassEvent();
1020 }
1021 }
1022
1023 preview.Clear();
1024 m_view->Remove( &preview );
1025
1026 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1027 controls->ForceCursorPosition( false );
1028
1029 return 0;
1030}
1031
1032
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:123
static TOOL_ACTION paste
Definition actions.h:76
static TOOL_ACTION cancelInteractive
Definition actions.h:68
static TOOL_ACTION arcPosture
Definition actions.h:268
static TOOL_ACTION updateUnits
Definition actions.h:203
static TOOL_ACTION deleteLastPoint
Definition actions.h:269
static TOOL_ACTION cursorDblClick
Definition actions.h:177
static TOOL_ACTION undo
Definition actions.h:71
static TOOL_ACTION duplicate
Definition actions.h:80
static TOOL_ACTION activatePointEditor
Definition actions.h:267
static TOOL_ACTION cursorClick
Definition actions.h:176
static TOOL_ACTION redo
Definition actions.h:72
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
static TOOL_ACTION refreshPreview
Definition actions.h:155
static TOOL_ACTION finishInteractive
Definition actions.h:69
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:228
Interactive arc drawing behaviour: center -> start -> end angle.
Interactive bezier drawing behaviour: start -> control1 -> end -> control2.
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
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition commit.h:74
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 SetFilenameOverride(const wxString &aFilenameOverride)
Set the filename override to be applied in TransferDataToWindow.
std::list< std::unique_ptr< EDA_ITEM > > & GetImportedItems()
int ShowModal() override
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
FILL_T GetFillMode() const
Definition eda_shape.h:148
COLOR4D GetFillColor() const
Definition eda_shape.h:159
bool IsItalic() const
Definition eda_text.h:200
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:239
virtual EDA_ANGLE GetTextAngle() const
Definition eda_text.h:178
bool IsBold() const
Definition eda_text.h:215
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition eda_text.h:242
bool Init() override
Init() is called once upon a registration of the tool.
COLOR4D m_lastTextboxFillColor
void applySymbolEditorFlags(SCH_ITEM &aItem) const
When in the symbol editor, apply unit and body-style restrictions to aItem according to the current d...
SHAPE_DRAW_RESULT drawManagedShape(const TOOL_EVENT &aTool, std::unique_ptr< SCH_SHAPE > &aShape, SHAPE_DRAW_BEHAVIOR &aBehavior, const std::vector< VECTOR2D > &aInitialPts)
Run the interactive drawing event loop for any shape driven by a SHAPE_DRAW_BEHAVIOR (arcs,...
int getDefaultTextSize() const
int DrawEllipseArc(const TOOL_EVENT &aEvent)
STROKE_PARAMS m_lastStroke
void setTransitions() override
The layer to use for new shapes in the current editor.
GR_TEXT_H_ALIGN_T m_lastTextboxHJustify
GR_TEXT_V_ALIGN_T m_lastTextboxVJustify
int DrawArc(const TOOL_EVENT &aEvent)
void commitItem(SCH_COMMIT &aCommit, std::unique_ptr< SCH_ITEM > aItem, const wxString &aDescription)
Return the default text size (in IU) for the active editor.
EDA_ANGLE m_lastTextboxAngle
int DrawBezier(const TOOL_EVENT &aEvent)
int DrawShape(const TOOL_EVENT &aEvent)
STROKE_PARAMS m_lastTextboxStroke
FILL_T m_lastTextboxFillStyle
int ImportGraphics(const TOOL_EVENT &aEvent)
SCH_LAYER_ID getShapeLayer() const
Commit a completed item.
Interactive elliptical-arc drawing behaviour: bbox corner 1 -> bbox corner 2 -> start angle -> end an...
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
Define a library symbol object.
Definition lib_symbol.h:119
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
static TOOL_ACTION drawEllipseArc
static TOOL_ACTION drawTextBox
Definition sch_actions.h:98
static TOOL_ACTION drawArc
static TOOL_ACTION drawSymbolLines
static TOOL_ACTION drawSymbolTextBox
static TOOL_ACTION properties
static TOOL_ACTION ddImportGraphics
static TOOL_ACTION drawRectangle
static TOOL_ACTION drawEllipse
static TOOL_ACTION drawCircle
static TOOL_ACTION importGraphics
static TOOL_ACTION drawBezier
static TOOL_ACTION drawSymbolPolygon
static TOOL_ACTION drawPolygon
static TOOL_ACTION repeatDrawItem
A shim class between EDA_DRAW_FRAME and several derived classes: SYMBOL_EDIT_FRAME,...
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Execute the changes.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:165
virtual void SetBodyStyle(int aBodyStyle)
Definition sch_item.h:246
virtual void SetUnit(int aUnit)
Definition sch_item.h:236
STROKE_PARAMS GetStroke() const override
Definition sch_shape.h:57
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
RAII class that sets an value at construction and resets it to the original value at destruction.
virtual void Add(EDA_ITEM *aItem)
A null aItem is ignored; the selection never holds null members.
Definition selection.cpp:38
virtual void Remove(EDA_ITEM *aItem)
Definition selection.cpp:60
virtual void Clear() override
Remove all the stored items from the group.
Definition selection.h:97
Abstract interface for interactive shape-drawing behaviours.
virtual void AddPoint(const VECTOR2I &aPosition)=0
Lock in a point and advance the construction state.
virtual void Reset()=0
Reset the behaviour to its initial state for chained object creation loops.
virtual bool IsComplete() const =0
True when all points have been locked in.
virtual void SetCursorPosition(const VECTOR2I &aPosition)=0
Preview the cursor position without advancing state.
virtual void SetUnits(EDA_UNITS aUnits)=0
Forward a units change to the assistant overlay.
virtual bool HasGeometryChanged() const =0
True if the geometry changed since the last call to ClearGeometryChanged().
virtual void RemoveLastPoint()=0
Undo the last locked-in point.
virtual EDA_ITEM & GetAssistant()=0
Return the visual assistant overlay item.
virtual void ClearGeometryChanged()=0
Reset the geometry-changed flag (call after updating the preview).
virtual void ApplyToShape(EDA_SHAPE &aShape) const =0
Transfer the current geometry to an EDA_SHAPE.
virtual void ToggleClockwise()
Flip arc direction (applies only when the shape has such a concept of directionality,...
The symbol library editor main window.
bool GetDrawSpecificUnit() const
bool GetDrawSpecificBodyStyle() const
LIB_SYMBOL * GetCurSymbol() const
Return the current symbol being edited or NULL if none selected.
bool IsSymbolGraphicallyEditable() const
Test if a symbol is loaded and can be edited graphically.
SCH_BASE_FRAME * getModel() const
Definition tool_base.h:195
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 HasPosition() const
Returns if it this event has a valid position (true for mouse events and context-menu or hotkey-based...
Definition tool_event.h:256
bool DisableGridSnapping() const
Definition tool_event.h:367
bool HasParameter() const
Definition tool_event.h:460
const VECTOR2D Position() const
Return mouse cursor position in world coordinates.
Definition tool_event.h:289
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:469
void Go(int(SCH_BASE_FRAME::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
std::unique_ptr< TOOL_MENU > m_menu
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
@ MOVING
Definition cursors.h:44
@ ARROW
Definition cursors.h:42
@ PENCIL
Definition cursors.h:48
#define DEFAULT_TEXT_SIZE
Ratio of the font height to the baseline of the text above the wire.
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:422
FILL_T
Definition eda_fill.h:29
@ NO_FILL
Definition eda_fill.h:30
#define IS_NEW
New item, just created.
SHAPE_T
Definition eda_shape.h:54
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:57
@ ELLIPSE_ARC
Definition eda_shape.h:63
SCOPED_SET_RESET< EE_GRAPHIC_TOOL::MODE > SCOPED_DRAW_MODE
@ GRID_GRAPHICS
Definition grid_helper.h:63
SCH_LAYER_ID
Eeschema drawing layers.
Definition layer_ids.h:471
@ LAYER_DEVICE
Definition layer_ids.h:488
@ LAYER_NOTES
Definition layer_ids.h:489
std::vector< EDA_ITEM * > EDA_ITEMS
SHAPE_DRAW_RESULT
Outcome of an interactive shape drawing loop, telling the caller how to continue.
@ NEXT_SHAPE
Commit the shape, if any, and start drawing another.
@ FINISHED
The user finished; commit the shape, if any, and stop drawing.
@ CANCELLED
The user cancelled; nothing to commit, stop drawing.
LINE_STYLE
Dashed line types.
wxString result
Test unit parsing edge cases and error handling.
int delta
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_TOP
@ MD_SHIFT
Definition tool_event.h:139
@ BUT_LEFT
Definition tool_event.h:128
@ BUT_RIGHT
Definition tool_event.h:129
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682