kicad/pcbnew/tools/drawing_tool.cpp

1035 lines
30 KiB
C++
Raw Normal View History

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 "drawing_tool.h"
#include "common_actions.h"
#include <wxPcbStruct.h>
2014-02-13 11:46:39 +00:00
#include <confirm.h>
#include <view/view_group.h>
#include <view/view_controls.h>
2014-02-13 11:46:39 +00:00
#include <gal/graphics_abstraction_layer.h>
#include <tool/tool_manager.h>
#include <router/direction.h>
2014-02-13 11:46:39 +00:00
#include <class_board.h>
#include <class_drawsegment.h>
2014-02-10 14:40:25 +00:00
#include <class_pcb_text.h>
2014-02-11 13:38:44 +00:00
#include <class_dimension.h>
2014-02-11 16:15:33 +00:00
#include <class_mire.h>
2014-02-13 15:10:32 +00:00
#include <class_zone.h>
2014-02-13 11:46:39 +00:00
#include <class_module.h>
DRAWING_TOOL::DRAWING_TOOL() :
TOOL_INTERACTIVE( "pcbnew.InteractiveDrawing" )
{
}
DRAWING_TOOL::~DRAWING_TOOL()
{
}
void DRAWING_TOOL::Reset( RESET_REASON aReason )
{
// Init variables used by every drawing tool
m_view = getView();
m_controls = getViewControls();
m_board = getModel<BOARD>( PCB_T );
m_frame = getEditFrame<PCB_EDIT_FRAME>();
setTransitions();
}
int DRAWING_TOOL::DrawLine( TOOL_EVENT& aEvent )
{
2014-02-14 10:35:48 +00:00
return drawSegment( S_SEGMENT, true );
}
int DRAWING_TOOL::DrawCircle( TOOL_EVENT& aEvent )
{
2014-02-14 10:35:48 +00:00
return drawSegment( S_CIRCLE, false );
}
2014-02-10 09:58:58 +00:00
int DRAWING_TOOL::DrawArc( TOOL_EVENT& aEvent )
{
bool clockwise = true; // drawing direction of the arc
2014-02-14 10:35:48 +00:00
double startAngle; // angle of the first arc line
VECTOR2I cursorPos = m_controls->GetCursorPosition();
2014-02-10 09:58:58 +00:00
// Init the new item attributes
DRAWSEGMENT* arc = new DRAWSEGMENT( m_board );
arc->SetShape( S_ARC );
arc->SetAngle( 0.0 );
arc->SetWidth( m_board->GetDesignSettings().m_DrawSegmentWidth );
arc->SetCenter( wxPoint( cursorPos.x, cursorPos.y ) );
2014-02-10 09:58:58 +00:00
2014-02-14 10:35:48 +00:00
DRAWSEGMENT helperLine;
2014-02-10 09:58:58 +00:00
helperLine.SetShape( S_SEGMENT );
helperLine.SetLayer( DRAW_N );
helperLine.SetWidth( 1 );
// Add a VIEW_GROUP that serves as a preview for the new item
KIGFX::VIEW_GROUP preview( m_view );
m_view->Add( &preview );
2014-02-10 09:58:58 +00:00
m_controls->ShowCursor( true );
m_controls->SetSnapping( true );
2014-02-10 09:58:58 +00:00
Activate();
2014-02-14 10:35:48 +00:00
enum ARC_STEPS
{
SET_ORIGIN = 0,
SET_END,
SET_ANGLE,
FINISHED
};
int step = SET_ORIGIN;
2014-02-10 09:58:58 +00:00
// Main loop: keep receiving events
while( OPT_TOOL_EVENT evt = Wait() )
{
2014-02-14 10:35:48 +00:00
cursorPos = m_controls->GetCursorPosition();
2014-02-10 09:58:58 +00:00
if( evt->IsCancel() )
{
delete arc;
2014-02-10 09:58:58 +00:00
break;
}
2014-02-10 09:58:58 +00:00
else if( evt->IsKeyUp() )
{
int width = arc->GetWidth();
2014-02-10 09:58:58 +00:00
// Modify the new item width
if( evt->KeyCode() == '-' && width > WIDTH_STEP )
arc->SetWidth( width - WIDTH_STEP );
2014-02-10 09:58:58 +00:00
else if( evt->KeyCode() == '=' )
arc->SetWidth( width + WIDTH_STEP );
2014-02-14 10:35:48 +00:00
else if( evt->KeyCode() == '/' )
2014-02-10 09:58:58 +00:00
{
2014-02-14 10:35:48 +00:00
if( clockwise )
arc->SetAngle( arc->GetAngle() - 3600.0 );
2014-02-10 09:58:58 +00:00
else
arc->SetAngle( arc->GetAngle() + 3600.0 );
2014-02-10 09:58:58 +00:00
2014-02-14 10:35:48 +00:00
clockwise = !clockwise;
2014-02-10 09:58:58 +00:00
}
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
}
else if( evt->IsClick( BUT_LEFT ) )
{
switch( step )
{
2014-02-14 10:35:48 +00:00
case SET_ORIGIN:
2014-02-10 09:58:58 +00:00
{
2014-02-14 10:35:48 +00:00
LAYER_NUM layer = m_frame->GetScreen()->m_Active_Layer;
2014-02-10 09:58:58 +00:00
if( IsCopperLayer( layer ) )
{
DisplayInfoMessage( NULL, _( "Graphic not allowed on Copper layers" ) );
--step;
}
else
{
helperLine.SetStart( arc->GetCenter() );
arc->SetCenter( wxPoint( cursorPos.x, cursorPos.y ) );
arc->SetLayer( layer );
preview.Add( arc );
2014-02-10 09:58:58 +00:00
preview.Add( &helperLine );
m_controls->SetAutoPan( true );
2014-02-10 09:58:58 +00:00
}
}
break;
2014-02-14 10:35:48 +00:00
case SET_END:
{
if( wxPoint( cursorPos.x, cursorPos.y ) != arc->GetCenter() )
{
VECTOR2D startLine( arc->GetArcStart() - arc->GetCenter() );
startAngle = startLine.Angle();
arc->SetArcStart( wxPoint( cursorPos.x, cursorPos.y ) );
}
else
--step; // one another chance to draw a proper arc
2014-02-14 10:35:48 +00:00
}
break;
case SET_ANGLE:
2014-02-10 09:58:58 +00:00
{
if( wxPoint( cursorPos.x, cursorPos.y ) != arc->GetArcStart() )
2014-02-10 09:58:58 +00:00
{
assert( arc->GetAngle() > 0 );
assert( arc->GetArcStart() != arc->GetArcEnd() );
assert( arc->GetWidth() > 0 );
m_view->Add( arc );
m_board->Add( arc );
arc->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
2014-02-17 13:53:01 +00:00
m_frame->OnModify();
m_frame->SaveCopyInUndoList( arc, UR_NEW );
}
else
--step; // one another chance to draw a proper arc
2014-02-10 09:58:58 +00:00
}
break;
}
2014-02-14 10:35:48 +00:00
if( ++step == FINISHED )
2014-02-10 09:58:58 +00:00
break;
}
else if( evt->IsMotion() )
{
switch( step )
{
2014-02-14 10:35:48 +00:00
case SET_ORIGIN:
arc->SetCenter( wxPoint( cursorPos.x, cursorPos.y ) );
2014-02-10 09:58:58 +00:00
break;
2014-02-14 10:35:48 +00:00
case SET_END:
2014-02-10 09:58:58 +00:00
helperLine.SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
arc->SetArcStart( wxPoint( cursorPos.x, cursorPos.y ) );
2014-02-10 09:58:58 +00:00
break;
2014-02-14 10:35:48 +00:00
case SET_ANGLE:
2014-02-10 09:58:58 +00:00
{
2014-02-14 10:35:48 +00:00
// Compute the current angle
VECTOR2D endLine( wxPoint( cursorPos.x, cursorPos.y ) - arc->GetCenter() );
2014-02-14 10:35:48 +00:00
double newAngle = RAD2DECIDEG( endLine.Angle() - startAngle );
2014-02-10 09:58:58 +00:00
2014-02-14 10:35:48 +00:00
if( clockwise && newAngle < 0.0 )
newAngle += 3600.0;
else if( !clockwise && newAngle > 0.0 )
newAngle -= 3600.0;
2014-02-10 09:58:58 +00:00
arc->SetAngle( newAngle );
2014-02-10 09:58:58 +00:00
}
break;
}
// Show a preview of the item
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
}
}
m_controls->ShowCursor( false );
m_controls->SetSnapping( false );
m_controls->SetAutoPan( false );
m_view->Remove( &preview );
2014-02-10 09:58:58 +00:00
setTransitions();
return 0;
}
2014-02-10 14:40:25 +00:00
int DRAWING_TOOL::DrawText( TOOL_EVENT& aEvent )
{
// Init the new item attributes
TEXTE_PCB* text = m_frame->CreateTextePcb( NULL );
if( text == NULL )
2014-02-11 13:38:44 +00:00
{
setTransitions();
return 0;
}
2014-02-10 14:40:25 +00:00
// Add a VIEW_GROUP that serves as a preview for the new item
KIGFX::VIEW_GROUP preview( m_view );
preview.Add( text );
m_view->Add( &preview );
2014-02-10 14:40:25 +00:00
m_controls->ShowCursor( true );
m_controls->SetSnapping( true );
m_controls->SetAutoPan( true );
2014-02-10 14:40:25 +00:00
Activate();
// Main loop: keep receiving events
while( OPT_TOOL_EVENT evt = Wait() )
{
VECTOR2I cursorPos = m_controls->GetCursorPosition();
2014-02-10 14:40:25 +00:00
if( evt->IsCancel() )
{
// it was already added by CreateTextPcb()
m_board->Delete( text );
2014-02-10 14:40:25 +00:00
break;
}
else if( evt->Category() == TC_COMMAND )
{
if( evt->IsAction( &COMMON_ACTIONS::rotate ) )
{
text->Rotate( text->GetPosition(), m_frame->GetRotationAngle() );
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
}
else if( evt->IsAction( &COMMON_ACTIONS::flip ) )
{
text->Flip( text->GetPosition() );
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
}
}
2014-02-10 14:40:25 +00:00
else if( evt->IsClick( BUT_LEFT ) )
{
assert( text->GetText().Length() > 0 );
assert( text->GetSize().x > 0 && text->GetSize().y > 0 );
text->ClearFlags();
m_view->Add( text );
// m_board->Add( text ); // it is already added by CreateTextePcb()
text->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
2014-02-17 13:53:01 +00:00
m_frame->OnModify();
m_frame->SaveCopyInUndoList( text, UR_NEW );
2014-02-10 14:40:25 +00:00
break;
}
else if( evt->IsMotion() )
{
text->SetTextPosition( wxPoint( cursorPos.x, cursorPos.y ) );
2014-02-10 14:40:25 +00:00
// Show a preview of the item
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
}
}
m_controls->ShowCursor( false );
m_controls->SetSnapping( false );
m_controls->SetAutoPan( false );
m_view->Remove( &preview );
2014-02-10 14:40:25 +00:00
setTransitions();
return 0;
}
2014-02-11 13:38:44 +00:00
int DRAWING_TOOL::DrawDimension( TOOL_EVENT& aEvent )
{
DIMENSION* dimension = new DIMENSION( m_board );
2014-02-11 13:38:44 +00:00
// Init the new item attributes
dimension->Text().SetSize( m_board->GetDesignSettings().m_PcbTextSize );
int width = m_board->GetDesignSettings().m_PcbTextWidth;
2014-02-14 10:35:48 +00:00
int maxThickness = Clamp_Text_PenSize( width, dimension->Text().GetSize() );
2014-02-11 13:38:44 +00:00
2014-02-14 10:35:48 +00:00
if( width > maxThickness )
width = maxThickness;
2014-02-11 13:38:44 +00:00
dimension->Text().SetThickness( width );
dimension->SetWidth( width );
dimension->AdjustDimensionDetails();
// Add a VIEW_GROUP that serves as a preview for the new item
KIGFX::VIEW_GROUP preview( m_view );
m_view->Add( &preview );
2014-02-11 13:38:44 +00:00
m_controls->ShowCursor( true );
m_controls->SetSnapping( true );
2014-02-11 13:38:44 +00:00
Activate();
2014-02-14 10:35:48 +00:00
enum DIMENSION_STEPS
{
SET_ORIGIN = 0,
SET_END,
SET_HEIGHT,
FINISHED
};
int step = SET_ORIGIN;
2014-02-11 13:38:44 +00:00
// Main loop: keep receiving events
while( OPT_TOOL_EVENT evt = Wait() )
{
VECTOR2I cursorPos = m_controls->GetCursorPosition();
2014-02-11 13:38:44 +00:00
if( evt->IsCancel() )
{
delete dimension;
break;
}
else if( evt->IsKeyUp() )
{
2014-02-14 10:35:48 +00:00
width = dimension->GetWidth();
2014-02-11 13:38:44 +00:00
// Modify the new item width
if( evt->KeyCode() == '-' && width > WIDTH_STEP )
dimension->SetWidth( width - WIDTH_STEP );
else if( evt->KeyCode() == '=' )
dimension->SetWidth( width + WIDTH_STEP );
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
}
else if( evt->IsClick( BUT_LEFT ) )
{
switch( step )
{
2014-02-14 10:35:48 +00:00
case SET_ORIGIN:
2014-02-11 13:38:44 +00:00
{
LAYER_NUM layer = m_frame->GetScreen()->m_Active_Layer;
2014-02-11 13:38:44 +00:00
if( IsCopperLayer( layer ) )
{
DisplayInfoMessage( NULL, _( "Graphic not allowed on Copper layers" ) );
--step;
}
else
{
m_controls->SetAutoPan( true );
2014-02-11 13:38:44 +00:00
dimension->SetLayer( layer );
dimension->SetOrigin( wxPoint( cursorPos.x, cursorPos.y ) );
preview.Add( dimension );
}
}
break;
case SET_END:
// Dimensions that have origin and end in the same spot are not valid
if( dimension->GetOrigin() == wxPoint( cursorPos.x, cursorPos.y ) )
--step;
break;
2014-02-14 10:35:48 +00:00
case SET_HEIGHT:
2014-02-11 13:38:44 +00:00
{
if( wxPoint( cursorPos.x, cursorPos.y ) != dimension->GetPosition() )
{
assert( dimension->GetOrigin() != dimension->GetEnd() );
assert( dimension->GetWidth() > 0 );
m_view->Add( dimension );
m_board->Add( dimension );
2014-02-11 13:38:44 +00:00
dimension->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
2014-02-17 13:53:01 +00:00
m_frame->OnModify();
m_frame->SaveCopyInUndoList( dimension, UR_NEW );
2014-02-11 13:38:44 +00:00
}
}
break;
}
2014-02-14 10:35:48 +00:00
if( ++step == FINISHED )
2014-02-11 13:38:44 +00:00
break;
}
else if( evt->IsMotion() )
{
switch( step )
{
2014-02-14 10:35:48 +00:00
case SET_END:
2014-02-11 13:38:44 +00:00
dimension->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
break;
2014-02-14 10:35:48 +00:00
case SET_HEIGHT:
2014-02-11 13:38:44 +00:00
{
2014-02-14 10:35:48 +00:00
// Calculating the direction of travel perpendicular to the selected axis
2014-02-11 13:38:44 +00:00
double angle = dimension->GetAngle() + ( M_PI / 2 );
wxPoint pos( cursorPos.x, cursorPos.y );
wxPoint delta( pos - dimension->m_featureLineDO );
double height = ( delta.x * cos( angle ) ) + ( delta.y * sin( angle ) );
dimension->SetHeight( height );
}
break;
}
// Show a preview of the item
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
}
}
m_controls->ShowCursor( false );
m_controls->SetSnapping( false );
m_controls->SetAutoPan( false );
m_view->Remove( &preview );
2014-02-11 13:38:44 +00:00
setTransitions();
return 0;
}
2014-02-13 15:10:32 +00:00
int DRAWING_TOOL::DrawZone( TOOL_EVENT& aEvent )
{
return drawZone( false );
}
2014-02-13 15:10:32 +00:00
int DRAWING_TOOL::DrawKeepout( TOOL_EVENT& aEvent )
{
return drawZone( true );
}
2014-02-13 15:10:32 +00:00
int DRAWING_TOOL::PlaceTarget( TOOL_EVENT& aEvent )
{
PCB_TARGET* target = new PCB_TARGET( m_board );
2014-02-13 15:10:32 +00:00
// Init the new item attributes
target->SetLayer( EDGE_N );
target->SetWidth( m_board->GetDesignSettings().m_EdgeSegmentWidth );
target->SetSize( Millimeter2iu( 5 ) );
VECTOR2I cursorPos = m_controls->GetCursorPosition();
target->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
2014-02-13 15:10:32 +00:00
// Add a VIEW_GROUP that serves as a preview for the new item
KIGFX::VIEW_GROUP preview( m_view );
preview.Add( target );
m_view->Add( &preview );
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
2014-02-13 15:10:32 +00:00
m_controls->SetSnapping( true );
2014-02-17 13:53:01 +00:00
m_controls->SetAutoPan( true );
2014-02-13 15:10:32 +00:00
Activate();
// Main loop: keep receiving events
while( OPT_TOOL_EVENT evt = Wait() )
{
2014-02-14 10:35:48 +00:00
cursorPos = m_controls->GetCursorPosition();
2014-02-13 15:10:32 +00:00
if( evt->IsCancel() )
{
delete target;
2014-02-13 15:10:32 +00:00
break;
}
else if( evt->IsKeyUp() )
2014-02-13 15:10:32 +00:00
{
int width = target->GetWidth();
2014-02-13 15:10:32 +00:00
// Modify the new item width
if( evt->KeyCode() == '-' && width > WIDTH_STEP )
target->SetWidth( width - WIDTH_STEP );
else if( evt->KeyCode() == '=' )
target->SetWidth( width + WIDTH_STEP );
2014-02-13 15:10:32 +00:00
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
}
2014-02-13 15:10:32 +00:00
else if( evt->IsClick( BUT_LEFT ) )
{
assert( target->GetSize() > 0 );
assert( target->GetWidth() > 0 );
m_view->Add( target );
m_board->Add( target );
target->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
2014-02-17 13:53:01 +00:00
m_frame->OnModify();
m_frame->SaveCopyInUndoList( target, UR_NEW );
break;
2014-02-13 15:10:32 +00:00
}
else if( evt->IsMotion() )
{
target->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
2014-02-13 15:10:32 +00:00
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
}
}
m_controls->SetSnapping( false );
m_controls->SetAutoPan( false );
m_view->Remove( &preview );
2014-02-13 15:10:32 +00:00
2014-02-13 15:24:33 +00:00
setTransitions();
return 0;
}
int DRAWING_TOOL::PlaceModule( TOOL_EVENT& aEvent )
2014-02-13 15:24:33 +00:00
{
MODULE* module = m_frame->LoadModuleFromLibrary( wxEmptyString,
m_frame->GetFootprintLibraryTable(), true, NULL );
if( module == NULL )
2014-02-13 15:24:33 +00:00
{
setTransitions();
return 0;
}
// Init the new item attributes
VECTOR2I cursorPos = m_controls->GetCursorPosition();
module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
2014-02-13 15:24:33 +00:00
// Add a VIEW_GROUP that serves as a preview for the new item
KIGFX::VIEW_GROUP preview( m_view );
preview.Add( module );
module->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW_GROUP::Add ), &preview ) );
m_view->Add( &preview );
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
2014-02-13 15:24:33 +00:00
m_controls->SetSnapping( true );
2014-02-17 13:53:01 +00:00
m_controls->SetAutoPan( true );
2014-02-13 15:24:33 +00:00
Activate();
// Main loop: keep receiving events
while( OPT_TOOL_EVENT evt = Wait() )
{
cursorPos = m_controls->GetCursorPosition();
2014-02-13 15:24:33 +00:00
if( evt->IsCancel() )
{
m_board->Delete( module );
2014-02-13 15:24:33 +00:00
break;
}
else if( evt->Category() == TC_COMMAND )
2014-02-13 15:24:33 +00:00
{
if( evt->IsAction( &COMMON_ACTIONS::rotate ) )
2014-02-13 15:24:33 +00:00
{
module->Rotate( module->GetPosition(), m_frame->GetRotationAngle() );
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
2014-02-13 15:24:33 +00:00
}
else if( evt->IsAction( &COMMON_ACTIONS::flip ) )
2014-02-13 15:24:33 +00:00
{
module->Flip( module->GetPosition() );
2014-02-13 15:24:33 +00:00
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
}
}
2014-02-13 15:24:33 +00:00
else if( evt->IsClick( BUT_LEFT ) )
{
module->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Add ), m_view ) );
m_view->Add( module );
module->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
2014-02-17 13:53:01 +00:00
m_frame->OnModify();
m_frame->SaveCopyInUndoList( module, UR_NEW );
break;
2014-02-13 15:24:33 +00:00
}
else if( evt->IsMotion() )
{
module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) );
2014-02-13 15:24:33 +00:00
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
}
}
m_controls->SetSnapping( false );
m_controls->SetAutoPan( false );
m_view->Remove( &preview );
2014-02-13 15:24:33 +00:00
2014-02-13 15:10:32 +00:00
setTransitions();
return 0;
}
2014-02-14 10:35:48 +00:00
int DRAWING_TOOL::drawSegment( int aShape, bool aContinous )
2014-02-11 16:15:33 +00:00
{
// Only two shapes are currently supported
assert( aShape == S_SEGMENT || aShape == S_CIRCLE );
2014-02-11 16:15:33 +00:00
// Init the new item attributes
DRAWSEGMENT* graphic = new DRAWSEGMENT( m_board );
graphic->SetShape( (STROKE_T) aShape );
graphic->SetWidth( m_board->GetDesignSettings().m_DrawSegmentWidth );
2014-02-11 16:15:33 +00:00
DRAWSEGMENT line45( *graphic ); // used only for direction 45 mode with lines
2014-02-11 16:15:33 +00:00
// Add a VIEW_GROUP that serves as a preview for the new item
KIGFX::VIEW_GROUP preview( m_view );
m_view->Add( &preview );
2014-02-11 16:15:33 +00:00
m_controls->ShowCursor( true );
m_controls->SetSnapping( true );
2014-02-11 16:15:33 +00:00
Activate();
bool started = false;
bool direction45 = false; // 45 degrees only mode
int addedSegments = 0;
2014-02-11 16:15:33 +00:00
// Main loop: keep receiving events
while( OPT_TOOL_EVENT evt = Wait() )
{
bool updatePreview = false; // should preview be updated
VECTOR2I cursorPos = m_controls->GetCursorPosition();
2014-02-11 16:15:33 +00:00
// Enable 45 degrees lines only mode by holding control
if( direction45 != ( evt->Modifier( MD_CTRL ) && aShape == S_SEGMENT && started ) )
{
direction45 = evt->Modifier( MD_CTRL );
if( direction45 )
{
preview.Add( &line45 );
make45DegLine( graphic, &line45 );
}
else
{
preview.Remove( &line45 );
graphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
}
updatePreview = true;
}
2014-02-11 16:15:33 +00:00
if( evt->IsCancel() )
{
if( direction45 )
preview.Remove( &line45 );
preview.FreeItems();
if( !started )
delete graphic;
2014-02-11 16:15:33 +00:00
break;
}
2014-02-11 16:15:33 +00:00
else if( evt->IsKeyUp() )
{
int width = graphic->GetWidth();
2014-02-11 16:15:33 +00:00
// Modify the new item width
if( evt->KeyCode() == '-' && width > WIDTH_STEP )
graphic->SetWidth( width - WIDTH_STEP );
2014-02-11 16:15:33 +00:00
else if( evt->KeyCode() == '=' )
graphic->SetWidth( width + WIDTH_STEP );
2014-02-11 16:15:33 +00:00
updatePreview = true;
2014-02-11 16:15:33 +00:00
}
else if( evt->IsClick( BUT_LEFT ) )
{
if( !started )
{
LAYER_NUM layer = m_frame->GetScreen()->m_Active_Layer;
if( IsCopperLayer( layer ) )
{
DisplayInfoMessage( NULL, _( "Graphic not allowed on Copper layers" ) );
}
else
{
m_controls->SetAutoPan( true );
graphic->SetStart( wxPoint( cursorPos.x, cursorPos.y ) );
graphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
graphic->SetLayer( layer );
line45.SetLayer( layer );
preview.Add( graphic );
started = true;
}
}
else
{
if( graphic->GetEnd() != graphic->GetStart() )
{
assert( graphic->GetLength() > 0 );
assert( graphic->GetWidth() > 0 );
m_view->Add( graphic );
m_board->Add( graphic );
graphic->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
preview.Remove( graphic );
++addedSegments;
2014-02-17 13:53:01 +00:00
m_frame->OnModify();
m_frame->SaveCopyInUndoList( graphic, UR_NEW );
2014-02-14 10:35:48 +00:00
if( aContinous )
{
graphic = new DRAWSEGMENT( *graphic );
// Start the new line in the same spot where the previous one has ended
graphic->SetStart( graphic->GetEnd() );
if( direction45 )
graphic->SetEnd( line45.GetEnd() );
preview.Add( graphic );
}
else
{
break;
}
}
else if( addedSegments > 0 ) // User has clicked twice in the same spot
{
delete graphic; // seems like a clear sign that the drawing is finished
break; // and we should remove the latest DRAWSEGMENT we have created
}
}
2014-02-11 16:15:33 +00:00
}
else if( evt->IsMotion() && started )
2014-02-11 16:15:33 +00:00
{
// 45 degree lines
if( direction45 && aShape == S_SEGMENT )
make45DegLine( graphic, &line45 );
else
graphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
updatePreview = true;
2014-02-11 16:15:33 +00:00
}
if( updatePreview )
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
2014-02-11 16:15:33 +00:00
}
m_controls->ShowCursor( false );
m_controls->SetSnapping( false );
m_controls->SetAutoPan( false );
m_view->Remove( &preview );
2014-02-11 16:15:33 +00:00
setTransitions();
return 0;
}
int DRAWING_TOOL::drawZone( bool aKeepout )
2014-02-13 11:46:39 +00:00
{
ZONE_CONTAINER* zone = new ZONE_CONTAINER( m_board );
// Get the current, default settings for zones
ZONE_SETTINGS zoneInfo = m_frame->GetZoneSettings();
zoneInfo.m_CurrentZone_Layer = m_frame->GetScreen()->m_Active_Layer;
// Show options dialog
ZONE_EDIT_T dialogResult;
if( aKeepout )
dialogResult = InvokeKeepoutAreaEditor( m_frame, &zoneInfo );
else
2014-02-13 11:46:39 +00:00
{
if( IsCopperLayer( zoneInfo.m_CurrentZone_Layer ) )
dialogResult = InvokeCopperZonesEditor( m_frame, &zoneInfo );
else
dialogResult = InvokeNonCopperZonesEditor( m_frame, NULL, &zoneInfo );
}
if( dialogResult == ZONE_ABORT )
{
delete zone;
2014-02-13 11:46:39 +00:00
setTransitions();
2014-02-13 11:46:39 +00:00
return 0;
}
// Apply the selected settings
zoneInfo.ExportSetting( *zone );
m_frame->SetTopLayer( zoneInfo.m_CurrentZone_Layer );
// Helper line represents the currently drawn line of the zone polygon
DRAWSEGMENT* helperLine = new DRAWSEGMENT;
helperLine->SetShape( S_SEGMENT );
helperLine->SetLayer( zoneInfo.m_CurrentZone_Layer );
helperLine->SetWidth( 1 );
DRAWSEGMENT line45( *helperLine );
2014-02-13 11:46:39 +00:00
// Add a VIEW_GROUP that serves as a preview for the new item
KIGFX::VIEW_GROUP preview( m_view );
m_view->Add( &preview );
2014-02-13 11:46:39 +00:00
m_controls->ShowCursor( true );
m_controls->SetSnapping( true );
m_controls->SetAutoPan( true );
2014-02-13 11:46:39 +00:00
Activate();
VECTOR2I lastCursorPos = m_controls->GetCursorPosition();
VECTOR2I origin;
int numPoints = 0;
bool direction45 = false; // 45 degrees only mode
bool cancelled = false;
2014-02-13 11:46:39 +00:00
// Main loop: keep receiving events
while( OPT_TOOL_EVENT evt = Wait() )
{
bool updatePreview = false; // should preview be updated
VECTOR2I cursorPos = m_controls->GetCursorPosition();
2014-02-13 11:46:39 +00:00
// 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 ) );
}
updatePreview = true;
}
2014-02-13 11:46:39 +00:00
if( evt->IsCancel() )
{
cancelled = true;
2014-02-13 11:46:39 +00:00
break;
}
else if( evt->IsClick( BUT_LEFT ) )
2014-02-13 11:46:39 +00:00
{
if( lastCursorPos == cursorPos || ( numPoints > 0 && cursorPos == origin ) )
2014-02-13 11:46:39 +00:00
{
if( numPoints > 2 )
{
assert( zone->GetNumCorners() > 2 );
// Finish the zone
zone->Outline()->CloseLastContour();
zone->Outline()->RemoveNullSegments();
m_board->Add( zone );
m_view->Add( zone );
if( !aKeepout )
m_frame->Fill_Zone( zone );
zone->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
2014-02-17 13:53:01 +00:00
m_frame->OnModify();
m_frame->SaveCopyInUndoList( zone, UR_NEW );
}
else
{
// If there are less than 3 points, then it is not a valid zone
cancelled = true;
}
break;
2014-02-13 11:46:39 +00:00
}
else
2014-02-13 11:46:39 +00:00
{
if( numPoints == 0 )
{
// Add the first point
zone->Outline()->Start( zoneInfo.m_CurrentZone_Layer,
cursorPos.x, cursorPos.y,
zone->GetHatchStyle() );
helperLine->SetStart( wxPoint( cursorPos.x, cursorPos.y ) );
origin = cursorPos;
preview.Add( helperLine );
}
else
{
zone->AppendCorner( helperLine->GetEnd() );
helperLine = new DRAWSEGMENT( *helperLine );
helperLine->SetStart( helperLine->GetEnd() );
preview.Add( helperLine );
}
++numPoints;
updatePreview = true;
2014-02-13 11:46:39 +00:00
}
lastCursorPos = cursorPos;
2014-02-13 11:46:39 +00:00
}
else if( evt->IsMotion() )
{
// 45 degree lines
if( direction45 )
make45DegLine( helperLine, &line45 );
else
helperLine->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
// Show a preview of the item
updatePreview = true;
2014-02-13 11:46:39 +00:00
}
if( updatePreview )
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
2014-02-13 11:46:39 +00:00
}
m_controls->ShowCursor( false );
m_controls->SetSnapping( false );
m_controls->SetAutoPan( false );
m_view->Remove( &preview );
2014-02-13 11:46:39 +00:00
// Clean
if( cancelled )
delete zone;
if( direction45 )
preview.Remove( &line45 );
preview.FreeItems();
2014-02-13 11:46:39 +00:00
setTransitions();
return 0;
}
void DRAWING_TOOL::make45DegLine( DRAWSEGMENT* aSegment, DRAWSEGMENT* aHelper ) const
{
VECTOR2I cursorPos = m_controls->GetCursorPosition();
VECTOR2I origin( aSegment->GetStart() );
DIRECTION_45 direction( origin - cursorPos );
SHAPE_LINE_CHAIN newChain = direction.BuildInitialTrace( origin, cursorPos );
if( newChain.PointCount() > 2 )
{
aSegment->SetEnd( wxPoint( newChain.Point( -2 ).x, newChain.Point( -2 ).y ) );
aHelper->SetStart( wxPoint( newChain.Point( -2 ).x, newChain.Point( -2 ).y ) );
aHelper->SetEnd( wxPoint( newChain.Point( -1 ).x, newChain.Point( -1 ).y ) );
}
else
{
aSegment->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
aHelper->SetStart( wxPoint( cursorPos.x, cursorPos.y ) );
aHelper->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
}
}
void DRAWING_TOOL::setTransitions()
{
Go( &DRAWING_TOOL::DrawLine, COMMON_ACTIONS::drawLine.MakeEvent() );
Go( &DRAWING_TOOL::DrawCircle, COMMON_ACTIONS::drawCircle.MakeEvent() );
2014-02-10 09:58:58 +00:00
Go( &DRAWING_TOOL::DrawArc, COMMON_ACTIONS::drawArc.MakeEvent() );
2014-02-10 14:40:25 +00:00
Go( &DRAWING_TOOL::DrawText, COMMON_ACTIONS::drawText.MakeEvent() );
2014-02-11 13:38:44 +00:00
Go( &DRAWING_TOOL::DrawDimension, COMMON_ACTIONS::drawDimension.MakeEvent() );
2014-02-13 15:10:32 +00:00
Go( &DRAWING_TOOL::DrawZone, COMMON_ACTIONS::drawZone.MakeEvent() );
2014-02-13 15:24:33 +00:00
Go( &DRAWING_TOOL::DrawKeepout, COMMON_ACTIONS::drawKeepout.MakeEvent() );
2014-02-11 16:15:33 +00:00
Go( &DRAWING_TOOL::PlaceTarget, COMMON_ACTIONS::placeTarget.MakeEvent() );
2014-02-13 11:46:39 +00:00
Go( &DRAWING_TOOL::PlaceModule, COMMON_ACTIONS::placeModule.MakeEvent() );
}