KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcbnew/widgets/search_handlers.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2023 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <footprint.h>
22#include <pcb_edit_frame.h>
23#include <pcb_marker.h>
24#include <pcb_painter.h>
25#include <pcb_group.h>
26#include <pcb_textbox.h>
27#include <pcb_text.h>
28#include <pcb_dimension.h>
29#include <pcbnew_settings.h>
31#include <string_utils.h>
32#include <tool/tool_manager.h>
33#include <tools/pcb_actions.h>
34#include <zone.h>
35#include <pad.h>
36#include <pcb_track.h>
37#include "search_handlers.h"
38
39
41{
42 std::vector<long> item = { aItemRow };
43 SelectItems( item );
44
45 m_frame->GetToolManager()->RunAction( PCB_ACTIONS::properties );
46}
47
48
49void PCB_SEARCH_HANDLER::Sort( int aCol, bool aAscending, std::vector<long>* aSelection )
50{
51 std::vector<BOARD_ITEM*> selection;
52
53 for( long i = 0; i < (long) m_hitlist.size(); ++i )
54 {
55 if( alg::contains( *aSelection, i ) )
56 selection.push_back( m_hitlist[i] );
57 }
58
59 int col = std::max( 0, aCol ); // Provide a stable order by sorting on first column if no
60 // sort column provided.
61
62 std::sort( m_hitlist.begin(), m_hitlist.end(),
63 [&]( BOARD_ITEM* a, BOARD_ITEM* b ) -> bool
64 {
65 // N.B. To meet the iterator sort conditions, we cannot simply invert the truth
66 // to get the opposite sort. i.e. ~(a<b) != (a>b)
67 if( aAscending )
68 return StrNumCmp( getResultCell( a, col ), getResultCell( b, col ), true ) < 0;
69 else
70 return StrNumCmp( getResultCell( b, col ), getResultCell( a, col ), true ) < 0;
71 } );
72
73
74 aSelection->clear();
75
76 for( long i = 0; i < (long) m_hitlist.size(); ++i )
77 {
78 if( alg::contains( selection, m_hitlist[i] ) )
79 aSelection->push_back( i );
80 }
81}
82
83
84void PCB_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
85{
86 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
87 std::vector<EDA_ITEM*> selectedItems;
88
89 for( long row : aItemRows )
90 {
91 if( row >= 0 && row < (long) m_hitlist.size() )
92 selectedItems.push_back( m_hitlist[row] );
93 }
94
95 m_frame->GetToolManager()->RunAction( ACTIONS::selectionClear );
96
97 if( selectedItems.size() )
98 {
99 m_frame->GetToolManager()->RunAction( ACTIONS::selectItems, &selectedItems );
100
101 switch( settings.selection_zoom )
102 {
104 m_frame->GetToolManager()->RunAction( ACTIONS::centerSelection );
105 break;
107 m_frame->GetToolManager()->RunAction( ACTIONS::zoomFitSelection );
108 break;
110 break;
111 }
112 }
113
114 m_frame->GetCanvas()->Refresh( false );
115}
116
117
119 PCB_SEARCH_HANDLER( _HKI( "Footprints" ), aFrame )
120{
121 m_columns.emplace_back( _HKI( "Reference" ), 2, wxLIST_FORMAT_LEFT );
122 m_columns.emplace_back( _HKI( "Value" ), 6, wxLIST_FORMAT_LEFT );
123 m_columns.emplace_back( _HKI( "Layer" ), 2, wxLIST_FORMAT_CENTER );
124 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
125 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
126 m_columns.emplace_back( _HKI( "Library Link" ), 8, wxLIST_FORMAT_LEFT );
127 m_columns.emplace_back( _HKI( "Library Description" ), 10, wxLIST_FORMAT_LEFT );
128}
129
130
131int FOOTPRINT_SEARCH_HANDLER::Search( const wxString& aQuery )
132{
133 m_hitlist.clear();
134 BOARD* board = m_frame->GetBoard();
135
136 if( board == nullptr )
137 return 0;
138
139 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
140 EDA_SEARCH_DATA frp;
141
143 frp.searchMetadata = settings.search_metadata;
144 frp.findString = aQuery;
145
146 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
148
149 for( FOOTPRINT* fp : board->Footprints() )
150 {
151 bool found = false;
152
153 if( frp.findString.IsEmpty() )
154 found = true;
155
156 if( !found && fp->Matches( frp, nullptr ) )
157 found = true;
158
159 if( !found )
160 {
161 for( PCB_FIELD* field : fp->GetFields() )
162 {
163 if( field->Matches( frp, nullptr ) )
164 {
165 found = true;
166 break;
167 }
168 }
169 }
170
171 if( found )
172 m_hitlist.push_back( fp );
173 }
174
175 return (int) m_hitlist.size();
176}
177
178
180{
181 FOOTPRINT* fp = static_cast<FOOTPRINT*>( aItem );
182
183 if( aCol == 0 )
184 return fp->GetReference();
185 else if( aCol == 1 )
186 return UnescapeString( fp->GetValue() );
187 else if( aCol == 2 )
188 return fp->GetLayerName();
189 else if( aCol == 3 )
190 return m_frame->MessageTextFromCoord( fp->GetX(), ORIGIN_TRANSFORMS::ABS_X_COORD );
191 else if( aCol == 4 )
192 return m_frame->MessageTextFromCoord( fp->GetY(), ORIGIN_TRANSFORMS::ABS_Y_COORD );
193 else if( aCol == 5 )
194 return fp->GetFPID().Format();
195 else if( aCol == 6 )
196 return fp->GetLibDescription();
197
198 return wxEmptyString;
199}
200
201
203 PCB_SEARCH_HANDLER( _HKI( "Zones" ), aFrame )
204{
205 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
206 m_columns.emplace_back( _HKI( "Net" ), 6, wxLIST_FORMAT_LEFT);
207 m_columns.emplace_back( _HKI( "Layer" ), 3, wxLIST_FORMAT_CENTER );
208 m_columns.emplace_back( _HKI( "Priority" ), 2, wxLIST_FORMAT_CENTER );
209 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
210 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
211 m_columns.emplace_back( _HKI( "Area" ), 3, wxLIST_FORMAT_RIGHT );
212}
213
214
215int ZONE_SEARCH_HANDLER::Search( const wxString& aQuery )
216{
217 m_hitlist.clear();
218 BOARD* board = m_frame->GetBoard();
219
220 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
221 EDA_SEARCH_DATA frp;
222
224 frp.searchMetadata = settings.search_metadata;
225 frp.findString = aQuery;
226
227 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
229
230 for( BOARD_ITEM* item : board->Zones() )
231 {
232 if( frp.findString.IsEmpty() || item->Matches( frp, nullptr ) )
233 m_hitlist.push_back( item );
234 }
235
236 return (int) m_hitlist.size();
237}
238
239
241{
242 ZONE* zone = static_cast<ZONE*>( aItem );
243
244 if( aCol == 0 )
245 return zone->GetZoneName();
246 else if( aCol == 1 )
247 return UnescapeString( zone->GetNetname() );
248 else if( aCol == 2 )
249 {
250 wxArrayString layers;
251 BOARD* board = m_frame->GetBoard();
252
253 for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
254 layers.Add( board->GetLayerName( layer ) );
255
256 return wxJoin( layers, ',' );
257 }
258 else if( aCol == 3 )
259 return wxString::Format( "%d", zone->GetAssignedPriority() );
260 else if( aCol == 4 )
261 return m_frame->MessageTextFromCoord( zone->GetX(), ORIGIN_TRANSFORMS::ABS_X_COORD );
262 else if( aCol == 5 )
263 return m_frame->MessageTextFromCoord( zone->GetY(), ORIGIN_TRANSFORMS::ABS_Y_COORD );
264 else if( aCol == 6 )
265 {
266 return m_frame->MessageTextFromValue( zone->GetIsRuleArea() ? zone->GetOutlineArea() : zone->GetFilledArea(),
267 true, EDA_DATA_TYPE::AREA );
268 }
269
270
271 return wxEmptyString;
272}
273
274
276 PCB_SEARCH_HANDLER( _HKI( "Text" ), aFrame )
277{
278 m_columns.emplace_back( _HKI( "Type" ), 2, wxLIST_FORMAT_LEFT );
279 m_columns.emplace_back( _HKI( "Text" ), 12, wxLIST_FORMAT_LEFT );
280 m_columns.emplace_back( _HKI( "Layer" ), 3, wxLIST_FORMAT_CENTER );
281 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
282 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
283}
284
285
286int TEXT_SEARCH_HANDLER::Search( const wxString& aQuery )
287{
288 m_hitlist.clear();
289 BOARD* board = m_frame->GetBoard();
290
292 EDA_SEARCH_DATA frp;
293
295 frp.searchMetadata = settings.search_metadata;
296 frp.findString = aQuery;
297
298 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
300
301 for( BOARD_ITEM* item : board->Drawings() )
302 {
303 if( item->Type() == PCB_TEXT_T
304 || BaseType( item->Type() ) == PCB_DIMENSION_T
305 || item->Type() == PCB_TEXTBOX_T
306 || item->Type() == PCB_TABLECELL_T )
307 {
308 if( frp.findString.IsEmpty() || item->Matches( frp, nullptr ) )
309 m_hitlist.push_back( item );
310 }
311 }
312
313 return (int) m_hitlist.size();
314}
315
316
318{
319 if( aCol == 0 )
320 {
321 if( PCB_TEXT::ClassOf( aItem ) )
322 return _( "Text" );
323 else if( PCB_TEXTBOX::ClassOf( aItem ) )
324 return _( "Textbox" );
325 else if( dynamic_cast<PCB_DIMENSION_BASE*>( aItem ) )
326 return _( "Dimension" );
327 }
328 else if( aCol == 1 )
329 {
330 if( PCB_TEXT::ClassOf( aItem ) )
331 return UnescapeString( static_cast<PCB_TEXT*>( aItem )->GetText() );
332 else if( PCB_TEXTBOX::ClassOf( aItem ) )
333 return UnescapeString( static_cast<PCB_TEXTBOX*>( aItem )->GetText() );
334 else if( PCB_DIMENSION_BASE* dimension = dynamic_cast<PCB_DIMENSION_BASE*>( aItem ) )
335 return UnescapeString( dimension->GetText() );
336 }
337 else if( aCol == 2 )
338 return aItem->GetLayerName();
339 else if( aCol == 3 )
340 return m_frame->MessageTextFromCoord( aItem->GetX(), ORIGIN_TRANSFORMS::ABS_X_COORD );
341 else if( aCol == 4 )
342 return m_frame->MessageTextFromCoord( aItem->GetY(), ORIGIN_TRANSFORMS::ABS_Y_COORD );
343
344 return wxEmptyString;
345}
346
347
349 PCB_SEARCH_HANDLER( _HKI( "Groups" ), aFrame )
350{
351 m_columns.emplace_back( _HKI( "Type" ), 2, wxLIST_FORMAT_LEFT );
352 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
353 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
354 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
355}
356
357
358int GROUP_SEARCH_HANDLER::Search( const wxString& aQuery )
359{
360 m_hitlist.clear();
361 BOARD* board = m_frame->GetBoard();
362
364 EDA_SEARCH_DATA frp;
365
367 frp.searchMetadata = settings.search_metadata;
368 frp.findString = aQuery;
369
370 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
372
373 for( BOARD_ITEM* item : board->Groups() )
374 {
375 // Skip generators, they are for internal use, not user-facing grouping
376 if( item->Type() == PCB_GENERATOR_T )
377 continue;
378
379 if( frp.findString.IsEmpty() || item->Matches( frp, nullptr ) )
380 m_hitlist.push_back( item );
381 }
382
383 return (int) m_hitlist.size();
384}
385
386
388{
389 if( aCol == 0 )
390 {
391 if( aItem->Type() == PCB_GROUP_T )
392 return _( "Group" );
393 else if( aItem->Type() == PCB_GENERATOR_T )
394 return _( "Generator" );
395 }
396 else if( aCol == 1 )
397 return static_cast<PCB_GROUP*>( aItem )->GetName();
398 else if( aCol == 2 )
399 return m_frame->MessageTextFromCoord( aItem->GetX(), ORIGIN_TRANSFORMS::ABS_X_COORD );
400 else if( aCol == 3 )
401 return m_frame->MessageTextFromCoord( aItem->GetY(), ORIGIN_TRANSFORMS::ABS_Y_COORD );
402
403 return wxEmptyString;
404}
405
406
408 PCB_SEARCH_HANDLER( _HKI( "Nets" ), aFrame )
409{
410 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
411 m_columns.emplace_back( _HKI( "Class" ), 6, wxLIST_FORMAT_LEFT );
412}
413
414
415int NETS_SEARCH_HANDLER::Search( const wxString& aQuery )
416{
417 m_hitlist.clear();
418
419 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
420 EDA_SEARCH_DATA frp;
421
423 frp.searchMetadata = settings.search_metadata;
424 frp.findString = aQuery;
425
426 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
428
429 BOARD* board = m_frame->GetBoard();
430
431 for( NETINFO_ITEM* net : board->GetNetInfo() )
432 {
433 if( net && ( aQuery.IsEmpty() || net->Matches( frp, nullptr ) ) )
434 m_hitlist.push_back( net );
435 }
436
437 return (int) m_hitlist.size();
438}
439
440
442{
443 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aItem );
444
445 if( net->GetNetCode() == 0 )
446 {
447 if( aCol == 0 )
448 return _( "No Net" );
449 else if( aCol == 1 )
450 return wxT( "" );
451 }
452
453 if( aCol == 0 )
454 return UnescapeString( net->GetNetname() );
455 else if( aCol == 1 )
456 return net->GetNetClass()->GetName();
457
458 return wxEmptyString;
459}
460
461
462void NETS_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
463{
464 RENDER_SETTINGS* ps = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
465 ps->SetHighlight( false );
466
467 std::vector<NETINFO_ITEM*> selectedItems;
468
469 for( long row : aItemRows )
470 {
471 if( row >= 0 && row < (long) m_hitlist.size() )
472 {
473 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( m_hitlist[row] );
474
475 ps->SetHighlight( true, net->GetNetCode(), true );
476 }
477 }
478
479 m_frame->GetCanvas()->GetView()->UpdateAllLayersColor();
480 m_frame->GetCanvas()->Refresh();
481}
482
483
485{
486 m_frame->ShowBoardSetupDialog( _( "Net Classes" ) );
487}
488
489
491 PCB_SEARCH_HANDLER( _HKI( "Ratsnest" ), aFrame )
492{
493 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
494 m_columns.emplace_back( _HKI( "Class" ), 6, wxLIST_FORMAT_LEFT );
495}
496
497
498int RATSNEST_SEARCH_HANDLER::Search( const wxString& aQuery )
499{
500 m_hitlist.clear();
501
502 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
503 EDA_SEARCH_DATA frp;
504
506 frp.searchMetadata = settings.search_metadata;
507 frp.findString = aQuery;
508
509 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
511
512 BOARD* board = m_frame->GetBoard();
513
514 for( NETINFO_ITEM* net : board->GetNetInfo() )
515 {
516 if( net == nullptr || !net->Matches( frp, nullptr ) )
517 continue;
518
519 RN_NET* rn = board->GetConnectivity()->GetRatsnestForNet( net->GetNetCode() );
520
521 if( rn && !rn->GetEdges().empty() )
522 m_hitlist.push_back( net );
523 }
524
525 return (int) m_hitlist.size();
526}
527
528
530{
531 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aItem );
532
533 if( net->GetNetCode() == 0 )
534 {
535 if( aCol == 0 )
536 return _( "No Net" );
537 else if( aCol == 1 )
538 return wxT( "" );
539 }
540
541 if( aCol == 0 )
542 return UnescapeString( net->GetNetname() );
543 else if( aCol == 1 )
544 return net->GetNetClass()->GetName();
545
546 return wxEmptyString;
547}
548
549
550void RATSNEST_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
551{
552 RENDER_SETTINGS* ps = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
553 ps->SetHighlight( false );
554
555 std::vector<NETINFO_ITEM*> selectedItems;
556
557 for( long row : aItemRows )
558 {
559 if( row >= 0 && row < (long) m_hitlist.size() )
560 {
561 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( m_hitlist[row] );
562
563 ps->SetHighlight( true, net->GetNetCode(), true );
564 }
565 }
566
567 m_frame->GetCanvas()->GetView()->UpdateAllLayersColor();
568 m_frame->GetCanvas()->Refresh();
569}
570
571
573{
574 m_frame->ShowBoardSetupDialog( _( "Net Classes" ) );
575}
576
577
579 PCB_SEARCH_HANDLER( _HKI( "Drills" ), aFrame ),
580 m_frame( aFrame )
581{
582 m_columns.emplace_back( _HKI( "Count" ), 2, wxLIST_FORMAT_RIGHT );
583 m_columns.emplace_back( _HKI( "Shape" ), 3, wxLIST_FORMAT_LEFT );
584 m_columns.emplace_back( _HKI( "X Size" ), 3, wxLIST_FORMAT_CENTER );
585 m_columns.emplace_back( _HKI( "Y Size" ), 3, wxLIST_FORMAT_CENTER );
586 m_columns.emplace_back( _HKI( "Plated" ), 2, wxLIST_FORMAT_CENTER );
587 m_columns.emplace_back( _HKI( "Via/Pad" ), 2, wxLIST_FORMAT_CENTER );
588 m_columns.emplace_back( _HKI( "Start Layer" ), 4, wxLIST_FORMAT_CENTER );
589 m_columns.emplace_back( _HKI( "Stop Layer" ), 4, wxLIST_FORMAT_CENTER );
590}
591
592
593int DRILL_SEARCH_HANDLER::Search( const wxString& aQuery )
594{
595 BOARD* board = m_frame->GetBoard();
596
597 m_drills.clear();
598 m_ptrToDrill.clear();
599 m_hitlist.clear();
600
601 auto addEntryOrIncrement = [&]( const DRILL_LINE_ITEM& d, BOARD_ITEM* rep )
602 {
603 for( DRILL_ROW& g : m_drills )
604 {
605 if( g.entry == d )
606 {
607 g.entry.m_Qty++;
608 return;
609 }
610 }
611
612 DRILL_ROW g = { .entry = d, .item = rep, };
613 g.entry.m_Qty = 1;
614
615 m_drills.push_back( g );
616 };
617
618 // Collect from pads
619 for( FOOTPRINT* fp : board->Footprints() )
620 {
621 for( PAD* pad : fp->Pads() )
622 {
623 if( !pad->HasHole() )
624 continue;
625
626 int xs = pad->GetDrillSize().x;
627 int ys = pad->GetDrillSize().y;
628 if( xs <= 0 || ys <= 0 )
629 continue;
630
631 PCB_LAYER_ID top, bottom;
632
633 if( pad->GetLayerSet().CuStack().empty() )
634 {
635 top = UNDEFINED_LAYER;
636 bottom = UNDEFINED_LAYER;
637 }
638 else
639 {
640 top = pad->GetLayerSet().CuStack().front();
641 bottom = pad->GetLayerSet().CuStack().back();
642 }
643
644 DRILL_LINE_ITEM d( xs, ys, pad->GetDrillShape(),
645 pad->GetAttribute() != PAD_ATTRIB::NPTH,
646 true, top, bottom );
647
648 addEntryOrIncrement( d, pad );
649 }
650 }
651
652 // Collect from vias
653 for( PCB_TRACK* t : board->Tracks() )
654 {
655 if( t->Type() != PCB_VIA_T )
656 continue;
657
658 PCB_VIA* via = static_cast<PCB_VIA*>( t );
659 int dmm = via->GetDrillValue();
660 if( dmm <= 0 )
661 continue;
662
663 DRILL_LINE_ITEM d( dmm, dmm, PAD_DRILL_SHAPE::CIRCLE, true,
664 false, via->TopLayer(), via->BottomLayer() );
665 addEntryOrIncrement( d, via );
666 }
667
668 std::sort( m_drills.begin(), m_drills.end(),
669 []( const DRILL_ROW& a, const DRILL_ROW& b )
670 {
671 DRILL_LINE_ITEM::COMPARE cmp( DRILL_LINE_ITEM::COL_COUNT, false );
672 return cmp( a.entry, b.entry );
673 } );
674
675 // Apply filter and populate display list
676 for( size_t i = 0; i < m_drills.size(); ++i )
677 {
678 if( aQuery.IsEmpty() || rowMatchesQuery( m_drills[i].entry, aQuery.Lower() ) )
679 {
680 m_hitlist.push_back( m_drills[i].item );
681 m_ptrToDrill[m_drills[i].item] = (int) i;
682 }
683 }
684
685 return (int) m_hitlist.size();
686}
687
688
690{
691 auto it = m_ptrToDrill.find( aItem );
692
693 if( it == m_ptrToDrill.end() )
694 return wxEmptyString;
695
696 const auto& e = m_drills[it->second].entry;
697
698 return cellText( e, aCol );
699}
700
701
702void DRILL_SEARCH_HANDLER::Sort( int aCol, bool aAscending, std::vector<long>* aSelection )
703{
704 // Preserve current selection pointers
705 std::vector<BOARD_ITEM*> selPtrs;
706
707 if( aSelection )
708 {
709 for( long row : *aSelection )
710 {
711 if( row >= 0 && row < (long) m_hitlist.size() )
712 selPtrs.push_back( m_hitlist[row] );
713 }
714 }
715
716 auto cmpPtr = [&]( BOARD_ITEM* pa, BOARD_ITEM* pb )
717 {
718 const auto& a = m_drills[m_ptrToDrill[pa]].entry;
719 const auto& b = m_drills[m_ptrToDrill[pb]].entry;
720
721 int col = aCol < 0 ? 0 : aCol;
722 DRILL_LINE_ITEM::COMPARE cmp( static_cast<DRILL_LINE_ITEM::COL_ID>( col ), aAscending );
723
724 return cmp( a, b );
725 };
726
727 std::sort( m_hitlist.begin(), m_hitlist.end(), cmpPtr );
728
729 // Rebuild selection rows from pointers
730 if( aSelection )
731 {
732 aSelection->clear();
733
734 for( long row = 0; row < (long) m_hitlist.size(); ++row )
735 {
736 if( alg::contains( selPtrs, m_hitlist[row] ) )
737 aSelection->push_back( row );
738 }
739 }
740}
741
742
743void DRILL_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
744{
745 BOARD* board = m_frame->GetBoard();
746 std::vector<EDA_ITEM*> selectedItems;
747 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
748
749 // Collect matching items
750 for( long row : aItemRows )
751 {
752 if( row < 0 || row >= (long) m_hitlist.size() )
753 continue;
754
755 BOARD_ITEM* rep = m_hitlist[row];
756 auto it = m_ptrToDrill.find( rep );
757
758 if( it == m_ptrToDrill.end() )
759 continue;
760
761 const auto* target = &m_drills[it->second].entry;
762
763 // Pads
764 for( FOOTPRINT* fp : board->Footprints() )
765 {
766 for( PAD* pad : fp->Pads() )
767 {
768 if( !pad->HasHole() )
769 continue;
770
771 int xs = pad->GetDrillSize().x;
772 int ys = pad->GetDrillSize().y;
773 PCB_LAYER_ID top, bottom;
774
775 if( pad->GetLayerSet().CuStack().empty() )
776 {
777 top = UNDEFINED_LAYER;
778 bottom = UNDEFINED_LAYER;
779 }
780 else
781 {
782 top = pad->GetLayerSet().CuStack().front();
783 bottom = pad->GetLayerSet().CuStack().back();
784 }
785
786 DRILL_LINE_ITEM e( xs, ys, pad->GetDrillShape(), pad->GetAttribute() != PAD_ATTRIB::NPTH, true,
787 top, bottom );
788
789 if( e == *target )
790 selectedItems.push_back( pad );
791 }
792 }
793
794 // Vias
795 for( PCB_TRACK* t : board->Tracks() )
796 {
797 if( t->Type() != PCB_VIA_T )
798 continue;
799
800 PCB_VIA* via = static_cast<PCB_VIA*>( t );
801 DRILL_LINE_ITEM e( via->GetDrillValue(), via->GetDrillValue(), PAD_DRILL_SHAPE::CIRCLE, true,
802 false, via->TopLayer(), via->BottomLayer() );
803
804 if( e == *target )
805 selectedItems.push_back( via );
806 }
807 }
808
809
810 m_frame->GetToolManager()->RunAction( ACTIONS::selectionClear );
811
812 if( selectedItems.size() )
813 {
814 m_frame->GetToolManager()->RunAction( ACTIONS::selectItems, &selectedItems );
815
816 switch( settings.selection_zoom )
817 {
819 m_frame->GetToolManager()->RunAction( ACTIONS::centerSelection );
820 break;
822 m_frame->GetToolManager()->RunAction( ACTIONS::zoomFitSelection );
823 break;
825 break;
826 }
827 }
828
829 m_frame->GetCanvas()->Refresh( false );
830}
831
832
833wxString DRILL_SEARCH_HANDLER::cellText( const DRILL_LINE_ITEM& e, int col ) const
834{
835 BOARD* board = m_frame->GetBoard();
836
837 switch( col )
838 {
839 case 0:
840 return wxString::Format( "%d", e.m_Qty );
841 case 1:
842 return e.shape == PAD_DRILL_SHAPE::CIRCLE ? _( "Round" ) : _( "Slot" );
843 case 2:
844 return m_frame->MessageTextFromValue( e.xSize );
845 case 3:
846 return m_frame->MessageTextFromValue( e.ySize );
847 case 4:
848 return e.isPlated ? _( "PTH" ) : _( "NPTH" );
849 case 5:
850 return e.isPad ? _( "Pad" ) : _( "Via" );
851 case 6:
852 return ( e.startLayer == UNDEFINED_LAYER ) ? _( "N/A" ) : board->GetLayerName( e.startLayer );
853 case 7:
854 return ( e.stopLayer == UNDEFINED_LAYER ) ? _( "N/A" ) : board->GetLayerName( e.stopLayer );
855 default:
856 return wxEmptyString;
857 }
858}
859
860
861bool DRILL_SEARCH_HANDLER::rowMatchesQuery( const DRILL_LINE_ITEM& e, const wxString& aQuery ) const
862{
863 if( aQuery.IsEmpty() )
864 return true;
865
866 for( int col = 0; col < 8; ++col )
867 {
868 if( cellText( e, col ).Lower().Contains( aQuery ) )
869 return true;
870 }
871
872 return false;
873}
static TOOL_ACTION zoomFitSelection
Definition actions.h:143
static TOOL_ACTION centerSelection
Definition actions.h:149
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:223
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:231
SEARCH_PANE m_SearchPane
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:79
int GetY() const
Definition board_item.h:101
int GetX() const
Definition board_item.h:95
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:317
const NETINFO_LIST & GetNetInfo() const
Definition board.h:933
const ZONES & Zones() const
Definition board.h:362
const GROUPS & Groups() const
The groups must maintain the following invariants.
Definition board.h:391
const FOOTPRINTS & Footprints() const
Definition board.h:358
const TRACKS & Tracks() const
Definition board.h:356
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:691
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition board.h:521
const DRAWINGS & Drawings() const
Definition board.h:360
RN_NET * GetRatsnestForNet(int aNet)
Function GetRatsnestForNet() Returns the ratsnest, expressed as a set of graph edges for a given net.
wxString cellText(const DRILL_LINE_ITEM &e, int col) const
std::unordered_map< BOARD_ITEM *, int > m_ptrToDrill
void SelectItems(std::vector< long > &aItemRows) override
int Search(const wxString &aQuery) override
bool rowMatchesQuery(const DRILL_LINE_ITEM &e, const wxString &aQuery) const
DRILL_SEARCH_HANDLER(PCB_EDIT_FRAME *aFrame)
void Sort(int aCol, bool aAscending, std::vector< long > *aSelection) override
std::vector< DRILL_ROW > m_drills
wxString getResultCell(BOARD_ITEM *aItem, int aCol) override
virtual APP_SETTINGS_BASE * config() const
Return the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
FOOTPRINT_SEARCH_HANDLER(PCB_EDIT_FRAME *aFrame)
int Search(const wxString &aQuery) override
wxString getResultCell(BOARD_ITEM *aItem, int aCol) override
wxString GetLibDescription() const
Definition footprint.h:278
const LIB_ID & GetFPID() const
Definition footprint.h:269
const wxString & GetValue() const
Definition footprint.h:683
const wxString & GetReference() const
Definition footprint.h:661
wxString getResultCell(const SCH_SEARCH_HIT &hit, int aCol) override
int Search(const wxString &aQuery) override
GROUP_SEARCH_HANDLER(SCH_EDIT_FRAME *aFrame)
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Turns on/off highlighting.
UTF8 Format() const
Definition lib_id.cpp:119
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition lset.cpp:296
const wxString GetName() const
Gets the name of this (maybe aggregate) netclass in a format for internal usage or for export to exte...
Definition netclass.cpp:322
Handle the data for a net.
Definition netinfo.h:54
const wxString & GetNetname() const
Definition netinfo.h:112
NETCLASS * GetNetClass()
Definition netinfo.h:99
int GetNetCode() const
Definition netinfo.h:106
void ActivateItem(long aItemRow) override
int Search(const wxString &aQuery) override
NETS_SEARCH_HANDLER(PCB_EDIT_FRAME *aFrame)
wxString getResultCell(BOARD_ITEM *aItem, int aCol) override
void SelectItems(std::vector< long > &aItemRows) override
Definition pad.h:54
static TOOL_ACTION properties
Activation of the edit tool.
Abstract dimension API.
The main frame for Pcbnew.
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:53
void ActivateItem(long aItemRow) override
PCB_SEARCH_HANDLER(const wxString &aName, PCB_EDIT_FRAME *aFrame)
void Sort(int aCol, bool aAscending, std::vector< long > *aSelection) override
void SelectItems(std::vector< long > &aItemRows) override
std::vector< BOARD_ITEM * > m_hitlist
static bool ClassOf(const EDA_ITEM *aItem)
Definition pcb_textbox.h:48
static bool ClassOf(const EDA_ITEM *aItem)
Definition pcb_text.h:51
wxString getResultCell(BOARD_ITEM *aItem, int aCol) override
RATSNEST_SEARCH_HANDLER(PCB_EDIT_FRAME *aFrame)
int Search(const wxString &aQuery) override
void SelectItems(std::vector< long > &aItemRows) override
void ActivateItem(long aItemRow) override
Describe ratsnest for a single net.
const std::vector< CN_EDGE > & GetEdges() const
std::vector< SCH_SEARCH_HIT > m_hitlist
std::vector< std::tuple< wxString, int, wxListColumnFormat > > m_columns
Definition search_pane.h:61
wxString GetName() const
Definition search_pane.h:45
TEXT_SEARCH_HANDLER(SCH_EDIT_FRAME *aFrame)
int Search(const wxString &aQuery) override
wxString getResultCell(const SCH_SEARCH_HIT &hit, int aCol) override
ZONE_SEARCH_HANDLER(PCB_EDIT_FRAME *aFrame)
wxString getResultCell(BOARD_ITEM *aItem, int aCol) override
int Search(const wxString &aQuery) override
Handle a list of polygons defining a copper zone.
Definition zone.h:74
double GetOutlineArea()
This area is cached from the most recent call to CalculateOutlineArea().
Definition zone.h:275
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition zone.h:704
double GetFilledArea()
This area is cached from the most recent call to CalculateFilledArea().
Definition zone.h:265
const wxString & GetZoneName() const
Definition zone.h:163
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:136
unsigned GetAssignedPriority() const
Definition zone.h:126
#define _(s)
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ UNDEFINED_LAYER
Definition layer_ids.h:61
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:100
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:87
#define _HKI(x)
Definition page_info.cpp:44
Class to handle a set of BOARD_ITEMs.
Class that computes missing connections on a PCB.
wxString UnescapeString(const wxString &aSource)
PCB_LAYER_ID stopLayer
PAD_DRILL_SHAPE shape
PCB_LAYER_ID startLayer
EDA_SEARCH_MATCH_MODE matchMode
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
Definition typeinfo.h:252
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition typeinfo.h:91
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:110
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:93
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:92
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:95
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition typeinfo.h:100