Commit b05885c2 authored by Maciej Suminski's avatar Maciej Suminski

Refactored drawing tools: lines, circles and arcs.

parent 69c73b0e
......@@ -74,208 +74,49 @@ int DRAWING_TOOL::DrawLine( TOOL_EVENT& aEvent )
{
m_frame->SetToolID( ID_PCB_ADD_LINE_BUTT, wxCURSOR_PENCIL, _( "Add graphic line" ) );
return drawSegment( S_SEGMENT, true );
}
int DRAWING_TOOL::DrawCircle( TOOL_EVENT& aEvent )
{
m_frame->SetToolID( ID_PCB_CIRCLE_BUTT, wxCURSOR_PENCIL, _( "Add graphic circle" ) );
return drawSegment( S_CIRCLE, false );
}
int DRAWING_TOOL::DrawArc( TOOL_EVENT& aEvent )
{
bool clockwise = true; // drawing direction of the arc
double startAngle = 0.0f; // angle of the first arc line
VECTOR2I cursorPos = m_controls->GetCursorPosition();
DRAWSEGMENT* arc = NULL;
DRAWSEGMENT helperLine;
helperLine.SetShape( S_SEGMENT );
helperLine.SetLayer( Dwgs_User );
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 );
DRAWSEGMENT* line = new DRAWSEGMENT;
m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear );
m_controls->ShowCursor( true );
m_controls->SetSnapping( true );
Activate();
m_frame->SetToolID( ID_PCB_ARC_BUTT, wxCURSOR_PENCIL, _( "Add graphic arc" ) );
enum ARC_STEPS
{
SET_ORIGIN = 0,
SET_END,
SET_ANGLE,
FINISHED
};
int step = SET_ORIGIN;
// Main loop: keep receiving events
while( OPT_TOOL_EVENT evt = Wait() )
while( drawSegment( S_SEGMENT, line ) )
{
cursorPos = m_controls->GetCursorPosition();
if( evt->IsCancel() || evt->IsActivate() )
{
if( step != SET_ORIGIN ) // start from the beginning
{
preview.Clear();
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
delete arc;
step = SET_ORIGIN;
}
else
break;
if( evt->IsActivate() ) // now finish unconditionally
break;
line = new DRAWSEGMENT;
}
else if( evt->IsKeyPressed() && step != SET_ORIGIN )
{
int width = arc->GetWidth();
// Modify the new item width
if( evt->KeyCode() == '-' && width > WIDTH_STEP )
arc->SetWidth( width - WIDTH_STEP );
else if( evt->KeyCode() == '=' )
arc->SetWidth( width + WIDTH_STEP );
else if( evt->KeyCode() == '/' )
{
if( clockwise )
arc->SetAngle( arc->GetAngle() - 3600.0 );
else
arc->SetAngle( arc->GetAngle() + 3600.0 );
clockwise = !clockwise;
}
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
}
else if( evt->IsClick( BUT_LEFT ) )
{
switch( step )
{
case SET_ORIGIN:
{
LAYER_ID layer = m_frame->GetScreen()->m_Active_Layer;
setTransitions();
m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString );
if( IsCopperLayer( layer ) )
{
DisplayInfoMessage( NULL, _( "Graphic not allowed on Copper layers" ) );
--step;
}
else
{
// Init the new item attributes
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 ) );
arc->SetLayer( layer );
return 0;
}
helperLine.SetStart( arc->GetCenter() );
helperLine.SetEnd( arc->GetCenter() );
preview.Add( arc );
preview.Add( &helperLine );
int DRAWING_TOOL::DrawCircle( TOOL_EVENT& aEvent )
{
m_frame->SetToolID( ID_PCB_CIRCLE_BUTT, wxCURSOR_PENCIL, _( "Add graphic circle" ) );
m_controls->SetAutoPan( true );
}
}
break;
DRAWSEGMENT* circle = new DRAWSEGMENT;
case SET_END:
{
if( wxPoint( cursorPos.x, cursorPos.y ) != arc->GetCenter() )
while( drawSegment( S_CIRCLE, circle ) )
{
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
circle = new DRAWSEGMENT;
}
break;
case SET_ANGLE:
{
if( wxPoint( cursorPos.x, cursorPos.y ) != arc->GetArcStart() )
{
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 );
setTransitions();
m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString );
m_frame->OnModify();
m_frame->SaveCopyInUndoList( arc, UR_NEW );
return 0;
}
preview.Remove( arc );
preview.Remove( &helperLine );
}
else
--step; // one another chance to draw a proper arc
}
break;
}
if( ++step == FINISHED )
{
step = SET_ORIGIN;
m_controls->SetAutoPan( false );
}
}
int DRAWING_TOOL::DrawArc( TOOL_EVENT& aEvent )
{
m_frame->SetToolID( ID_PCB_ARC_BUTT, wxCURSOR_PENCIL, _( "Add graphic arc" ) );
else if( evt->IsMotion() )
{
switch( step )
{
case SET_END:
helperLine.SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
arc->SetArcStart( wxPoint( cursorPos.x, cursorPos.y ) );
break;
DRAWSEGMENT* arc = new DRAWSEGMENT;
case SET_ANGLE:
while( drawArc( arc ) )
{
VECTOR2D endLine( wxPoint( cursorPos.x, cursorPos.y ) - arc->GetCenter() );
double newAngle = RAD2DECIDEG( endLine.Angle() - startAngle );
// Adjust the new angle to (counter)clockwise setting
if( clockwise && newAngle < 0.0 )
newAngle += 3600.0;
else if( !clockwise && newAngle > 0.0 )
newAngle -= 3600.0;
arc->SetAngle( newAngle );
}
break;
}
// Show a preview of the item
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
}
arc = new DRAWSEGMENT;
}
m_controls->ShowCursor( false );
m_controls->SetSnapping( false );
m_controls->SetAutoPan( false );
m_view->Remove( &preview );
setTransitions();
m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString );
......@@ -884,12 +725,11 @@ int DRAWING_TOOL::PlaceModule( TOOL_EVENT& aEvent )
}
int DRAWING_TOOL::drawSegment( int aShape, bool aContinous )
bool DRAWING_TOOL::drawSegment( int aShape, DRAWSEGMENT* aGraphic )
{
// Only two shapes are currently supported
assert( aShape == S_SEGMENT || aShape == S_CIRCLE );
DRAWSEGMENT* graphic = NULL;
DRAWSEGMENT line45;
// Add a VIEW_GROUP that serves as a preview for the new item
......@@ -903,7 +743,7 @@ int DRAWING_TOOL::drawSegment( int aShape, bool aContinous )
Activate();
bool direction45 = false; // 45 degrees only mode
int addedSegments = 0;
bool started = false;
// Main loop: keep receiving events
while( OPT_TOOL_EVENT evt = Wait() )
......@@ -912,19 +752,19 @@ int DRAWING_TOOL::drawSegment( int aShape, bool aContinous )
VECTOR2I cursorPos = m_controls->GetCursorPosition();
// Enable 45 degrees lines only mode by holding control
if( direction45 != evt->Modifier( MD_CTRL ) && graphic && aShape == S_SEGMENT )
if( direction45 != evt->Modifier( MD_CTRL ) && started && aShape == S_SEGMENT )
{
direction45 = evt->Modifier( MD_CTRL );
if( direction45 )
{
preview.Add( &line45 );
make45DegLine( graphic, &line45 );
make45DegLine( aGraphic, &line45 );
}
else
{
preview.Remove( &line45 );
graphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
}
updatePreview = true;
......@@ -932,37 +772,28 @@ int DRAWING_TOOL::drawSegment( int aShape, bool aContinous )
if( evt->IsCancel() || evt->IsActivate() )
{
if( !graphic )
break;
preview.Clear();
updatePreview = true;
delete graphic;
graphic = NULL;
m_controls->SetAutoPan( false );
if( evt->IsActivate() ) // now finish unconditionally
delete aGraphic;
break;
}
else if( graphic && evt->IsKeyPressed() )
else if( evt->IsKeyPressed() )
{
int width = graphic->GetWidth();
int width = aGraphic->GetWidth();
// Modify the new item width
if( evt->KeyCode() == '-' && width > WIDTH_STEP )
graphic->SetWidth( width - WIDTH_STEP );
if( evt->KeyCode() == '-' && width > WIDTH_STEP ) // TODO change it to TOOL_ACTIONs
aGraphic->SetWidth( width - WIDTH_STEP );
else if( evt->KeyCode() == '=' )
graphic->SetWidth( width + WIDTH_STEP );
aGraphic->SetWidth( width + WIDTH_STEP );
updatePreview = true;
}
else if( evt->IsClick( BUT_LEFT ) )
{
if( !graphic )
if( !started )
{
LAYER_ID layer = m_frame->GetScreen()->m_Active_Layer;
......@@ -973,95 +804,248 @@ int DRAWING_TOOL::drawSegment( int aShape, bool aContinous )
else
{
// Init the new item attributes
graphic = new DRAWSEGMENT( m_board );
graphic->SetShape( (STROKE_T) aShape );
graphic->SetWidth( m_board->GetDesignSettings().m_DrawSegmentWidth );
graphic->SetStart( wxPoint( cursorPos.x, cursorPos.y ) );
graphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
graphic->SetLayer( layer );
aGraphic->SetShape( (STROKE_T) aShape );
aGraphic->SetWidth( m_board->GetDesignSettings().m_DrawSegmentWidth );
aGraphic->SetStart( wxPoint( cursorPos.x, cursorPos.y ) );
aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
aGraphic->SetLayer( layer );
if( aShape == S_SEGMENT )
{
line45 = *graphic; // used only for direction 45 mode with lines
line45 = *aGraphic; // used only for direction 45 mode with lines
line45.SetLayer( layer );
}
preview.Add( graphic );
preview.Add( aGraphic );
m_controls->SetAutoPan( true );
started = true;
}
}
else
{
if( graphic->GetEnd() != graphic->GetStart() )
if( aGraphic->GetEnd() != aGraphic->GetStart() )
{
assert( graphic->GetLength() > 0 );
assert( graphic->GetWidth() > 0 );
assert( aGraphic->GetLength() > 0 );
assert( aGraphic->GetWidth() > 0 );
m_view->Add( graphic );
m_board->Add( graphic );
graphic->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
m_view->Add( aGraphic );
m_board->Add( aGraphic );
aGraphic->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
m_frame->OnModify();
m_frame->SaveCopyInUndoList( graphic, UR_NEW );
m_frame->SaveCopyInUndoList( aGraphic, UR_NEW );
}
else // User has clicked twice in the same spot
{ // a clear sign that the current drawing is finished
delete aGraphic; // but only if at least one graphic was created
started = false; // otherwise - force user to draw more or cancel
}
preview.Remove( graphic );
++addedSegments;
preview.Clear();
break;
}
}
if( aContinous )
else if( evt->IsMotion() )
{
graphic = new DRAWSEGMENT( *graphic );
// 45 degree lines
if( direction45 && aShape == S_SEGMENT )
make45DegLine( aGraphic, &line45 );
else
aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
updatePreview = true;
}
// Start the new line in the same spot where the previous one has ended
graphic->SetStart( graphic->GetEnd() );
if( updatePreview )
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
}
if( direction45 )
graphic->SetEnd( line45.GetEnd() );
m_controls->ShowCursor( false );
m_controls->SetSnapping( false );
m_controls->SetAutoPan( false );
m_view->Remove( &preview );
return started;
}
preview.Add( graphic );
bool DRAWING_TOOL::drawArc( DRAWSEGMENT* aGraphic )
{
bool clockwise = true; // drawing direction of the arc
double startAngle = 0.0f; // angle of the first arc line
VECTOR2I cursorPos = m_controls->GetCursorPosition();
DRAWSEGMENT helperLine;
helperLine.SetShape( S_SEGMENT );
helperLine.SetLayer( Dwgs_User );
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 );
m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear );
m_controls->ShowCursor( true );
m_controls->SetSnapping( true );
Activate();
enum ARC_STEPS
{
SET_ORIGIN = 0,
SET_END,
SET_ANGLE,
FINISHED
};
int step = SET_ORIGIN;
// Main loop: keep receiving events
while( OPT_TOOL_EVENT evt = Wait() )
{
cursorPos = m_controls->GetCursorPosition();
if( evt->IsCancel() || evt->IsActivate() )
{
preview.Clear();
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
delete aGraphic;
break;
}
else // start a new graphic
else if( evt->IsKeyPressed() && step != SET_ORIGIN )
{
addedSegments = 0;
m_controls->SetAutoPan( false );
graphic = NULL;
int width = aGraphic->GetWidth();
// Modify the new item width
if( evt->KeyCode() == '-' && width > WIDTH_STEP ) // TODO convert to tool actions
aGraphic->SetWidth( width - WIDTH_STEP );
else if( evt->KeyCode() == '=' )
aGraphic->SetWidth( width + WIDTH_STEP );
else if( evt->KeyCode() == '/' )
{
if( clockwise )
aGraphic->SetAngle( aGraphic->GetAngle() - 3600.0 );
else
aGraphic->SetAngle( aGraphic->GetAngle() + 3600.0 );
clockwise = !clockwise;
}
preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
}
else if( addedSegments > 0 ) // User has clicked twice in the same spot
{ // a clear sign that the current drawing is finished
preview.Clear(); // but only if at least one graphic was created
// otherwise - force user to draw more or cancel
delete graphic;
graphic = NULL;
m_controls->SetAutoPan( false );
else if( evt->IsClick( BUT_LEFT ) )
{
switch( step )
{
case SET_ORIGIN:
{
LAYER_ID layer = m_frame->GetScreen()->m_Active_Layer;
if( IsCopperLayer( layer ) )
{
DisplayInfoMessage( NULL, _( "Graphic not allowed on Copper layers" ) );
--step;
}
else
{
// Init the new item attributes
aGraphic->SetShape( S_ARC );
aGraphic->SetAngle( 0.0 );
aGraphic->SetWidth( m_board->GetDesignSettings().m_DrawSegmentWidth );
aGraphic->SetCenter( wxPoint( cursorPos.x, cursorPos.y ) );
aGraphic->SetLayer( layer );
helperLine.SetStart( aGraphic->GetCenter() );
helperLine.SetEnd( aGraphic->GetCenter() );
preview.Add( aGraphic );
preview.Add( &helperLine );
m_controls->SetAutoPan( true );
}
}
break;
else if( graphic && evt->IsMotion() )
case SET_END:
{
// 45 degree lines
if( direction45 && aShape == S_SEGMENT )
make45DegLine( graphic, &line45 );
if( wxPoint( cursorPos.x, cursorPos.y ) != aGraphic->GetCenter() )
{
VECTOR2D startLine( aGraphic->GetArcStart() - aGraphic->GetCenter() );
startAngle = startLine.Angle();
aGraphic->SetArcStart( wxPoint( cursorPos.x, cursorPos.y ) );
}
else
graphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
--step; // one another chance to draw a proper arc
}
break;
updatePreview = true;
case SET_ANGLE:
{
if( wxPoint( cursorPos.x, cursorPos.y ) != aGraphic->GetArcStart() )
{
assert( aGraphic->GetAngle() != 0 );
assert( aGraphic->GetArcStart() != aGraphic->GetArcEnd() );
assert( aGraphic->GetWidth() > 0 );
m_view->Add( aGraphic );
m_board->Add( aGraphic );
aGraphic->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
m_frame->OnModify();
m_frame->SaveCopyInUndoList( aGraphic, UR_NEW );
preview.Remove( aGraphic );
preview.Remove( &helperLine );
}
else
--step; // one another chance to draw a proper arc
}
break;
}
if( updatePreview )
if( ++step == FINISHED )
break;
}
else if( evt->IsMotion() )
{
switch( step )
{
case SET_END:
helperLine.SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
aGraphic->SetArcStart( wxPoint( cursorPos.x, cursorPos.y ) );
break;
case SET_ANGLE:
{
VECTOR2D endLine( wxPoint( cursorPos.x, cursorPos.y ) - aGraphic->GetCenter() );
double newAngle = RAD2DECIDEG( endLine.Angle() - startAngle );
// Adjust the new angle to (counter)clockwise setting
if( clockwise && newAngle < 0.0 )
newAngle += 3600.0;
else if( !clockwise && newAngle > 0.0 )
newAngle -= 3600.0;
aGraphic->SetAngle( newAngle );
}
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 );
setTransitions();
m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString );
return 0;
return ( step > SET_ORIGIN );
}
......
......@@ -130,8 +130,18 @@ public:
private:
///> Starts drawing a selected shape (i.e. DRAWSEGMENT).
///> @param aShape is the type of created shape (@see STROKE_T).
///> @param aContinous decides if there is only one or multiple shapes to draw.
int drawSegment( int aShape, bool aContinous );
///> @param aGraphic is an object that is going to be used by the tool for drawing. It has to
///> be already created. The tool deletes the object if it is not added to a BOARD.
///> @return False if the tool was cancelled before the origin was set or origin and end are
///> the same point.
bool drawSegment( int aShape, DRAWSEGMENT* aGraphic );
///> Starts drawing an arc.
///> @param aGraphic is an object that is going to be used by the tool for drawing. It has to
///> be already created. The tool deletes the object if it is not added to a BOARD.
///> @return False if the tool was cancelled before the origin was set or origin and end are
///> the same point.
bool drawArc( DRAWSEGMENT* aGraphic );
///> Draws a polygon, that is added as a zone or a keepout area.
///> @param aKeepout decides if the drawn polygon is a zone or a keepout area.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment