1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2017-2021 Kicad Developers, see change_log.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, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
22  */
23 
24 #include <bitmaps.h>
25 #include <board_commit.h>
26 #include <board_item.h>
27 #include <class_draw_panel_gal.h>
28 #include <footprint.h>
29 #include <confirm.h>
30 #include <gal/graphics_abstraction_layer.h>
31 #include <microwave/microwave_tool.h>
32 #include <preview_items/two_point_geom_manager.h>
33 #include <preview_items/centreline_rect_item.h>
34 #include <tool/tool_manager.h>
35 #include <tools/pcb_actions.h>
36 #include <view/view_controls.h>
37 #include <view/view.h>
38 
39 
MICROWAVE_TOOL()40 MICROWAVE_TOOL::MICROWAVE_TOOL() :
41         PCB_TOOL_BASE( "pcbnew.MicrowaveTool" )
42 {
43 }
44 
45 
~MICROWAVE_TOOL()46 MICROWAVE_TOOL::~MICROWAVE_TOOL()
47 {}
48 
49 
Reset(RESET_REASON aReason)50 void MICROWAVE_TOOL::Reset( RESET_REASON aReason )
51 {
52 }
53 
54 
addMicrowaveFootprint(const TOOL_EVENT & aEvent)55 int MICROWAVE_TOOL::addMicrowaveFootprint( const TOOL_EVENT& aEvent )
56 {
57     struct MICROWAVE_PLACER : public INTERACTIVE_PLACER_BASE
58     {
59         MICROWAVE_PLACER( MICROWAVE_TOOL* aTool, MICROWAVE_FOOTPRINT_SHAPE aType ) :
60                 m_tool( aTool ),
61                 m_itemType( aType )
62         { };
63 
64         virtual ~MICROWAVE_PLACER()
65         {
66         }
67 
68         std::unique_ptr<BOARD_ITEM> CreateItem() override
69         {
70             switch( m_itemType )
71             {
72             case MICROWAVE_FOOTPRINT_SHAPE::GAP:
73             case MICROWAVE_FOOTPRINT_SHAPE::STUB:
74             case MICROWAVE_FOOTPRINT_SHAPE::STUB_ARC:
75                 return std::unique_ptr<FOOTPRINT>( m_tool->createFootprint( m_itemType ) );
76 
77             case MICROWAVE_FOOTPRINT_SHAPE::FUNCTION_SHAPE:
78                 return std::unique_ptr<FOOTPRINT>( m_tool->createPolygonShape() );
79 
80             default:
81                 return std::unique_ptr<FOOTPRINT>();
82             };
83         }
84 
85     private:
86         MICROWAVE_TOOL*           m_tool;
87         MICROWAVE_FOOTPRINT_SHAPE m_itemType;
88     };
89 
90     MICROWAVE_PLACER placer( this, aEvent.Parameter<MICROWAVE_FOOTPRINT_SHAPE>() );
91 
92     doInteractiveItemPlacement( aEvent.GetCommandStr().get(), &placer,
93                                 _( "Place microwave feature" ),
94                                 IPO_REPEAT | IPO_ROTATE | IPO_FLIP );
95 
96     return 0;
97 }
98 
99 
100 static const COLOR4D inductorAreaFill( 0.3, 0.3, 0.5, 0.3 );
101 static const COLOR4D inductorAreaStroke( 0.4, 1.0, 1.0, 1.0 );
102 static const double  inductorAreaStrokeWidth = 1.0;
103 
104 ///< Aspect of the preview rectangle - this is hardcoded in the
105 ///< microwave backend for now
106 static const double  inductorAreaAspect = 0.5;
107 
108 
drawMicrowaveInductor(const TOOL_EVENT & aEvent)109 int MICROWAVE_TOOL::drawMicrowaveInductor( const TOOL_EVENT& aEvent )
110 {
111     using namespace KIGFX::PREVIEW;
112 
113     KIGFX::VIEW&          view = *getView();
114     KIGFX::VIEW_CONTROLS& controls = *getViewControls();
115     PCB_EDIT_FRAME&       frame = *getEditFrame<PCB_EDIT_FRAME>();
116 
117     std::string tool = aEvent.GetCommandStr().get();
118     frame.PushTool( tool );
119 
120     auto setCursor =
121             [&]()
122             {
123                 frame.GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
124             };
125 
126     Activate();
127     // Must be done after Activate() so that it gets set into the correct context
128     controls.ShowCursor( true );
129     controls.CaptureCursor( false );
130     controls.SetAutoPan( false );
131     // Set initial cursor
132     setCursor();
133 
134     bool                       originSet = false;
135     TWO_POINT_GEOMETRY_MANAGER tpGeomMgr;
136     CENTRELINE_RECT_ITEM       previewRect( tpGeomMgr, inductorAreaAspect );
137 
138     previewRect.SetFillColor( inductorAreaFill );
139     previewRect.SetStrokeColor( inductorAreaStroke );
140     previewRect.SetLineWidth( inductorAreaStrokeWidth );
141     view.Add( &previewRect );
142 
143     while( auto evt = Wait() )
144     {
145         setCursor();
146         VECTOR2I cursorPos = controls.GetCursorPosition();
147 
148         auto cleanup =
149                 [&] ()
150                 {
151                     originSet = false;
152                     controls.CaptureCursor( false );
153                     controls.SetAutoPan( false );
154                     view.SetVisible( &previewRect, false );
155                     view.Update( &previewRect, KIGFX::GEOMETRY );
156                 };
157 
158         if( evt->IsCancelInteractive() )
159         {
160             if( originSet )
161                 cleanup();
162             else
163             {
164                 frame.PopTool( tool );
165                 break;
166             }
167         }
168         else if( evt->IsActivate() )
169         {
170             if( originSet )
171                 cleanup();
172 
173             if( evt->IsMoveTool() )
174             {
175                 // leave ourselves on the stack so we come back after the move
176                 break;
177             }
178             else
179             {
180                 frame.PopTool( tool );
181                 break;
182             }
183         }
184         // A click or drag starts
185         else if( !originSet && ( evt->IsClick( BUT_LEFT ) || evt->IsDrag( BUT_LEFT ) ) )
186         {
187             tpGeomMgr.SetOrigin( cursorPos );
188             tpGeomMgr.SetEnd( cursorPos );
189 
190             originSet = true;
191             controls.CaptureCursor( true );
192             controls.SetAutoPan( true );
193         }
194         // another click after origin set is the end
195         // left up is also the end, as you'll only get that after a drag
196         else if( originSet && ( evt->IsClick( BUT_LEFT ) || evt->IsMouseUp( BUT_LEFT ) ) )
197         {
198             // second click, we're done:
199             // delegate to the point-to-point inductor creator function
200             createInductorBetween( tpGeomMgr.GetOrigin(), tpGeomMgr.GetEnd() );
201 
202             // start again if needed
203             originSet = false;
204             controls.CaptureCursor( false );
205             controls.SetAutoPan( false );
206 
207             view.SetVisible( &previewRect, false );
208             view.Update( &previewRect, KIGFX::GEOMETRY );
209         }
210         // any move or drag once the origin was set updates
211         // the end point
212         else if( originSet && ( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) )
213         {
214             tpGeomMgr.SetAngleSnap( Is45Limited() );
215             tpGeomMgr.SetEnd( cursorPos );
216 
217             view.SetVisible( &previewRect, true );
218             view.Update( &previewRect, KIGFX::GEOMETRY );
219         }
220         else if( evt->IsClick( BUT_RIGHT ) )
221         {
222             m_menu.ShowContextMenu( selection() );
223         }
224         else
225         {
226             evt->SetPassEvent();
227         }
228     }
229 
230     view.Remove( &previewRect );
231 
232     frame.GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
233     controls.CaptureCursor( false );
234     controls.SetAutoPan( false );
235     return 0;
236 }
237 
238 
239 
setTransitions()240 void MICROWAVE_TOOL::setTransitions()
241 {
242     Go( &MICROWAVE_TOOL::addMicrowaveFootprint, PCB_ACTIONS::microwaveCreateGap.MakeEvent() );
243     Go( &MICROWAVE_TOOL::addMicrowaveFootprint, PCB_ACTIONS::microwaveCreateStub.MakeEvent() );
244     Go( &MICROWAVE_TOOL::addMicrowaveFootprint, PCB_ACTIONS::microwaveCreateStubArc.MakeEvent() );
245     Go( &MICROWAVE_TOOL::addMicrowaveFootprint,
246         PCB_ACTIONS::microwaveCreateFunctionShape.MakeEvent() );
247 
248     Go( &MICROWAVE_TOOL::drawMicrowaveInductor, PCB_ACTIONS::microwaveCreateLine.MakeEvent() );
249 }
250