diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 42e5a50451..522c2c9838 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -187,6 +187,7 @@ set( COMMON_PAGE_LAYOUT_SRCS set( COMMON_PREVIEW_ITEMS_SRCS preview_items/arc_assistant.cpp preview_items/arc_geom_manager.cpp + preview_items/centreline_rect_item.cpp preview_items/preview_utils.cpp preview_items/ruler_item.cpp preview_items/simple_overlay_item.cpp diff --git a/common/preview_items/centreline_rect_item.cpp b/common/preview_items/centreline_rect_item.cpp new file mode 100644 index 0000000000..b5c5cae39e --- /dev/null +++ b/common/preview_items/centreline_rect_item.cpp @@ -0,0 +1,100 @@ +/* + * 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 + +#include + +#include + + +using namespace KIGFX::PREVIEW; + +static SHAPE_POLY_SET getRectangleAlongCentreLine( + const VECTOR2D& aClStart, const VECTOR2D& aClEnd, double aAspect ) +{ + SHAPE_POLY_SET poly; + poly.NewOutline(); + + /* + * The point layout of the rectangle goes like this, + * but start/end don't have to be horz/vert + * + * 0 ---------------- 1 ----- + * | | ^ + * s--------cl------->e |cl|/aspect + * | | v + * 3----------------- 2 ----- + */ + + // vector down the centre line of the rectangle + const VECTOR2D cl = aClEnd - aClStart; + + // the "side" of the rectangle is the centre line rotated by 90 deg + // and scaled by the aspect ratio + const VECTOR2D side = cl.Rotate( M_PI / 2.0 ) * aAspect; + + VECTOR2D pt = aClStart + ( side / 2.0 ); + poly.Append( pt ); + + pt += cl; + poly.Append( pt ); + + pt -= side; + poly.Append( pt ); + + pt -= cl; + poly.Append( pt ); + + return poly; +} + + +CENTRELINE_RECT_ITEM::CENTRELINE_RECT_ITEM( + const TWO_POINT_GEOMETRY_MANAGER& aGeomMgr, + double aAspect ): + m_geomMgr( aGeomMgr ), + m_aspect( aAspect ) +{ +} + + +SHAPE_POLY_SET CENTRELINE_RECT_ITEM::getOutline() const +{ + return getRectangleAlongCentreLine( m_geomMgr.GetOrigin(), + m_geomMgr.GetEnd(), + m_aspect ); +} + + +const BOX2I CENTRELINE_RECT_ITEM::ViewBBox() const +{ + return getOutline().BBox(); +} + + +void CENTRELINE_RECT_ITEM::drawPreviewShape( KIGFX::GAL& aGal ) const +{ + aGal.DrawLine( m_geomMgr.GetOrigin(), m_geomMgr.GetEnd() ); + aGal.DrawPolygon( getOutline() ); +} diff --git a/include/preview_items/centreline_rect_item.h b/include/preview_items/centreline_rect_item.h new file mode 100644 index 0000000000..5c6bbf8028 --- /dev/null +++ b/include/preview_items/centreline_rect_item.h @@ -0,0 +1,78 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 KiCad Developers, see AUTHORS.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 + */ + +#ifndef PREVIEW_ITEMS_CENTERLINE_RECT_ITEM_H +#define PREVIEW_ITEMS_CENTERLINE_RECT_ITEM_H + +#include + +#include + +#include + +namespace KIGFX +{ +class GAL; + +namespace PREVIEW +{ +class TWO_POINT_GEOMETRY_MANAGER; + +/** + * Class CENTRELINE_RECT_ITEM + * + * Represents an area drawn by drawing a rectangle of a given aspect + * along a vector, with the midpoiunt of one side on the start point + * and the mid point of the opposite side on the end. + * + * The centre line does not have to horizontal or vertical, it + * can be at any angle. + */ +class CENTRELINE_RECT_ITEM : public SIMPLE_OVERLAY_ITEM +{ +public: + + CENTRELINE_RECT_ITEM( const TWO_POINT_GEOMETRY_MANAGER& aGeomMgr, + double aAspect ); + + ///> Gets the bounding box of the rectangle + virtual const BOX2I ViewBBox() const override; + +private: + + ///> Get the rectangular outline + SHAPE_POLY_SET getOutline() const; + + ///> Draw rectangle and centre line onto GAL + void drawPreviewShape( KIGFX::GAL& aGal ) const override; + + const TWO_POINT_GEOMETRY_MANAGER& m_geomMgr; + + ///> The aspect ratio of the rectangle to draw + double m_aspect; +}; + +} // PREVIEW +} // KIGFX + +#endif // PREVIEW_ITEMS_CENTERLINE_RECT_ITEM_H diff --git a/include/preview_items/two_point_geom_manager.h b/include/preview_items/two_point_geom_manager.h new file mode 100644 index 0000000000..4d218cb027 --- /dev/null +++ b/include/preview_items/two_point_geom_manager.h @@ -0,0 +1,97 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 KiCad Developers, see AUTHORS.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 + */ + +#ifndef PREVIEW_ITEMS_TWO_POINT_GEOMETRY_MANAGER_H +#define PREVIEW_ITEMS_TWO_POINT_GEOMETRY_MANAGER_H + +#include +#include + +namespace KIGFX +{ +class GAL; + +namespace PREVIEW +{ + +/** + * Class TWO_POINT_GEOMETRY_MANAGER + * + * Represents a very simple geometry manager for items that have + * a start and end point. + */ +class TWO_POINT_GEOMETRY_MANAGER +{ +public: + + ///> Set the origin of the ruler (the fixed end) + void SetOrigin( const VECTOR2I& aOrigin ) + { + m_origin = aOrigin; + } + + VECTOR2I GetOrigin() const + { + return m_origin; + } + + /** + * Set the current end of the rectangle (the end that moves + * with the cursor. + */ + void SetEnd( const VECTOR2I& aEnd ) + { + if( m_angleSnap ) + { + const auto vec = aEnd - m_origin; + const auto len = vec.EuclideanNorm(); + const auto angle = KiROUND( vec.Angle() / M_PI_4 ) * M_PI_4; + + m_end = m_origin + VECTOR2I( len, 0 ).Rotate( angle ); + } + else + { + m_end = aEnd; + } + } + + VECTOR2I GetEnd() const + { + return m_end; + } + + void SetAngleSnap( bool aSnap ) + { + m_angleSnap = aSnap; + } + +private: + + VECTOR2I m_origin, m_end; + bool m_angleSnap = false; +}; + +} // PREVIEW +} // KIGFX + +#endif // PREVIEW_ITEMS_TWO_POINT_GEOMETRY_MANAGER_H diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 4cd63eb4a5..261d4f4b8b 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -294,6 +294,7 @@ set( PCBNEW_CLASS_SRCS class_footprint_wizard.cpp class_action_plugin.cpp + tools/pcb_tool.cpp tools/selection_tool.cpp tools/pcb_selection_conditions.cpp tools/pcb_bright_box.cpp @@ -304,6 +305,7 @@ set( PCBNEW_CLASS_SRCS tools/edit_tool.cpp tools/pcbnew_control.cpp tools/pcb_editor_control.cpp + tools/microwave_tool.cpp tools/module_editor_tools.cpp tools/placement_tool.cpp tools/pcb_actions.cpp diff --git a/pcbnew/microwave/microwave_inductor.cpp b/pcbnew/microwave/microwave_inductor.cpp index f7a875a798..b0394a2ec2 100644 --- a/pcbnew/microwave/microwave_inductor.cpp +++ b/pcbnew/microwave/microwave_inductor.cpp @@ -307,10 +307,10 @@ MODULE* MWAVE::CreateMicrowaveInductor( INDUCTOR_PATTERN& inductorPattern, // Enter the desired length. msg = StringFromValue( g_UserUnit, inductorPattern.m_length ); - wxTextEntryDialog dlg( NULL, wxEmptyString, _( "Length of Trace:" ), msg ); + wxTextEntryDialog dlg( nullptr, wxEmptyString, _( "Length of Trace:" ), msg ); if( dlg.ShowModal() != wxID_OK ) - return NULL; // canceled by user + return nullptr; // canceled by user msg = dlg.GetValue(); inductorPattern.m_length = ValueFromString( g_UserUnit, msg ); @@ -319,7 +319,7 @@ MODULE* MWAVE::CreateMicrowaveInductor( INDUCTOR_PATTERN& inductorPattern, if( inductorPattern.m_length < min_len ) { aErrorMessage = _( "Requested length < minimum length" ); - return NULL; + return nullptr; } // Calculate the elements. @@ -331,16 +331,16 @@ MODULE* MWAVE::CreateMicrowaveInductor( INDUCTOR_PATTERN& inductorPattern, if( !ll ) { aErrorMessage = _( "Requested length too large" ); - return NULL; + return nullptr; } // Generate footprint. the value is also used as footprint name. - msg.Empty(); - wxTextEntryDialog cmpdlg( NULL, wxEmptyString, _( "Component Value:" ), msg ); + msg = "L"; + wxTextEntryDialog cmpdlg( nullptr, wxEmptyString, _( "Component Value:" ), msg ); cmpdlg.SetTextValidator( FILE_NAME_CHAR_VALIDATOR( &msg ) ); if( ( cmpdlg.ShowModal() != wxID_OK ) || msg.IsEmpty() ) - return NULL; // Aborted by user + return nullptr; // Aborted by user MODULE* module = aPcbFrame->CreateNewModule( msg ); diff --git a/pcbnew/tools/microwave_tool.cpp b/pcbnew/tools/microwave_tool.cpp new file mode 100644 index 0000000000..a3b1b856c7 --- /dev/null +++ b/pcbnew/tools/microwave_tool.cpp @@ -0,0 +1,385 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +// For frame ToolID values +#include + +// For action icons +#include + +#include +#include + +#include + +#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" ), + m_menu( *this ) +{ +} + + +MICROWAVE_TOOL::~MICROWAVE_TOOL() +{} + + +void MICROWAVE_TOOL::Reset( RESET_REASON aReason ) +{ +} + + +bool MICROWAVE_TOOL::Init() +{ + auto activeToolFunctor = [ this ] ( const SELECTION& aSel ) { + return true; + }; + + auto& ctxMenu = m_menu.GetMenu(); + + // cancel current goes in main context menu at the top if present + ctxMenu.AddItem( ACTIONS::cancelInteractive, activeToolFunctor, 1000 ); + ctxMenu.AddSeparator( activeToolFunctor, 1000 ); + + m_menu.AddStandardSubMenus( *getEditFrame() ); + + return true; +} + + +struct MICROWAVE_TOOL_INFO +{ + using MOD_CREATOR = std::function()>; + + 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( 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( 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( 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( frame.Create_MuWavePolygonShape() ); + }; + break; + }; + + return info; +} + + +int MICROWAVE_TOOL::addMicrowaveFootprint( const TOOL_EVENT& aEvent ) +{ + auto& frame = *getEditFrame(); + + const int param = aEvent.Parameter(); + + 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 ); + + ITEM_CREATOR moduleCreator = [this, &info] ( const TOOL_EVENT& aAddingEvent ) { + auto module = info.creatorFunc(); + + // Module has been added in the legacy backend, + // so we have to remove it before committing the change + // @todo LEGACY + if( module ) + { + board()->Remove( module.get() ); + } + + return module; + }; + + doInteractiveItemPlacement( moduleCreator, _( "Place microwave feature" ) ); + + frame.SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); + + return 0; +} + + +void MICROWAVE_TOOL::createInductorBetween( const VECTOR2I& aStart, const VECTOR2I& aEnd ) +{ + auto& frame = *getEditFrame(); + + 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( + 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(); + + 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 ); + + 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; + 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; + + 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(); + } + } + + view.Remove( &previewRect ); + + frame.SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); + + 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() ); +} diff --git a/pcbnew/tools/microwave_tool.h b/pcbnew/tools/microwave_tool.h new file mode 100644 index 0000000000..adad7ad7af --- /dev/null +++ b/pcbnew/tools/microwave_tool.h @@ -0,0 +1,68 @@ +/* + * 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 + */ + +#ifndef TOOLS_MICROWAVE_TOOL_H +#define TOOLS_MICROWAVE_TOOL_H + +#include + +#include + + +/** + * Class MICROWAVE_TOOL + * + * Tool responsible for adding microwave features to PCBs + */ +class MICROWAVE_TOOL : public PCB_TOOL +{ +public: + MICROWAVE_TOOL(); + ~MICROWAVE_TOOL(); + + ///> React to model/view changes + void Reset( RESET_REASON aReason ) override; + + ///> Basic initalization + bool Init() override; + + ///> Bind handlers to corresponding TOOL_ACTIONs + void SetTransitions() override; + +private: + + ///> Main interactive tool + int addMicrowaveFootprint( const TOOL_EVENT& aEvent ); + + ///> Create an inductor between the two points + void createInductorBetween( const VECTOR2I& aStart, const VECTOR2I& aEnd ); + + ///> Draw a microwave inductor interactively + int drawMicrowaveInductor( const TOOL_EVENT& aEvent ); + + /// Menu model displayed by the tool. + TOOL_MENU m_menu; +}; + + +#endif // TOOLS_MICROWAVE_TOOL_H diff --git a/pcbnew/tools/pcb_actions.cpp b/pcbnew/tools/pcb_actions.cpp index 486450f9fa..be83c37041 100644 --- a/pcbnew/tools/pcb_actions.cpp +++ b/pcbnew/tools/pcb_actions.cpp @@ -163,6 +163,21 @@ boost::optional PCB_ACTIONS::TranslateLegacyId( int aId ) case ID_PCB_SHOW_1_RATSNEST_BUTT: return PCB_ACTIONS::toBeDone.MakeEvent(); + + case ID_PCB_MUWAVE_TOOL_GAP_CMD: + return PCB_ACTIONS::microwaveCreateGap.MakeEvent(); + + case ID_PCB_MUWAVE_TOOL_STUB_CMD: + return PCB_ACTIONS::microwaveCreateStub.MakeEvent(); + + case ID_PCB_MUWAVE_TOOL_STUB_ARC_CMD: + return PCB_ACTIONS::microwaveCreateStubArc.MakeEvent(); + + case ID_PCB_MUWAVE_TOOL_FUNCTION_SHAPE_CMD: + return PCB_ACTIONS::microwaveCreateFunctionShape.MakeEvent(); + + case ID_PCB_MUWAVE_TOOL_SELF_CMD: + return PCB_ACTIONS::microwaveCreateLine.MakeEvent(); } return boost::optional(); diff --git a/pcbnew/tools/pcb_actions.h b/pcbnew/tools/pcb_actions.h index 21615c7ff0..1ebfa7bbba 100644 --- a/pcbnew/tools/pcb_actions.h +++ b/pcbnew/tools/pcb_actions.h @@ -294,6 +294,17 @@ public: /// Copy the current pad's settings to other pads in the module or on the board static TOOL_ACTION pushPadSettings; + // Microwave tools + static TOOL_ACTION microwaveCreateGap; + + static TOOL_ACTION microwaveCreateStub; + + static TOOL_ACTION microwaveCreateStubArc; + + static TOOL_ACTION microwaveCreateFunctionShape; + + static TOOL_ACTION microwaveCreateLine; + /// Cursor control with keyboard static TOOL_ACTION cursorUp; static TOOL_ACTION cursorDown; diff --git a/pcbnew/tools/pcb_tool.cpp b/pcbnew/tools/pcb_tool.cpp new file mode 100644 index 0000000000..9f921b4b7c --- /dev/null +++ b/pcbnew/tools/pcb_tool.cpp @@ -0,0 +1,169 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 KiCad Developers, see AUTHORS.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 "pcb_tool.h" + +#include +#include +#include +#include + +#include + +#include "selection_tool.h" +#include "pcb_actions.h" +#include "tool_event_utils.h" + + +void PCB_TOOL::doInteractiveItemPlacement( ITEM_CREATOR aItemCreator, + const wxString& aCommitMessage ) +{ + using namespace std::placeholders; + + KIGFX::VIEW& view = *getView(); + KIGFX::VIEW_CONTROLS& controls = *getViewControls(); + auto& frame = *getEditFrame(); + + std::unique_ptr newItem; + + Activate(); + + BOARD_COMMIT commit( &frame ); + + GetManager()->RunAction( PCB_ACTIONS::selectionClear, true ); + + // do not capture or auto-pan until we start placing an item + controls.ShowCursor( true ); + controls.SetSnapping( true ); + + // Add a VIEW_GROUP that serves as a preview for the new item + SELECTION preview; + view.Add( &preview ); + + // Main loop: keep receiving events + while( OPT_TOOL_EVENT evt = Wait() ) + { + VECTOR2I cursorPos = controls.GetCursorPosition(); + + if( TOOL_EVT_UTILS::IsCancelInteractive( *evt ) ) + { + if( newItem ) + { + // Delete the old item and have another try + newItem = nullptr; + + preview.Clear(); + + controls.SetAutoPan( false ); + controls.CaptureCursor( false ); + controls.ShowCursor( true ); + } + else + { + break; + } + + if( evt->IsActivate() ) // now finish unconditionally + break; + } + + else if( evt->IsClick( BUT_LEFT ) ) + { + if( !newItem ) + { + // create the item if possible + newItem = aItemCreator( *evt ); + + // no item created, so wait for another click + if( !newItem ) + continue; + + controls.CaptureCursor( true ); + controls.SetAutoPan( true ); + + newItem->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); + + preview.Add( newItem.get() ); + + if( newItem->Type() == PCB_MODULE_T ) + { + auto module = dyn_cast( newItem.get() ); + + // modules have more drawable parts + module->RunOnChildren( std::bind( &KIGFX::VIEW_GROUP::Add, &preview, _1 ) ); + } + } + else + { + newItem->ClearFlags(); + preview.Remove( newItem.get() ); + + if( newItem->Type() == PCB_MODULE_T ) + { + auto module = dyn_cast( newItem.get() ); + module->RunOnChildren( std::bind( &KIGFX::VIEW_GROUP::Remove, &preview, _1 ) ); + } + + commit.Add( newItem.release() ); + commit.Push( aCommitMessage ); + + controls.CaptureCursor( false ); + controls.SetAutoPan( false ); + controls.ShowCursor( true ); + } + } + + else if( newItem && evt->Category() == TC_COMMAND ) + { + /* + * Handle any events that can affect the item as we move + * it around, eg rotate and flip + */ + + if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) ) + { + const auto rotationAngle = TOOL_EVT_UTILS::GetEventRotationAngle( + frame, *evt ); + newItem->Rotate( newItem->GetPosition(), rotationAngle ); + view.Update( &preview ); + } + else if( evt->IsAction( &PCB_ACTIONS::flip ) ) + { + newItem->Flip( newItem->GetPosition() ); + view.Update( &preview ); + } + } + + else if( newItem && evt->IsMotion() ) + { + // track the cursor + newItem->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); + + // Show a preview of the item + view.Update( &preview ); + } + } + + view.Remove( &preview ); +} diff --git a/pcbnew/tools/pcb_tool.h b/pcbnew/tools/pcb_tool.h index accc8f0d32..cac03fc42e 100644 --- a/pcbnew/tools/pcb_tool.h +++ b/pcbnew/tools/pcb_tool.h @@ -33,6 +33,9 @@ #include #include +#include + + /** * Class PCB_TOOL * @@ -78,6 +81,30 @@ public: } protected: + + /** + * Callable that returns a new board item. + * + * The event that triggered it is provided, so you can check modifier + * keys, position, etc, if required + */ + using ITEM_CREATOR = std::function< std::unique_ptr< BOARD_ITEM >( const TOOL_EVENT& aEvt ) >; + + /** + * Helper function for performing a common interactive idiom: + * wait for a left click, place an item there (perhaps with a + * dialog or other user interaction), then have it move with + * the mouse and respond to rotate/flip, etc + * + * More complex interactive processes are not supported here, you + * should implement a customised event loop for those. + * + * @param aItemCreator the callable that will attempt to create the item + * @param aCommitMessage the message used on a successful commit + */ + void doInteractiveItemPlacement( ITEM_CREATOR aItemCreator, + const wxString& aCommitMessage ); + KIGFX::VIEW* view() const { return getView(); } PCB_EDIT_FRAME* frame() const { return getEditFrame(); } BOARD* board() const { return getModel(); } diff --git a/pcbnew/tools/tools_common.cpp b/pcbnew/tools/tools_common.cpp index d06efedecf..a653ebf24c 100644 --- a/pcbnew/tools/tools_common.cpp +++ b/pcbnew/tools/tools_common.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -58,4 +59,5 @@ void PCB_ACTIONS::RegisterAllTools( TOOL_MANAGER* aToolManager ) aToolManager->RegisterTool( new PCBNEW_CONTROL ); aToolManager->RegisterTool( new PCB_EDITOR_CONTROL ); aToolManager->RegisterTool( new PLACEMENT_TOOL ); + aToolManager->RegisterTool( new MICROWAVE_TOOL ); }