|
|
/*
* This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2017 Kicad Developers, see change_log.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
#include "microwave_tool.h"
#include <gal/graphics_abstraction_layer.h>
#include <class_draw_panel_gal.h>
#include <view/view_controls.h>
#include <view/view.h>
#include <tool/tool_manager.h>
#include <board_commit.h>
#include <confirm.h>
#include <preview_items/two_point_geom_manager.h>
#include <preview_items/centreline_rect_item.h>
// For frame ToolID values
#include <pcbnew_id.h>
// For action icons
#include <bitmaps.h>
#include <class_board_item.h>
#include <class_module.h>
#include <microwave/microwave_inductor.h>
#include "pcb_actions.h"
#include "selection_tool.h"
#include "tool_event_utils.h"
///> Type of items that are "simple" - just get placed on
///> the board directly, without a graphical interactive setup stage
enum MWAVE_TOOL_SIMPLE_ID{ GAP, STUB, STUB_ARC, FUNCTION_SHAPE,};
TOOL_ACTION PCB_ACTIONS::microwaveCreateGap( "pcbnew.MicrowaveTool.createGap", AS_GLOBAL, 0, _( "Add Gap" ), _( "Create gap of specified length for microwave applications" ), mw_add_gap_xpm, AF_ACTIVATE, (void*) MWAVE_TOOL_SIMPLE_ID::GAP );
TOOL_ACTION PCB_ACTIONS::microwaveCreateStub( "pcbnew.MicrowaveTool.createStub", AS_GLOBAL, 0, _( "Add Stub" ), _( "Create stub of specified length for microwave applications" ), mw_add_stub_xpm, AF_ACTIVATE, (void*) MWAVE_TOOL_SIMPLE_ID::STUB );
TOOL_ACTION PCB_ACTIONS::microwaveCreateStubArc( "pcbnew.MicrowaveTool.createStubArc", AS_GLOBAL, 0, _( "Add Arc Stub" ), _( "Create stub (arc) of specified length for microwave applications" ), mw_add_stub_arc_xpm, AF_ACTIVATE, (void*) MWAVE_TOOL_SIMPLE_ID::STUB_ARC );
TOOL_ACTION PCB_ACTIONS::microwaveCreateFunctionShape( "pcbnew.MicrowaveTool.createFunctionShape", AS_GLOBAL, 0, _( "Add Polynomial Shape" ), _( "Create polynomial shape for microwave applications" ), mw_add_gap_xpm, AF_ACTIVATE, (void*) MWAVE_TOOL_SIMPLE_ID::FUNCTION_SHAPE );
TOOL_ACTION PCB_ACTIONS::microwaveCreateLine( "pcbnew.MicrowaveTool.createLine", AS_GLOBAL, 0, _( "Add Microwave Line" ), _( "Create line of specified length for microwave applications" ), mw_add_line_xpm, AF_ACTIVATE );
MICROWAVE_TOOL::MICROWAVE_TOOL() : PCB_TOOL( "pcbnew.MicrowaveTool" ){}
MICROWAVE_TOOL::~MICROWAVE_TOOL(){}
void MICROWAVE_TOOL::Reset( RESET_REASON aReason ){}
struct MICROWAVE_TOOL_INFO{ using MOD_CREATOR = std::function<std::unique_ptr<MODULE>()>;
wxString name; int toolId; MOD_CREATOR creatorFunc;};
MICROWAVE_TOOL_INFO getMicrowaveItemCreator( PCB_EDIT_FRAME& frame, int aParam ){ MICROWAVE_TOOL_INFO info;
switch( aParam ) { case MWAVE_TOOL_SIMPLE_ID::GAP: info.name = _( "Add Gap" ); info.toolId = ID_PCB_MUWAVE_TOOL_GAP_CMD; info.creatorFunc = [&frame] () { return std::unique_ptr<MODULE>( frame.Create_MuWaveComponent( 0 ) ); }; break;
case MWAVE_TOOL_SIMPLE_ID::STUB: info.name = _( "Add Stub" ); info.toolId = ID_PCB_MUWAVE_TOOL_STUB_CMD; info.creatorFunc = [&frame] () { return std::unique_ptr<MODULE>( frame.Create_MuWaveComponent( 1 ) ); }; break;
case MWAVE_TOOL_SIMPLE_ID::STUB_ARC: info.name = _( "Add Stub (Arc)" ); info.toolId = ID_PCB_MUWAVE_TOOL_STUB_ARC_CMD; info.creatorFunc = [&frame] () { return std::unique_ptr<MODULE>( frame.Create_MuWaveComponent( 2 ) ); }; break;
case MWAVE_TOOL_SIMPLE_ID::FUNCTION_SHAPE: info.name = _( "Add Polynomial Shape" ); info.toolId = ID_PCB_MUWAVE_TOOL_FUNCTION_SHAPE_CMD; info.creatorFunc = [&frame] () { return std::unique_ptr<MODULE>( frame.Create_MuWavePolygonShape() ); }; break;
default: // Avoid uninitilized value:
info.toolId = 0; // info.name is already set to empty string
break; };
return info;}
int MICROWAVE_TOOL::addMicrowaveFootprint( const TOOL_EVENT& aEvent ){ auto& frame = *getEditFrame<PCB_EDIT_FRAME>();
const int param = aEvent.Parameter<intptr_t>();
MICROWAVE_TOOL_INFO info = getMicrowaveItemCreator( frame, param );
// failed to find suitable item info - shouldn't be possible
// if all the id's are handled
if( !info.name ) { wxASSERT_MSG( 0, "Failed to find suitable microwave tool info" ); return 0; }
frame.SetToolID( info.toolId, wxCURSOR_PENCIL, info.name );
struct MICROWAVE_PLACER : public INTERACTIVE_PLACER_BASE { MICROWAVE_TOOL_INFO& m_info;
MICROWAVE_PLACER( MICROWAVE_TOOL_INFO& aInfo ) : m_info( aInfo ) {};
std::unique_ptr<BOARD_ITEM> CreateItem() override { auto module = m_info.creatorFunc();
// Module has been added in the legacy backend,
// so we have to remove it before committing the change
// @todo LEGACY
if( module ) { m_board->Remove( module.get() ); }
return std::unique_ptr<BOARD_ITEM>( module.release() ); } };
MICROWAVE_PLACER placer ( info );
doInteractiveItemPlacement( &placer, _( "Place microwave feature" ), IPO_REPEAT | IPO_SINGLE_CLICK | IPO_ROTATE | IPO_FLIP | IPO_PROPERTIES );
frame.SetNoToolSelected();
return 0;}
void MICROWAVE_TOOL::createInductorBetween( const VECTOR2I& aStart, const VECTOR2I& aEnd ){ auto& frame = *getEditFrame<PCB_EDIT_FRAME>();
MWAVE::INDUCTOR_PATTERN pattern;
pattern.m_Width = board()->GetDesignSettings().GetCurrentTrackWidth();
pattern.m_Start = { aStart.x, aStart.y }; pattern.m_End = { aEnd.x, aEnd.y };
wxString errorMessage;
auto inductorModule = std::unique_ptr<MODULE>( CreateMicrowaveInductor( pattern, &frame, errorMessage ) );
if( inductorModule ) { // legacy mode tools add to the board
// so remove it and add it back with the commit object
// this has to happen, even if we don't end up storing the module
// @todo LEGACY
board()->Remove( inductorModule.get() ); }
// on any error, report if we can
if ( !inductorModule || !errorMessage.IsEmpty() ) { if ( !errorMessage.IsEmpty() ) { DisplayError( &frame, errorMessage ); } } else { // at this point, we can save the module
frame.SetCurItem( inductorModule.get() );
BOARD_COMMIT commit( this ); commit.Add( inductorModule.release() ); commit.Push( _("Add microwave inductor" ) ); }}
static const COLOR4D inductorAreaFill( 0.3, 0.3, 0.5, 0.3 );static const COLOR4D inductorAreaStroke( 0.4, 1.0, 1.0, 1.0 );static const double inductorAreaStrokeWidth = 1.0;
///> Aspect of the preview rectangle - this is hardcoded in the
///> microwave backend for now
static const double inductorAreaAspect = 0.5;
int MICROWAVE_TOOL::drawMicrowaveInductor( const TOOL_EVENT& aEvent ){ using namespace KIGFX::PREVIEW;
KIGFX::VIEW& view = *getView(); KIGFX::VIEW_CONTROLS& controls = *getViewControls(); auto& frame = *getEditFrame<PCB_EDIT_FRAME>();
frame.SetToolID( ID_PCB_MUWAVE_TOOL_SELF_CMD, wxCURSOR_PENCIL, _( "Add Microwave Inductor" ) );
Activate();
TWO_POINT_GEOMETRY_MANAGER tpGeomMgr;
CENTRELINE_RECT_ITEM previewRect( tpGeomMgr, inductorAreaAspect );
previewRect.SetFillColor( inductorAreaFill ); previewRect.SetStrokeColor( inductorAreaStroke ); previewRect.SetLineWidth( inductorAreaStrokeWidth );
bool originSet = false;
controls.ShowCursor( true ); controls.SetSnapping( true ); controls.CaptureCursor( false ); controls.SetAutoPan( false );
view.Add( &previewRect );
while( auto evt = Wait() ) { VECTOR2I cursorPos = controls.GetCursorPosition();
if( TOOL_EVT_UTILS::IsCancelInteractive( *evt ) ) { // overriding action, or we're cancelling without
// an in-progress preview area
if ( evt->IsActivate() || !originSet ) { break; }
// had an in-progress area, so start again but don't
// cancel the tool
originSet = false; controls.CaptureCursor( false ); controls.SetAutoPan( false );
view.SetVisible( &previewRect, false ); view.Update( &previewRect, KIGFX::GEOMETRY ); }
// A click or drag starts
else if( !originSet && ( evt->IsClick( BUT_LEFT ) || evt->IsDrag( BUT_LEFT ) ) ) { tpGeomMgr.SetOrigin( cursorPos ); tpGeomMgr.SetEnd( cursorPos );
originSet = true; controls.CaptureCursor( true ); controls.SetAutoPan( true ); }
// another click after origin set is the end
// left up is also the end, as you'll only get that after a drag
else if( originSet && ( evt->IsClick( BUT_LEFT ) || evt->IsMouseUp( BUT_LEFT ) ) ) { // second click, we're done:
// delegate to the point-to-point inductor creator function
createInductorBetween( tpGeomMgr.GetOrigin(), tpGeomMgr.GetEnd() );
// start again if needed
originSet = false; controls.CaptureCursor( false ); controls.SetAutoPan( false );
view.SetVisible( &previewRect, false ); view.Update( &previewRect, KIGFX::GEOMETRY ); }
// any move or drag once the origin was set updates
// the end point
else if( originSet && ( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) ) { tpGeomMgr.SetAngleSnap( evt->Modifier( MD_CTRL ) ); tpGeomMgr.SetEnd( cursorPos );
view.SetVisible( &previewRect, true ); view.Update( &previewRect, KIGFX::GEOMETRY ); }
else if( evt->IsClick( BUT_RIGHT ) ) { m_menu.ShowContextMenu(); } }
controls.CaptureCursor( false ); controls.SetAutoPan( false ); view.Remove( &previewRect );
frame.SetNoToolSelected();
return 0;}
void MICROWAVE_TOOL::setTransitions(){ Go( &MICROWAVE_TOOL::addMicrowaveFootprint, PCB_ACTIONS::microwaveCreateGap.MakeEvent() ); Go( &MICROWAVE_TOOL::addMicrowaveFootprint, PCB_ACTIONS::microwaveCreateStub.MakeEvent() ); Go( &MICROWAVE_TOOL::addMicrowaveFootprint, PCB_ACTIONS::microwaveCreateStubArc.MakeEvent() ); Go( &MICROWAVE_TOOL::addMicrowaveFootprint, PCB_ACTIONS::microwaveCreateFunctionShape.MakeEvent() );
Go( &MICROWAVE_TOOL::drawMicrowaveInductor, PCB_ACTIONS::microwaveCreateLine.MakeEvent() );}
|