mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-15 02:33:15 +02:00
Board BBox uses the visible size of the board, which includes edge cut thickness. This is not appropriate for the Board characteristics. Using the outline polygon gives accurate results and falls back to a bounding box in the case where the outline is invalid Fixes https://gitlab.com/kicad/code/kicad/issues/10972 (cherry picked from commit 54f621c570174e08dbc3359effb46ae66cf275c6)
850 lines
27 KiB
C++
850 lines
27 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2014-2017 CERN
|
|
* Copyright (C) 2018-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, you may find one here:
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include "drawing_tool.h"
|
|
#include "pcb_actions.h"
|
|
#include <pcb_edit_frame.h>
|
|
#include <view/view.h>
|
|
#include <tool/tool_manager.h>
|
|
#include <tools/pcb_actions.h>
|
|
#include <tools/tool_event_utils.h>
|
|
#include <tools/drawing_tool.h>
|
|
#include <board_commit.h>
|
|
#include <scoped_set_reset.h>
|
|
#include <bitmaps.h>
|
|
#include <painter.h>
|
|
#include <board.h>
|
|
#include <board_design_settings.h>
|
|
#include <footprint.h>
|
|
#include <fp_shape.h>
|
|
#include <pcb_group.h>
|
|
#include <pcb_text.h>
|
|
#include <string_utils.h>
|
|
#include <wx/utils.h>
|
|
|
|
|
|
using SCOPED_DRAW_MODE = SCOPED_SET_RESET<DRAWING_TOOL::MODE>;
|
|
|
|
|
|
static 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 table lines.
|
|
//
|
|
// +--------------------------------+
|
|
// | ^ |
|
|
// | | ymargin |
|
|
// | v |
|
|
// |<------->TEXT_TEXT_TEXT<------->|
|
|
// | xmargin ^ xmargin |
|
|
// | | ymargin |
|
|
// | v |
|
|
// +--------------------------------+
|
|
//
|
|
|
|
int xmargin = Millimeter2iu( 0.75 );
|
|
int ymargin = Millimeter2iu( 0.75 );
|
|
|
|
// 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( const std::vector<PCB_TEXT*>& col : aContent )
|
|
{
|
|
j = 0;
|
|
|
|
if( i >= nbCols )
|
|
break;
|
|
|
|
for( const PCB_TEXT* 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( std::vector<PCB_TEXT*>& col : aContent )
|
|
{
|
|
j = 0;
|
|
|
|
if( i >= nbCols )
|
|
break;
|
|
|
|
pos.y = origin.y + ymargin;
|
|
|
|
for( PCB_TEXT* 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( const wxPoint& aOrigin,
|
|
PCB_LAYER_ID aLayer,
|
|
bool aDrawNow,
|
|
wxPoint* tableSize )
|
|
{
|
|
BOARD_COMMIT commit( m_frame );
|
|
std::vector<std::vector<PCB_TEXT*>> texts;
|
|
|
|
// Style : Header
|
|
std::unique_ptr<PCB_TEXT> headStyle =
|
|
std::make_unique<PCB_TEXT>( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
|
|
headStyle->SetLayer( Eco1_User );
|
|
headStyle->SetTextSize( wxSize( Millimeter2iu( 1.5 ), Millimeter2iu( 1.5 ) ) );
|
|
headStyle->SetTextThickness( Millimeter2iu( 0.3 ) );
|
|
headStyle->SetItalic( false );
|
|
headStyle->SetTextPos( wxPoint( 0, 0 ) );
|
|
headStyle->SetText( _( "Layer" ) );
|
|
headStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
|
|
headStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
|
|
|
|
// Style : data
|
|
std::unique_ptr<PCB_TEXT> dataStyle =
|
|
std::make_unique<PCB_TEXT>( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
|
|
dataStyle->SetLayer( Eco1_User );
|
|
dataStyle->SetTextSize( wxSize( Millimeter2iu( 1.5 ), Millimeter2iu( 1.5 ) ) );
|
|
dataStyle->SetTextThickness( Millimeter2iu( 0.1 ) );
|
|
dataStyle->SetItalic( false );
|
|
dataStyle->SetTextPos( wxPoint( 0, 0 ) );
|
|
dataStyle->SetText( _( "Layer" ) );
|
|
dataStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
|
|
dataStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
|
|
|
|
//Get Layer names
|
|
BOARD_DESIGN_SETTINGS& dsnSettings = m_frame->GetDesignSettings();
|
|
BOARD_STACKUP& stackup = dsnSettings.GetStackupDescriptor();
|
|
stackup.SynchronizeWithBoard( &dsnSettings );
|
|
|
|
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() );
|
|
|
|
switch( m_frame->GetUserUnits() )
|
|
{
|
|
case EDA_UNITS::MILLIMETRES: t->SetText( _( "Thickness (mm)" ) ); break;
|
|
case EDA_UNITS::INCHES: t->SetText( _( "Thickness (inches)" ) ); break;
|
|
case EDA_UNITS::MILS: t->SetText( _( "Thickness (mils)" ) ); break;
|
|
default: wxFAIL_MSG( wxT( "Unhandled unit type" ) );
|
|
}
|
|
|
|
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 );
|
|
|
|
for( int i = 0; i < stackup.GetCount(); i++ )
|
|
{
|
|
BOARD_STACKUP_ITEM* stackup_item = layers.at( i );
|
|
|
|
for( int j = 0; j < stackup_item->GetSublayersCount(); j++ )
|
|
{
|
|
t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
|
|
|
|
// Layer names are empty until we close at least once the board setup dialog.
|
|
// If the user did not open the dialog, then get the names from the board.
|
|
// But dielectric layer names will be missing.
|
|
// In this case, for dielectric, a dummy name will be used
|
|
if( stackup_item->GetLayerName().IsEmpty() )
|
|
{
|
|
wxString ly_name;
|
|
|
|
if( IsValidLayer( stackup_item->GetBrdLayerId() ) )
|
|
ly_name = m_frame->GetBoard()->GetLayerName( stackup_item->GetBrdLayerId() );
|
|
|
|
if( ly_name.IsEmpty() && stackup_item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
|
|
ly_name = _( "Dielectric" );
|
|
|
|
t->SetText( ly_name );
|
|
}
|
|
else
|
|
t->SetText( stackup_item->GetLayerName() );
|
|
|
|
colLayer.push_back( t );
|
|
|
|
t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
|
|
t->SetText( stackup_item->GetTypeName() );
|
|
colType.push_back( t );
|
|
|
|
t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
|
|
t->SetText( stackup_item->GetMaterial( j ) );
|
|
colMaterial.push_back( t );
|
|
|
|
t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
|
|
t->SetText( StringFromValue( m_frame->GetUserUnits(), stackup_item->GetThickness( j ),
|
|
true ) );
|
|
colThickness.push_back( t );
|
|
|
|
t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
|
|
t->SetText( stackup_item->GetColor() );
|
|
colColor.push_back( t );
|
|
|
|
t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
|
|
t->SetText( StringFromValue( EDA_UNITS::UNSCALED, stackup_item->GetEpsilonR( j ),
|
|
false ) );
|
|
colEpsilon.push_back( t );
|
|
|
|
t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
|
|
t->SetText( StringFromValue( EDA_UNITS::UNSCALED, stackup_item->GetLossTangent( j ),
|
|
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( BOARD_ITEM* item : table )
|
|
commit.Add( item );
|
|
|
|
commit.Push( _( "Insert board stackup table" ) );
|
|
}
|
|
|
|
return table;
|
|
}
|
|
|
|
|
|
std::vector<BOARD_ITEM*> DRAWING_TOOL::DrawBoardCharacteristics( const 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
|
|
std::unique_ptr<PCB_TEXT> headStyle =
|
|
std::make_unique<PCB_TEXT>( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
|
|
headStyle->SetLayer( Eco1_User );
|
|
headStyle->SetTextSize( wxSize( Millimeter2iu( 2.0 ), Millimeter2iu( 2.0 ) ) );
|
|
headStyle->SetTextThickness( Millimeter2iu( 0.4 ) );
|
|
headStyle->SetItalic( false );
|
|
headStyle->SetTextPos( wxPoint( 0, 0 ) );
|
|
headStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
|
|
headStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
|
|
|
|
// Style : Data
|
|
std::unique_ptr<PCB_TEXT> dataStyle =
|
|
std::make_unique<PCB_TEXT>( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
|
|
dataStyle->SetLayer( Eco1_User );
|
|
dataStyle->SetTextSize( wxSize( Millimeter2iu( 1.5 ), Millimeter2iu( 1.5 ) ) );
|
|
dataStyle->SetTextThickness( Millimeter2iu( 0.2 ) );
|
|
dataStyle->SetItalic( false );
|
|
dataStyle->SetTextPos( wxPoint( 0, 0 ) );
|
|
dataStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
|
|
dataStyle->SetVertJustify( GR_TEXT_V_ALIGN_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;
|
|
|
|
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 );
|
|
|
|
SHAPE_POLY_SET outline;
|
|
m_frame->GetBoard()->GetBoardPolygonOutlines( outline );
|
|
BOX2I size = outline.BBox();
|
|
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( wxT( "%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( wxT( "%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_HasDielectricConstrains ? _( "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_EdgePlating ? _( "Yes" ) : _( "No" ) );
|
|
colData2.push_back( t );
|
|
|
|
t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
|
|
t->SetText( _( "Edge card connectors: " ) );
|
|
colLabel1.push_back( t );
|
|
|
|
t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
|
|
switch( stackup.m_EdgeConnectorConstraints )
|
|
{
|
|
case BS_EDGE_CONNECTOR_NONE: t->SetText( _( "No" ) ); break;
|
|
case BS_EDGE_CONNECTOR_IN_USE: t->SetText( _( "Yes" ) ); break;
|
|
case BS_EDGE_CONNECTOR_BEVELLED: t->SetText( _( "Yes, Bevelled" ) ); break;
|
|
}
|
|
colData1.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( BOARD_ITEM* item : table )
|
|
objects.push_back( item );
|
|
|
|
if( aDrawNow )
|
|
{
|
|
for( auto item : objects )
|
|
commit.Add( item );
|
|
|
|
commit.Push( wxT( "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 );
|
|
|
|
// 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();
|
|
// Must be done after Activate() so that it gets set into the correct context
|
|
m_controls->ShowCursor( true );
|
|
|
|
// 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( BOARD_ITEM* 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 != nullptr )
|
|
{
|
|
PCB_LAYER_ID destLayer = frame()->SelectOneLayer( PCB_LAYER_ID::PCB_LAYER_ID_COUNT,
|
|
*aLayers, wxGetMousePosition() );
|
|
|
|
view()->ClearPreview();
|
|
|
|
if( destLayer == PCB_LAYER_ID::UNDEFINED_LAYER )
|
|
{
|
|
// The user did not pick any layer.
|
|
m_frame->PopTool( tool );
|
|
cancelled = true;
|
|
break;
|
|
}
|
|
|
|
for( BOARD_ITEM* item : aItems )
|
|
{
|
|
if( item->Type() == PCB_GROUP_T )
|
|
static_cast<PCB_GROUP*>( item )->SetLayerRecursive( destLayer, 200 );
|
|
else
|
|
item->SetLayer( destLayer );
|
|
}
|
|
}
|
|
|
|
for( BOARD_ITEM* item : aItems )
|
|
{
|
|
item->Move( wxCursorPosition );
|
|
|
|
if( item->Type() == PCB_GROUP_T )
|
|
static_cast<PCB_GROUP*>( item )->AddChildrenToCommit( commit );
|
|
|
|
commit.Add( item );
|
|
}
|
|
|
|
commit.Push( wxT( "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;
|
|
std::vector<BOARD_ITEM*> items;
|
|
|
|
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;
|
|
std::vector<BOARD_ITEM*> items;
|
|
|
|
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( BOARD_ITEM* 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;
|
|
}
|