You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

392 lines
12 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2017 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. #include "microwave_tool.h"
  24. #include <gal/graphics_abstraction_layer.h>
  25. #include <class_draw_panel_gal.h>
  26. #include <view/view_controls.h>
  27. #include <view/view.h>
  28. #include <tool/tool_manager.h>
  29. #include <board_commit.h>
  30. #include <confirm.h>
  31. #include <preview_items/two_point_geom_manager.h>
  32. #include <preview_items/centreline_rect_item.h>
  33. // For frame ToolID values
  34. #include <pcbnew_id.h>
  35. // For action icons
  36. #include <bitmaps.h>
  37. #include <class_board_item.h>
  38. #include <class_module.h>
  39. #include <microwave/microwave_inductor.h>
  40. #include "pcb_actions.h"
  41. #include "selection_tool.h"
  42. #include "tool_event_utils.h"
  43. ///> Type of items that are "simple" - just get placed on
  44. ///> the board directly, without a graphical interactive setup stage
  45. enum MWAVE_TOOL_SIMPLE_ID
  46. {
  47. GAP,
  48. STUB,
  49. STUB_ARC,
  50. FUNCTION_SHAPE,
  51. };
  52. TOOL_ACTION PCB_ACTIONS::microwaveCreateGap(
  53. "pcbnew.MicrowaveTool.createGap",
  54. AS_GLOBAL, 0,
  55. _( "Add Gap" ), _( "Create gap of specified length for microwave applications" ),
  56. mw_add_gap_xpm, AF_ACTIVATE, (void*) MWAVE_TOOL_SIMPLE_ID::GAP );
  57. TOOL_ACTION PCB_ACTIONS::microwaveCreateStub(
  58. "pcbnew.MicrowaveTool.createStub",
  59. AS_GLOBAL, 0,
  60. _( "Add Stub" ), _( "Create stub of specified length for microwave applications" ),
  61. mw_add_stub_xpm, AF_ACTIVATE, (void*) MWAVE_TOOL_SIMPLE_ID::STUB );
  62. TOOL_ACTION PCB_ACTIONS::microwaveCreateStubArc(
  63. "pcbnew.MicrowaveTool.createStubArc",
  64. AS_GLOBAL, 0,
  65. _( "Add Arc Stub" ), _( "Create stub (arc) of specified length for microwave applications" ),
  66. mw_add_stub_arc_xpm, AF_ACTIVATE, (void*) MWAVE_TOOL_SIMPLE_ID::STUB_ARC );
  67. TOOL_ACTION PCB_ACTIONS::microwaveCreateFunctionShape(
  68. "pcbnew.MicrowaveTool.createFunctionShape",
  69. AS_GLOBAL, 0,
  70. _( "Add Polynomial Shape" ), _( "Create polynomial shape for microwave applications" ),
  71. mw_add_gap_xpm, AF_ACTIVATE, (void*) MWAVE_TOOL_SIMPLE_ID::FUNCTION_SHAPE );
  72. TOOL_ACTION PCB_ACTIONS::microwaveCreateLine(
  73. "pcbnew.MicrowaveTool.createLine",
  74. AS_GLOBAL, 0,
  75. _( "Add Microwave Line" ), _( "Create line of specified length for microwave applications" ),
  76. mw_add_line_xpm, AF_ACTIVATE );
  77. MICROWAVE_TOOL::MICROWAVE_TOOL() :
  78. PCB_TOOL( "pcbnew.MicrowaveTool" )
  79. {
  80. }
  81. MICROWAVE_TOOL::~MICROWAVE_TOOL()
  82. {}
  83. void MICROWAVE_TOOL::Reset( RESET_REASON aReason )
  84. {
  85. }
  86. struct MICROWAVE_TOOL_INFO
  87. {
  88. using MOD_CREATOR = std::function<std::unique_ptr<MODULE>()>;
  89. wxString name;
  90. int toolId;
  91. MOD_CREATOR creatorFunc;
  92. };
  93. MICROWAVE_TOOL_INFO getMicrowaveItemCreator( PCB_EDIT_FRAME& frame, int aParam )
  94. {
  95. MICROWAVE_TOOL_INFO info;
  96. switch( aParam )
  97. {
  98. case MWAVE_TOOL_SIMPLE_ID::GAP:
  99. info.name = _( "Add Gap" );
  100. info.toolId = ID_PCB_MUWAVE_TOOL_GAP_CMD;
  101. info.creatorFunc = [&frame] () {
  102. return std::unique_ptr<MODULE>( frame.Create_MuWaveComponent( 0 ) );
  103. };
  104. break;
  105. case MWAVE_TOOL_SIMPLE_ID::STUB:
  106. info.name = _( "Add Stub" );
  107. info.toolId = ID_PCB_MUWAVE_TOOL_STUB_CMD;
  108. info.creatorFunc = [&frame] () {
  109. return std::unique_ptr<MODULE>( frame.Create_MuWaveComponent( 1 ) );
  110. };
  111. break;
  112. case MWAVE_TOOL_SIMPLE_ID::STUB_ARC:
  113. info.name = _( "Add Stub (Arc)" );
  114. info.toolId = ID_PCB_MUWAVE_TOOL_STUB_ARC_CMD;
  115. info.creatorFunc = [&frame] () {
  116. return std::unique_ptr<MODULE>( frame.Create_MuWaveComponent( 2 ) );
  117. };
  118. break;
  119. case MWAVE_TOOL_SIMPLE_ID::FUNCTION_SHAPE:
  120. info.name = _( "Add Polynomial Shape" );
  121. info.toolId = ID_PCB_MUWAVE_TOOL_FUNCTION_SHAPE_CMD;
  122. info.creatorFunc = [&frame] () {
  123. return std::unique_ptr<MODULE>( frame.Create_MuWavePolygonShape() );
  124. };
  125. break;
  126. default:
  127. // Avoid uninitilized value:
  128. info.toolId = 0;
  129. // info.name is already set to empty string
  130. break;
  131. };
  132. return info;
  133. }
  134. int MICROWAVE_TOOL::addMicrowaveFootprint( const TOOL_EVENT& aEvent )
  135. {
  136. auto& frame = *getEditFrame<PCB_EDIT_FRAME>();
  137. const int param = aEvent.Parameter<intptr_t>();
  138. MICROWAVE_TOOL_INFO info = getMicrowaveItemCreator( frame, param );
  139. // failed to find suitable item info - shouldn't be possible
  140. // if all the id's are handled
  141. if( !info.name )
  142. {
  143. wxASSERT_MSG( 0, "Failed to find suitable microwave tool info" );
  144. return 0;
  145. }
  146. frame.SetToolID( info.toolId, wxCURSOR_PENCIL, info.name );
  147. struct MICROWAVE_PLACER : public INTERACTIVE_PLACER_BASE
  148. {
  149. MICROWAVE_TOOL_INFO& m_info;
  150. MICROWAVE_PLACER( MICROWAVE_TOOL_INFO& aInfo ) :
  151. m_info( aInfo ) {};
  152. std::unique_ptr<BOARD_ITEM> CreateItem() override
  153. {
  154. auto module = m_info.creatorFunc();
  155. // Module has been added in the legacy backend,
  156. // so we have to remove it before committing the change
  157. // @todo LEGACY
  158. if( module )
  159. {
  160. m_board->Remove( module.get() );
  161. }
  162. return std::unique_ptr<BOARD_ITEM>( module.release() );
  163. }
  164. };
  165. MICROWAVE_PLACER placer ( info );
  166. doInteractiveItemPlacement( &placer, _( "Place microwave feature" ),
  167. IPO_REPEAT | IPO_SINGLE_CLICK | IPO_ROTATE | IPO_FLIP | IPO_PROPERTIES );
  168. frame.SetNoToolSelected();
  169. return 0;
  170. }
  171. void MICROWAVE_TOOL::createInductorBetween( const VECTOR2I& aStart, const VECTOR2I& aEnd )
  172. {
  173. auto& frame = *getEditFrame<PCB_EDIT_FRAME>();
  174. MWAVE::INDUCTOR_PATTERN pattern;
  175. pattern.m_Width = board()->GetDesignSettings().GetCurrentTrackWidth();
  176. pattern.m_Start = { aStart.x, aStart.y };
  177. pattern.m_End = { aEnd.x, aEnd.y };
  178. wxString errorMessage;
  179. auto inductorModule = std::unique_ptr<MODULE>(
  180. CreateMicrowaveInductor( pattern, &frame, errorMessage )
  181. );
  182. if( inductorModule )
  183. {
  184. // legacy mode tools add to the board
  185. // so remove it and add it back with the commit object
  186. // this has to happen, even if we don't end up storing the module
  187. // @todo LEGACY
  188. board()->Remove( inductorModule.get() );
  189. }
  190. // on any error, report if we can
  191. if ( !inductorModule || !errorMessage.IsEmpty() )
  192. {
  193. if ( !errorMessage.IsEmpty() )
  194. {
  195. DisplayError( &frame, errorMessage );
  196. }
  197. }
  198. else
  199. {
  200. // at this point, we can save the module
  201. frame.SetCurItem( inductorModule.get() );
  202. BOARD_COMMIT commit( this );
  203. commit.Add( inductorModule.release() );
  204. commit.Push( _("Add microwave inductor" ) );
  205. }
  206. }
  207. static const COLOR4D inductorAreaFill( 0.3, 0.3, 0.5, 0.3 );
  208. static const COLOR4D inductorAreaStroke( 0.4, 1.0, 1.0, 1.0 );
  209. static const double inductorAreaStrokeWidth = 1.0;
  210. ///> Aspect of the preview rectangle - this is hardcoded in the
  211. ///> microwave backend for now
  212. static const double inductorAreaAspect = 0.5;
  213. int MICROWAVE_TOOL::drawMicrowaveInductor( const TOOL_EVENT& aEvent )
  214. {
  215. using namespace KIGFX::PREVIEW;
  216. KIGFX::VIEW& view = *getView();
  217. KIGFX::VIEW_CONTROLS& controls = *getViewControls();
  218. auto& frame = *getEditFrame<PCB_EDIT_FRAME>();
  219. frame.SetToolID( ID_PCB_MUWAVE_TOOL_SELF_CMD, wxCURSOR_PENCIL, _( "Add Microwave Inductor" ) );
  220. Activate();
  221. TWO_POINT_GEOMETRY_MANAGER tpGeomMgr;
  222. CENTRELINE_RECT_ITEM previewRect( tpGeomMgr, inductorAreaAspect );
  223. previewRect.SetFillColor( inductorAreaFill );
  224. previewRect.SetStrokeColor( inductorAreaStroke );
  225. previewRect.SetLineWidth( inductorAreaStrokeWidth );
  226. bool originSet = false;
  227. controls.ShowCursor( true );
  228. controls.SetSnapping( true );
  229. controls.CaptureCursor( false );
  230. controls.SetAutoPan( false );
  231. view.Add( &previewRect );
  232. while( auto evt = Wait() )
  233. {
  234. VECTOR2I cursorPos = controls.GetCursorPosition();
  235. if( TOOL_EVT_UTILS::IsCancelInteractive( *evt ) )
  236. {
  237. // overriding action, or we're cancelling without
  238. // an in-progress preview area
  239. if ( evt->IsActivate() || !originSet )
  240. {
  241. break;
  242. }
  243. // had an in-progress area, so start again but don't
  244. // cancel the tool
  245. originSet = false;
  246. controls.CaptureCursor( false );
  247. controls.SetAutoPan( false );
  248. view.SetVisible( &previewRect, false );
  249. view.Update( &previewRect, KIGFX::GEOMETRY );
  250. }
  251. // A click or drag starts
  252. else if( !originSet &&
  253. ( evt->IsClick( BUT_LEFT ) || evt->IsDrag( BUT_LEFT ) ) )
  254. {
  255. tpGeomMgr.SetOrigin( cursorPos );
  256. tpGeomMgr.SetEnd( cursorPos );
  257. originSet = true;
  258. controls.CaptureCursor( true );
  259. controls.SetAutoPan( true );
  260. }
  261. // another click after origin set is the end
  262. // left up is also the end, as you'll only get that after a drag
  263. else if( originSet &&
  264. ( evt->IsClick( BUT_LEFT ) || evt->IsMouseUp( BUT_LEFT ) ) )
  265. {
  266. // second click, we're done:
  267. // delegate to the point-to-point inductor creator function
  268. createInductorBetween( tpGeomMgr.GetOrigin(), tpGeomMgr.GetEnd() );
  269. // start again if needed
  270. originSet = false;
  271. controls.CaptureCursor( false );
  272. controls.SetAutoPan( false );
  273. view.SetVisible( &previewRect, false );
  274. view.Update( &previewRect, KIGFX::GEOMETRY );
  275. }
  276. // any move or drag once the origin was set updates
  277. // the end point
  278. else if( originSet &&
  279. ( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) )
  280. {
  281. tpGeomMgr.SetAngleSnap( evt->Modifier( MD_CTRL ) );
  282. tpGeomMgr.SetEnd( cursorPos );
  283. view.SetVisible( &previewRect, true );
  284. view.Update( &previewRect, KIGFX::GEOMETRY );
  285. }
  286. else if( evt->IsClick( BUT_RIGHT ) )
  287. {
  288. m_menu.ShowContextMenu();
  289. }
  290. }
  291. controls.CaptureCursor( false );
  292. controls.SetAutoPan( false );
  293. view.Remove( &previewRect );
  294. frame.SetNoToolSelected();
  295. return 0;
  296. }
  297. void MICROWAVE_TOOL::setTransitions()
  298. {
  299. Go( &MICROWAVE_TOOL::addMicrowaveFootprint, PCB_ACTIONS::microwaveCreateGap.MakeEvent() );
  300. Go( &MICROWAVE_TOOL::addMicrowaveFootprint, PCB_ACTIONS::microwaveCreateStub.MakeEvent() );
  301. Go( &MICROWAVE_TOOL::addMicrowaveFootprint, PCB_ACTIONS::microwaveCreateStubArc.MakeEvent() );
  302. Go( &MICROWAVE_TOOL::addMicrowaveFootprint, PCB_ACTIONS::microwaveCreateFunctionShape.MakeEvent() );
  303. Go( &MICROWAVE_TOOL::drawMicrowaveInductor, PCB_ACTIONS::microwaveCreateLine.MakeEvent() );
  304. }