|  | @ -2,7 +2,7 @@ | 
		
	
		
			
				|  |  |  * This program source code file is part of KiCad, a free EDA CAD application. |  |  |  * This program source code file is part of KiCad, a free EDA CAD application. | 
		
	
		
			
				|  |  |  * |  |  |  * | 
		
	
		
			
				|  |  |  * Copyright (C) 2014-2017 CERN |  |  |  * Copyright (C) 2014-2017 CERN | 
		
	
		
			
				|  |  |  * Copyright (C) 2018-2020 KiCad Developers, see AUTHORS.txt for contributors. |  |  |  | 
		
	
		
			
				|  |  |  |  |  |  * Copyright (C) 2018-2021 KiCad Developers, see AUTHORS.txt for contributors. | 
		
	
		
			
				|  |  |  * @author Maciej Suminski <maciej.suminski@cern.ch> |  |  |  * @author Maciej Suminski <maciej.suminski@cern.ch> | 
		
	
		
			
				|  |  |  * |  |  |  * | 
		
	
		
			
				|  |  |  * This program is free software; you can redistribute it and/or |  |  |  * This program is free software; you can redistribute it and/or | 
		
	
	
		
			
				|  | @ -23,6 +23,8 @@ | 
		
	
		
			
				|  |  |  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA |  |  |  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA | 
		
	
		
			
				|  |  |  */ |  |  |  */ | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | #include "drawing_tool.h"
 | 
		
	
		
			
				|  |  |  |  |  | #include "pcb_actions.h"
 | 
		
	
		
			
				|  |  | #include <pcb_edit_frame.h>
 |  |  | #include <pcb_edit_frame.h>
 | 
		
	
		
			
				|  |  | #include <confirm.h>
 |  |  | #include <confirm.h>
 | 
		
	
		
			
				|  |  | #include <import_gfx/dialog_import_gfx.h>
 |  |  | #include <import_gfx/dialog_import_gfx.h>
 | 
		
	
	
		
			
				|  | @ -236,6 +238,751 @@ DRAWING_TOOL::MODE DRAWING_TOOL::GetDrawingMode() const | 
		
	
		
			
				|  |  |     return m_mode; |  |  |     return m_mode; | 
		
	
		
			
				|  |  | } |  |  | } | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | std::vector<BOARD_ITEM*> initTextTable( std::vector<std::vector<PCB_TEXT*>> aContent, | 
		
	
		
			
				|  |  |  |  |  |                                         wxPoint origin, PCB_LAYER_ID aLayer, wxPoint* aTableSize, | 
		
	
		
			
				|  |  |  |  |  |                                         bool aDrawFrame = true ) | 
		
	
		
			
				|  |  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |  |     int i; | 
		
	
		
			
				|  |  |  |  |  |     int j; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     int nbCols = aContent.size(); | 
		
	
		
			
				|  |  |  |  |  |     int nbRows = 0; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     for( auto col : aContent ) | 
		
	
		
			
				|  |  |  |  |  |         nbRows = std::max( nbRows, static_cast<int>( col.size() ) ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     // Limit the number of cells
 | 
		
	
		
			
				|  |  |  |  |  |     nbCols = std::min( nbCols, 99 ); | 
		
	
		
			
				|  |  |  |  |  |     nbRows = std::min( nbRows, 99 ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     int rowHeight[99]; | 
		
	
		
			
				|  |  |  |  |  |     int colWidth[99]; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     std::vector<BOARD_ITEM*> table; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     // xmargin and ymargin are margins between the text and the the table lines.
 | 
		
	
		
			
				|  |  |  |  |  |     //
 | 
		
	
		
			
				|  |  |  |  |  |     //  +--------------------------------+
 | 
		
	
		
			
				|  |  |  |  |  |     //  |            ^                   |
 | 
		
	
		
			
				|  |  |  |  |  |     //  |            | ymargin           |
 | 
		
	
		
			
				|  |  |  |  |  |     //  |            v                   |
 | 
		
	
		
			
				|  |  |  |  |  |     //  |<------->TEXT_TEXT_TEXT<------->|
 | 
		
	
		
			
				|  |  |  |  |  |     //  | xmargin    ^           xmargin |
 | 
		
	
		
			
				|  |  |  |  |  |     //  |            | ymargin           |
 | 
		
	
		
			
				|  |  |  |  |  |     //  |            v                   |
 | 
		
	
		
			
				|  |  |  |  |  |     //  +--------------------------------+
 | 
		
	
		
			
				|  |  |  |  |  |     //
 | 
		
	
		
			
				|  |  |  |  |  |     // Note: these are internal units.
 | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     int xmargin = 750000; | 
		
	
		
			
				|  |  |  |  |  |     int ymargin = 750000; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     // Init table
 | 
		
	
		
			
				|  |  |  |  |  |     for( i = 0; i < nbRows; i++ ) | 
		
	
		
			
				|  |  |  |  |  |         rowHeight[i] = 0; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     for( i = 0; i < nbCols; i++ ) | 
		
	
		
			
				|  |  |  |  |  |         colWidth[i] = 0; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     // First, we determine what the height/Width should be for every cell
 | 
		
	
		
			
				|  |  |  |  |  |     i = 0; | 
		
	
		
			
				|  |  |  |  |  |      | 
		
	
		
			
				|  |  |  |  |  |     for( auto col : aContent ) | 
		
	
		
			
				|  |  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |  |         j = 0; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         if( i >= nbCols ) | 
		
	
		
			
				|  |  |  |  |  |             break; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         for( auto cell : col ) | 
		
	
		
			
				|  |  |  |  |  |         { | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |             if( j >= nbRows ) | 
		
	
		
			
				|  |  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |             int height   = cell->GetBoundingBox().GetHeight() + 2 * ymargin; | 
		
	
		
			
				|  |  |  |  |  |             int width    = cell->GetBoundingBox().GetWidth() + 2 * xmargin; | 
		
	
		
			
				|  |  |  |  |  |             rowHeight[j] = rowHeight[j] > height ? rowHeight[j] : height; | 
		
	
		
			
				|  |  |  |  |  |             colWidth[i]  = colWidth[i] > width ? colWidth[i] : width; | 
		
	
		
			
				|  |  |  |  |  |             j++; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         i++; | 
		
	
		
			
				|  |  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     // get table size
 | 
		
	
		
			
				|  |  |  |  |  |     int height = std::accumulate( rowHeight, rowHeight + nbRows, 0 ); | 
		
	
		
			
				|  |  |  |  |  |     int width  = std::accumulate( colWidth, colWidth + nbCols, 0 ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     aTableSize->x = width; | 
		
	
		
			
				|  |  |  |  |  |     aTableSize->y = height; | 
		
	
		
			
				|  |  |  |  |  |     // Draw the frame
 | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     if( aDrawFrame ) | 
		
	
		
			
				|  |  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |  |         int          y = origin.y; | 
		
	
		
			
				|  |  |  |  |  |         PCB_SHAPE*   line; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         for( i = 0; i < nbRows; i++ ) | 
		
	
		
			
				|  |  |  |  |  |         { | 
		
	
		
			
				|  |  |  |  |  |             line = new PCB_SHAPE; | 
		
	
		
			
				|  |  |  |  |  |             line->SetLayer( aLayer ); | 
		
	
		
			
				|  |  |  |  |  |             line->SetStartX( origin.x ); | 
		
	
		
			
				|  |  |  |  |  |             line->SetStartY( y ); | 
		
	
		
			
				|  |  |  |  |  |             line->SetEndX( origin.x + width ); | 
		
	
		
			
				|  |  |  |  |  |             line->SetEndY( y ); | 
		
	
		
			
				|  |  |  |  |  |             y += rowHeight[i]; | 
		
	
		
			
				|  |  |  |  |  |             table.push_back( line ); | 
		
	
		
			
				|  |  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         line = new PCB_SHAPE; | 
		
	
		
			
				|  |  |  |  |  |         line->SetLayer( aLayer ); | 
		
	
		
			
				|  |  |  |  |  |         line->SetStartX( origin.x ); | 
		
	
		
			
				|  |  |  |  |  |         line->SetStartY( y ); | 
		
	
		
			
				|  |  |  |  |  |         line->SetEndX( origin.x + width ); | 
		
	
		
			
				|  |  |  |  |  |         line->SetEndY( y ); | 
		
	
		
			
				|  |  |  |  |  |         table.push_back( line ); | 
		
	
		
			
				|  |  |  |  |  |         int x = origin.x; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         for( i = 0; i < nbCols; i++ ) | 
		
	
		
			
				|  |  |  |  |  |         { | 
		
	
		
			
				|  |  |  |  |  |             line = new PCB_SHAPE; | 
		
	
		
			
				|  |  |  |  |  |             line->SetLayer( aLayer ); | 
		
	
		
			
				|  |  |  |  |  |             line->SetStartX( x ); | 
		
	
		
			
				|  |  |  |  |  |             line->SetStartY( origin.y ); | 
		
	
		
			
				|  |  |  |  |  |             line->SetEndX( x ); | 
		
	
		
			
				|  |  |  |  |  |             line->SetEndY( origin.y + height ); | 
		
	
		
			
				|  |  |  |  |  |             x += colWidth[i]; | 
		
	
		
			
				|  |  |  |  |  |             table.push_back( line ); | 
		
	
		
			
				|  |  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         line = new PCB_SHAPE; | 
		
	
		
			
				|  |  |  |  |  |         line->SetLayer( aLayer ); | 
		
	
		
			
				|  |  |  |  |  |         line->SetStartX( x ); | 
		
	
		
			
				|  |  |  |  |  |         line->SetStartY( origin.y ); | 
		
	
		
			
				|  |  |  |  |  |         line->SetEndX( x ); | 
		
	
		
			
				|  |  |  |  |  |         line->SetEndY( origin.y + height ); | 
		
	
		
			
				|  |  |  |  |  |         table.push_back( line ); | 
		
	
		
			
				|  |  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  |     //Now add the text
 | 
		
	
		
			
				|  |  |  |  |  |     i           = 0; | 
		
	
		
			
				|  |  |  |  |  |     wxPoint pos = wxPoint( origin.x + xmargin, origin.y + ymargin ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     for( auto col : aContent ) | 
		
	
		
			
				|  |  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |  |         j = 0; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         if( i >= nbCols ) | 
		
	
		
			
				|  |  |  |  |  |             break; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         pos.y = origin.y + ymargin; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         for( auto cell : col ) | 
		
	
		
			
				|  |  |  |  |  |         { | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |             if( j >= nbRows ) | 
		
	
		
			
				|  |  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |             cell->SetTextPos( pos ); | 
		
	
		
			
				|  |  |  |  |  |             cell->SetLayer( aLayer ); | 
		
	
		
			
				|  |  |  |  |  |             pos.y = pos.y + rowHeight[j]; | 
		
	
		
			
				|  |  |  |  |  |             table.push_back( cell ); | 
		
	
		
			
				|  |  |  |  |  |             j++; | 
		
	
		
			
				|  |  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         pos.x = pos.x + colWidth[i]; | 
		
	
		
			
				|  |  |  |  |  |         i++; | 
		
	
		
			
				|  |  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  |     return table; | 
		
	
		
			
				|  |  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | std::vector<BOARD_ITEM*> DRAWING_TOOL::DrawSpecificationStackup( | 
		
	
		
			
				|  |  |  |  |  |         wxPoint aOrigin, PCB_LAYER_ID aLayer, bool aDrawNow, wxPoint* tableSize ) | 
		
	
		
			
				|  |  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |  |     BOARD_COMMIT               commit( m_frame ); | 
		
	
		
			
				|  |  |  |  |  |     std::vector<std::vector<PCB_TEXT*>> texts; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     // Style : Header
 | 
		
	
		
			
				|  |  |  |  |  |     PCB_TEXT* headStyle = new PCB_TEXT( static_cast<FOOTPRINT*>( m_frame->GetModel() ) ); | 
		
	
		
			
				|  |  |  |  |  |     headStyle->SetLayer( Eco1_User ); | 
		
	
		
			
				|  |  |  |  |  |     headStyle->SetTextSize( wxSize( 1500000, 1500000 ) ); | 
		
	
		
			
				|  |  |  |  |  |     headStyle->SetTextThickness( 300000 ); | 
		
	
		
			
				|  |  |  |  |  |     headStyle->SetItalic( false ); | 
		
	
		
			
				|  |  |  |  |  |     headStyle->SetTextPos( wxPoint( 0, 0 ) ); | 
		
	
		
			
				|  |  |  |  |  |     headStyle->SetText( "Layer" ); | 
		
	
		
			
				|  |  |  |  |  |     headStyle->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT ); | 
		
	
		
			
				|  |  |  |  |  |     headStyle->SetVertJustify( GR_TEXT_VJUSTIFY_TOP ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     // Style : data
 | 
		
	
		
			
				|  |  |  |  |  |     PCB_TEXT* dataStyle = new PCB_TEXT( static_cast<FOOTPRINT*>( m_frame->GetModel() ) ); | 
		
	
		
			
				|  |  |  |  |  |     dataStyle->SetLayer( Eco1_User ); | 
		
	
		
			
				|  |  |  |  |  |     dataStyle->SetTextSize( wxSize( 1500000, 1500000 ) ); | 
		
	
		
			
				|  |  |  |  |  |     dataStyle->SetTextThickness( 100000 ); | 
		
	
		
			
				|  |  |  |  |  |     dataStyle->SetItalic( false ); | 
		
	
		
			
				|  |  |  |  |  |     dataStyle->SetTextPos( wxPoint( 0, 0 ) ); | 
		
	
		
			
				|  |  |  |  |  |     dataStyle->SetText( "Layer" ); | 
		
	
		
			
				|  |  |  |  |  |     dataStyle->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT ); | 
		
	
		
			
				|  |  |  |  |  |     dataStyle->SetVertJustify( GR_TEXT_VJUSTIFY_TOP ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     //Get Layer names
 | 
		
	
		
			
				|  |  |  |  |  |     BOARD_DESIGN_SETTINGS&           dsnSettings = m_frame->GetDesignSettings(); | 
		
	
		
			
				|  |  |  |  |  |     BOARD_STACKUP&                   stackup     = dsnSettings.GetStackupDescriptor(); | 
		
	
		
			
				|  |  |  |  |  |     std::vector<BOARD_STACKUP_ITEM*> layers      = stackup.GetList(); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     std::vector<PCB_TEXT*> colLayer; | 
		
	
		
			
				|  |  |  |  |  |     std::vector<PCB_TEXT*> colType; | 
		
	
		
			
				|  |  |  |  |  |     std::vector<PCB_TEXT*> colMaterial; | 
		
	
		
			
				|  |  |  |  |  |     std::vector<PCB_TEXT*> colThickness; | 
		
	
		
			
				|  |  |  |  |  |     std::vector<PCB_TEXT*> colColor; | 
		
	
		
			
				|  |  |  |  |  |     std::vector<PCB_TEXT*> colEpsilon; | 
		
	
		
			
				|  |  |  |  |  |     std::vector<PCB_TEXT*> colTanD; | 
		
	
		
			
				|  |  |  |  |  |     PCB_TEXT*              t; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( headStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( _( "Layer Name" ) ); | 
		
	
		
			
				|  |  |  |  |  |     colLayer.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( headStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( _( "Type" ) ); | 
		
	
		
			
				|  |  |  |  |  |     colType.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( headStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( _( "Material" ) ); | 
		
	
		
			
				|  |  |  |  |  |     colMaterial.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( headStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     if( m_frame->GetUserUnits() == EDA_UNITS::MILLIMETRES ) | 
		
	
		
			
				|  |  |  |  |  |         t->SetText( _( "Thickness (mm)" ) ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     else if( m_frame->GetUserUnits() == EDA_UNITS::INCHES ) | 
		
	
		
			
				|  |  |  |  |  |         t->SetText( _( "Thickness (mils)" ) ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     colThickness.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( headStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( _( "Color" ) ); | 
		
	
		
			
				|  |  |  |  |  |     colColor.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( headStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( _( "Epsilon R" ) ); | 
		
	
		
			
				|  |  |  |  |  |     colEpsilon.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( headStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( _( "Loss Tangent" ) ); | 
		
	
		
			
				|  |  |  |  |  |     colTanD.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     int i; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     for( i = 0; i < stackup.GetCount(); i++ ) | 
		
	
		
			
				|  |  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |  |         t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |         t->SetText( layers.at( i )->GetLayerName() ); | 
		
	
		
			
				|  |  |  |  |  |         colLayer.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |         t->SetText( layers.at( i )->GetTypeName() ); | 
		
	
		
			
				|  |  |  |  |  |         colType.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |         t->SetText( layers.at( i )->GetMaterial() ); | 
		
	
		
			
				|  |  |  |  |  |         colMaterial.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |         t->SetText( | 
		
	
		
			
				|  |  |  |  |  |                 StringFromValue( m_frame->GetUserUnits(), layers.at( i )->GetThickness(), true ) ); | 
		
	
		
			
				|  |  |  |  |  |         colThickness.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |         t->SetText( layers.at( i )->GetColor() ); | 
		
	
		
			
				|  |  |  |  |  |         colColor.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |         t->SetText( StringFromValue( EDA_UNITS::UNSCALED, layers.at( i )->GetEpsilonR(), false ) ); | 
		
	
		
			
				|  |  |  |  |  |         colEpsilon.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |         t->SetText( | 
		
	
		
			
				|  |  |  |  |  |                 StringFromValue( EDA_UNITS::UNSCALED, layers.at( i )->GetLossTangent(), false ) ); | 
		
	
		
			
				|  |  |  |  |  |         colTanD.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     texts.push_back( colLayer ); | 
		
	
		
			
				|  |  |  |  |  |     texts.push_back( colType ); | 
		
	
		
			
				|  |  |  |  |  |     texts.push_back( colMaterial ); | 
		
	
		
			
				|  |  |  |  |  |     texts.push_back( colThickness ); | 
		
	
		
			
				|  |  |  |  |  |     texts.push_back( colColor ); | 
		
	
		
			
				|  |  |  |  |  |     texts.push_back( colEpsilon ); | 
		
	
		
			
				|  |  |  |  |  |     texts.push_back( colTanD ); | 
		
	
		
			
				|  |  |  |  |  |     std::vector<BOARD_ITEM*> table = | 
		
	
		
			
				|  |  |  |  |  |             initTextTable( texts, aOrigin, aLayer, tableSize, true ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     if( aDrawNow ) | 
		
	
		
			
				|  |  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         for( auto item : table ) | 
		
	
		
			
				|  |  |  |  |  |             commit.Add( item ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         commit.Push( _( "Insert board stackup table" ) ); | 
		
	
		
			
				|  |  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     return table; | 
		
	
		
			
				|  |  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | std::vector<BOARD_ITEM*> DRAWING_TOOL::DrawBoardCharacteristics( | 
		
	
		
			
				|  |  |  |  |  |         wxPoint aOrigin, PCB_LAYER_ID aLayer, bool aDrawNow, wxPoint* tableSize ) | 
		
	
		
			
				|  |  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |  |     BOARD_COMMIT        commit( m_frame ); | 
		
	
		
			
				|  |  |  |  |  |     std::vector<BOARD_ITEM*> objects; | 
		
	
		
			
				|  |  |  |  |  |     BOARD_DESIGN_SETTINGS&   settings = m_frame->GetBoard()->GetDesignSettings(); | 
		
	
		
			
				|  |  |  |  |  |     BOARD_STACKUP&           stackup  = settings.GetStackupDescriptor(); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     wxPoint cursorPos = aOrigin; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     // Style : Section header
 | 
		
	
		
			
				|  |  |  |  |  |     PCB_TEXT* headStyle = new PCB_TEXT( static_cast<FOOTPRINT*>( m_frame->GetModel() ) ); | 
		
	
		
			
				|  |  |  |  |  |     headStyle->SetLayer( Eco1_User ); | 
		
	
		
			
				|  |  |  |  |  |     headStyle->SetTextSize( wxSize( 2000000, 2000000 ) ); | 
		
	
		
			
				|  |  |  |  |  |     headStyle->SetTextThickness( 4000000 ); | 
		
	
		
			
				|  |  |  |  |  |     headStyle->SetItalic( false ); | 
		
	
		
			
				|  |  |  |  |  |     headStyle->SetTextPos( wxPoint( 0, 0 ) ); | 
		
	
		
			
				|  |  |  |  |  |     headStyle->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT ); | 
		
	
		
			
				|  |  |  |  |  |     headStyle->SetVertJustify( GR_TEXT_VJUSTIFY_TOP ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     // Style : Data
 | 
		
	
		
			
				|  |  |  |  |  |     PCB_TEXT* dataStyle = new PCB_TEXT( static_cast<FOOTPRINT*>( m_frame->GetModel() ) ); | 
		
	
		
			
				|  |  |  |  |  |     dataStyle->SetLayer( Eco1_User ); | 
		
	
		
			
				|  |  |  |  |  |     dataStyle->SetTextSize( wxSize( 1500000, 1500000 ) ); | 
		
	
		
			
				|  |  |  |  |  |     dataStyle->SetTextThickness( 200000 ); | 
		
	
		
			
				|  |  |  |  |  |     dataStyle->SetItalic( false ); | 
		
	
		
			
				|  |  |  |  |  |     dataStyle->SetTextPos( wxPoint( 0, 0 ) ); | 
		
	
		
			
				|  |  |  |  |  |     dataStyle->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT ); | 
		
	
		
			
				|  |  |  |  |  |     dataStyle->SetVertJustify( GR_TEXT_VJUSTIFY_TOP ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     PCB_TEXT* t; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( headStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( _( "BOARD CHARACTERISTICS" ) ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetPosition( cursorPos ); | 
		
	
		
			
				|  |  |  |  |  |     objects.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     cursorPos.y = cursorPos.y + t->GetBoundingBox().GetHeight() | 
		
	
		
			
				|  |  |  |  |  |                   + From_User_Unit( EDA_UNITS::MILLIMETRES, 1.0 ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     std::vector<std::vector<PCB_TEXT*>> texts; | 
		
	
		
			
				|  |  |  |  |  |     std::vector<PCB_TEXT*>              colLabel1; | 
		
	
		
			
				|  |  |  |  |  |     std::vector<PCB_TEXT*>              colData1; | 
		
	
		
			
				|  |  |  |  |  |     std::vector<PCB_TEXT*>              colbreak; | 
		
	
		
			
				|  |  |  |  |  |     std::vector<PCB_TEXT*>              colLabel2; | 
		
	
		
			
				|  |  |  |  |  |     std::vector<PCB_TEXT*>              colData2; | 
		
	
		
			
				|  |  |  |  |  |     wxString                   text = wxString( "" ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( _( "Copper Layer Count: " ) ); | 
		
	
		
			
				|  |  |  |  |  |     colLabel1.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( StringFromValue( EDA_UNITS::UNSCALED, settings.GetCopperLayerCount(), false ) ); | 
		
	
		
			
				|  |  |  |  |  |     colData1.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     EDA_RECT size = m_frame->GetBoard()->ComputeBoundingBox( true ); | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( _( "Board overall dimensions: " ) ); | 
		
	
		
			
				|  |  |  |  |  |     colLabel1.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( wxString::Format( "%s x %s", | 
		
	
		
			
				|  |  |  |  |  |                 MessageTextFromValue( m_frame->GetUserUnits(), size.GetWidth(), true ), | 
		
	
		
			
				|  |  |  |  |  |                 MessageTextFromValue( m_frame->GetUserUnits(), size.GetHeight(), true ) ) ); | 
		
	
		
			
				|  |  |  |  |  |     colData1.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( _( "Min track/spacing: " ) ); | 
		
	
		
			
				|  |  |  |  |  |     colLabel1.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( wxString::Format( "%s / %s", | 
		
	
		
			
				|  |  |  |  |  |                 MessageTextFromValue( m_frame->GetUserUnits(), settings.m_TrackMinWidth, true ), | 
		
	
		
			
				|  |  |  |  |  |                 MessageTextFromValue( m_frame->GetUserUnits(), settings.m_MinClearance, true ) ) ); | 
		
	
		
			
				|  |  |  |  |  |     colData1.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( _( "Copper Finish: " ) ); | 
		
	
		
			
				|  |  |  |  |  |     colLabel1.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( stackup.m_FinishType ); | 
		
	
		
			
				|  |  |  |  |  |     colData1.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( _( "Castellated pads: " ) ); | 
		
	
		
			
				|  |  |  |  |  |     colLabel1.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( stackup.m_CastellatedPads ? _( "Yes" ) : _( "No" ) ); | 
		
	
		
			
				|  |  |  |  |  |     colData1.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( _( "Board Thickness: " ) ); | 
		
	
		
			
				|  |  |  |  |  |     colLabel2.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     text = MessageTextFromValue( m_frame->GetUserUnits(), settings.GetBoardThickness(), true ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( text ); | 
		
	
		
			
				|  |  |  |  |  |     colData2.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     // some empty cells
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     colLabel2.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     colData2.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( _( "Min hole diameter: " ) ); | 
		
	
		
			
				|  |  |  |  |  |     colLabel2.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     double holeSize = std::min( settings.m_MinThroughDrill, settings.m_ViasMinSize ); | 
		
	
		
			
				|  |  |  |  |  |     text            = MessageTextFromValue( m_frame->GetUserUnits(), holeSize, true ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( text ); | 
		
	
		
			
				|  |  |  |  |  |     colData2.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( _( "Impedance Control: " ) ); | 
		
	
		
			
				|  |  |  |  |  |     colLabel2.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( stackup.m_CastellatedPads ? _( "Yes" ) : _( "No" ) ); | 
		
	
		
			
				|  |  |  |  |  |     colData2.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( _( "Plated Board Edge: " ) ); | 
		
	
		
			
				|  |  |  |  |  |     colLabel2.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  |     t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() ); | 
		
	
		
			
				|  |  |  |  |  |     t->SetText( stackup.m_HasDielectricConstrains ? _( "Yes" ) : _( "No" ) ); | 
		
	
		
			
				|  |  |  |  |  |     colData2.push_back( t ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     texts.push_back( colLabel1 ); | 
		
	
		
			
				|  |  |  |  |  |     texts.push_back( colData1 ); | 
		
	
		
			
				|  |  |  |  |  |     texts.push_back( colbreak ); | 
		
	
		
			
				|  |  |  |  |  |     texts.push_back( colLabel2 ); | 
		
	
		
			
				|  |  |  |  |  |     texts.push_back( colData2 ); | 
		
	
		
			
				|  |  |  |  |  |     wxPoint tableSize2 = wxPoint(); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     std::vector<BOARD_ITEM*> table = initTextTable( texts, cursorPos, Eco1_User, &tableSize2, | 
		
	
		
			
				|  |  |  |  |  |                                                     false ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     for( auto item : table ) | 
		
	
		
			
				|  |  |  |  |  |         objects.push_back( item ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     if( aDrawNow ) | 
		
	
		
			
				|  |  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |  |         for( auto item : objects ) | 
		
	
		
			
				|  |  |  |  |  |             commit.Add( item ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         commit.Push( "Board Characteristics" ); | 
		
	
		
			
				|  |  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     tableSize->x = tableSize2.x; | 
		
	
		
			
				|  |  |  |  |  |     tableSize->y = cursorPos.y + tableSize2.y + From_User_Unit( EDA_UNITS::MILLIMETRES, 2.0 ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     return objects; | 
		
	
		
			
				|  |  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | int DRAWING_TOOL::InteractivePlaceWithPreview( const TOOL_EVENT& aEvent, std::vector<BOARD_ITEM*> aItems, | 
		
	
		
			
				|  |  |  |  |  |         std::vector<BOARD_ITEM*> aPreview, LSET* aLayers ) | 
		
	
		
			
				|  |  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |  |     if( m_isFootprintEditor && !m_frame->GetModel() ) | 
		
	
		
			
				|  |  |  |  |  |         return -1; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     bool cancelled = false; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     BOARD_COMMIT commit( m_frame ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true ); | 
		
	
		
			
				|  |  |  |  |  |     m_controls->ShowCursor( true ); | 
		
	
		
			
				|  |  |  |  |  |     // do not capture or auto-pan until we start placing the table
 | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TEXT ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     std::string tool = aEvent.GetCommandStr().get(); | 
		
	
		
			
				|  |  |  |  |  |     m_frame->PushTool( tool ); | 
		
	
		
			
				|  |  |  |  |  |     Activate(); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     // Prime the pump
 | 
		
	
		
			
				|  |  |  |  |  |     if( aEvent.HasPosition() ) | 
		
	
		
			
				|  |  |  |  |  |         m_toolMgr->RunAction( ACTIONS::cursorClick ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     // Main loop: keep receiving events
 | 
		
	
		
			
				|  |  |  |  |  |     wxPoint wxCursorPosition = wxPoint(); | 
		
	
		
			
				|  |  |  |  |  |     wxPoint wxPreviousCursorPosition = wxPoint( 0, 0 ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     view()->ClearPreview(); | 
		
	
		
			
				|  |  |  |  |  |     view()->InitPreview(); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     for( auto item : aPreview ) | 
		
	
		
			
				|  |  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |  |         item->Move( wxCursorPosition - wxPreviousCursorPosition ); | 
		
	
		
			
				|  |  |  |  |  |         view()->AddToPreview( item ); | 
		
	
		
			
				|  |  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     while( TOOL_EVENT* evt = Wait() ) | 
		
	
		
			
				|  |  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |  |         m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL ); | 
		
	
		
			
				|  |  |  |  |  |         VECTOR2D pos       = m_controls->GetCursorPosition(); | 
		
	
		
			
				|  |  |  |  |  |         wxCursorPosition.x = pos.x; | 
		
	
		
			
				|  |  |  |  |  |         wxCursorPosition.y = pos.y; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         if( evt->IsCancelInteractive() ) | 
		
	
		
			
				|  |  |  |  |  |         { | 
		
	
		
			
				|  |  |  |  |  |             m_frame->PopTool( tool ); | 
		
	
		
			
				|  |  |  |  |  |             cancelled = true; | 
		
	
		
			
				|  |  |  |  |  |             break; | 
		
	
		
			
				|  |  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         if( evt->IsMotion() ) | 
		
	
		
			
				|  |  |  |  |  |         { | 
		
	
		
			
				|  |  |  |  |  |             view()->ShowPreview( false ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |             for( auto item : aPreview ) | 
		
	
		
			
				|  |  |  |  |  |             { | 
		
	
		
			
				|  |  |  |  |  |                 item->Move( wxCursorPosition - wxPreviousCursorPosition ); | 
		
	
		
			
				|  |  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |             view()->ShowPreview( true ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |             wxPreviousCursorPosition.x = wxCursorPosition.x; | 
		
	
		
			
				|  |  |  |  |  |             wxPreviousCursorPosition.y = wxCursorPosition.y; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |  |         else if( evt->IsActivate() ) | 
		
	
		
			
				|  |  |  |  |  |         { | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |             if( evt->IsMoveTool() ) | 
		
	
		
			
				|  |  |  |  |  |             { | 
		
	
		
			
				|  |  |  |  |  |                 // leave ourselves on the stack so we come back after the move
 | 
		
	
		
			
				|  |  |  |  |  |                 cancelled = true; | 
		
	
		
			
				|  |  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |  |             else | 
		
	
		
			
				|  |  |  |  |  |             { | 
		
	
		
			
				|  |  |  |  |  |                 m_frame->PopTool( tool ); | 
		
	
		
			
				|  |  |  |  |  |                 cancelled = true; | 
		
	
		
			
				|  |  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |  |         else if( evt->IsClick( BUT_RIGHT ) ) | 
		
	
		
			
				|  |  |  |  |  |         { | 
		
	
		
			
				|  |  |  |  |  |             m_menu.ShowContextMenu( selection() ); | 
		
	
		
			
				|  |  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |  |         else if( evt->IsClick( BUT_LEFT ) ) | 
		
	
		
			
				|  |  |  |  |  |         { | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |             if( aLayers != NULL ) | 
		
	
		
			
				|  |  |  |  |  |             { | 
		
	
		
			
				|  |  |  |  |  |                 PCB_LAYER_ID targetLayer = frame()->SelectOneLayer( | 
		
	
		
			
				|  |  |  |  |  |                         PCB_LAYER_ID::PCB_LAYER_ID_COUNT, *aLayers, wxPoint( pos.x, pos.y ) ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |                 view()->ClearPreview(); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |                 if( targetLayer == PCB_LAYER_ID::PCB_LAYER_ID_COUNT ) | 
		
	
		
			
				|  |  |  |  |  |                 { | 
		
	
		
			
				|  |  |  |  |  |                     cancelled = true; | 
		
	
		
			
				|  |  |  |  |  |                     break; // The user did not pick any layer.
 | 
		
	
		
			
				|  |  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |                 for( auto item : aItems ) | 
		
	
		
			
				|  |  |  |  |  |                 { | 
		
	
		
			
				|  |  |  |  |  |                     if( item->Type() == PCB_GROUP_T ) | 
		
	
		
			
				|  |  |  |  |  |                     { | 
		
	
		
			
				|  |  |  |  |  |                         static_cast<PCB_GROUP*>( item )->SetLayerRecursive( targetLayer, 200 ); | 
		
	
		
			
				|  |  |  |  |  |                     } | 
		
	
		
			
				|  |  |  |  |  |                     else | 
		
	
		
			
				|  |  |  |  |  |                     { | 
		
	
		
			
				|  |  |  |  |  |                         item->SetLayer( targetLayer ); | 
		
	
		
			
				|  |  |  |  |  |                     } | 
		
	
		
			
				|  |  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |             for( auto item : aItems ) | 
		
	
		
			
				|  |  |  |  |  |             { | 
		
	
		
			
				|  |  |  |  |  |                 item->Move( wxCursorPosition ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |                 if( item->Type() == PCB_GROUP_T ) | 
		
	
		
			
				|  |  |  |  |  |                 { | 
		
	
		
			
				|  |  |  |  |  |                     static_cast<PCB_GROUP*>( item )->AddChildrenToCommit( commit ); | 
		
	
		
			
				|  |  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |  |                  | 
		
	
		
			
				|  |  |  |  |  |                 commit.Add( item ); | 
		
	
		
			
				|  |  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |             commit.Push( "Placing items" ); | 
		
	
		
			
				|  |  |  |  |  |             m_frame->PopTool( tool ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |             break; | 
		
	
		
			
				|  |  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         else | 
		
	
		
			
				|  |  |  |  |  |             evt->SetPassEvent(); | 
		
	
		
			
				|  |  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     view()->ClearPreview(); | 
		
	
		
			
				|  |  |  |  |  |     frame()->SetMsgPanel( board() ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     if( cancelled ) | 
		
	
		
			
				|  |  |  |  |  |         return -1; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | int DRAWING_TOOL::PlaceCharacteristics( const TOOL_EVENT& aEvent ) | 
		
	
		
			
				|  |  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |  |     wxPoint             tableSize = wxPoint(); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     LSET layerSet = ( layerSet.AllCuMask() | layerSet.AllTechMask() ); | 
		
	
		
			
				|  |  |  |  |  |     layerSet      = static_cast<LSET>( layerSet.set( Edge_Cuts ).set( Margin ) ); | 
		
	
		
			
				|  |  |  |  |  |     layerSet      = static_cast<LSET>( layerSet.reset( F_Fab ).reset( B_Fab ) ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     PCB_LAYER_ID layer      = m_frame->GetActiveLayer(); | 
		
	
		
			
				|  |  |  |  |  |     PCB_LAYER_ID savedLayer = layer; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     if( ( layerSet & LSET( layer ) ).count() ) // if layer is a forbidden layer
 | 
		
	
		
			
				|  |  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |  |         m_frame->SetActiveLayer( Cmts_User ); | 
		
	
		
			
				|  |  |  |  |  |         layer = Cmts_User; | 
		
	
		
			
				|  |  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     std::vector<BOARD_ITEM*> table     = DrawBoardCharacteristics( | 
		
	
		
			
				|  |  |  |  |  |             wxPoint( 0, 0 ), m_frame->GetActiveLayer(), false, &tableSize ); | 
		
	
		
			
				|  |  |  |  |  |     std::vector<BOARD_ITEM*>* preview = new std::vector<BOARD_ITEM*>; | 
		
	
		
			
				|  |  |  |  |  |     std::vector<BOARD_ITEM*>* items   = new std::vector<BOARD_ITEM*>; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     PCB_SHAPE* line1 = new PCB_SHAPE; | 
		
	
		
			
				|  |  |  |  |  |     PCB_SHAPE* line2 = new PCB_SHAPE; | 
		
	
		
			
				|  |  |  |  |  |     PCB_SHAPE* line3 = new PCB_SHAPE; | 
		
	
		
			
				|  |  |  |  |  |     PCB_SHAPE* line4 = new PCB_SHAPE; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     line1->SetStartX( 0 ); | 
		
	
		
			
				|  |  |  |  |  |     line1->SetStartY( 0 ); | 
		
	
		
			
				|  |  |  |  |  |     line1->SetEndX( tableSize.x ); | 
		
	
		
			
				|  |  |  |  |  |     line1->SetEndY( 0 ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     line2->SetStartX( 0 ); | 
		
	
		
			
				|  |  |  |  |  |     line2->SetStartY( 0 ); | 
		
	
		
			
				|  |  |  |  |  |     line2->SetEndX( 0 ); | 
		
	
		
			
				|  |  |  |  |  |     line2->SetEndY( tableSize.y ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     line3->SetStartX( tableSize.x ); | 
		
	
		
			
				|  |  |  |  |  |     line3->SetStartY( 0 ); | 
		
	
		
			
				|  |  |  |  |  |     line3->SetEndX( tableSize.x ); | 
		
	
		
			
				|  |  |  |  |  |     line3->SetEndY( tableSize.y ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     line4->SetStartX( 0 ); | 
		
	
		
			
				|  |  |  |  |  |     line4->SetStartY( tableSize.y ); | 
		
	
		
			
				|  |  |  |  |  |     line4->SetEndX( tableSize.x ); | 
		
	
		
			
				|  |  |  |  |  |     line4->SetEndY( tableSize.y ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     line1->SetLayer( m_frame->GetActiveLayer() ); | 
		
	
		
			
				|  |  |  |  |  |     line2->SetLayer( m_frame->GetActiveLayer() ); | 
		
	
		
			
				|  |  |  |  |  |     line3->SetLayer( m_frame->GetActiveLayer() ); | 
		
	
		
			
				|  |  |  |  |  |     line4->SetLayer( m_frame->GetActiveLayer() ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     preview->push_back( line1 ); | 
		
	
		
			
				|  |  |  |  |  |     preview->push_back( line2 ); | 
		
	
		
			
				|  |  |  |  |  |     preview->push_back( line3 ); | 
		
	
		
			
				|  |  |  |  |  |     preview->push_back( line4 ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     PCB_GROUP* group = new PCB_GROUP( m_board ); | 
		
	
		
			
				|  |  |  |  |  |     group->SetName("group-boardCharacteristics"); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     for( auto item : table ) | 
		
	
		
			
				|  |  |  |  |  |         group->AddItem( static_cast<BOARD_ITEM*>( item ) ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     items->push_back( static_cast<BOARD_ITEM*>( group ) ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     if( InteractivePlaceWithPreview( aEvent, *items, *preview, &layerSet ) == -1 ) | 
		
	
		
			
				|  |  |  |  |  |         m_frame->SetActiveLayer( savedLayer ); | 
		
	
		
			
				|  |  |  |  |  |     else | 
		
	
		
			
				|  |  |  |  |  |         m_frame->SetActiveLayer( table.front()->GetLayer() ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | int DRAWING_TOOL::PlaceStackup( const TOOL_EVENT& aEvent ) | 
		
	
		
			
				|  |  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |  |     wxPoint             tableSize = wxPoint(); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     LSET layerSet = ( layerSet.AllCuMask() | layerSet.AllTechMask() ); | 
		
	
		
			
				|  |  |  |  |  |     layerSet      = static_cast<LSET>( layerSet.set( Edge_Cuts ).set( Margin ) ); | 
		
	
		
			
				|  |  |  |  |  |     layerSet      = static_cast<LSET>( layerSet.reset( F_Fab ).reset( B_Fab ) ); | 
		
	
		
			
				|  |  |  |  |  |      | 
		
	
		
			
				|  |  |  |  |  |     PCB_LAYER_ID layer      = m_frame->GetActiveLayer(); | 
		
	
		
			
				|  |  |  |  |  |     PCB_LAYER_ID savedLayer = layer; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     if( ( layerSet & LSET( layer ) ).count() ) // if layer is a forbidden layer
 | 
		
	
		
			
				|  |  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |  |         m_frame->SetActiveLayer( Cmts_User ); | 
		
	
		
			
				|  |  |  |  |  |         layer = Cmts_User; | 
		
	
		
			
				|  |  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     std::vector<BOARD_ITEM*> table     = DrawSpecificationStackup( | 
		
	
		
			
				|  |  |  |  |  |             wxPoint( 0, 0 ), m_frame->GetActiveLayer(), false, &tableSize ); | 
		
	
		
			
				|  |  |  |  |  |     std::vector<BOARD_ITEM*>* preview = new std::vector<BOARD_ITEM*>; | 
		
	
		
			
				|  |  |  |  |  |     std::vector<BOARD_ITEM*>* items   = new std::vector<BOARD_ITEM*>; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     PCB_SHAPE* line1 = new PCB_SHAPE; | 
		
	
		
			
				|  |  |  |  |  |     PCB_SHAPE* line2 = new PCB_SHAPE; | 
		
	
		
			
				|  |  |  |  |  |     PCB_SHAPE* line3 = new PCB_SHAPE; | 
		
	
		
			
				|  |  |  |  |  |     PCB_SHAPE* line4 = new PCB_SHAPE; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     line1->SetStartX( 0 ); | 
		
	
		
			
				|  |  |  |  |  |     line1->SetStartY( 0 ); | 
		
	
		
			
				|  |  |  |  |  |     line1->SetEndX( tableSize.x ); | 
		
	
		
			
				|  |  |  |  |  |     line1->SetEndY( 0 ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     line2->SetStartX( 0 ); | 
		
	
		
			
				|  |  |  |  |  |     line2->SetStartY( 0 ); | 
		
	
		
			
				|  |  |  |  |  |     line2->SetEndX( 0 ); | 
		
	
		
			
				|  |  |  |  |  |     line2->SetEndY( tableSize.y ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     line3->SetStartX( tableSize.x ); | 
		
	
		
			
				|  |  |  |  |  |     line3->SetStartY( 0 ); | 
		
	
		
			
				|  |  |  |  |  |     line3->SetEndX( tableSize.x ); | 
		
	
		
			
				|  |  |  |  |  |     line3->SetEndY( tableSize.y ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     line4->SetStartX( 0 ); | 
		
	
		
			
				|  |  |  |  |  |     line4->SetStartY( tableSize.y ); | 
		
	
		
			
				|  |  |  |  |  |     line4->SetEndX( tableSize.x ); | 
		
	
		
			
				|  |  |  |  |  |     line4->SetEndY( tableSize.y ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     line1->SetLayer( m_frame->GetActiveLayer() ); | 
		
	
		
			
				|  |  |  |  |  |     line2->SetLayer( m_frame->GetActiveLayer() ); | 
		
	
		
			
				|  |  |  |  |  |     line3->SetLayer( m_frame->GetActiveLayer() ); | 
		
	
		
			
				|  |  |  |  |  |     line4->SetLayer( m_frame->GetActiveLayer() ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     preview->push_back( line1 ); | 
		
	
		
			
				|  |  |  |  |  |     preview->push_back( line2 ); | 
		
	
		
			
				|  |  |  |  |  |     preview->push_back( line3 ); | 
		
	
		
			
				|  |  |  |  |  |     preview->push_back( line4 ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     PCB_GROUP* group = new PCB_GROUP( m_board ); | 
		
	
		
			
				|  |  |  |  |  |     group->SetName("group-boardStackUp"); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     for( auto item : table ) | 
		
	
		
			
				|  |  |  |  |  |         group->AddItem( item ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     items->push_back( static_cast<BOARD_ITEM*>( group ) ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     if( InteractivePlaceWithPreview( aEvent, *items, *preview, &layerSet ) == -1 ) | 
		
	
		
			
				|  |  |  |  |  |         m_frame->SetActiveLayer( savedLayer ); | 
		
	
		
			
				|  |  |  |  |  |     else | 
		
	
		
			
				|  |  |  |  |  |         m_frame->SetActiveLayer( table.front()->GetLayer() ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  |  | } | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  | int DRAWING_TOOL::DrawLine( const TOOL_EVENT& aEvent ) |  |  | int DRAWING_TOOL::DrawLine( const TOOL_EVENT& aEvent ) | 
		
	
		
			
				|  |  | { |  |  | { | 
		
	
	
		
			
				|  | @ -1356,14 +2103,7 @@ bool DRAWING_TOOL::drawSegment( const std::string& aTool, PCB_SHAPE** aGraphic, | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |         grid.SetSnap( !evt->Modifier( MD_SHIFT ) ); |  |  |         grid.SetSnap( !evt->Modifier( MD_SHIFT ) ); | 
		
	
		
			
				|  |  |         grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->Modifier( MD_ALT ) ); |  |  |         grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->Modifier( MD_ALT ) ); | 
		
	
		
			
				|  |  | 
 |  |  |  | 
		
	
		
			
				|  |  |         // The first point in a circle should be able to snap to items on all layers because it doesn't
 |  |  |  | 
		
	
		
			
				|  |  |         // overlap the graphical line
 |  |  |  | 
		
	
		
			
				|  |  |         if( !started && graphic && shape == S_CIRCLE ) |  |  |  | 
		
	
		
			
				|  |  |             cursorPos = grid.BestSnapAnchor( m_controls->GetMousePosition(), nullptr ); |  |  |  | 
		
	
		
			
				|  |  |         else |  |  |  | 
		
	
		
			
				|  |  |             cursorPos = grid.BestSnapAnchor( m_controls->GetMousePosition(), m_frame->GetActiveLayer() ); |  |  |  | 
		
	
		
			
				|  |  | 
 |  |  |  | 
		
	
		
			
				|  |  |  |  |  |         cursorPos = grid.BestSnapAnchor( m_controls->GetMousePosition(), m_frame->GetActiveLayer() ); | 
		
	
		
			
				|  |  |         m_controls->ForceCursorPosition( true, cursorPos ); |  |  |         m_controls->ForceCursorPosition( true, cursorPos ); | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |         // 45 degree angle constraint enabled with an option and toggled with Ctrl
 |  |  |         // 45 degree angle constraint enabled with an option and toggled with Ctrl
 | 
		
	
	
		
			
				|  | @ -1666,15 +2406,7 @@ bool DRAWING_TOOL::drawArc( const std::string& aTool, PCB_SHAPE** aGraphic, bool | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |         grid.SetSnap( !evt->Modifier( MD_SHIFT ) ); |  |  |         grid.SetSnap( !evt->Modifier( MD_SHIFT ) ); | 
		
	
		
			
				|  |  |         grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->Modifier( MD_ALT ) ); |  |  |         grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->Modifier( MD_ALT ) ); | 
		
	
		
			
				|  |  |         VECTOR2I cursorPos; |  |  |  | 
		
	
		
			
				|  |  | 
 |  |  |  | 
		
	
		
			
				|  |  |         // The first point in an arc should be able to snap to items on all layers because it doesn't
 |  |  |  | 
		
	
		
			
				|  |  |         // overlap the graphical line
 |  |  |  | 
		
	
		
			
				|  |  |         if( firstPoint ) |  |  |  | 
		
	
		
			
				|  |  |             cursorPos = grid.BestSnapAnchor( m_controls->GetMousePosition(), graphic ); |  |  |  | 
		
	
		
			
				|  |  |         else |  |  |  | 
		
	
		
			
				|  |  |             cursorPos = grid.BestSnapAnchor( m_controls->GetMousePosition(), nullptr ); |  |  |  | 
		
	
		
			
				|  |  | 
 |  |  |  | 
		
	
		
			
				|  |  |  |  |  |         VECTOR2I cursorPos = grid.BestSnapAnchor( m_controls->GetMousePosition(), graphic ); | 
		
	
		
			
				|  |  |         m_controls->ForceCursorPosition( true, cursorPos ); |  |  |         m_controls->ForceCursorPosition( true, cursorPos ); | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |         auto cleanup = |  |  |         auto cleanup = | 
		
	
	
		
			
				|  | @ -2512,6 +3244,9 @@ const unsigned int DRAWING_TOOL::WIDTH_STEP = Millimeter2iu( 0.1 ); | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  | void DRAWING_TOOL::setTransitions() |  |  | void DRAWING_TOOL::setTransitions() | 
		
	
		
			
				|  |  | { |  |  | { | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     Go( &DRAWING_TOOL::PlaceStackup,          PCB_ACTIONS::placeStackup.MakeEvent() ); | 
		
	
		
			
				|  |  |  |  |  |     Go( &DRAWING_TOOL::PlaceCharacteristics,  PCB_ACTIONS::placeCharacteristics.MakeEvent() ); | 
		
	
		
			
				|  |  |     Go( &DRAWING_TOOL::DrawLine,              PCB_ACTIONS::drawLine.MakeEvent() ); |  |  |     Go( &DRAWING_TOOL::DrawLine,              PCB_ACTIONS::drawLine.MakeEvent() ); | 
		
	
		
			
				|  |  |     Go( &DRAWING_TOOL::DrawZone,              PCB_ACTIONS::drawPolygon.MakeEvent() ); |  |  |     Go( &DRAWING_TOOL::DrawZone,              PCB_ACTIONS::drawPolygon.MakeEvent() ); | 
		
	
		
			
				|  |  |     Go( &DRAWING_TOOL::DrawRectangle,         PCB_ACTIONS::drawRectangle.MakeEvent() ); |  |  |     Go( &DRAWING_TOOL::DrawRectangle,         PCB_ACTIONS::drawRectangle.MakeEvent() ); | 
		
	
	
		
			
				|  | 
 |