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