diff --git a/common/eda_units.cpp b/common/eda_units.cpp index 309585f2bd..cdc61fc335 100644 --- a/common/eda_units.cpp +++ b/common/eda_units.cpp @@ -135,7 +135,7 @@ wxString EDA_UNIT_UTILS::GetText( EDA_UNITS aUnits, EDA_DATA_TYPE aType ) case EDA_UNITS::CM: label = wxT( " cm" ); break; case EDA_UNITS::DEGREES: label = wxT( "°" ); break; case EDA_UNITS::MILS: label = wxT( " mils" ); break; - case EDA_UNITS::INCH: label = wxT( " in" ); break; + case EDA_UNITS::INCH: label = wxT( " in" ); break; case EDA_UNITS::PERCENT: label = wxT( "%" ); break; case EDA_UNITS::UNSCALED: break; default: UNIMPLEMENTED_FOR( wxS( "Unknown units" ) ); break; diff --git a/common/string_utils.cpp b/common/string_utils.cpp index ac2d4ebe65..0d1c9638b0 100644 --- a/common/string_utils.cpp +++ b/common/string_utils.cpp @@ -407,6 +407,27 @@ wxString TitleCaps( const wxString& aString ) } +wxString InitialCaps( const wxString& aString ) +{ + wxArrayString words; + wxString result; + + wxStringSplit( aString, words, ' ' ); + + result.reserve( aString.length() ); + + for( const wxString& word : words ) + { + if( result.IsEmpty() ) + result += word.Capitalize(); + else + result += wxT( " " ) + word.Lower(); + } + + return result; +} + + int ReadDelimitedText( wxString* aDest, const char* aSource ) { std::string utf8; // utf8 but without escapes and quotes. diff --git a/include/string_utils.h b/include/string_utils.h index c49dc6376b..7a618da90a 100644 --- a/include/string_utils.h +++ b/include/string_utils.h @@ -83,6 +83,11 @@ KICOMMON_API wxString PrettyPrintForMenu( const wxString& aString ); */ KICOMMON_API wxString TitleCaps( const wxString& aString ); +/** + * Capitalize only the first word. + */ +KICOMMON_API wxString InitialCaps( const wxString& aString ); + /** * Copy bytes from @a aSource delimited string segment to @a aDest buffer. * diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 0041b70bed..21d2869e9a 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -386,7 +386,6 @@ set( PCBNEW_CLASS_SRCS tools/board_reannotate_tool.cpp tools/convert_tool.cpp tools/drawing_tool.cpp - tools/drawing_stackup_table_tool.cpp tools/drc_tool.cpp tools/edit_tool.cpp tools/edit_tool_move_fct.cpp diff --git a/pcbnew/pcb_table.cpp b/pcbnew/pcb_table.cpp index b61a65fb3f..5d99bb1fbf 100644 --- a/pcbnew/pcb_table.cpp +++ b/pcbnew/pcb_table.cpp @@ -178,6 +178,54 @@ void PCB_TABLE::Normalize() } +void PCB_TABLE::Autosize() +{ + std::vector> extents; + + for( int row = 0; row < GetRowCount(); ++row ) + { + extents.push_back( std::vector() ); + + for( int col = 0; col < GetColCount(); ++col ) + { + SHAPE_POLY_SET textPoly; + GetCell( row, col )->TransformTextToPolySet( textPoly, 0, ARC_LOW_DEF, ERROR_INSIDE ); + extents[row].push_back( textPoly.BBox() ); + } + } + + for( int col = 0; col < GetColCount(); ++col ) + { + int colWidth = 0; + + for( int row = 0; row < GetRowCount(); ++row ) + { + PCB_TABLECELL* cell = GetCell( row, col ); + int margins = cell->GetMarginLeft() + cell->GetMarginRight(); + colWidth = std::max( colWidth, extents[row][col].GetWidth() + ( margins * 1.5 ) ); + } + + SetColWidth( col, colWidth ); + } + + for( int row = 0; row < GetRowCount(); ++row ) + { + int rowHeight = 0; + + for( int col = 0; col < GetColCount(); ++col ) + { + PCB_TABLECELL* cell = GetCell( row, col ); + int margins = cell->GetMarginLeft() + cell->GetMarginRight(); + rowHeight = std::max( rowHeight, (int) extents[row][col].GetHeight() + margins ); + } + + SetRowHeight( row, rowHeight ); + } + + Normalize(); +} + + void PCB_TABLE::Move( const VECTOR2I& aMoveVector ) { for( PCB_TABLECELL* cell : m_cells ) diff --git a/pcbnew/pcb_table.h b/pcbnew/pcb_table.h index 8f43e4f9be..8228d9cab2 100644 --- a/pcbnew/pcb_table.h +++ b/pcbnew/pcb_table.h @@ -196,6 +196,8 @@ public: void Normalize() override; + void Autosize(); + void Move( const VECTOR2I& aMoveVector ) override; void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override; diff --git a/pcbnew/pcb_tablecell.cpp b/pcbnew/pcb_tablecell.cpp index 7313e96053..b5e6ff4bc1 100644 --- a/pcbnew/pcb_tablecell.cpp +++ b/pcbnew/pcb_tablecell.cpp @@ -36,6 +36,9 @@ PCB_TABLECELL::PCB_TABLECELL( BOARD_ITEM* aParent ) : { if( IsBackLayer( aParent->GetLayer() ) ) SetMirrored( true ); + + SetRectangleHeight( std::numeric_limits::max() / 2 ); + SetRectangleWidth( std::numeric_limits::max() / 2 ); } diff --git a/pcbnew/tools/drawing_stackup_table_tool.cpp b/pcbnew/tools/drawing_stackup_table_tool.cpp deleted file mode 100644 index aa746d704b..0000000000 --- a/pcbnew/tools/drawing_stackup_table_tool.cpp +++ /dev/null @@ -1,819 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2014-2017 CERN - * Copyright The 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 -#include "pcb_actions.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -using SCOPED_DRAW_MODE = SCOPED_SET_RESET; - - -static std::vector initTextTable( std::vector> aContent, - VECTOR2I origin, PCB_LAYER_ID aLayer, - VECTOR2I* aTableSize, bool aDrawFrame = true ) -{ - int i; - int j; - - int nbCols = aContent.size(); - int nbRows = 0; - - for( const std::vector& col : aContent ) - nbRows = std::max( nbRows, static_cast( 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 table; - - // xmargin and ymargin are margins between the text and the table lines. - // - // +--------------------------------+ - // | ^ | - // | | ymargin | - // | v | - // |<------->TEXT_TEXT_TEXT<------->| - // | xmargin ^ xmargin | - // | | ymargin | - // | v | - // +--------------------------------+ - // - - int xmargin = pcbIUScale.mmToIU( 0.75 ); - int ymargin = pcbIUScale.mmToIU( 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& 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->SetStart( VECTOR2I( origin.x, y ) ); - line->SetEnd( VECTOR2I( origin.x + width, y ) ); - y += rowHeight[i]; - table.push_back( line ); - } - - line = new PCB_SHAPE; - line->SetLayer( aLayer ); - line->SetStart( VECTOR2I( origin.x, y ) ); - line->SetEnd( VECTOR2I( origin.x + width, y ) ); - table.push_back( line ); - int x = origin.x; - - for( i = 0; i < nbCols; i++ ) - { - line = new PCB_SHAPE; - line->SetLayer( aLayer ); - line->SetStart( VECTOR2I( x, origin.y ) ); - line->SetEnd( VECTOR2I( x, origin.y + height ) ); - x += colWidth[i]; - table.push_back( line ); - } - - line = new PCB_SHAPE; - line->SetLayer( aLayer ); - line->SetStart( VECTOR2I( x, origin.y ) ); - line->SetEnd( VECTOR2I( x, origin.y + height ) ); - table.push_back( line ); - } - - //Now add the text - i = 0; - VECTOR2I pos( origin.x + xmargin, origin.y + ymargin ); - - for( std::vector& 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 DRAWING_TOOL::DrawSpecificationStackup( const VECTOR2I& aOrigin, - PCB_LAYER_ID aLayer, - bool aDrawNow, - VECTOR2I* tableSize ) -{ - BOARD_COMMIT commit( m_frame ); - FOOTPRINT* footprint = static_cast( m_frame->GetModel() ); - - std::vector> texts; - - // Style : Header - std::unique_ptr headStyle = std::make_unique( footprint ); - headStyle->SetLayer( Eco1_User ); - headStyle->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) ); - headStyle->SetTextThickness( pcbIUScale.mmToIU( 0.3 ) ); - headStyle->SetItalic( false ); - headStyle->SetTextPos( VECTOR2I( 0, 0 ) ); - headStyle->SetText( _( "Layer" ) ); - headStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); - headStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP ); - - // Style : data - std::unique_ptr dataStyle = std::make_unique( footprint ); - dataStyle->SetLayer( Eco1_User ); - dataStyle->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) ); - dataStyle->SetTextThickness( pcbIUScale.mmToIU( 0.1 ) ); - dataStyle->SetItalic( false ); - dataStyle->SetTextPos( VECTOR2I( 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 layers = stackup.GetList(); - - std::vector colLayer; - std::vector colType; - std::vector colMaterial; - std::vector colThickness; - std::vector colColor; - std::vector colEpsilon; - std::vector colTanD; - PCB_TEXT* t; - - t = static_cast( headStyle->Duplicate() ); - t->SetText( _( "Layer Name" ) ); - colLayer.push_back( t ); - - t = static_cast( headStyle->Duplicate() ); - t->SetText( _( "Type" ) ); - colType.push_back( t ); - - t = static_cast( headStyle->Duplicate() ); - t->SetText( _( "Material" ) ); - colMaterial.push_back( t ); - - t = static_cast( headStyle->Duplicate() ); - - switch( m_frame->GetUserUnits() ) - { - case EDA_UNITS::MM: t->SetText( _( "Thickness (mm)" ) ); break; - case EDA_UNITS::INCH: 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( headStyle->Duplicate() ); - t->SetText( _( "Color" ) ); - colColor.push_back( t ); - - t = static_cast( headStyle->Duplicate() ); - t->SetText( _( "Epsilon R" ) ); - colEpsilon.push_back( t ); - - t = static_cast( 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 sublayer_id = 0; sublayer_id < stackup_item->GetSublayersCount(); sublayer_id++ ) - { - t = static_cast( 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( dataStyle->Duplicate() ); - t->SetText( stackup_item->GetTypeName() ); - colType.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( stackup_item->GetMaterial( sublayer_id ) ); - colMaterial.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( m_frame->StringFromValue( stackup_item->GetThickness( sublayer_id ), true ) ); - colThickness.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( stackup_item->GetColor( sublayer_id ) ); - colColor.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( EDA_UNIT_UTILS::UI::StringFromValue( unityScale, EDA_UNITS::UNSCALED, - stackup_item->GetEpsilonR( sublayer_id ), false ) ); - colEpsilon.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( EDA_UNIT_UTILS::UI::StringFromValue( unityScale, EDA_UNITS::UNSCALED, - stackup_item->GetLossTangent( sublayer_id ), 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 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 DRAWING_TOOL::DrawBoardCharacteristics( const VECTOR2I& aOrigin, - PCB_LAYER_ID aLayer, - bool aDrawNow, - VECTOR2I* tableSize ) -{ - BOARD_COMMIT commit( m_frame ); - std::vector objects; - BOARD_DESIGN_SETTINGS& settings = m_frame->GetBoard()->GetDesignSettings(); - BOARD_STACKUP& stackup = settings.GetStackupDescriptor(); - - VECTOR2I cursorPos = aOrigin; - - // Style : Section header - std::unique_ptr headStyle = - std::make_unique( static_cast( m_frame->GetModel() ) ); - headStyle->SetLayer( Eco1_User ); - headStyle->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 2.0 ), pcbIUScale.mmToIU( 2.0 ) ) ); - headStyle->SetTextThickness( pcbIUScale.mmToIU( 0.4 ) ); - headStyle->SetItalic( false ); - headStyle->SetTextPos( VECTOR2I( 0, 0 ) ); - headStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); - headStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP ); - - // Style : Data - std::unique_ptr dataStyle = - std::make_unique( static_cast( m_frame->GetModel() ) ); - dataStyle->SetLayer( Eco1_User ); - dataStyle->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) ); - dataStyle->SetTextThickness( pcbIUScale.mmToIU( 0.2 ) ); - dataStyle->SetItalic( false ); - dataStyle->SetTextPos( VECTOR2I( 0, 0 ) ); - dataStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); - dataStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP ); - - PCB_TEXT* t; - - t = static_cast( headStyle->Duplicate() ); - t->SetText( _( "BOARD CHARACTERISTICS" ) ); - t->SetPosition( cursorPos ); - objects.push_back( t ); - - cursorPos.y += t->GetBoundingBox().GetHeight() - + EDA_UNIT_UTILS::UI::FromUserUnit( pcbIUScale, EDA_UNITS::MM, 1.0 ); - - std::vector> texts; - std::vector colLabel1; - std::vector colData1; - std::vector colbreak; - std::vector colLabel2; - std::vector colData2; - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( _( "Copper Layer Count: " ) ); - colLabel1.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( EDA_UNIT_UTILS::UI::StringFromValue( unityScale, 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( dataStyle->Duplicate() ); - t->SetText( _( "Board overall dimensions: " ) ); - colLabel1.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( wxString::Format( wxT( "%s x %s" ), - m_frame->MessageTextFromValue( size.GetWidth(), true ), - m_frame->MessageTextFromValue( size.GetHeight(), true ) ) ); - colData1.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( _( "Min track/spacing: " ) ); - colLabel1.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( wxString::Format( wxT( "%s / %s" ), - m_frame->MessageTextFromValue( settings.m_TrackMinWidth, true ), - m_frame->MessageTextFromValue( settings.m_MinClearance, true ) ) ); - colData1.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( _( "Copper Finish: " ) ); - colLabel1.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( stackup.m_FinishType ); - colData1.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( _( "Castellated pads: " ) ); - colLabel1.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( stackup.m_CastellatedPads ? _( "Yes" ) : _( "No" ) ); - colData1.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( _( "Board Thickness: " ) ); - colLabel2.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( m_frame->MessageTextFromValue( settings.GetBoardThickness(), true ) ); - colData2.push_back( t ); - - // some empty cells - t = static_cast( dataStyle->Duplicate() ); - colLabel2.push_back( t ); - t = static_cast( dataStyle->Duplicate() ); - colData2.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( _( "Min hole diameter: " ) ); - colLabel2.push_back( t ); - t = static_cast( dataStyle->Duplicate() ); - - double holeSize = std::min( settings.m_MinThroughDrill, settings.m_ViasMinSize ); - t->SetText( m_frame->MessageTextFromValue( holeSize, true ) ); - colData2.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( _( "Impedance Control: " ) ); - colLabel2.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( stackup.m_HasDielectricConstrains ? _( "Yes" ) : _( "No" ) ); - colData2.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( _( "Plated Board Edge: " ) ); - colLabel2.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( stackup.m_EdgePlating ? _( "Yes" ) : _( "No" ) ); - colData2.push_back( t ); - - t = static_cast( dataStyle->Duplicate() ); - t->SetText( _( "Edge card connectors: " ) ); - colLabel1.push_back( t ); - - t = static_cast( 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 ); - VECTOR2I tableSize2; - - std::vector table = initTextTable( texts, cursorPos, Eco1_User, &tableSize2, - false ); - - for( BOARD_ITEM* item : table ) - objects.push_back( item ); - - if( aDrawNow ) - { - for( BOARD_ITEM* item : objects ) - commit.Add( item ); - - commit.Push( _( "Board Characteristics" ) ); - } - - tableSize->x = tableSize2.x; - tableSize->y = cursorPos.y + tableSize2.y - + EDA_UNIT_UTILS::UI::FromUserUnit( pcbIUScale, EDA_UNITS::MM, 2.0 ); - - return objects; -} - - -int DRAWING_TOOL::InteractivePlaceWithPreview( const TOOL_EVENT& aEvent, - std::vector& aItems, - std::vector& aPreview, - LSET* aLayers ) -{ - if( m_isFootprintEditor && !m_frame->GetModel() ) - return -1; - - bool cancelled = false; - - BOARD_COMMIT commit( m_frame ); - - m_toolMgr->RunAction( ACTIONS::selectionClear ); - - // do not capture or auto-pan until we start placing the table - SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TEXT ); - - m_frame->PushTool( aEvent ); - - Activate(); - // Must be done after Activate() so that it gets set into the correct context - m_controls->ShowCursor( true ); - - if( aEvent.HasPosition() ) - m_toolMgr->PrimeTool( aEvent.Position() ); - - // Main loop: keep receiving events - VECTOR2I cursorPosition; - VECTOR2I previousCursorPosition; - - view()->ClearPreview(); - view()->InitPreview(); - - for( BOARD_ITEM* item : aPreview ) - { - item->Move( cursorPosition - previousCursorPosition ); - view()->AddToPreview( item ); - } - - while( TOOL_EVENT* evt = Wait() ) - { - m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL ); - cursorPosition = m_controls->GetCursorPosition(); - - if( evt->IsCancelInteractive() ) - { - m_frame->PopTool( aEvent ); - cancelled = true; - break; - } - else if( evt->IsMotion() ) - { - view()->ShowPreview( false ); - - for( BOARD_ITEM* item : aPreview ) - item->Move( cursorPosition - previousCursorPosition ); - - view()->ShowPreview( true ); - - previousCursorPosition = cursorPosition; - } - 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( aEvent ); - 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, - KIPLATFORM::UI::GetMousePosition() ); - - view()->ClearPreview(); - - if( destLayer == PCB_LAYER_ID::UNDEFINED_LAYER ) - { - // The user did not pick any layer. - m_frame->PopTool( aEvent ); - cancelled = true; - break; - } - - for( BOARD_ITEM* item : aItems ) - { - item->SetLayer( destLayer ); - - item->RunOnChildren( - [&]( BOARD_ITEM* descendant ) - { - descendant->SetLayer( destLayer ); - }, - RECURSE_MODE::RECURSE ); - } - } - - for( BOARD_ITEM* item : aItems ) - { - item->Move( cursorPosition ); - commit.Add( item ); - - item->RunOnChildren( - [&]( BOARD_ITEM* descendant ) - { - commit.Add( descendant ); - }, - RECURSE_MODE::RECURSE ); - } - - commit.Push( _( "Place Items" ) ); - m_frame->PopTool( aEvent ); - - break; - } - // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions", - // but we don't at present have that, so we just knock out some of the egregious ones. - else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) ) - { - wxBell(); - } - else - { - evt->SetPassEvent(); - } - } - - view()->ClearPreview(); - frame()->SetMsgPanel( board() ); - - if( cancelled ) - return -1; - - return 0; -} - - -int DRAWING_TOOL::PlaceCharacteristics( const TOOL_EVENT& aEvent ) -{ - VECTOR2I tableSize; - - LSET layerSet = ( layerSet.AllCuMask() | layerSet.AllTechMask() ); - layerSet = layerSet.set( Edge_Cuts ).set( Margin ); - layerSet = layerSet.reset( F_Fab ).reset( B_Fab ); - - PCB_LAYER_ID layer = m_frame->GetActiveLayer(); - - if( ( layerSet & LSET( { layer } ) ).count() ) // if layer is a forbidden layer - m_frame->SetActiveLayer( Cmts_User ); - - std::vector table = DrawBoardCharacteristics( { 0, 0 }, m_frame->GetActiveLayer(), - false, &tableSize ); - std::vector preview; - std::vector 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->SetStart( VECTOR2I( 0, 0 ) ); - line1->SetEnd( VECTOR2I( tableSize.x, 0 ) ); - - line2->SetStart( VECTOR2I( 0, 0 ) ); - line2->SetEnd( VECTOR2I( 0, tableSize.y ) ); - - line3->SetStart( VECTOR2I( tableSize.x, 0 ) ); - line3->SetEnd( tableSize ); - - line4->SetStart( VECTOR2I( 0, tableSize.y ) ); - line4->SetEnd( tableSize ); - - 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( item ) ); - - items.push_back( static_cast( group ) ); - - if( InteractivePlaceWithPreview( aEvent, items, preview, &layerSet ) == -1 ) - m_frame->SetActiveLayer( layer ); - else - m_frame->SetActiveLayer( table.front()->GetLayer() ); - - return 0; -} - - -int DRAWING_TOOL::PlaceStackup( const TOOL_EVENT& aEvent ) -{ - VECTOR2I tableSize; - - LSET layerSet = ( layerSet.AllCuMask() | layerSet.AllTechMask() ); - layerSet = layerSet.set( Edge_Cuts ).set( Margin ); - layerSet = 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 table = DrawSpecificationStackup( VECTOR2I( 0, 0 ), - m_frame->GetActiveLayer(), false, - &tableSize ); - std::vector preview; - std::vector 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->SetStart( VECTOR2I( 0, 0 ) ); - line1->SetEnd( VECTOR2I( tableSize.x, 0 ) ); - - line2->SetStart( VECTOR2I( 0, 0 ) ); - line2->SetEnd( VECTOR2I( 0, tableSize.y ) ); - - line3->SetStart( VECTOR2I( tableSize.x, 0 ) ); - line3->SetEnd( tableSize ); - - line4->SetStart( VECTOR2I( 0, tableSize.y ) ); - line4->SetEnd( tableSize ); - - 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( group ) ); - - if( InteractivePlaceWithPreview( aEvent, items, preview, &layerSet ) == -1 ) - m_frame->SetActiveLayer( savedLayer ); - else - m_frame->SetActiveLayer( table.front()->GetLayer() ); - - return 0; -} diff --git a/pcbnew/tools/drawing_tool.cpp b/pcbnew/tools/drawing_tool.cpp index 8d7e199036..cc670daa61 100644 --- a/pcbnew/tools/drawing_tool.cpp +++ b/pcbnew/tools/drawing_tool.cpp @@ -4152,8 +4152,6 @@ const unsigned int DRAWING_TOOL::WIDTH_STEP = pcbIUScale.mmToIU( 0.1 ); void DRAWING_TOOL::setTransitions() { // clang-format off - 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::DrawZone, PCB_ACTIONS::drawPolygon.MakeEvent() ); Go( &DRAWING_TOOL::DrawRectangle, PCB_ACTIONS::drawRectangle.MakeEvent() ); diff --git a/pcbnew/tools/drawing_tool.h b/pcbnew/tools/drawing_tool.h index b0bff30464..12388a37db 100644 --- a/pcbnew/tools/drawing_tool.h +++ b/pcbnew/tools/drawing_tool.h @@ -90,20 +90,11 @@ public: */ MODE GetDrawingMode() const; - /** - */ - std::vector DrawBoardCharacteristics( const VECTOR2I& origin, PCB_LAYER_ID aLayer, - bool aDrawNow, VECTOR2I* tablesize ); - /** */ std::vector DrawSpecificationStackup( const VECTOR2I& origin, PCB_LAYER_ID aLayer, bool aDrawNow, VECTOR2I* tablesize ); - /** - */ - int PlaceCharacteristics( const TOOL_EVENT& aEvent ); - /** */ int PlaceStackup( const TOOL_EVENT& aEvent ); diff --git a/pcbnew/tools/pcb_control.cpp b/pcbnew/tools/pcb_control.cpp index b15b24e2e7..91b7de673d 100644 --- a/pcbnew/tools/pcb_control.cpp +++ b/pcbnew/tools/pcb_control.cpp @@ -2165,6 +2165,221 @@ int PCB_CONTROL::DdAppendBoard( const TOOL_EVENT& aEvent ) } +int PCB_CONTROL::PlaceCharacteristics( const TOOL_EVENT& aEvent ) +{ + BOARD_COMMIT commit( this ); + BOARD_DESIGN_SETTINGS& settings = m_frame->GetBoard()->GetDesignSettings(); + BOARD_STACKUP& stackup = settings.GetStackupDescriptor(); + + stackup.SynchronizeWithBoard( &settings ); + + PCB_TABLE* table = new PCB_TABLE( m_frame->GetModel(), pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH ) ); + table->SetLayer( m_frame->GetActiveLayer() ); + table->SetColCount( 4 ); + + auto addHeaderCell = + [&]( const wxString& text ) + { + PCB_TABLECELL* c = new PCB_TABLECELL( table ); + c->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 2.0 ), pcbIUScale.mmToIU( 2.0 ) ) ); + c->SetTextThickness( pcbIUScale.mmToIU( 0.4 ) ); + c->SetText( text ); + c->SetColSpan( table->GetColCount() ); + table->AddCell( c ); + }; + + auto addDataCell = + [&]( const wxString& text ) + { + PCB_TABLECELL* c = new PCB_TABLECELL( table ); + c->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) ); + c->SetTextThickness( pcbIUScale.mmToIU( 0.2 ) ); + c->SetText( text ); + table->AddCell( c ); + }; + + addHeaderCell( _( "BOARD CHARACTERISTICS" ) ); + + for( int col = 1; col < table->GetColCount(); ++col ) + { + addHeaderCell( wxEmptyString ); + table->GetCell( 0, col )->SetColSpan( 0 ); + } + + addDataCell( _( "Copper layer count: " ) ); + addDataCell( EDA_UNIT_UTILS::UI::StringFromValue( unityScale, EDA_UNITS::UNSCALED, + settings.GetCopperLayerCount(), false ) ); + + addDataCell( _( "Board thickness: " ) ); + addDataCell( m_frame->MessageTextFromValue( settings.GetBoardThickness(), true ) ); + + SHAPE_POLY_SET outline; + m_frame->GetBoard()->GetBoardPolygonOutlines( outline ); + BOX2I size = outline.BBox(); + + addDataCell( _( "Board overall dimensions: " ) ); + addDataCell( wxString::Format( wxT( "%s x %s" ), + m_frame->MessageTextFromValue( size.GetWidth(), true ), + m_frame->MessageTextFromValue( size.GetHeight(), true ) ) ); + + addDataCell( wxEmptyString ); + addDataCell( wxEmptyString ); + + addDataCell( _( "Min track/spacing: " ) ); + addDataCell( wxString::Format( wxT( "%s / %s" ), + m_frame->MessageTextFromValue( settings.m_TrackMinWidth, true ), + m_frame->MessageTextFromValue( settings.m_MinClearance, true ) ) ); + + double holeSize = std::min( settings.m_MinThroughDrill, settings.m_ViasMinSize ); + + addDataCell( _( "Min hole diameter: " ) ); + addDataCell( m_frame->MessageTextFromValue( holeSize, true ) ); + + addDataCell( _( "Copper finish: " ) ); + addDataCell( stackup.m_FinishType ); + + addDataCell( _( "Impedance control: " ) ); + addDataCell( stackup.m_HasDielectricConstrains ? _( "Yes" ) : _( "No" ) ); + + addDataCell( _( "Castellated pads: " ) ); + addDataCell( stackup.m_CastellatedPads ? _( "Yes" ) : _( "No" ) ); + + addDataCell( _( "Plated board edge: " ) ); + addDataCell( stackup.m_EdgePlating ? _( "Yes" ) : _( "No" ) ); + + wxString msg; + + switch( stackup.m_EdgeConnectorConstraints ) + { + case BS_EDGE_CONNECTOR_NONE: msg = _( "No" ); break; + case BS_EDGE_CONNECTOR_IN_USE: msg = _( "Yes" ); break; + case BS_EDGE_CONNECTOR_BEVELLED: msg = _( "Yes, Bevelled" ); break; + } + + addDataCell( _( "Edge card connectors: " ) ); + addDataCell( msg ); + + addDataCell( wxEmptyString ); + addDataCell( wxEmptyString ); + + table->SetStrokeExternal( false ); + table->SetStrokeHeaderSeparator( false ); + table->SetStrokeColumns( false ); + table->SetStrokeRows( false ); + table->Autosize(); + + std::vector items; + items.push_back( table ); + + if( placeBoardItems( &commit, items, true, true, false ) ) + commit.Push( _( "Place Board Characteristics" ) ); + else + delete table; + + return 0; +} + + + +int PCB_CONTROL::PlaceStackup( const TOOL_EVENT& aEvent ) +{ + BOARD_COMMIT commit( this ); + BOARD_DESIGN_SETTINGS& settings = m_frame->GetBoard()->GetDesignSettings(); + BOARD_STACKUP& stackup = settings.GetStackupDescriptor(); + + stackup.SynchronizeWithBoard( &settings ); + + std::vector layers = stackup.GetList(); + + PCB_TABLE* table = new PCB_TABLE( m_frame->GetModel(), pcbIUScale.mmToIU( DEFAULT_LINE_WIDTH ) ); + table->SetLayer( m_frame->GetActiveLayer() ); + table->SetColCount( 7 ); + + auto addHeaderCell = + [&]( const wxString& text ) + { + PCB_TABLECELL* c = new PCB_TABLECELL( table ); + c->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) ); + c->SetTextThickness( pcbIUScale.mmToIU( 0.3 ) ); + c->SetText( text ); + table->AddCell( c ); + }; + + auto addDataCell = + [&]( const wxString& text, const char align = 'L' ) + { + PCB_TABLECELL* c = new PCB_TABLECELL( table ); + c->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) ); + c->SetTextThickness( pcbIUScale.mmToIU( 0.2 ) ); + + if( align == 'R' ) + c->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT ); + + c->SetText( text ); + table->AddCell( c ); + }; + + addHeaderCell( _( "Layer Name" ) ); + addHeaderCell( _( "Type" ) ); + addHeaderCell( _( "Material" ) ); + addHeaderCell( _( "Thickness" ) ); + addHeaderCell( _( "Color" ) ); + addHeaderCell( _( "Epsilon R" ) ); + addHeaderCell( _( "Loss Tangent" ) ); + + for( int i = 0; i < stackup.GetCount(); i++ ) + { + BOARD_STACKUP_ITEM* stackup_item = layers.at( i ); + + for( int sublayer_id = 0; sublayer_id < stackup_item->GetSublayersCount(); sublayer_id++ ) + { + // 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 layerName; + + if( IsValidLayer( stackup_item->GetBrdLayerId() ) ) + layerName = m_frame->GetBoard()->GetLayerName( stackup_item->GetBrdLayerId() ); + + if( layerName.IsEmpty() && stackup_item->GetType() == BS_ITEM_TYPE_DIELECTRIC ) + layerName = _( "Dielectric" ); + + addDataCell( layerName ); + } + else + { + addDataCell( stackup_item->GetLayerName() ); + } + + addDataCell( InitialCaps( stackup_item->GetTypeName() ) ); + addDataCell( stackup_item->GetMaterial( sublayer_id ) ); + addDataCell( m_frame->StringFromValue( stackup_item->GetThickness( sublayer_id ), true ), 'R' ); + addDataCell( stackup_item->GetColor( sublayer_id ) ); + addDataCell( EDA_UNIT_UTILS::UI::StringFromValue( unityScale, EDA_UNITS::UNSCALED, + stackup_item->GetEpsilonR( sublayer_id ) ), 'R' ); + addDataCell( EDA_UNIT_UTILS::UI::StringFromValue( unityScale, EDA_UNITS::UNSCALED, + stackup_item->GetLossTangent( sublayer_id ) ), 'R' ); + } + } + + table->Autosize(); + + std::vector items; + items.push_back( table ); + + if( placeBoardItems( &commit, items, true, true, false ) ) + commit.Push( _( "Place Board Stackup Table" ) ); + else + delete table; + + return 0; +} + + + int PCB_CONTROL::FlipPcbView( const TOOL_EVENT& aEvent ) { view()->SetMirror( !view()->IsMirroredX(), false ); @@ -2293,6 +2508,8 @@ void PCB_CONTROL::setTransitions() Go( &PCB_CONTROL::AppendDesignBlock, PCB_ACTIONS::placeDesignBlock.MakeEvent() ); Go( &PCB_CONTROL::AppendBoardFromFile, PCB_ACTIONS::appendBoard.MakeEvent() ); Go( &PCB_CONTROL::DdAppendBoard, PCB_ACTIONS::ddAppendBoard.MakeEvent() ); + Go( &PCB_CONTROL::PlaceCharacteristics, PCB_ACTIONS::placeCharacteristics.MakeEvent() ); + Go( &PCB_CONTROL::PlaceStackup, PCB_ACTIONS::placeStackup.MakeEvent() ); Go( &PCB_CONTROL::Paste, ACTIONS::paste.MakeEvent() ); Go( &PCB_CONTROL::Paste, ACTIONS::pasteSpecial.MakeEvent() ); diff --git a/pcbnew/tools/pcb_control.h b/pcbnew/tools/pcb_control.h index 10e724bc8a..0a7c1f0c37 100644 --- a/pcbnew/tools/pcb_control.h +++ b/pcbnew/tools/pcb_control.h @@ -109,6 +109,8 @@ public: int AppendDesignBlock( const TOOL_EVENT& aEvent ); int AppendBoard( PCB_IO& pi, const wxString& fileName ); int UpdateMessagePanel( const TOOL_EVENT& aEvent ); + int PlaceCharacteristics( const TOOL_EVENT& aEvent ); + int PlaceStackup( const TOOL_EVENT& aEvent ); int FlipPcbView( const TOOL_EVENT& aEvent );