mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 10:13:19 +02:00
PCB search: add Drills column
Fixes: https://gitlab.com/kicad/code/kicad/-/issues/1982
This commit is contained in:
parent
05d04e665a
commit
7a09960b46
@ -329,6 +329,7 @@ set( PCBNEW_CLASS_SRCS
|
|||||||
|
|
||||||
action_plugin.cpp
|
action_plugin.cpp
|
||||||
array_pad_number_provider.cpp
|
array_pad_number_provider.cpp
|
||||||
|
board_statistics.cpp
|
||||||
build_BOM_from_board.cpp
|
build_BOM_from_board.cpp
|
||||||
cleanup_item.cpp
|
cleanup_item.cpp
|
||||||
convert_shape_list_to_polygon.cpp
|
convert_shape_list_to_polygon.cpp
|
||||||
|
100
pcbnew/board_statistics.cpp
Normal file
100
pcbnew/board_statistics.cpp
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <board.h>
|
||||||
|
#include <footprint.h>
|
||||||
|
#include <pad.h>
|
||||||
|
#include <pcb_track.h>
|
||||||
|
#include <board_statistics.h>
|
||||||
|
|
||||||
|
|
||||||
|
void CollectDrillLineItems( BOARD* board, std::vector<DRILL_LINE_ITEM>& out )
|
||||||
|
{
|
||||||
|
out.clear();
|
||||||
|
|
||||||
|
auto addOrIncrement = [&]( const DRILL_LINE_ITEM& d )
|
||||||
|
{
|
||||||
|
for( DRILL_LINE_ITEM& e : out )
|
||||||
|
{
|
||||||
|
if( e == d )
|
||||||
|
{
|
||||||
|
e.m_Qty++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DRILL_LINE_ITEM n = d;
|
||||||
|
n.m_Qty = 1;
|
||||||
|
out.push_back( n );
|
||||||
|
};
|
||||||
|
|
||||||
|
if( !board )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Pads
|
||||||
|
for( FOOTPRINT* fp : board->Footprints() )
|
||||||
|
{
|
||||||
|
for( PAD* pad : fp->Pads() )
|
||||||
|
{
|
||||||
|
if( !pad->HasHole() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int xs = pad->GetDrillSize().x;
|
||||||
|
int ys = pad->GetDrillSize().y;
|
||||||
|
|
||||||
|
if( xs <= 0 || ys <= 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PCB_LAYER_ID top, bottom;
|
||||||
|
|
||||||
|
if( pad->GetLayerSet().CuStack().empty() )
|
||||||
|
{
|
||||||
|
top = UNDEFINED_LAYER;
|
||||||
|
bottom = UNDEFINED_LAYER;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
top = pad->GetLayerSet().CuStack().front();
|
||||||
|
bottom = pad->GetLayerSet().CuStack().back();
|
||||||
|
}
|
||||||
|
|
||||||
|
DRILL_LINE_ITEM d( xs, ys, pad->GetDrillShape(), pad->GetAttribute() != PAD_ATTRIB::NPTH, true, top,
|
||||||
|
bottom );
|
||||||
|
|
||||||
|
addOrIncrement( d );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vias
|
||||||
|
for( PCB_TRACK* t : board->Tracks() )
|
||||||
|
{
|
||||||
|
if( t->Type() != PCB_VIA_T )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PCB_VIA* via = static_cast<PCB_VIA*>( t );
|
||||||
|
int dmm = via->GetDrillValue();
|
||||||
|
|
||||||
|
if( dmm <= 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DRILL_LINE_ITEM d( dmm, dmm, PAD_DRILL_SHAPE::CIRCLE, true, false, via->TopLayer(), via->BottomLayer() );
|
||||||
|
addOrIncrement( d );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
112
pcbnew/board_statistics.h
Normal file
112
pcbnew/board_statistics.h
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PCBNEW_BOARD_STATISTICS_H
|
||||||
|
#define PCBNEW_BOARD_STATISTICS_H
|
||||||
|
|
||||||
|
#include <layer_ids.h>
|
||||||
|
#include <padstack.h>
|
||||||
|
|
||||||
|
class BOARD;
|
||||||
|
|
||||||
|
struct DRILL_LINE_ITEM
|
||||||
|
{
|
||||||
|
enum COL_ID
|
||||||
|
{
|
||||||
|
COL_COUNT,
|
||||||
|
COL_SHAPE,
|
||||||
|
COL_X_SIZE,
|
||||||
|
COL_Y_SIZE,
|
||||||
|
COL_PLATED,
|
||||||
|
COL_VIA_PAD,
|
||||||
|
COL_START_LAYER,
|
||||||
|
COL_STOP_LAYER
|
||||||
|
};
|
||||||
|
|
||||||
|
DRILL_LINE_ITEM( int aXSize, int aYSize, PAD_DRILL_SHAPE aShape, bool aIsPlated,
|
||||||
|
bool aIsPad, PCB_LAYER_ID aStartLayer, PCB_LAYER_ID aStopLayer ) :
|
||||||
|
xSize( aXSize ),
|
||||||
|
ySize( aYSize ),
|
||||||
|
shape( aShape ),
|
||||||
|
isPlated( aIsPlated ),
|
||||||
|
isPad( aIsPad ),
|
||||||
|
startLayer( aStartLayer ),
|
||||||
|
stopLayer( aStopLayer ),
|
||||||
|
m_Qty( 0 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==( const DRILL_LINE_ITEM& other ) const
|
||||||
|
{
|
||||||
|
return xSize == other.xSize && ySize == other.ySize && shape == other.shape
|
||||||
|
&& isPlated == other.isPlated && isPad == other.isPad && startLayer == other.startLayer
|
||||||
|
&& stopLayer == other.stopLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct COMPARE
|
||||||
|
{
|
||||||
|
COMPARE( COL_ID aColId, bool aAscending ) : colId( aColId ), ascending( aAscending ) {}
|
||||||
|
|
||||||
|
bool operator()( const DRILL_LINE_ITEM& aLeft, const DRILL_LINE_ITEM& aRight )
|
||||||
|
{
|
||||||
|
switch( colId )
|
||||||
|
{
|
||||||
|
case COL_COUNT:
|
||||||
|
return compareDrillParameters( aLeft.m_Qty, aRight.m_Qty );
|
||||||
|
case COL_SHAPE:
|
||||||
|
return compareDrillParameters( static_cast<int>( aLeft.shape ), static_cast<int>( aRight.shape ) );
|
||||||
|
case COL_X_SIZE:
|
||||||
|
return compareDrillParameters( aLeft.xSize, aRight.xSize );
|
||||||
|
case COL_Y_SIZE:
|
||||||
|
return compareDrillParameters( aLeft.ySize, aRight.ySize );
|
||||||
|
case COL_PLATED:
|
||||||
|
return ascending ? aLeft.isPlated : aRight.isPlated;
|
||||||
|
case COL_VIA_PAD:
|
||||||
|
return ascending ? aLeft.isPad : aRight.isPad;
|
||||||
|
case COL_START_LAYER:
|
||||||
|
return compareDrillParameters( aLeft.startLayer, aRight.startLayer );
|
||||||
|
case COL_STOP_LAYER:
|
||||||
|
return compareDrillParameters( aLeft.stopLayer, aRight.stopLayer );
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compareDrillParameters( int aLeft, int aRight )
|
||||||
|
{
|
||||||
|
return ascending ? aLeft < aRight : aLeft > aRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
COL_ID colId;
|
||||||
|
bool ascending;
|
||||||
|
};
|
||||||
|
|
||||||
|
int xSize;
|
||||||
|
int ySize;
|
||||||
|
PAD_DRILL_SHAPE shape;
|
||||||
|
bool isPlated;
|
||||||
|
bool isPad;
|
||||||
|
PCB_LAYER_ID startLayer;
|
||||||
|
PCB_LAYER_ID stopLayer;
|
||||||
|
int m_Qty;
|
||||||
|
};
|
||||||
|
|
||||||
|
void CollectDrillLineItems( BOARD* board, std::vector<DRILL_LINE_ITEM>& out );
|
||||||
|
|
||||||
|
#endif
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "dialog_board_statistics.h"
|
#include "dialog_board_statistics.h"
|
||||||
|
#include <board_statistics.h>
|
||||||
|
|
||||||
#include <wx/filedlg.h>
|
#include <wx/filedlg.h>
|
||||||
|
|
||||||
@ -244,9 +245,6 @@ void DIALOG_BOARD_STATISTICS::getDataFromPCB()
|
|||||||
SHAPE_POLY_SET frontHoles;
|
SHAPE_POLY_SET frontHoles;
|
||||||
SHAPE_POLY_SET backHoles;
|
SHAPE_POLY_SET backHoles;
|
||||||
|
|
||||||
m_drillTypes.clear();
|
|
||||||
m_gridDrills->ClearRows();
|
|
||||||
|
|
||||||
// Type list for track-related statistics gathering
|
// Type list for track-related statistics gathering
|
||||||
static const std::vector<KICAD_T> trackTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T };
|
static const std::vector<KICAD_T> trackTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T };
|
||||||
|
|
||||||
@ -294,46 +292,6 @@ void DIALOG_BOARD_STATISTICS::getDataFromPCB()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pad->GetDrillSize().x > 0 && pad->GetDrillSize().y > 0 )
|
|
||||||
{
|
|
||||||
PCB_LAYER_ID top, bottom;
|
|
||||||
|
|
||||||
if( pad->GetLayerSet().CuStack().empty() )
|
|
||||||
{
|
|
||||||
// The pad is not on any copper layer
|
|
||||||
top = UNDEFINED_LAYER;
|
|
||||||
bottom = UNDEFINED_LAYER;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
top = pad->GetLayerSet().CuStack().front();
|
|
||||||
bottom = pad->GetLayerSet().CuStack().back();
|
|
||||||
}
|
|
||||||
|
|
||||||
DRILL_LINE_ITEM drill( pad->GetDrillSize().x, pad->GetDrillSize().y,
|
|
||||||
pad->GetDrillShape(),
|
|
||||||
pad->GetAttribute() != PAD_ATTRIB::NPTH,
|
|
||||||
true, top, bottom );
|
|
||||||
|
|
||||||
auto it = m_drillTypes.begin();
|
|
||||||
|
|
||||||
for( ; it != m_drillTypes.end(); ++it )
|
|
||||||
{
|
|
||||||
if( *it == drill )
|
|
||||||
{
|
|
||||||
it->m_Qty++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( it == m_drillTypes.end() )
|
|
||||||
{
|
|
||||||
drill.m_Qty = 1;
|
|
||||||
m_drillTypes.push_back( drill );
|
|
||||||
m_gridDrills->InsertRows();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,30 +340,21 @@ void DIALOG_BOARD_STATISTICS::getDataFromPCB()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DRILL_LINE_ITEM drill( via->GetDrillValue(), via->GetDrillValue(),
|
|
||||||
PAD_DRILL_SHAPE::CIRCLE, true, false, via->TopLayer(),
|
|
||||||
via->BottomLayer() );
|
|
||||||
|
|
||||||
auto it = m_drillTypes.begin();
|
|
||||||
|
|
||||||
for( ; it != m_drillTypes.end(); ++it )
|
|
||||||
{
|
|
||||||
if( *it == drill )
|
|
||||||
{
|
|
||||||
it->m_Qty++;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( it == m_drillTypes.end() )
|
// Collect drill information
|
||||||
|
m_drillTypes.clear();
|
||||||
|
m_gridDrills->ClearRows();
|
||||||
|
|
||||||
|
std::vector<DRILL_LINE_ITEM> drills;
|
||||||
|
CollectDrillLineItems( board, drills );
|
||||||
|
|
||||||
|
for( const auto& d : drills )
|
||||||
{
|
{
|
||||||
drill.m_Qty = 1;
|
m_drillTypes.push_back( d );
|
||||||
m_drillTypes.push_back( drill );
|
|
||||||
m_gridDrills->InsertRows();
|
m_gridDrills->InsertRows();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sort( m_drillTypes.begin(), m_drillTypes.end(),
|
sort( m_drillTypes.begin(), m_drillTypes.end(),
|
||||||
DRILL_LINE_ITEM::COMPARE( DRILL_LINE_ITEM::COL_COUNT, false ) );
|
DRILL_LINE_ITEM::COMPARE( DRILL_LINE_ITEM::COL_COUNT, false ) );
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
#include <footprint.h>
|
#include <footprint.h>
|
||||||
#include <pcb_track.h>
|
#include <pcb_track.h>
|
||||||
#include <dialog_board_statistics_base.h>
|
#include <dialog_board_statistics_base.h>
|
||||||
#include <padstack.h>
|
#include <board_statistics.h>
|
||||||
#include <pcb_base_frame.h>
|
#include <pcb_base_frame.h>
|
||||||
#include <pcb_edit_frame.h>
|
#include <pcb_edit_frame.h>
|
||||||
#include <project.h>
|
#include <project.h>
|
||||||
@ -83,89 +83,6 @@ public:
|
|||||||
int m_BackSideQty;
|
int m_BackSideQty;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DRILL_LINE_ITEM
|
|
||||||
{
|
|
||||||
enum COL_ID
|
|
||||||
{
|
|
||||||
COL_COUNT,
|
|
||||||
COL_SHAPE,
|
|
||||||
COL_X_SIZE,
|
|
||||||
COL_Y_SIZE,
|
|
||||||
COL_PLATED,
|
|
||||||
COL_VIA_PAD,
|
|
||||||
COL_START_LAYER,
|
|
||||||
COL_STOP_LAYER
|
|
||||||
};
|
|
||||||
|
|
||||||
DRILL_LINE_ITEM( int aXSize, int aYSize, PAD_DRILL_SHAPE aShape, bool aIsPlated,
|
|
||||||
bool aIsPad, PCB_LAYER_ID aStartLayer, PCB_LAYER_ID aStopLayer ) :
|
|
||||||
xSize( aXSize ),
|
|
||||||
ySize( aYSize ),
|
|
||||||
shape( aShape ),
|
|
||||||
isPlated( aIsPlated ),
|
|
||||||
isPad( aIsPad ),
|
|
||||||
startLayer( aStartLayer ),
|
|
||||||
stopLayer( aStopLayer ),
|
|
||||||
m_Qty( 0 )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==( const DRILL_LINE_ITEM& other ) const
|
|
||||||
{
|
|
||||||
return xSize == other.xSize && ySize == other.ySize && shape == other.shape
|
|
||||||
&& isPlated == other.isPlated && isPad == other.isPad
|
|
||||||
&& startLayer == other.startLayer && stopLayer == other.stopLayer;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct COMPARE
|
|
||||||
{
|
|
||||||
COMPARE( COL_ID aColId, bool aAscending ) : colId( aColId ), ascending( aAscending )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
bool operator()( const DRILL_LINE_ITEM& aLeft, const DRILL_LINE_ITEM& aRight )
|
|
||||||
{
|
|
||||||
switch( colId )
|
|
||||||
{
|
|
||||||
case COL_COUNT:
|
|
||||||
return compareDrillParameters( aLeft.m_Qty, aRight.m_Qty );
|
|
||||||
case COL_SHAPE:
|
|
||||||
return compareDrillParameters( static_cast<int>( aLeft.shape ),
|
|
||||||
static_cast<int>( aRight.shape ) );
|
|
||||||
case COL_X_SIZE:
|
|
||||||
return compareDrillParameters( aLeft.xSize, aRight.xSize );
|
|
||||||
case COL_Y_SIZE:
|
|
||||||
return compareDrillParameters( aLeft.ySize, aRight.ySize );
|
|
||||||
case COL_PLATED:
|
|
||||||
return ascending ? aLeft.isPlated : aRight.isPlated;
|
|
||||||
case COL_VIA_PAD:
|
|
||||||
return ascending ? aLeft.isPad : aRight.isPad;
|
|
||||||
case COL_START_LAYER:
|
|
||||||
return compareDrillParameters( aLeft.startLayer, aRight.startLayer );
|
|
||||||
case COL_STOP_LAYER:
|
|
||||||
return compareDrillParameters( aLeft.stopLayer, aRight.stopLayer );
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compareDrillParameters( int aLeft, int aRight )
|
|
||||||
{
|
|
||||||
return ascending ? aLeft < aRight : aLeft > aRight;
|
|
||||||
}
|
|
||||||
|
|
||||||
COL_ID colId;
|
|
||||||
bool ascending;
|
|
||||||
};
|
|
||||||
|
|
||||||
int xSize;
|
|
||||||
int ySize;
|
|
||||||
PAD_DRILL_SHAPE shape;
|
|
||||||
bool isPlated;
|
|
||||||
bool isPad;
|
|
||||||
PCB_LAYER_ID startLayer;
|
|
||||||
PCB_LAYER_ID stopLayer;
|
|
||||||
int m_Qty;
|
|
||||||
};
|
|
||||||
|
|
||||||
DIALOG_BOARD_STATISTICS( PCB_EDIT_FRAME* aParentFrame );
|
DIALOG_BOARD_STATISTICS( PCB_EDIT_FRAME* aParentFrame );
|
||||||
~DIALOG_BOARD_STATISTICS();
|
~DIALOG_BOARD_STATISTICS();
|
||||||
|
@ -47,6 +47,7 @@ PCB_SEARCH_PANE::PCB_SEARCH_PANE( PCB_EDIT_FRAME* aFrame ) :
|
|||||||
AddSearcher( std::make_shared<RATSNEST_SEARCH_HANDLER>( aFrame ) );
|
AddSearcher( std::make_shared<RATSNEST_SEARCH_HANDLER>( aFrame ) );
|
||||||
AddSearcher( std::make_shared<TEXT_SEARCH_HANDLER>( aFrame ) );
|
AddSearcher( std::make_shared<TEXT_SEARCH_HANDLER>( aFrame ) );
|
||||||
AddSearcher( std::make_shared<GROUP_SEARCH_HANDLER>( aFrame ) );
|
AddSearcher( std::make_shared<GROUP_SEARCH_HANDLER>( aFrame ) );
|
||||||
|
AddSearcher( std::make_shared<DRILL_SEARCH_HANDLER>( aFrame ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
#include <tool/tool_manager.h>
|
#include <tool/tool_manager.h>
|
||||||
#include <tools/pcb_actions.h>
|
#include <tools/pcb_actions.h>
|
||||||
#include <zone.h>
|
#include <zone.h>
|
||||||
|
#include <pad.h>
|
||||||
|
#include <pcb_track.h>
|
||||||
#include "search_handlers.h"
|
#include "search_handlers.h"
|
||||||
|
|
||||||
|
|
||||||
@ -571,3 +573,301 @@ void RATSNEST_SEARCH_HANDLER::ActivateItem( long aItemRow )
|
|||||||
{
|
{
|
||||||
m_frame->ShowBoardSetupDialog( _( "Net Classes" ) );
|
m_frame->ShowBoardSetupDialog( _( "Net Classes" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DRILL_SEARCH_HANDLER::DRILL_SEARCH_HANDLER( PCB_EDIT_FRAME* aFrame ) :
|
||||||
|
PCB_SEARCH_HANDLER( _HKI( "Drills" ), aFrame ),
|
||||||
|
m_frame( aFrame )
|
||||||
|
{
|
||||||
|
m_columns.emplace_back( _HKI( "Count" ), 2, wxLIST_FORMAT_RIGHT );
|
||||||
|
m_columns.emplace_back( _HKI( "Shape" ), 3, wxLIST_FORMAT_LEFT );
|
||||||
|
m_columns.emplace_back( _HKI( "X Size" ), 3, wxLIST_FORMAT_CENTER );
|
||||||
|
m_columns.emplace_back( _HKI( "Y Size" ), 3, wxLIST_FORMAT_CENTER );
|
||||||
|
m_columns.emplace_back( _HKI( "Plated" ), 2, wxLIST_FORMAT_CENTER );
|
||||||
|
m_columns.emplace_back( _HKI( "Via/Pad" ), 2, wxLIST_FORMAT_CENTER );
|
||||||
|
m_columns.emplace_back( _HKI( "Start Layer" ), 4, wxLIST_FORMAT_CENTER );
|
||||||
|
m_columns.emplace_back( _HKI( "Stop Layer" ), 4, wxLIST_FORMAT_CENTER );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DRILL_SEARCH_HANDLER::Search( const wxString& aQuery )
|
||||||
|
{
|
||||||
|
BOARD* board = m_frame->GetBoard();
|
||||||
|
|
||||||
|
m_drills.clear();
|
||||||
|
m_ptrToDrill.clear();
|
||||||
|
m_hitlist.clear();
|
||||||
|
|
||||||
|
auto addEntryOrIncrement = [&]( const DRILL_LINE_ITEM& d, BOARD_ITEM* rep )
|
||||||
|
{
|
||||||
|
for( DRILL_ROW& g : m_drills )
|
||||||
|
{
|
||||||
|
if( g.entry == d )
|
||||||
|
{
|
||||||
|
g.entry.m_Qty++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DRILL_ROW g = { .entry = d, .item = rep, };
|
||||||
|
g.entry.m_Qty = 1;
|
||||||
|
|
||||||
|
m_drills.push_back( g );
|
||||||
|
};
|
||||||
|
|
||||||
|
// Collect from pads
|
||||||
|
for( FOOTPRINT* fp : board->Footprints() )
|
||||||
|
{
|
||||||
|
for( PAD* pad : fp->Pads() )
|
||||||
|
{
|
||||||
|
if( !pad->HasHole() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int xs = pad->GetDrillSize().x;
|
||||||
|
int ys = pad->GetDrillSize().y;
|
||||||
|
if( xs <= 0 || ys <= 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PCB_LAYER_ID top, bottom;
|
||||||
|
|
||||||
|
if( pad->GetLayerSet().CuStack().empty() )
|
||||||
|
{
|
||||||
|
top = UNDEFINED_LAYER;
|
||||||
|
bottom = UNDEFINED_LAYER;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
top = pad->GetLayerSet().CuStack().front();
|
||||||
|
bottom = pad->GetLayerSet().CuStack().back();
|
||||||
|
}
|
||||||
|
|
||||||
|
DRILL_LINE_ITEM d( xs, ys, pad->GetDrillShape(),
|
||||||
|
pad->GetAttribute() != PAD_ATTRIB::NPTH,
|
||||||
|
true, top, bottom );
|
||||||
|
|
||||||
|
addEntryOrIncrement( d, pad );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect from vias
|
||||||
|
for( PCB_TRACK* t : board->Tracks() )
|
||||||
|
{
|
||||||
|
if( t->Type() != PCB_VIA_T )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PCB_VIA* via = static_cast<PCB_VIA*>( t );
|
||||||
|
int dmm = via->GetDrillValue();
|
||||||
|
if( dmm <= 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DRILL_LINE_ITEM d( dmm, dmm, PAD_DRILL_SHAPE::CIRCLE, true,
|
||||||
|
false, via->TopLayer(), via->BottomLayer() );
|
||||||
|
addEntryOrIncrement( d, via );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort( m_drills.begin(), m_drills.end(),
|
||||||
|
[]( const DRILL_ROW& a, const DRILL_ROW& b )
|
||||||
|
{
|
||||||
|
DRILL_LINE_ITEM::COMPARE cmp( DRILL_LINE_ITEM::COL_COUNT, false );
|
||||||
|
return cmp( a.entry, b.entry );
|
||||||
|
} );
|
||||||
|
|
||||||
|
// Apply filter and populate display list
|
||||||
|
for( size_t i = 0; i < m_drills.size(); ++i )
|
||||||
|
{
|
||||||
|
if( aQuery.IsEmpty() || rowMatchesQuery( m_drills[i].entry, aQuery.Lower() ) )
|
||||||
|
{
|
||||||
|
m_hitlist.push_back( m_drills[i].item );
|
||||||
|
m_ptrToDrill[m_drills[i].item] = (int) i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) m_hitlist.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wxString DRILL_SEARCH_HANDLER::getResultCell( BOARD_ITEM* aItem, int aCol )
|
||||||
|
{
|
||||||
|
auto it = m_ptrToDrill.find( aItem );
|
||||||
|
|
||||||
|
if( it == m_ptrToDrill.end() )
|
||||||
|
return wxEmptyString;
|
||||||
|
|
||||||
|
const auto& e = m_drills[it->second].entry;
|
||||||
|
|
||||||
|
return cellText( e, aCol );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DRILL_SEARCH_HANDLER::Sort( int aCol, bool aAscending, std::vector<long>* aSelection )
|
||||||
|
{
|
||||||
|
// Preserve current selection pointers
|
||||||
|
std::vector<BOARD_ITEM*> selPtrs;
|
||||||
|
|
||||||
|
if( aSelection )
|
||||||
|
{
|
||||||
|
for( long row : *aSelection )
|
||||||
|
{
|
||||||
|
if( row >= 0 && row < (long) m_hitlist.size() )
|
||||||
|
selPtrs.push_back( m_hitlist[row] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cmpPtr = [&]( BOARD_ITEM* pa, BOARD_ITEM* pb )
|
||||||
|
{
|
||||||
|
const auto& a = m_drills[m_ptrToDrill[pa]].entry;
|
||||||
|
const auto& b = m_drills[m_ptrToDrill[pb]].entry;
|
||||||
|
|
||||||
|
int col = aCol < 0 ? 0 : aCol;
|
||||||
|
DRILL_LINE_ITEM::COMPARE cmp( static_cast<DRILL_LINE_ITEM::COL_ID>( col ), aAscending );
|
||||||
|
|
||||||
|
return cmp( a, b );
|
||||||
|
};
|
||||||
|
|
||||||
|
std::sort( m_hitlist.begin(), m_hitlist.end(), cmpPtr );
|
||||||
|
|
||||||
|
// Rebuild selection rows from pointers
|
||||||
|
if( aSelection )
|
||||||
|
{
|
||||||
|
aSelection->clear();
|
||||||
|
|
||||||
|
for( long row = 0; row < (long) m_hitlist.size(); ++row )
|
||||||
|
{
|
||||||
|
if( alg::contains( selPtrs, m_hitlist[row] ) )
|
||||||
|
aSelection->push_back( row );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DRILL_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
|
||||||
|
{
|
||||||
|
BOARD* board = m_frame->GetBoard();
|
||||||
|
std::vector<EDA_ITEM*> selectedItems;
|
||||||
|
APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
|
||||||
|
|
||||||
|
// Collect matching items
|
||||||
|
for( long row : aItemRows )
|
||||||
|
{
|
||||||
|
if( row < 0 || row >= (long) m_hitlist.size() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
BOARD_ITEM* rep = m_hitlist[row];
|
||||||
|
auto it = m_ptrToDrill.find( rep );
|
||||||
|
|
||||||
|
if( it == m_ptrToDrill.end() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto* target = &m_drills[it->second].entry;
|
||||||
|
|
||||||
|
// Pads
|
||||||
|
for( FOOTPRINT* fp : board->Footprints() )
|
||||||
|
{
|
||||||
|
for( PAD* pad : fp->Pads() )
|
||||||
|
{
|
||||||
|
if( !pad->HasHole() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int xs = pad->GetDrillSize().x;
|
||||||
|
int ys = pad->GetDrillSize().y;
|
||||||
|
PCB_LAYER_ID top, bottom;
|
||||||
|
|
||||||
|
if( pad->GetLayerSet().CuStack().empty() )
|
||||||
|
{
|
||||||
|
top = UNDEFINED_LAYER;
|
||||||
|
bottom = UNDEFINED_LAYER;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
top = pad->GetLayerSet().CuStack().front();
|
||||||
|
bottom = pad->GetLayerSet().CuStack().back();
|
||||||
|
}
|
||||||
|
|
||||||
|
DRILL_LINE_ITEM e( xs, ys, pad->GetDrillShape(), pad->GetAttribute() != PAD_ATTRIB::NPTH, true,
|
||||||
|
top, bottom );
|
||||||
|
|
||||||
|
if( e == *target )
|
||||||
|
selectedItems.push_back( pad );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vias
|
||||||
|
for( PCB_TRACK* t : board->Tracks() )
|
||||||
|
{
|
||||||
|
if( t->Type() != PCB_VIA_T )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PCB_VIA* via = static_cast<PCB_VIA*>( t );
|
||||||
|
DRILL_LINE_ITEM e( via->GetDrillValue(), via->GetDrillValue(), PAD_DRILL_SHAPE::CIRCLE, true,
|
||||||
|
false, via->TopLayer(), via->BottomLayer() );
|
||||||
|
|
||||||
|
if( e == *target )
|
||||||
|
selectedItems.push_back( via );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
m_frame->GetToolManager()->RunAction( ACTIONS::selectionClear );
|
||||||
|
|
||||||
|
if( selectedItems.size() )
|
||||||
|
{
|
||||||
|
m_frame->GetToolManager()->RunAction( ACTIONS::selectItems, &selectedItems );
|
||||||
|
|
||||||
|
switch( settings.selection_zoom )
|
||||||
|
{
|
||||||
|
case APP_SETTINGS_BASE::SEARCH_PANE::SELECTION_ZOOM::PAN:
|
||||||
|
m_frame->GetToolManager()->RunAction( ACTIONS::centerSelection );
|
||||||
|
break;
|
||||||
|
case APP_SETTINGS_BASE::SEARCH_PANE::SELECTION_ZOOM::ZOOM:
|
||||||
|
m_frame->GetToolManager()->RunAction( ACTIONS::zoomFitSelection );
|
||||||
|
break;
|
||||||
|
case APP_SETTINGS_BASE::SEARCH_PANE::SELECTION_ZOOM::NONE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_frame->GetCanvas()->Refresh( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wxString DRILL_SEARCH_HANDLER::cellText( const DRILL_LINE_ITEM& e, int col ) const
|
||||||
|
{
|
||||||
|
BOARD* board = m_frame->GetBoard();
|
||||||
|
|
||||||
|
switch( col )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return wxString::Format( "%d", e.m_Qty );
|
||||||
|
case 1:
|
||||||
|
return e.shape == PAD_DRILL_SHAPE::CIRCLE ? _( "Round" ) : _( "Slot" );
|
||||||
|
case 2:
|
||||||
|
return m_frame->MessageTextFromValue( e.xSize );
|
||||||
|
case 3:
|
||||||
|
return m_frame->MessageTextFromValue( e.ySize );
|
||||||
|
case 4:
|
||||||
|
return e.isPlated ? _( "PTH" ) : _( "NPTH" );
|
||||||
|
case 5:
|
||||||
|
return e.isPad ? _( "Pad" ) : _( "Via" );
|
||||||
|
case 6:
|
||||||
|
return ( e.startLayer == UNDEFINED_LAYER ) ? _( "N/A" ) : board->GetLayerName( e.startLayer );
|
||||||
|
case 7:
|
||||||
|
return ( e.stopLayer == UNDEFINED_LAYER ) ? _( "N/A" ) : board->GetLayerName( e.stopLayer );
|
||||||
|
default:
|
||||||
|
return wxEmptyString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DRILL_SEARCH_HANDLER::rowMatchesQuery( const DRILL_LINE_ITEM& e, const wxString& aQuery ) const
|
||||||
|
{
|
||||||
|
if( aQuery.IsEmpty() )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for( int col = 0; col < 8; ++col )
|
||||||
|
{
|
||||||
|
if( cellText( e, col ).Lower().Contains( aQuery ) )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
#define SEARCH_HANDLERS_H
|
#define SEARCH_HANDLERS_H
|
||||||
|
|
||||||
#include <widgets/search_pane.h>
|
#include <widgets/search_pane.h>
|
||||||
|
#include <board_statistics.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
class PCB_EDIT_FRAME;
|
class PCB_EDIT_FRAME;
|
||||||
|
|
||||||
@ -142,4 +144,40 @@ private:
|
|||||||
wxString getResultCell( BOARD_ITEM* aItem, int aCol ) override;
|
wxString getResultCell( BOARD_ITEM* aItem, int aCol ) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DRILL_SEARCH_HANDLER : public PCB_SEARCH_HANDLER
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DRILL_SEARCH_HANDLER( PCB_EDIT_FRAME* aFrame );
|
||||||
|
|
||||||
|
int Search( const wxString& aQuery ) override;
|
||||||
|
void Sort( int aCol, bool aAscending, std::vector<long>* aSelection ) override;
|
||||||
|
void SelectItems( std::vector<long>& aItemRows ) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
wxString getResultCell( BOARD_ITEM* aItem, int aCol ) override;
|
||||||
|
|
||||||
|
wxString cellText( const DRILL_LINE_ITEM& e, int col ) const;
|
||||||
|
bool rowMatchesQuery( const DRILL_LINE_ITEM& e, const wxString& aQuery ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct DRILL_ROW
|
||||||
|
{
|
||||||
|
DRILL_LINE_ITEM entry;
|
||||||
|
// While a DRILL_ROW will usually represent multiple identical drills/BOARD_ITEMs,
|
||||||
|
// keeping a pointer to one BOARD_ITEM allows use to provide
|
||||||
|
// compatibility with the rest of PCB_SEARCH_HANDLER, and also to allow
|
||||||
|
// some convenience actions to work when there is just a single entry, e.g.
|
||||||
|
// activating the item to show its properties.
|
||||||
|
BOARD_ITEM* item;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<DRILL_ROW> m_drills;
|
||||||
|
|
||||||
|
// This maps the DRILL_ROW.item to the index in m_drills to allow fast lookup
|
||||||
|
std::unordered_map<BOARD_ITEM*, int> m_ptrToDrill;
|
||||||
|
|
||||||
|
PCB_EDIT_FRAME* m_frame;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user