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 canUndoPoint = [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, canUndoPoint, 200 );
90 // clang-format on
91
92 return true;
93}
94
95
100
101
103{
104 if( IsSymbolEditor() )
105 {
106 const SYMBOL_EDITOR_SETTINGS* cfg = frame<SYMBOL_EDIT_FRAME>()->libeditconfig();
107
108 return schIUScale.MilsToIU( cfg ? cfg->m_Defaults.text_size : DEFAULT_TEXT_SIZE );
109 }
110
111 return getModel<SCHEMATIC>()->Settings().m_DefaultTextSize;
112}
113
114
116{
117 if( !IsSymbolEditor() )
118 return;
119
121
122 if( symFrame->GetDrawSpecificUnit() )
123 aItem.SetUnit( symFrame->GetUnit() );
124
125 if( symFrame->GetDrawSpecificBodyStyle() )
126 aItem.SetBodyStyle( symFrame->GetBodyStyle() );
127}
128
129
130void EE_GRAPHIC_TOOL::commitItem( SCH_COMMIT& aCommit, std::unique_ptr<SCH_ITEM> aItem, const wxString& aDescription )
131{
132 aItem->ClearEditFlags();
133
134 if( IsSymbolEditor() )
135 {
137 LIB_SYMBOL* symbol = symFrame->GetCurSymbol();
138
139 aCommit.Modify( symbol, frame()->GetScreen() );
140 symbol->AddDrawItem( aItem.release() );
141 aCommit.Push( aDescription );
142 symFrame->RebuildView();
143 }
144 else
145 {
146 aCommit.Add( aItem.release(), frame()->GetScreen() );
147 aCommit.Push( aDescription );
148 }
149}
150
151
153{
154 EDA_ITEM* parent = getDrawParent();
155
156 if( !parent )
157 return 0;
158
159 int defaultTextSize = getDefaultTextSize();
160 bool isTextBox = aEvent.IsAction( &SCH_ACTIONS::drawTextBox )
162 SHAPE_T type = isTextBox ? SHAPE_T::RECTANGLE : aEvent.Parameter<SHAPE_T>();
163
164 if( m_inDrawingTool )
165 return 0;
166
168
171 VECTOR2I cursorPos;
172
173 std::unique_ptr<SCH_SHAPE> item;
174
175 // We might be running as the same shape in another co-routine. Make sure that one
176 // gets whacked.
177 m_toolMgr->DeactivateTool();
178
180
181 frame()->PushTool( aEvent );
182
183 auto setCursor =
184 [&]()
185 {
186 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
187 };
188
189 auto cleanup =
190 [&] ()
191 {
193 m_view->ClearPreview();
194 item.reset();
195 };
196
197 Activate();
198
199 // Must be done after Activate() so that it gets set into the correct context
200 getViewControls()->ShowCursor( true );
201
202 // Set initial cursor
203 setCursor();
204
205 if( aEvent.HasPosition() )
206 m_toolMgr->PrimeTool( aEvent.Position() );
207
208 SCH_LAYER_ID shapeLayer = getShapeLayer();
209
210 // Main loop: keep receiving events
211 while( TOOL_EVENT* evt = Wait() )
212 {
213 setCursor();
214 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
215 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
216
217 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
218 controls->ForceCursorPosition( true, cursorPos );
219
220 // The tool hotkey is interpreted as a click when drawing
221 bool isSyntheticClick = item && evt->IsActivate() && evt->HasPosition() && evt->Matches( aEvent );
222
223 if( evt->IsCancelInteractive() || ( item && evt->IsAction( &ACTIONS::undo ) ) )
224 {
225 if( item )
226 {
227 cleanup();
228 }
229 else
230 {
231 frame()->PopTool( aEvent );
232 break;
233 }
234 }
235 else if( evt->IsActivate() && !isSyntheticClick )
236 {
237 if( item && evt->IsMoveTool() )
238 {
239 // we're already drawing our own item; ignore the move tool
240 evt->SetPassEvent( false );
241 continue;
242 }
243
244 if( item )
245 cleanup();
246
247 if( evt->IsPointEditor() )
248 {
249 // don't exit (the point editor runs in the background)
250 }
251 else if( evt->IsMoveTool() )
252 {
253 // leave ourselves on the stack so we come back after the move
254 break;
255 }
256 else
257 {
258 frame()->PopTool( aEvent );
259 break;
260 }
261 }
262 else if( !item && ( evt->IsClick( BUT_LEFT )
263 || evt->IsAction( &ACTIONS::cursorClick ) ) )
264 {
266
267 if( isTextBox )
268 {
269 auto textbox = std::make_unique<SCH_TEXTBOX>( shapeLayer, 0, m_lastTextboxFillStyle );
270
271 textbox->SetTextSize( VECTOR2I( defaultTextSize, defaultTextSize ) );
272
273 // Must come after SetTextSize()
274 textbox->SetBold( m_lastTextBold );
275 textbox->SetItalic( m_lastTextItalic );
276
277 textbox->SetTextAngle( m_lastTextboxAngle );
278 textbox->SetHorizJustify( m_lastTextboxHJustify );
279 textbox->SetVertJustify( m_lastTextboxVJustify );
280 textbox->SetStroke( m_lastTextboxStroke );
281 textbox->SetFillColor( m_lastTextboxFillColor );
282 textbox->SetParent( parent );
283
284 item = std::move( textbox );
285 }
286 else
287 {
288 item = std::make_unique<SCH_SHAPE>( type, shapeLayer, 0, m_lastFillStyle );
289
290 item->SetStroke( m_lastStroke );
291 item->SetFillColor( m_lastFillColor );
292 item->SetParent( parent );
293 }
294
295 item->SetFlags( IS_NEW );
296
297 applySymbolEditorFlags( *item );
298
299 item->BeginEdit( cursorPos );
300
301 m_view->ClearPreview();
302 m_view->AddToPreview( item->Clone() );
303 }
304 else if( item && ( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
305 || isSyntheticClick
306 || evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick )
307 || evt->IsAction( &ACTIONS::finishInteractive ) ) )
308 {
309 bool finished = false;
310
311 if( evt->IsDblClick( BUT_LEFT )
312 || evt->IsAction( &ACTIONS::cursorDblClick )
313 || evt->IsAction( &ACTIONS::finishInteractive ) )
314 {
315 finished = true;
316 }
317 else
318 {
319 finished = !item->ContinueEdit( cursorPos );
320 }
321
322 if( finished )
323 {
324 item->EndEdit();
325 item->SetFlags( IS_NEW );
326
327 if( isTextBox )
328 {
329 SCH_TEXTBOX* textbox = static_cast<SCH_TEXTBOX*>( item.get() );
330 DIALOG_TEXT_PROPERTIES dlg( frame(), textbox );
331
332 getViewControls()->SetAutoPan( false );
333 getViewControls()->CaptureCursor( false );
334
335 // QuasiModal required for syntax help and Scintilla auto-complete
336 if( dlg.ShowQuasiModal() != wxID_OK )
337 {
338 cleanup();
339 continue;
340 }
341
342 m_lastTextBold = textbox->IsBold();
343 m_lastTextItalic = textbox->IsItalic();
344 m_lastTextboxAngle = textbox->GetTextAngle();
347 m_lastTextboxStroke = textbox->GetStroke();
350 }
351 else
352 {
353 m_lastStroke = item->GetStroke();
354 m_lastFillStyle = item->GetFillMode();
355 m_lastFillColor = item->GetFillColor();
356 }
357
358 m_selectionTool->AddItemToSel( item.get() );
359
360 SCH_COMMIT commit( m_toolMgr );
361 commitItem( commit, std::move( item ), wxString::Format( _( "Draw %s" ), item->GetClass() ) );
362
363 item = nullptr;
364
365 m_view->ClearPreview();
367 }
368 }
369 else if( evt->IsAction( &ACTIONS::duplicate )
370 || evt->IsAction( &SCH_ACTIONS::repeatDrawItem )
371 || evt->IsAction( &ACTIONS::paste ) )
372 {
373 if( item )
374 {
375 wxBell();
376 continue;
377 }
378
379 // Exit. The duplicate/repeat/paste will run in its own loop.
380 frame()->PopTool( aEvent );
381 evt->SetPassEvent();
382 break;
383 }
384 else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
385 {
386 item->CalcEdit( cursorPos );
387 m_view->ClearPreview();
388 m_view->AddToPreview( item->Clone() );
389
390 frame()->SetMsgPanel( item.get() );
391 }
392 else if( evt->IsDblClick( BUT_LEFT ) && !item )
393 {
395 }
396 else if( evt->IsClick( BUT_RIGHT ) )
397 {
398 // Warp after context menu only if dragging...
399 if( !item )
400 m_toolMgr->VetoContextMenuMouseWarp();
401
402 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
403 }
404 else if( item && evt->IsAction( &ACTIONS::redo ) )
405 {
406 wxBell();
407 }
408 else
409 {
410 evt->SetPassEvent();
411 }
412
413 // Enable autopanning and cursor capture only when there is a shape being drawn
414 getViewControls()->SetAutoPan( item != nullptr );
415 getViewControls()->CaptureCursor( item != nullptr );
416 }
417
418 getViewControls()->SetAutoPan( false );
419 getViewControls()->CaptureCursor( false );
420 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
421 return 0;
422}
423
424
426{
427 if( m_inDrawingTool )
428 return 0;
429
430 EDA_ITEM* parent = getDrawParent();
431
432 if( !parent )
433 return 0;
434
436 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::ARC );
437
438 SCH_LAYER_ID shapeLayer = getShapeLayer();
439 std::vector<VECTOR2D> initialPts;
440
441 const auto makeNewArc =
442 [&]()
443 {
444 std::unique_ptr<SCH_SHAPE> arc = std::make_unique<SCH_SHAPE>( SHAPE_T::ARC, shapeLayer, 0, m_lastFillStyle );
445 arc->SetStroke( m_lastStroke );
446 arc->SetFillColor( m_lastFillColor );
447 arc->SetParent( parent );
448 arc->SetFlags( IS_NEW );
449
451
452 return arc;
453 };
454
455 std::unique_ptr<SCH_SHAPE> arc = makeNewArc();
456
457 arc->SetFlags( IS_NEW );
458
459 m_frame->PushTool( aEvent );
460 Activate();
461
462 if( aEvent.HasPosition() )
463 initialPts.push_back( aEvent.Position() );
464
465 ARC_DRAW_BEHAVIOR arcBehavior( schIUScale, frame()->GetUserUnits() );
466
467 while( drawManagedShape( aEvent, arc, arcBehavior, initialPts ) )
468 {
469 if( arc )
470 {
471 m_lastStroke = arc->GetStroke();
472 m_lastFillStyle = arc->GetFillMode();
473 m_lastFillColor = arc->GetFillColor();
474
475 m_selectionTool->AddItemToSel( arc.get() );
476
477 SCH_COMMIT commit( m_toolMgr );
478 commitItem( commit, std::move( arc ), _( "Draw Arc" ) );
479
481 }
482
483 arc = makeNewArc();
484 initialPts.clear();
485 }
486
487 return 0;
488}
489
490
492{
493 if( m_inDrawingTool )
494 return 0;
495
496 EDA_ITEM* parent = getDrawParent();
497
498 if( !parent )
499 return 0;
500
502 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::ELLIPSE_ARC );
503
504 SCH_LAYER_ID shapeLayer = getShapeLayer();
505 std::vector<VECTOR2D> initialPts;
506
507 const auto makeNewEllipseArc =
508 [&]()
509 {
510 std::unique_ptr<SCH_SHAPE> arc = std::make_unique<SCH_SHAPE>(
511 SHAPE_T::ELLIPSE_ARC, shapeLayer, 0, m_lastFillStyle );
512 arc->SetStroke( m_lastStroke );
513 arc->SetFillColor( m_lastFillColor );
514 arc->SetParent( parent );
515 arc->SetFlags( IS_NEW );
516
518
519 return arc;
520 };
521
522 std::unique_ptr<SCH_SHAPE> arc = makeNewEllipseArc();
523
524 m_frame->PushTool( aEvent );
525 Activate();
526
527 if( aEvent.HasPosition() )
528 initialPts.push_back( aEvent.Position() );
529
530 ELLIPSE_ARC_DRAW_BEHAVIOR ellipseBehavior( schIUScale, frame()->GetUserUnits() );
531
532 while( drawManagedShape( aEvent, arc, ellipseBehavior, initialPts ) )
533 {
534 if( arc )
535 {
536 m_lastStroke = arc->GetStroke();
537 m_lastFillStyle = arc->GetFillMode();
538 m_lastFillColor = arc->GetFillColor();
539
540 m_selectionTool->AddItemToSel( arc.get() );
541
542 SCH_COMMIT commit( m_toolMgr );
543 commitItem( commit, std::move( arc ), _( "Draw Elliptical Arc" ) );
544
546 }
547
548 arc = makeNewEllipseArc();
549 initialPts.clear();
550 }
551
552 return 0;
553}
554
555
557{
558 if( m_inDrawingTool )
559 return 0;
560
561 EDA_ITEM* parent = getDrawParent();
562
563 if( !parent )
564 return 0;
565
567 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::BEZIER );
568
569 SCH_LAYER_ID shapeLayer = getShapeLayer();
570 std::vector<VECTOR2D> initialPts;
571
572 const auto makeNewBezier =
573 [&]()
574 {
575 std::unique_ptr<SCH_SHAPE> bezier = std::make_unique<SCH_SHAPE>(
576 SHAPE_T::BEZIER, shapeLayer, 0, m_lastFillStyle );
577 bezier->SetStroke( m_lastStroke );
578 bezier->SetFillColor( m_lastFillColor );
579 bezier->SetParent( parent );
580 bezier->SetFlags( IS_NEW );
581
582 applySymbolEditorFlags( *bezier );
583
584 return bezier;
585 };
586
587 std::unique_ptr<SCH_SHAPE> bezier = makeNewBezier();
588
589 m_frame->PushTool( aEvent );
590 Activate();
591
592 if( aEvent.HasPosition() )
593 initialPts.push_back( aEvent.Position() );
594
595 BEZIER_DRAW_BEHAVIOR bezierBehavior( schIUScale, frame()->GetUserUnits() );
596
597 while( drawManagedShape( aEvent, bezier, bezierBehavior, initialPts ) )
598 {
599 if( bezier )
600 {
601 m_lastStroke = bezier->GetStroke();
602 m_lastFillStyle = bezier->GetFillMode();
603 m_lastFillColor = bezier->GetFillColor();
604
605 // Chain: next bezier starts at the end of this one
606 initialPts.clear();
607 initialPts.push_back( bezier->GetEnd() );
608
609 // If the last control arm is non-zero, mirror it for tangent continuity
610 if( bezier->GetEnd() != bezier->GetBezierC2() )
611 {
612 VECTOR2D mirroredC1 = bezier->GetEnd() - ( bezier->GetBezierC2() - bezier->GetEnd() );
613 initialPts.push_back( mirroredC1 );
614 }
615
616 m_selectionTool->AddItemToSel( bezier.get() );
617
618 SCH_COMMIT commit( m_toolMgr );
619 commitItem( commit, std::move( bezier ), _( "Draw Bezier" ) );
620
622 }
623 else
624 {
625 initialPts.clear();
626 }
627
628 bezier = makeNewBezier();
629 }
630
631 return 0;
632}
633
634
635bool EE_GRAPHIC_TOOL::drawManagedShape( const TOOL_EVENT& aTool, std::unique_ptr<SCH_SHAPE>& aShape,
636 SHAPE_DRAW_BEHAVIOR& aBehavior,
637 const std::vector<VECTOR2D>& aInitialPts )
638{
639 if( !aShape )
640 return false;
641
642 aBehavior.Reset();
643
644 SELECTION preview;
647 VECTOR2I cursorPos;
648 EDA_ITEM* parent = getDrawParent();
649
650 m_view->Add( &preview );
651 m_view->Add( &aBehavior.GetAssistant() );
652
653 auto setCursor =
654 [&]()
655 {
656 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
657 };
658
659 auto cleanup =
660 [&]()
661 {
663 preview.Clear();
664 aShape.reset();
665 };
666
667 controls->ShowCursor( true );
668 setCursor();
669
670 bool started = false;
671 bool cancelled = false;
672
673 m_toolMgr->PostAction( ACTIONS::refreshPreview );
674
675 // Pre-load any initial points into the behaviour, advancing the construction
676 // state machine so that the next user click adds the subsequent point.
677 // The user can still undo these points if they want to change them.
678 for( const VECTOR2D& pt : aInitialPts )
679 aBehavior.AddPoint( pt );
680
681 if( !aInitialPts.empty() )
682 {
684
685 controls->SetAutoPan( true );
686 controls->CaptureCursor( true );
687
688 preview.Add( aShape.get() );
689 frame()->SetMsgPanel( aShape.get() );
690
691 m_toolMgr->PrimeTool( aInitialPts.back() );
692
693 started = true;
694 }
695
696 while( TOOL_EVENT* evt = Wait() )
697 {
698 setCursor();
699 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
700 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
701
702 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
703 controls->ForceCursorPosition( true, cursorPos );
704
705 if( evt->IsCancelInteractive() )
706 {
707 cleanup();
708
709 if( !started )
710 {
711 evt->SetPassEvent( false );
712 m_frame->PopTool( aTool );
713 cancelled = true;
714 }
715
716 break;
717 }
718 else if( started && evt->IsAction( &ACTIONS::undo ) )
719 {
720 cleanup();
721 break;
722 }
723 else if( evt->IsActivate() )
724 {
725 if( evt->IsPointEditor() )
726 {
727 // don't exit (the point editor runs in the background)
728 }
729 else if( evt->IsMoveTool() )
730 {
731 cleanup();
732 cancelled = true;
733 break;
734 }
735 else
736 {
737 cleanup();
738 m_frame->PopTool( aTool );
739 cancelled = true;
740 break;
741 }
742 }
743 else if( evt->IsClick( BUT_LEFT ) )
744 {
745 if( !started )
746 {
748
749 controls->SetAutoPan( true );
750 controls->CaptureCursor( true );
751
752 preview.Add( aShape.get() );
753 frame()->SetMsgPanel( aShape.get() );
754 started = true;
755 }
756
757 aBehavior.AddPoint( cursorPos );
758 }
759 else if( evt->IsAction( &ACTIONS::arcPosture ) )
760 {
761 aBehavior.ToggleClockwise();
762 }
763 else if( evt->IsAction( &ACTIONS::deleteLastPoint ) )
764 {
765 aBehavior.RemoveLastPoint();
766 grid.FullReset();
767 }
768 else if( evt->IsMotion() )
769 {
770 aBehavior.SetCursorPosition( cursorPos );
771 }
772 else if( evt->IsClick( BUT_RIGHT ) )
773 {
774 if( !aShape )
775 m_toolMgr->VetoContextMenuMouseWarp();
776
777 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
778 }
779 else if( evt->IsAction( &ACTIONS::updateUnits ) )
780 {
781 aBehavior.SetUnits( frame()->GetUserUnits() );
782 m_view->Update( &aBehavior.GetAssistant() );
783 evt->SetPassEvent();
784 }
785 else if( started && evt->IsAction( &ACTIONS::redo ) )
786 {
787 wxBell();
788 }
789 else
790 {
791 evt->SetPassEvent();
792 }
793
794 if( aBehavior.IsComplete() )
795 {
796 break;
797 }
798 else if( aBehavior.HasGeometryChanged() )
799 {
800 aBehavior.ApplyToShape( *aShape );
801 m_view->Update( &preview );
802 m_view->Update( &aBehavior.GetAssistant() );
803 aBehavior.ClearGeometryChanged();
804
805 if( started )
806 frame()->SetMsgPanel( aShape.get() );
807 else
808 frame()->SetMsgPanel( parent );
809 }
810 }
811
812 preview.Remove( aShape.get() );
813 m_view->Remove( &aBehavior.GetAssistant() );
814 m_view->Remove( &preview );
815
816 if( !started )
817 frame()->SetMsgPanel( parent );
818
819 controls->SetAutoPan( false );
820 controls->CaptureCursor( false );
821 controls->ForceCursorPosition( false );
822 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
823
824 if( cancelled )
825 {
826 aShape.reset();
827 }
828
829 return !cancelled;
830}
831
832
834{
835 if( m_inDrawingTool )
836 return 0;
837
838 EDA_ITEM* parent = getDrawParent();
839
840 if( !parent )
841 return 0;
842
844
846
847 // Set filename on drag-and-drop
848 if( aEvent.HasParameter() )
849 dlg.SetFilenameOverride( *aEvent.Parameter<wxString*>() );
850
851 int dlgResult = dlg.ShowModal();
852
853 std::list<std::unique_ptr<EDA_ITEM>>& list = dlg.GetImportedItems();
854
855 if( dlgResult != wxID_OK )
856 return 0;
857
858 // Ensure the list is not empty:
859 if( list.empty() )
860 {
861 wxMessageBox( _( "No graphic items found in file." ) );
862 return 0;
863 }
864
866
868 std::vector<SCH_ITEM*> newItems;
869 std::vector<SCH_ITEM*> selectedItems;
870 SCH_SELECTION preview;
871 SCH_COMMIT commit( m_toolMgr );
872
873 auto commitImport =
874 [&]( const std::vector<SCH_ITEM*>& aItems )
875 {
876 if( IsSymbolEditor() )
877 {
878 LIB_SYMBOL* symbol = static_cast<LIB_SYMBOL*>( parent );
879 commit.Modify( symbol, frame()->GetScreen() );
880
881 for( SCH_ITEM* item : aItems )
882 {
883 symbol->AddDrawItem( item );
884 item->ClearEditFlags();
885 }
886 }
887 else
888 {
889 for( SCH_ITEM* item : aItems )
890 commit.Add( item, frame()->GetScreen() );
891 }
892
893 commit.Push( _( "Import Graphic" ) );
894
895 if( IsSymbolEditor() )
896 frame<SYMBOL_EDIT_FRAME>()->RebuildView();
897 };
898
899 for( std::unique_ptr<EDA_ITEM>& ptr : list )
900 {
901 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( ptr.get() );
902 wxCHECK2_MSG( item, continue, wxString::Format( "Bad item type: ", ptr->Type() ) );
903
904 newItems.push_back( item );
905 selectedItems.push_back( item );
906 preview.Add( item );
907
908 ptr.release();
909 }
910
911 if( !dlg.IsPlacementInteractive() )
912 {
913 commitImport( newItems );
914 return 0;
915 }
916
917 m_view->Add( &preview );
918
920
921 EDA_ITEMS selItems( selectedItems.begin(), selectedItems.end() );
922 m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &selItems );
923
924 frame()->PushTool( aEvent );
925
926 auto setCursor =
927 [&]()
928 {
929 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
930 };
931
932 Activate();
933 controls->ShowCursor( true );
934 controls->ForceCursorPosition( false );
935 setCursor();
936
938
939 VECTOR2I cursorPos = controls->GetCursorPosition( !aEvent.DisableGridSnapping() );
940 VECTOR2I delta = cursorPos;
941 VECTOR2I currentOffset;
942
943 for( SCH_ITEM* item : selectedItems )
944 item->Move( delta );
945
946 currentOffset += delta;
947 m_view->Update( &preview );
948
949 // Main loop: keep receiving events
950 while( TOOL_EVENT* evt = Wait() )
951 {
952 setCursor();
953
954 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
955 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
956
957 cursorPos = grid.Align( controls->GetMousePosition(), GRID_GRAPHICS );
958 controls->ForceCursorPosition( true, cursorPos );
959
960 if( evt->IsCancelInteractive() || evt->IsActivate() )
961 {
963
964 for( SCH_ITEM* item : newItems )
965 delete item;
966
967 break;
968 }
969 else if( evt->IsMotion() )
970 {
971 delta = cursorPos - currentOffset;
972
973 for( SCH_ITEM* item : selectedItems )
974 item->Move( delta );
975
976 currentOffset += delta;
977 m_view->Update( &preview );
978 }
979 else if( evt->IsClick( BUT_RIGHT ) )
980 {
981 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
982 }
983 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
984 || evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick ) )
985 {
986 commitImport( newItems );
987 break;
988 }
989 else
990 {
991 evt->SetPassEvent();
992 }
993 }
994
995 preview.Clear();
996 m_view->Remove( &preview );
997
998 frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
999 controls->ForceCursorPosition( false );
1000 frame()->PopTool( aEvent );
1001
1002 return 0;
1003}
1004
1005
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:96
FILL_T GetFillMode() const
Definition eda_shape.h:158
COLOR4D GetFillColor() const
Definition eda_shape.h:169
bool IsItalic() const
Definition eda_text.h:190
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:221
virtual EDA_ANGLE GetTextAngle() const
Definition eda_text.h:168
bool IsBold() const
Definition eda_text.h:205
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition eda_text.h:224
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...
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)
bool 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 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:114
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
Definition sch_actions.h:94
static TOOL_ACTION drawTextBox
Definition sch_actions.h:89
static TOOL_ACTION drawArc
Definition sch_actions.h:95
static TOOL_ACTION drawSymbolLines
static TOOL_ACTION drawSymbolTextBox
static TOOL_ACTION properties
static TOOL_ACTION ddImportGraphics
static TOOL_ACTION drawRectangle
Definition sch_actions.h:91
static TOOL_ACTION drawEllipse
Definition sch_actions.h:93
static TOOL_ACTION drawCircle
Definition sch_actions.h:92
static TOOL_ACTION importGraphics
static TOOL_ACTION drawBezier
Definition sch_actions.h:96
static TOOL_ACTION drawSymbolPolygon
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:162
virtual void SetBodyStyle(int aBodyStyle)
Definition sch_item.h:241
virtual void SetUnit(int aUnit)
Definition sch_item.h:232
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)
Definition selection.cpp:38
virtual void Remove(EDA_ITEM *aItem)
Definition selection.cpp:56
virtual void Clear() override
Remove all the stored items from the group.
Definition selection.h:94
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.
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:411
#define IS_NEW
New item, just created.
SHAPE_T
Definition eda_shape.h:44
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:47
@ ELLIPSE_ARC
Definition eda_shape.h:53
FILL_T
Definition eda_shape.h:59
@ NO_FILL
Definition eda_shape.h:60
SCOPED_SET_RESET< EE_GRAPHIC_TOOL::MODE > SCOPED_DRAW_MODE
@ GRID_GRAPHICS
Definition grid_helper.h:48
SCH_LAYER_ID
Eeschema drawing layers.
Definition layer_ids.h:455
@ LAYER_DEVICE
Definition layer_ids.h:472
@ LAYER_NOTES
Definition layer_ids.h:473
std::vector< EDA_ITEM * > EDA_ITEMS
LINE_STYLE
Dashed line types.
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