Rework zone creation in GAL
The zone creation in DRAWING_TOOL was a complex event loop whici simultaneously managed the event handling, construction of the preview polygon and the creation and commiting of the zone, all in the same scope. This has been broken into several pieces: * POLYGON_ITEM preview item, used to preview the polygon in progress * POLYGON_GEOM_MANAGER is a class that collects points from user input and used them to describe a polygon's geometry, including calculation of 45-degree constrained leader lines * ZONE_CREATE_HELPER is a class which deals with creating zones based on geometry from a geometry manager and parameters from the DRAWING_TOOL * The (much simpler) event loop in DRAWING_TOOL drives the POLYGON_GEOM_MANAGER. With a minor refactor, this loop can be reused in future for other polygonal tools if wanted. The polygon preview now has a translucent fill which makes it easier to visualise the zone. This also adds the Close Zone Outline and Delete Last Corner actions as part of the new event loop. Fixes: lp:1663885 * https://bugs.launchpad.net/kicad/+bug/1663885 Fixes: lp:1667885 * https://bugs.launchpad.net/kicad/+bug/1667885
This commit is contained in:
parent
1fd503bf58
commit
9fe780f1b3
|
@ -193,6 +193,8 @@ set( COMMON_PREVIEW_ITEMS_SRCS
|
|||
preview_items/simple_overlay_item.cpp
|
||||
preview_items/selection_area.cpp
|
||||
preview_items/bright_box.cpp
|
||||
preview_items/polygon_geom_manager.cpp
|
||||
preview_items/polygon_item.cpp
|
||||
)
|
||||
|
||||
set( COMMON_SRCS
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* 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 <preview_items/polygon_geom_manager.h>
|
||||
|
||||
#include <geometry/direction45.h>
|
||||
|
||||
|
||||
POLYGON_GEOM_MANAGER::POLYGON_GEOM_MANAGER( CLIENT& aClient ):
|
||||
m_client( aClient ),
|
||||
m_leaderMode( LEADER_MODE::DIRECT )
|
||||
{}
|
||||
|
||||
|
||||
void POLYGON_GEOM_MANAGER::AddPoint( const VECTOR2I& aPt )
|
||||
{
|
||||
// if this is the first point, make sure the client is happy
|
||||
// for us to continue
|
||||
if( !IsPolygonInProgress() && !m_client.OnFirstPoint() )
|
||||
return;
|
||||
|
||||
if( m_leaderPts.size() > 1 )
|
||||
{
|
||||
// there are enough leader points - the next
|
||||
// locked-in point is the end of the first leader
|
||||
// segment
|
||||
m_lockedPoints.push_back( m_leaderPts[1] );
|
||||
}
|
||||
else
|
||||
{
|
||||
// no leader lines, directly add the cursor
|
||||
m_lockedPoints.push_back( aPt );
|
||||
}
|
||||
|
||||
m_client.OnGeometryChange( *this );
|
||||
}
|
||||
|
||||
|
||||
void POLYGON_GEOM_MANAGER::SetFinished()
|
||||
{
|
||||
m_client.OnComplete( *this );
|
||||
}
|
||||
|
||||
|
||||
void POLYGON_GEOM_MANAGER::SetLeaderMode( LEADER_MODE aMode )
|
||||
{
|
||||
m_leaderMode = aMode;
|
||||
}
|
||||
|
||||
|
||||
void POLYGON_GEOM_MANAGER::SetCursorPosition( const VECTOR2I& aPos )
|
||||
{
|
||||
updateLeaderPoints( aPos );
|
||||
}
|
||||
|
||||
|
||||
bool POLYGON_GEOM_MANAGER::IsPolygonInProgress() const
|
||||
{
|
||||
return m_lockedPoints.size() > 0;
|
||||
}
|
||||
|
||||
|
||||
bool POLYGON_GEOM_MANAGER::NewPointClosesOutline( const VECTOR2I& aPt ) const
|
||||
{
|
||||
return m_lockedPoints.size() && m_lockedPoints[0] == aPt;
|
||||
}
|
||||
|
||||
|
||||
void POLYGON_GEOM_MANAGER::DeleteLastCorner()
|
||||
{
|
||||
if( m_lockedPoints.size() > 0 )
|
||||
{
|
||||
m_lockedPoints.pop_back();
|
||||
}
|
||||
|
||||
// update the new last segment (was previously
|
||||
// locked in), reusing last constraints
|
||||
if( m_lockedPoints.size() > 0 )
|
||||
{
|
||||
updateLeaderPoints( m_leaderPts.back() );
|
||||
}
|
||||
|
||||
m_client.OnGeometryChange( *this );
|
||||
}
|
||||
|
||||
|
||||
void POLYGON_GEOM_MANAGER::Reset()
|
||||
{
|
||||
m_lockedPoints.clear();
|
||||
m_leaderPts.clear();
|
||||
|
||||
m_client.OnGeometryChange( *this );
|
||||
}
|
||||
|
||||
|
||||
void POLYGON_GEOM_MANAGER::updateLeaderPoints( const VECTOR2I& aEndPoint )
|
||||
{
|
||||
SHAPE_LINE_CHAIN newChain;
|
||||
|
||||
if( m_leaderMode == LEADER_MODE::DEG45 )
|
||||
{
|
||||
// get a restricted 45/H/V line from the last fixed point to the cursor
|
||||
DIRECTION_45 direction( m_lockedPoints.back() - aEndPoint );
|
||||
newChain = direction.BuildInitialTrace( m_lockedPoints.back(), aEndPoint );
|
||||
|
||||
// Can also add chain back to start, but this rearely produces
|
||||
// usable result
|
||||
//DIRECTION_45 directionToStart( aEndPoint - m_lockedPoints.front() );
|
||||
//newChain.Append( directionToStart.BuildInitialTrace( aEndPoint, m_lockedPoints.front() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// direct segment
|
||||
newChain = SHAPE_LINE_CHAIN( m_lockedPoints.back(), aEndPoint );
|
||||
}
|
||||
|
||||
// rebuild leader point list from the chain
|
||||
m_leaderPts.clear();
|
||||
|
||||
for( int i = 0; i < newChain.PointCount(); ++i )
|
||||
{
|
||||
m_leaderPts.push_back( newChain.Point( i ) );
|
||||
}
|
||||
|
||||
m_client.OnGeometryChange( *this );
|
||||
}
|
||||
|
||||
|
||||
const std::vector<VECTOR2I>& POLYGON_GEOM_MANAGER::GetLockedInPoints() const
|
||||
{
|
||||
return m_lockedPoints;
|
||||
}
|
||||
|
||||
|
||||
const std::vector<VECTOR2I>& POLYGON_GEOM_MANAGER::GetLeaderLinePoints() const
|
||||
{
|
||||
return m_leaderPts;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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 <preview_items/polygon_item.h>
|
||||
|
||||
#include <preview_items/preview_utils.h>
|
||||
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
#include <view/view.h>
|
||||
|
||||
using namespace KIGFX::PREVIEW;
|
||||
|
||||
|
||||
POLYGON_ITEM::POLYGON_ITEM():
|
||||
SIMPLE_OVERLAY_ITEM()
|
||||
{
|
||||
}
|
||||
|
||||
void POLYGON_ITEM::SetPoints( const std::vector<VECTOR2I>& aLockedPts,
|
||||
const std::vector<VECTOR2I>& aLeaderPts )
|
||||
{
|
||||
m_lockedChain.Clear();
|
||||
m_leaderChain.Clear();
|
||||
|
||||
m_polyfill.RemoveAllContours();
|
||||
m_polyfill.NewOutline();
|
||||
|
||||
for( auto& pt: aLockedPts )
|
||||
{
|
||||
m_lockedChain.Append( pt, false );
|
||||
m_polyfill.Append( pt );
|
||||
}
|
||||
|
||||
for( auto& pt: aLeaderPts )
|
||||
{
|
||||
m_leaderChain.Append( pt, false );
|
||||
m_polyfill.Append( pt );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void POLYGON_ITEM::drawPreviewShape( KIGFX::GAL& aGal ) const
|
||||
{
|
||||
aGal.DrawPolyline( m_lockedChain );
|
||||
aGal.DrawPolygon( m_polyfill );
|
||||
|
||||
// draw the leader line in a different color
|
||||
aGal.SetStrokeColor( PreviewOverlayDefaultColor() );
|
||||
aGal.DrawPolyline( m_leaderChain );
|
||||
}
|
||||
|
||||
|
||||
const BOX2I POLYGON_ITEM::ViewBBox() const
|
||||
{
|
||||
return m_polyfill.BBox();
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* 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_POLYGON_GEOM_MANAGER__H_
|
||||
#define PREVIEW_POLYGON_GEOM_MANAGER__H_
|
||||
|
||||
#include <vector>
|
||||
#include <math/vector2d.h>
|
||||
|
||||
/**
|
||||
* Class that handles the drawing of a polygon, including
|
||||
* management of last corner deletion and drawing of leader lines
|
||||
* with various constraints (eg 45 deg only).
|
||||
*
|
||||
* This class handles only the geometry of the process.
|
||||
*/
|
||||
class POLYGON_GEOM_MANAGER
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* "Listener" interface for a class that wants to be updated about
|
||||
* polygon geometry changes
|
||||
*/
|
||||
class CLIENT
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Called before the first point is added - clients can do
|
||||
* initialisation here, and can veto the start of the process
|
||||
* (eg if user cancels a dialog)
|
||||
*
|
||||
* @return false to veto start of new polygon
|
||||
*/
|
||||
virtual bool OnFirstPoint() = 0;
|
||||
|
||||
///> Sent when the polygon geometry changes
|
||||
virtual void OnGeometryChange( const POLYGON_GEOM_MANAGER& aMgr ) = 0;
|
||||
|
||||
///> Called when the polygon is complete
|
||||
virtual void OnComplete( const POLYGON_GEOM_MANAGER& aMgr ) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* The kind of the leader line
|
||||
*/
|
||||
enum class LEADER_MODE
|
||||
{
|
||||
DIRECT, ///> Unconstrained point-to-point
|
||||
DEG45, ///> 45 Degree only
|
||||
};
|
||||
|
||||
/**
|
||||
* @param the client to pass the results onto
|
||||
*/
|
||||
POLYGON_GEOM_MANAGER( CLIENT& aClient );
|
||||
|
||||
/**
|
||||
* Lock in a polygon point.
|
||||
*/
|
||||
void AddPoint( const VECTOR2I& aPt );
|
||||
|
||||
/**
|
||||
* Mark the polygon finished and update the client
|
||||
*/
|
||||
void SetFinished();
|
||||
|
||||
/**
|
||||
* Clear the manager state and start again
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/**
|
||||
* Set the leader mode to use when calculating the leader/returner
|
||||
* lines
|
||||
*/
|
||||
void SetLeaderMode( LEADER_MODE aMode );
|
||||
|
||||
/**
|
||||
* Set the current cursor position
|
||||
*/
|
||||
void SetCursorPosition( const VECTOR2I& aPos );
|
||||
|
||||
/**
|
||||
* @return true if the polygon in "in progress", i.e. it has at least
|
||||
* one locked-in point
|
||||
*/
|
||||
bool IsPolygonInProgress() const;
|
||||
|
||||
/**
|
||||
* @return true if locking in the given point would close the
|
||||
* current polygon
|
||||
*/
|
||||
bool NewPointClosesOutline( const VECTOR2I& aPt ) const;
|
||||
|
||||
/**
|
||||
* Remove the last-added point from the polygon
|
||||
*/
|
||||
void DeleteLastCorner();
|
||||
|
||||
/* =================================================================
|
||||
* Interfaces for users of the geometry
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the "locked-in" points that describe the polygon itself
|
||||
*/
|
||||
const std::vector<VECTOR2I>& GetLockedInPoints() const;
|
||||
|
||||
/**
|
||||
* Get the points comprising the leader line (the line from the
|
||||
* last locked-in point to the current cursor position
|
||||
*
|
||||
* How this is drawn will depend on the LEADER_MODE
|
||||
*/
|
||||
const std::vector<VECTOR2I>& GetLeaderLinePoints() const;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Update the leader line points based on a new endpoint (probably
|
||||
* a cursor position)
|
||||
*/
|
||||
void updateLeaderPoints( const VECTOR2I& aEndPoint );
|
||||
|
||||
///> The "user" of the polygon data that is informed when the geometry changes
|
||||
CLIENT& m_client;
|
||||
|
||||
///> The current mode of the leader line
|
||||
LEADER_MODE m_leaderMode;
|
||||
|
||||
///> Point that have been "locked in"
|
||||
std::vector<VECTOR2I> m_lockedPoints;
|
||||
|
||||
///> Points in the temporary "leader" line(s)
|
||||
std::vector<VECTOR2I> m_leaderPts;
|
||||
};
|
||||
|
||||
#endif // PREVIEW_POLYGON_GEOM_MANAGER__H_
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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 PREVIEW_POLYGON_ITEM__H_
|
||||
#define PREVIEW_POLYGON_ITEM__H_
|
||||
|
||||
#include <preview_items/simple_overlay_item.h>
|
||||
|
||||
#include <geometry/shape_poly_set.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
|
||||
namespace KIGFX
|
||||
{
|
||||
|
||||
class GAL;
|
||||
|
||||
namespace PREVIEW
|
||||
{
|
||||
|
||||
/**
|
||||
* Class POLYGON_ITEM
|
||||
*
|
||||
* A preview item which shows an in-progress polygon, which
|
||||
* can be used for zone outlines, etc
|
||||
*/
|
||||
class POLYGON_ITEM : public SIMPLE_OVERLAY_ITEM
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
POLYGON_ITEM();
|
||||
|
||||
///> Gets the bounding box of the polygon
|
||||
virtual const BOX2I ViewBBox() const override;
|
||||
|
||||
|
||||
/**
|
||||
* Set the polygon points
|
||||
*
|
||||
* @param locked in points - the "fixed point" of the outline
|
||||
* @param leader line points - the lines from the last fixed point to
|
||||
* another point, eg the cursor.
|
||||
*/
|
||||
void SetPoints( const std::vector<VECTOR2I>& aLockedInPts,
|
||||
const std::vector<VECTOR2I>& aLeaderPts );
|
||||
|
||||
private:
|
||||
|
||||
///> Draw rectangle and centre line onto GAL
|
||||
void drawPreviewShape( KIGFX::GAL& aGal ) const override;
|
||||
|
||||
///> complete polyline of locked in and leader points
|
||||
SHAPE_LINE_CHAIN m_lockedChain, m_leaderChain;
|
||||
|
||||
///> polygon fill
|
||||
SHAPE_POLY_SET m_polyfill;
|
||||
};
|
||||
|
||||
} // PREVIEW
|
||||
} // KIGFX
|
||||
|
||||
#endif // PREVIEW_POLYGON_ITEM__H_
|
|
@ -316,6 +316,7 @@ set( PCBNEW_CLASS_SRCS
|
|||
tools/pad_tool.cpp
|
||||
tools/picker_tool.cpp
|
||||
tools/zoom_tool.cpp
|
||||
tools/zone_create_helper.cpp
|
||||
tools/tools_common.cpp
|
||||
tools/tool_event_utils.cpp
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include <scoped_set_reset.h>
|
||||
#include <bitmaps.h>
|
||||
#include <hotkeys.h>
|
||||
#include <painter.h>
|
||||
|
||||
#include <preview_items/arc_assistant.h>
|
||||
|
||||
|
@ -58,6 +59,7 @@
|
|||
|
||||
#include <tools/selection_tool.h>
|
||||
#include <tools/tool_event_utils.h>
|
||||
#include <tools/zone_create_helper.h>
|
||||
|
||||
using SCOPED_DRAW_MODE = SCOPED_SET_RESET<DRAWING_TOOL::MODE>;
|
||||
|
||||
|
@ -130,6 +132,11 @@ static TOOL_ACTION deleteLastPoint( "pcbnew.InteractiveDrawing.deleteLastPoint",
|
|||
_( "Delete Last Point" ), _( "Delete the last point added to the current item" ),
|
||||
undo_xpm );
|
||||
|
||||
static TOOL_ACTION closeZoneOutline( "pcbnew.InteractiveDrawing.closeZoneOutline",
|
||||
AS_CONTEXT, 0,
|
||||
_( "Close Zone Outline" ), _( "Close the outline of a zone in progress" ),
|
||||
checked_ok_xpm );
|
||||
|
||||
|
||||
DRAWING_TOOL::DRAWING_TOOL() :
|
||||
PCB_TOOL( "pcbnew.InteractiveDrawing" ),
|
||||
|
@ -152,8 +159,14 @@ bool DRAWING_TOOL::Init()
|
|||
return m_mode != MODE::NONE;
|
||||
};
|
||||
|
||||
// some interactive drawing tools can undo the last point
|
||||
auto canUndoPoint = [ this ] ( const SELECTION& aSel ) {
|
||||
return m_mode == MODE::ARC;
|
||||
return m_mode == MODE::ARC || m_mode == MODE::ZONE;
|
||||
};
|
||||
|
||||
// functor for zone-only actions
|
||||
auto zoneActiveFunctor = [this ] ( const SELECTION& aSel ) {
|
||||
return m_mode == MODE::ZONE;
|
||||
};
|
||||
|
||||
auto& ctxMenu = m_menu.GetMenu();
|
||||
|
@ -161,12 +174,16 @@ bool DRAWING_TOOL::Init()
|
|||
// cancel current toool goes in main context menu at the top if present
|
||||
ctxMenu.AddItem( ACTIONS::cancelInteractive, activeToolFunctor, 1000 );
|
||||
|
||||
// some interactive drawing tools can undo the last point
|
||||
// tool-specific actions
|
||||
ctxMenu.AddItem( closeZoneOutline, zoneActiveFunctor, 1000 );
|
||||
ctxMenu.AddItem( deleteLastPoint, canUndoPoint, 1000 );
|
||||
|
||||
ctxMenu.AddSeparator( activeToolFunctor, 1000 );
|
||||
|
||||
// Drawing type-specific options will be added by the PCB control tool
|
||||
// Type-specific sub-menus will be added for us by other tools
|
||||
// For example, zone fill/unfill is provided by the PCB control tool
|
||||
|
||||
// Finally, add the standard zoom/grid items
|
||||
m_menu.AddStandardSubMenus( *getEditFrame<PCB_BASE_FRAME>() );
|
||||
|
||||
return true;
|
||||
|
@ -431,7 +448,6 @@ int DRAWING_TOOL::PlaceText( const TOOL_EVENT& aEvent )
|
|||
text = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
else if( text && evt->IsMotion() )
|
||||
{
|
||||
text->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
|
||||
|
@ -1192,62 +1208,6 @@ bool DRAWING_TOOL::drawArc( DRAWSEGMENT*& aGraphic )
|
|||
}
|
||||
|
||||
|
||||
std::unique_ptr<ZONE_CONTAINER> DRAWING_TOOL::createNewZone( bool aKeepout )
|
||||
{
|
||||
const auto& board = *getModel<BOARD>();
|
||||
|
||||
// Get the current default settings for zones
|
||||
ZONE_SETTINGS zoneInfo = m_frame->GetZoneSettings();
|
||||
zoneInfo.m_CurrentZone_Layer = m_frame->GetScreen()->m_Active_Layer;
|
||||
zoneInfo.m_NetcodeSelection = board.GetHighLightNetCode();
|
||||
zoneInfo.SetIsKeepout( aKeepout );
|
||||
|
||||
m_controls->SetAutoPan( true );
|
||||
m_controls->CaptureCursor( true );
|
||||
|
||||
// Show options dialog
|
||||
ZONE_EDIT_T dialogResult;
|
||||
|
||||
if( aKeepout )
|
||||
dialogResult = InvokeKeepoutAreaEditor( m_frame, &zoneInfo );
|
||||
else
|
||||
{
|
||||
if( IsCopperLayer( zoneInfo.m_CurrentZone_Layer ) )
|
||||
dialogResult = InvokeCopperZonesEditor( m_frame, &zoneInfo );
|
||||
else
|
||||
dialogResult = InvokeNonCopperZonesEditor( m_frame, NULL, &zoneInfo );
|
||||
}
|
||||
|
||||
if( dialogResult == ZONE_ABORT )
|
||||
{
|
||||
m_controls->SetAutoPan( false );
|
||||
m_controls->CaptureCursor( false );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto newZone = std::make_unique<ZONE_CONTAINER>( m_board );
|
||||
|
||||
// Apply the selected settings
|
||||
zoneInfo.ExportSetting( *newZone );
|
||||
|
||||
return newZone;
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<ZONE_CONTAINER> DRAWING_TOOL::createZoneFromExisting(
|
||||
const ZONE_CONTAINER& aSrcZone )
|
||||
{
|
||||
auto newZone = std::make_unique<ZONE_CONTAINER>( m_board );
|
||||
|
||||
ZONE_SETTINGS zoneSettings;
|
||||
zoneSettings << aSrcZone;
|
||||
|
||||
zoneSettings.ExportSetting( *newZone );
|
||||
|
||||
return newZone;
|
||||
}
|
||||
|
||||
|
||||
bool DRAWING_TOOL::getSourceZoneForAction( ZONE_MODE aMode, ZONE_CONTAINER*& aZone )
|
||||
{
|
||||
aZone = nullptr;
|
||||
|
@ -1276,230 +1236,129 @@ bool DRAWING_TOOL::getSourceZoneForAction( ZONE_MODE aMode, ZONE_CONTAINER*& aZo
|
|||
}
|
||||
|
||||
|
||||
void DRAWING_TOOL::performZoneCutout( ZONE_CONTAINER& aExistingZone, ZONE_CONTAINER& aCutout )
|
||||
void DRAWING_TOOL::runPolygonEventLoop( POLYGON_GEOM_MANAGER& polyGeomMgr )
|
||||
{
|
||||
// Copy cutout corners into existing zone
|
||||
for( int ii = 0; ii < aCutout.GetNumCorners(); ii++ )
|
||||
auto& controls = *getViewControls();
|
||||
bool started = false;
|
||||
|
||||
while( OPT_TOOL_EVENT evt = Wait() )
|
||||
{
|
||||
aExistingZone.AppendCorner( aCutout.GetCornerPosition( ii ) );
|
||||
}
|
||||
VECTOR2I cursorPos = controls.GetCursorPosition();
|
||||
|
||||
// Close the current corner list
|
||||
aExistingZone.Outline()->CloseLastContour();
|
||||
if( TOOL_EVT_UTILS::IsCancelInteractive( *evt ) )
|
||||
{
|
||||
// pre-empted by another tool, give up
|
||||
// cancelled without an inprogress polygon, give up
|
||||
if( !polyGeomMgr.IsPolygonInProgress() || evt->IsActivate() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
m_board->OnAreaPolygonModified( nullptr, &aExistingZone );
|
||||
polyGeomMgr.Reset();
|
||||
// start again
|
||||
started = false;
|
||||
|
||||
// Re-fill if needed
|
||||
if( aExistingZone.IsFilled() )
|
||||
{
|
||||
SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
|
||||
controls.SetAutoPan( false );
|
||||
controls.CaptureCursor( false );
|
||||
}
|
||||
|
||||
auto& selection = selTool->GetSelection();
|
||||
else if( evt->IsClick( BUT_RIGHT ) )
|
||||
{
|
||||
m_menu.ShowContextMenu();
|
||||
}
|
||||
|
||||
selection.Clear();
|
||||
selection.Add( &aExistingZone );
|
||||
// events that lock in nodes
|
||||
else if( evt->IsClick( BUT_LEFT )
|
||||
|| evt->IsDblClick( BUT_LEFT )
|
||||
|| evt->IsAction( &closeZoneOutline ) )
|
||||
{
|
||||
// Check if it is double click / closing line (so we have to finish the zone)
|
||||
const bool endPolygon = evt->IsDblClick( BUT_LEFT )
|
||||
|| evt->IsAction( &closeZoneOutline )
|
||||
|| polyGeomMgr.NewPointClosesOutline( cursorPos );
|
||||
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::zoneFill, true );
|
||||
}
|
||||
if( endPolygon )
|
||||
{
|
||||
polyGeomMgr.SetFinished();
|
||||
polyGeomMgr.Reset();
|
||||
|
||||
// ready to start again
|
||||
started = false;
|
||||
controls.SetAutoPan( false );
|
||||
controls.CaptureCursor( false );
|
||||
}
|
||||
else // adding a corner
|
||||
{
|
||||
polyGeomMgr.AddPoint( cursorPos );
|
||||
|
||||
if( !started )
|
||||
{
|
||||
started = true;
|
||||
controls.SetAutoPan( true );
|
||||
controls.CaptureCursor( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if( evt->IsAction( &deleteLastPoint ) )
|
||||
{
|
||||
polyGeomMgr.DeleteLastCorner();
|
||||
|
||||
if( !polyGeomMgr.IsPolygonInProgress() )
|
||||
{
|
||||
// report finished as an empty shape
|
||||
polyGeomMgr.SetFinished();
|
||||
|
||||
// start again
|
||||
started = false;
|
||||
controls.SetAutoPan( false );
|
||||
controls.CaptureCursor( false );
|
||||
}
|
||||
}
|
||||
|
||||
else if( polyGeomMgr.IsPolygonInProgress()
|
||||
&& ( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) )
|
||||
{
|
||||
bool draw45 = evt->Modifier( MD_CTRL );
|
||||
polyGeomMgr.SetLeaderMode( draw45 ? POLYGON_GEOM_MANAGER::LEADER_MODE::DEG45
|
||||
: POLYGON_GEOM_MANAGER::LEADER_MODE::DIRECT );
|
||||
polyGeomMgr.SetCursorPosition( cursorPos );
|
||||
}
|
||||
} // end while
|
||||
}
|
||||
|
||||
|
||||
int DRAWING_TOOL::drawZone( bool aKeepout, ZONE_MODE aMode )
|
||||
{
|
||||
std::unique_ptr<ZONE_CONTAINER> zone;
|
||||
DRAWSEGMENT line45;
|
||||
DRAWSEGMENT* helperLine = NULL; // we will need more than one helper line
|
||||
BOARD_COMMIT commit( m_frame );
|
||||
// get a source zone, if we need one
|
||||
ZONE_CONTAINER* sourceZone = nullptr;
|
||||
|
||||
// get a source zone, if we need one
|
||||
if( !getSourceZoneForAction( aMode, sourceZone ) )
|
||||
return 0;
|
||||
|
||||
// Add a VIEW_GROUP that serves as a preview for the new item
|
||||
SELECTION preview;
|
||||
m_view->Add( &preview );
|
||||
ZONE_CREATE_HELPER::PARAMS params;
|
||||
|
||||
params.m_keepout = aKeepout;
|
||||
params.m_mode = aMode;
|
||||
params.m_sourceZone = sourceZone;
|
||||
|
||||
ZONE_CREATE_HELPER zoneTool( *this, params );
|
||||
|
||||
// the geometry manager which handles the zone geometry, and
|
||||
// hands the calculated points over to the zone creator tool
|
||||
POLYGON_GEOM_MANAGER polyGeomMgr( zoneTool );
|
||||
|
||||
Activate(); // register for events
|
||||
|
||||
auto& controls = *getViewControls();
|
||||
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
|
||||
m_controls->ShowCursor( true );
|
||||
m_controls->SetSnapping( true );
|
||||
|
||||
Activate();
|
||||
controls.ShowCursor( true );
|
||||
controls.SetSnapping( true );
|
||||
|
||||
VECTOR2I origin;
|
||||
int numPoints = 0;
|
||||
bool direction45 = false; // 45 degrees only mode
|
||||
runPolygonEventLoop( polyGeomMgr );
|
||||
|
||||
// Main loop: keep receiving events
|
||||
while( OPT_TOOL_EVENT evt = Wait() )
|
||||
{
|
||||
VECTOR2I cursorPos = m_controls->GetCursorPosition();
|
||||
|
||||
// Enable 45 degrees lines only mode by holding control
|
||||
if( direction45 != ( evt->Modifier( MD_CTRL ) && numPoints > 0 ) )
|
||||
{
|
||||
direction45 = evt->Modifier( MD_CTRL );
|
||||
|
||||
if( direction45 )
|
||||
{
|
||||
preview.Add( &line45 );
|
||||
make45DegLine( helperLine, &line45 );
|
||||
}
|
||||
else
|
||||
{
|
||||
preview.Remove( &line45 );
|
||||
helperLine->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
|
||||
}
|
||||
|
||||
m_view->Update( &preview );
|
||||
}
|
||||
|
||||
if( TOOL_EVT_UTILS::IsCancelInteractive( *evt ) )
|
||||
{
|
||||
if( numPoints > 0 ) // cancel the current zone
|
||||
{
|
||||
zone = nullptr;
|
||||
m_controls->SetAutoPan( false );
|
||||
m_controls->CaptureCursor( false );
|
||||
|
||||
if( direction45 )
|
||||
{
|
||||
preview.Remove( &line45 );
|
||||
direction45 = false;
|
||||
}
|
||||
|
||||
preview.FreeItems();
|
||||
m_view->Update( &preview );
|
||||
|
||||
numPoints = 0;
|
||||
}
|
||||
else // there is no zone currently drawn - just stop the tool
|
||||
break;
|
||||
|
||||
if( evt->IsActivate() ) // now finish unconditionally
|
||||
break;
|
||||
}
|
||||
else if( evt->IsClick( BUT_RIGHT ) )
|
||||
{
|
||||
m_menu.ShowContextMenu();
|
||||
}
|
||||
else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
|
||||
{
|
||||
// Check if it is double click / closing line (so we have to finish the zone)
|
||||
if( evt->IsDblClick( BUT_LEFT ) || ( numPoints > 0 && cursorPos == origin ) )
|
||||
{
|
||||
if( numPoints > 2 ) // valid zone consists of more than 2 points
|
||||
{
|
||||
assert( zone->GetNumCorners() > 2 );
|
||||
|
||||
// Finish the zone
|
||||
if( direction45 )
|
||||
zone->AppendCorner( cursorPos == origin ? line45.GetStart() : line45.GetEnd() );
|
||||
|
||||
zone->Outline()->CloseLastContour();
|
||||
zone->Outline()->RemoveNullSegments();
|
||||
zone->Outline()->Hatch();
|
||||
|
||||
if( !aKeepout )
|
||||
static_cast<PCB_EDIT_FRAME*>( m_frame )->Fill_Zone( zone.get() );
|
||||
|
||||
if( aMode == ZONE_MODE::CUTOUT )
|
||||
{
|
||||
// For cutouts, subtract from the source
|
||||
commit.Modify( sourceZone );
|
||||
|
||||
performZoneCutout( *sourceZone, *zone );
|
||||
|
||||
commit.Push( _( "Add a zone cutout" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add the zone as a new board item
|
||||
commit.Add( zone.release() );
|
||||
commit.Push( _( "Draw a zone" ) );
|
||||
}
|
||||
}
|
||||
|
||||
// if kept, this was released. if still not null,
|
||||
// this zone is now unwanted and can be removed
|
||||
zone = nullptr;
|
||||
|
||||
numPoints = 0;
|
||||
m_controls->SetAutoPan( false );
|
||||
m_controls->CaptureCursor( false );
|
||||
|
||||
if( direction45 )
|
||||
{
|
||||
preview.Remove( &line45 );
|
||||
direction45 = false;
|
||||
}
|
||||
|
||||
preview.FreeItems();
|
||||
m_view->Update( &preview );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( numPoints == 0 ) // it's the first click
|
||||
{
|
||||
if( sourceZone )
|
||||
{
|
||||
zone = createZoneFromExisting( *sourceZone );
|
||||
}
|
||||
else
|
||||
{
|
||||
zone = createNewZone( aKeepout );
|
||||
}
|
||||
|
||||
if( !zone )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
m_frame->GetGalCanvas()->SetTopLayer( zone->GetLayer() );
|
||||
|
||||
// Add the first point
|
||||
zone->Outline()->Start( zone->GetLayer(),
|
||||
cursorPos.x, cursorPos.y,
|
||||
zone->GetHatchStyle() );
|
||||
origin = cursorPos;
|
||||
|
||||
// Helper line represents the currently drawn line of the zone polygon
|
||||
helperLine = new DRAWSEGMENT;
|
||||
helperLine->SetShape( S_SEGMENT );
|
||||
helperLine->SetWidth( 1 );
|
||||
helperLine->SetLayer( zone->GetLayer() );
|
||||
helperLine->SetStart( wxPoint( cursorPos.x, cursorPos.y ) );
|
||||
helperLine->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
|
||||
line45 = *helperLine;
|
||||
|
||||
preview.Add( helperLine );
|
||||
}
|
||||
else
|
||||
{
|
||||
zone->AppendCorner( helperLine->GetEnd() );
|
||||
helperLine = new DRAWSEGMENT( *helperLine );
|
||||
helperLine->SetStart( helperLine->GetEnd() );
|
||||
preview.Add( helperLine );
|
||||
}
|
||||
|
||||
++numPoints;
|
||||
m_view->Update( &preview );
|
||||
}
|
||||
}
|
||||
|
||||
else if( evt->IsMotion() && numPoints > 0 )
|
||||
{
|
||||
// 45 degree lines
|
||||
if( direction45 )
|
||||
make45DegLine( helperLine, &line45 );
|
||||
else
|
||||
helperLine->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
|
||||
|
||||
m_view->Update( &preview );
|
||||
}
|
||||
}
|
||||
|
||||
m_view->Remove( &preview );
|
||||
m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString );
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace KIGFX
|
|||
class BOARD;
|
||||
class PCB_BASE_EDIT_FRAME;
|
||||
class DRAWSEGMENT;
|
||||
class POLYGON_GEOM_MANAGER;
|
||||
|
||||
/**
|
||||
* Class DRAWING_TOOL
|
||||
|
@ -215,27 +216,6 @@ private:
|
|||
*/
|
||||
int drawZone( bool aKeepout, ZONE_MODE aMode );
|
||||
|
||||
/**
|
||||
* Function createNewZone()
|
||||
*
|
||||
* Prompt the user for new zone settings, and create a new zone with
|
||||
* those settings
|
||||
*
|
||||
* @param aKeepout should the zone be a keepout
|
||||
* @return the new zone, can be null if the user aborted
|
||||
*/
|
||||
std::unique_ptr<ZONE_CONTAINER> createNewZone( bool aKeepout );
|
||||
|
||||
/**
|
||||
* Function createZoneFromExisting
|
||||
*
|
||||
* Create a new zone with the settings from an existing zone
|
||||
*
|
||||
* @param aSrcZone the zone to copy settings from
|
||||
* @return the new zone
|
||||
*/
|
||||
std::unique_ptr<ZONE_CONTAINER> createZoneFromExisting( const ZONE_CONTAINER& aSrcZone );
|
||||
|
||||
/**
|
||||
* Function getSourceZoneForAction()
|
||||
*
|
||||
|
@ -252,15 +232,11 @@ private:
|
|||
bool getSourceZoneForAction( ZONE_MODE aMode, ZONE_CONTAINER*& aZone );
|
||||
|
||||
/**
|
||||
* Function performZoneCutout()
|
||||
*
|
||||
* Cut one zone out of another one (i.e. subtraction) and
|
||||
* update the zone.
|
||||
*
|
||||
* @param aExistingZone the zone to removed area from
|
||||
* @param aCutout the area to remove
|
||||
* Run the event loop for polygon creation, sending user input
|
||||
* on to the given POLYGON_GEOM_MANAGER for processing into a
|
||||
* complete polygon.
|
||||
*/
|
||||
void performZoneCutout( ZONE_CONTAINER& aExistingZone, ZONE_CONTAINER& aCutout );
|
||||
void runPolygonEventLoop( POLYGON_GEOM_MANAGER& aPolyGeomMgr );
|
||||
|
||||
/**
|
||||
* Function make45DegLine()
|
||||
|
@ -291,6 +267,10 @@ private:
|
|||
|
||||
// How does line width change after one -/+ key press.
|
||||
static const unsigned int WIDTH_STEP;
|
||||
|
||||
|
||||
// give internal access to drawing helper classes
|
||||
friend class ZONE_CREATE_HELPER;
|
||||
};
|
||||
|
||||
#endif /* __DRAWING_TOOL_H */
|
||||
|
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* 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 <tools/zone_create_helper.h>
|
||||
|
||||
#include <view/view.h>
|
||||
#include <tool/tool_manager.h>
|
||||
#include <class_zone.h>
|
||||
#include <board_commit.h>
|
||||
#include <pcb_painter.h>
|
||||
|
||||
#include <tools/pcb_actions.h>
|
||||
#include <tools/selection_tool.h>
|
||||
|
||||
|
||||
ZONE_CREATE_HELPER::ZONE_CREATE_HELPER( DRAWING_TOOL& aTool,
|
||||
const PARAMS& aParams ):
|
||||
m_tool( aTool ),
|
||||
m_params( aParams ),
|
||||
m_parentView( *aTool.getView() )
|
||||
{
|
||||
m_parentView.Add( &m_previewItem );
|
||||
}
|
||||
|
||||
|
||||
ZONE_CREATE_HELPER::~ZONE_CREATE_HELPER()
|
||||
{
|
||||
// remove the preview from the view
|
||||
m_parentView.SetVisible( &m_previewItem, false );
|
||||
m_parentView.Remove( &m_previewItem );
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<ZONE_CONTAINER> ZONE_CREATE_HELPER::createNewZone( bool aKeepout )
|
||||
{
|
||||
auto& frame = *m_tool.getEditFrame<PCB_BASE_EDIT_FRAME>();
|
||||
auto& board = *m_tool.getModel<BOARD>();
|
||||
|
||||
// Get the current default settings for zones
|
||||
ZONE_SETTINGS zoneInfo = frame.GetZoneSettings();
|
||||
zoneInfo.m_CurrentZone_Layer = frame.GetScreen()->m_Active_Layer;
|
||||
zoneInfo.m_NetcodeSelection = board.GetHighLightNetCode();
|
||||
zoneInfo.SetIsKeepout( m_params.m_keepout );
|
||||
|
||||
// Show options dialog
|
||||
ZONE_EDIT_T dialogResult;
|
||||
|
||||
if( m_params.m_keepout )
|
||||
dialogResult = InvokeKeepoutAreaEditor( &frame, &zoneInfo );
|
||||
else
|
||||
{
|
||||
if( IsCopperLayer( zoneInfo.m_CurrentZone_Layer ) )
|
||||
dialogResult = InvokeCopperZonesEditor( &frame, &zoneInfo );
|
||||
else
|
||||
dialogResult = InvokeNonCopperZonesEditor( &frame, nullptr, &zoneInfo );
|
||||
}
|
||||
|
||||
if( dialogResult == ZONE_ABORT )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto newZone = std::make_unique<ZONE_CONTAINER>( &board );
|
||||
|
||||
// Apply the selected settings
|
||||
zoneInfo.ExportSetting( *newZone );
|
||||
|
||||
return newZone;
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<ZONE_CONTAINER> ZONE_CREATE_HELPER::createZoneFromExisting(
|
||||
const ZONE_CONTAINER& aSrcZone )
|
||||
{
|
||||
auto& board = *m_tool.getModel<BOARD>();
|
||||
|
||||
auto newZone = std::make_unique<ZONE_CONTAINER>( &board );
|
||||
|
||||
ZONE_SETTINGS zoneSettings;
|
||||
zoneSettings << aSrcZone;
|
||||
|
||||
zoneSettings.ExportSetting( *newZone );
|
||||
|
||||
return newZone;
|
||||
}
|
||||
|
||||
|
||||
void ZONE_CREATE_HELPER::performZoneCutout( ZONE_CONTAINER& aExistingZone,
|
||||
ZONE_CONTAINER& aCutout )
|
||||
{
|
||||
auto& board = *m_tool.getModel<BOARD>();
|
||||
auto& toolMgr = *m_tool.GetManager();
|
||||
|
||||
// Copy cutout corners into existing zone
|
||||
for( int ii = 0; ii < aCutout.GetNumCorners(); ii++ )
|
||||
{
|
||||
aExistingZone.AppendCorner( aCutout.GetCornerPosition( ii ) );
|
||||
}
|
||||
|
||||
// Close the current corner list
|
||||
aExistingZone.Outline()->CloseLastContour();
|
||||
|
||||
board.OnAreaPolygonModified( nullptr, &aExistingZone );
|
||||
|
||||
// Re-fill if needed
|
||||
if( aExistingZone.IsFilled() )
|
||||
{
|
||||
SELECTION_TOOL* selTool = toolMgr.GetTool<SELECTION_TOOL>();
|
||||
|
||||
auto& selection = selTool->GetSelection();
|
||||
|
||||
selection.Clear();
|
||||
selection.Add( &aExistingZone );
|
||||
|
||||
toolMgr.RunAction( PCB_ACTIONS::zoneFill, true );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ZONE_CREATE_HELPER::commitZone( std::unique_ptr<ZONE_CONTAINER> aZone )
|
||||
{
|
||||
auto& frame = *m_tool.getEditFrame<PCB_EDIT_FRAME>();
|
||||
|
||||
if( !m_params.m_keepout )
|
||||
frame.Fill_Zone( aZone.get() );
|
||||
|
||||
BOARD_COMMIT bCommit( &m_tool );
|
||||
|
||||
if( m_params.m_mode == DRAWING_TOOL::ZONE_MODE::CUTOUT )
|
||||
{
|
||||
// For cutouts, subtract from the source
|
||||
bCommit.Modify( m_params.m_sourceZone );
|
||||
|
||||
performZoneCutout( *m_params.m_sourceZone, *aZone );
|
||||
|
||||
bCommit.Push( _( "Add a zone cutout" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add the zone as a new board item
|
||||
bCommit.Add( aZone.release() );
|
||||
bCommit.Push( _( "Add a zone" ) );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
bool ZONE_CREATE_HELPER::OnFirstPoint()
|
||||
{
|
||||
// if we don't have a zone, create one
|
||||
// the user's choice here can affect things like the colour
|
||||
// of the preview
|
||||
|
||||
if( !m_zone )
|
||||
{
|
||||
if( m_params.m_sourceZone )
|
||||
m_zone = createZoneFromExisting( *m_params.m_sourceZone );
|
||||
else
|
||||
m_zone = createNewZone( m_params.m_keepout );
|
||||
|
||||
if( m_zone )
|
||||
{
|
||||
// set up poperties from zone
|
||||
const auto& settings = *m_parentView.GetPainter()->GetSettings();
|
||||
COLOR4D color = settings.GetColor( nullptr, m_zone->GetLayer() );
|
||||
|
||||
m_previewItem.SetStrokeColor( color );
|
||||
m_previewItem.SetFillColor( color.WithAlpha( 0.2 ) );
|
||||
|
||||
m_parentView.SetVisible( &m_previewItem, true );
|
||||
}
|
||||
}
|
||||
|
||||
if( !m_zone )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ZONE_CREATE_HELPER::OnGeometryChange( const POLYGON_GEOM_MANAGER& aMgr )
|
||||
{
|
||||
// send the points to the preview item
|
||||
m_previewItem.SetPoints( aMgr.GetLockedInPoints(), aMgr.GetLeaderLinePoints() );
|
||||
m_parentView.Update( &m_previewItem, KIGFX::GEOMETRY );
|
||||
}
|
||||
|
||||
|
||||
void ZONE_CREATE_HELPER::OnComplete( const POLYGON_GEOM_MANAGER& aMgr )
|
||||
{
|
||||
auto& finalPoints = aMgr.GetLockedInPoints();
|
||||
|
||||
if( finalPoints.size() < 3 )
|
||||
{
|
||||
// just scrap the zone in progress
|
||||
m_zone = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_zone->Outline()->Start( m_zone->GetLayer(),
|
||||
finalPoints[0].x, finalPoints[0].y,
|
||||
m_zone->GetHatchStyle() );
|
||||
|
||||
for( size_t i = 1; i < finalPoints.size(); ++i )
|
||||
{
|
||||
m_zone->AppendCorner( { finalPoints[i].x, finalPoints[i].y } );
|
||||
}
|
||||
|
||||
m_zone->Outline()->CloseLastContour();
|
||||
m_zone->Outline()->RemoveNullSegments();
|
||||
m_zone->Outline()->Hatch();
|
||||
|
||||
// hand the zone over to the committer
|
||||
commitZone( std::move( m_zone ) );
|
||||
}
|
||||
|
||||
m_parentView.SetVisible( &m_previewItem, false );
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* 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 TOOLS_ZONE_CREATE_HELPER__H_
|
||||
#define TOOLS_ZONE_CREATE_HELPER__H_
|
||||
|
||||
#include <preview_items/polygon_geom_manager.h>
|
||||
#include <preview_items/polygon_item.h>
|
||||
|
||||
#include <tools/drawing_tool.h>
|
||||
|
||||
namespace KIGFX
|
||||
{
|
||||
class VIEW;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is an adjuct helper to the DRAWING_TOOL interactive
|
||||
* tool, which handles incoming geometry changes from a
|
||||
* POLYGON_GEOM_MANAGER and translates that into a ZONE_CONTAINER
|
||||
* based on given parameters
|
||||
*/
|
||||
class ZONE_CREATE_HELPER : public POLYGON_GEOM_MANAGER::CLIENT
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Parameters used to fully describe a zone creation process
|
||||
*/
|
||||
struct PARAMS
|
||||
{
|
||||
///> Should create a keepout zone?
|
||||
bool m_keepout;
|
||||
|
||||
///> The zone mode to operate in
|
||||
DRAWING_TOOL::ZONE_MODE m_mode;
|
||||
|
||||
///> Zone settings source (for similar and cutout zones)
|
||||
ZONE_CONTAINER* m_sourceZone;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param aTool the DRAWING_TOOL to provide the zone tool to
|
||||
* @param aParams the parameters to use to guide the zone creation
|
||||
*/
|
||||
ZONE_CREATE_HELPER( DRAWING_TOOL& aTool, const PARAMS& aParams );
|
||||
|
||||
~ZONE_CREATE_HELPER();
|
||||
|
||||
/*
|
||||
* Interface for receiving POLYGON_GEOM_MANAGER update
|
||||
*/
|
||||
|
||||
void OnGeometryChange( const POLYGON_GEOM_MANAGER& aMgr ) override;
|
||||
|
||||
bool OnFirstPoint() override;
|
||||
|
||||
void OnComplete( const POLYGON_GEOM_MANAGER& aMgr ) override;
|
||||
|
||||
/**
|
||||
* Function createNewZone()
|
||||
*
|
||||
* Prompt the user for new zone settings, and create a new zone with
|
||||
* those settings
|
||||
*
|
||||
* @param aKeepout should the zone be a keepout
|
||||
* @return the new zone, can be null if the user aborted
|
||||
*/
|
||||
std::unique_ptr<ZONE_CONTAINER> createNewZone( bool aKeepout );
|
||||
|
||||
/**
|
||||
* Function createZoneFromExisting
|
||||
*
|
||||
* Create a new zone with the settings from an existing zone
|
||||
*
|
||||
* @param aSrcZone the zone to copy settings from
|
||||
* @return the new zone
|
||||
*/
|
||||
std::unique_ptr<ZONE_CONTAINER> createZoneFromExisting( const ZONE_CONTAINER& aSrcZone );
|
||||
|
||||
/**
|
||||
* Function performZoneCutout()
|
||||
*
|
||||
* Cut one zone out of another one (i.e. subtraction) and
|
||||
* update the zone.
|
||||
*
|
||||
* @param aExistingZone the zone to removed area from
|
||||
* @param aCutout the area to remove
|
||||
*/
|
||||
void performZoneCutout( ZONE_CONTAINER& aExistingZone, ZONE_CONTAINER& aCutout );
|
||||
|
||||
/**
|
||||
* Commit the current zone-in-progress to the BOARD. This might
|
||||
* be adding a new zone, or modifying an existing zone with a
|
||||
* cutout, depending on parameters.
|
||||
*
|
||||
* @param aZone - the drawn zone outline to commit
|
||||
*/
|
||||
void commitZone( std::unique_ptr<ZONE_CONTAINER> aZone );
|
||||
|
||||
private:
|
||||
|
||||
DRAWING_TOOL& m_tool;
|
||||
|
||||
///> Parameters of the zone to be drawn
|
||||
const PARAMS& m_params;
|
||||
|
||||
///> The preview item to display
|
||||
KIGFX::PREVIEW::POLYGON_ITEM m_previewItem;
|
||||
|
||||
///> view that show the preview item
|
||||
KIGFX::VIEW& m_parentView;
|
||||
|
||||
///> The zone-in-progress
|
||||
std::unique_ptr<ZONE_CONTAINER> m_zone;
|
||||
};
|
||||
|
||||
#endif /* __DRAWING_TOOL_H */
|
Loading…
Reference in New Issue