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 "search_handlers.h"
22
23#include <board.h>
24#include <footprint.h>
25#include <pcb_edit_frame.h>
26#include <pcb_marker.h>
27#include <pcb_painter.h>
28#include <pcb_group.h>
29#include <pcb_textbox.h>
30#include <pcb_text.h>
31#include <pcb_dimension.h>
32#include <pcbnew_settings.h>
34#include <string_utils.h>
35#include <tool/tool_manager.h>
36#include <tools/pcb_actions.h>
37#include <zone.h>
38#include <pad.h>
39#include <pcb_track.h>
40
41
43{
44 std::vector<long> item = { aItemRow };
45 SelectItems( item );
46
47 m_frame->GetToolManager()->RunAction( PCB_ACTIONS::properties );
48}
49
50
51wxString PCB_SEARCH_HANDLER::GetResultCell( int aRow, int aCol )
52{
53 if( m_frame->IsClosing() )
54 return wxEmptyString;
55
56 if( aRow >= static_cast<int>(m_hitlist.size() ) )
57 return wxEmptyString;
58
59 BOARD_ITEM* item = m_hitlist[aRow];
60
61 if( !item )
62 return wxEmptyString;
63
64 return getResultCell( item, aCol );
65}
66
67
68void PCB_SEARCH_HANDLER::Sort( int aCol, bool aAscending, std::vector<long>* aSelection )
69{
70 std::vector<BOARD_ITEM*> selection;
71
72 for( long i = 0; i < (long) m_hitlist.size(); ++i )
73 {
74 if( alg::contains( *aSelection, i ) )
75 selection.push_back( m_hitlist[i] );
76 }
77
78 int col = std::max( 0, aCol ); // Provide a stable order by sorting on first column if no
79 // sort column provided.
80
81 std::sort( m_hitlist.begin(), m_hitlist.end(),
82 [&]( BOARD_ITEM* a, BOARD_ITEM* b ) -> bool
83 {
84 // N.B. To meet the iterator sort conditions, we cannot simply invert the truth
85 // to get the opposite sort. i.e. ~(a<b) != (a>b)
86 if( aAscending )
87 return StrNumCmp( getResultCell( a, col ), getResultCell( b, col ), true ) < 0;
88 else
89 return StrNumCmp( getResultCell( b, col ), getResultCell( a, col ), true ) < 0;
90 } );
91
92
93 aSelection->clear();
94
95 for( long i = 0; i < (long) m_hitlist.size(); ++i )
96 {
97 if( alg::contains( selection, m_hitlist[i] ) )
98 aSelection->push_back( i );
99 }
100}
101
102
103void PCB_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
104{
105 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
106 std::vector<EDA_ITEM*> selectedItems;
107
108 for( long row : aItemRows )
109 {
110 if( row >= 0 && row < (long) m_hitlist.size() )
111 selectedItems.push_back( m_hitlist[row] );
112 }
113
114 m_frame->GetToolManager()->RunAction( ACTIONS::selectionClear );
115
116 if( selectedItems.size() )
117 {
118 m_frame->GetToolManager()->RunAction( ACTIONS::selectItems, &selectedItems );
119
120 switch( settings.selection_zoom )
121 {
123 m_frame->GetToolManager()->RunAction( ACTIONS::centerSelection );
124 break;
126 m_frame->GetToolManager()->RunAction( ACTIONS::zoomFitSelection );
127 break;
129 break;
130 }
131 }
132
133 m_frame->GetCanvas()->Refresh( false );
134}
135
136
138 PCB_SEARCH_HANDLER( _HKI( "Footprints" ), aFrame )
139{
140 m_columns.emplace_back( _HKI( "Reference" ), 2, wxLIST_FORMAT_LEFT );
141 m_columns.emplace_back( _HKI( "Value" ), 6, wxLIST_FORMAT_LEFT );
142 m_columns.emplace_back( _HKI( "Layer" ), 2, wxLIST_FORMAT_CENTER );
143 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
144 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
145 m_columns.emplace_back( _HKI( "Library Link" ), 8, wxLIST_FORMAT_LEFT );
146 m_columns.emplace_back( _HKI( "Library Description" ), 10, wxLIST_FORMAT_LEFT );
147}
148
149
150int FOOTPRINT_SEARCH_HANDLER::Search( const wxString& aQuery )
151{
152 m_hitlist.clear();
153 BOARD* board = m_frame->GetBoard();
154
155 if( board == nullptr )
156 return 0;
157
158 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
159 EDA_SEARCH_DATA frp;
160
162 frp.searchMetadata = settings.search_metadata;
163 frp.findString = aQuery;
164
165 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
167
168 for( FOOTPRINT* fp : board->Footprints() )
169 {
170 bool found = false;
171
172 if( frp.findString.IsEmpty() )
173 found = true;
174
175 if( !found && fp->Matches( frp, nullptr ) )
176 found = true;
177
178 if( !found )
179 {
180 for( PCB_FIELD* field : fp->GetFields() )
181 {
182 wxCHECK2( field, continue );
183
184 if( field->Matches( frp, nullptr ) )
185 {
186 found = true;
187 break;
188 }
189 }
190 }
191
192 if( found )
193 m_hitlist.push_back( fp );
194 }
195
196 return (int) m_hitlist.size();
197}
198
199
201{
202 FOOTPRINT* fp = static_cast<FOOTPRINT*>( aItem );
203
204 if( aCol == 0 )
205 return fp->GetReference();
206 else if( aCol == 1 )
207 return UnescapeString( fp->GetValue() );
208 else if( aCol == 2 )
209 return fp->GetLayerName();
210 else if( aCol == 3 )
211 return m_frame->MessageTextFromCoord( fp->GetX(), ORIGIN_TRANSFORMS::ABS_X_COORD );
212 else if( aCol == 4 )
213 return m_frame->MessageTextFromCoord( fp->GetY(), ORIGIN_TRANSFORMS::ABS_Y_COORD );
214 else if( aCol == 5 )
215 return fp->GetFPID().Format();
216 else if( aCol == 6 )
217 return fp->GetLibDescription();
218
219 return wxEmptyString;
220}
221
222
224 PCB_SEARCH_HANDLER( _HKI( "Zones" ), aFrame )
225{
226 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
227 m_columns.emplace_back( _HKI( "Net" ), 6, wxLIST_FORMAT_LEFT);
228 m_columns.emplace_back( _HKI( "Layer" ), 3, wxLIST_FORMAT_CENTER );
229 m_columns.emplace_back( _HKI( "Priority" ), 2, wxLIST_FORMAT_CENTER );
230 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
231 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
232 m_columns.emplace_back( _HKI( "Area" ), 3, wxLIST_FORMAT_RIGHT );
233}
234
235
236int ZONE_SEARCH_HANDLER::Search( const wxString& aQuery )
237{
238 m_hitlist.clear();
239 BOARD* board = m_frame->GetBoard();
240
241 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
242 EDA_SEARCH_DATA frp;
243
245 frp.searchMetadata = settings.search_metadata;
246 frp.findString = aQuery;
247
248 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
250
251 for( BOARD_ITEM* item : board->Zones() )
252 {
253 if( frp.findString.IsEmpty() || item->Matches( frp, nullptr ) )
254 m_hitlist.push_back( item );
255 }
256
257 return (int) m_hitlist.size();
258}
259
260
262{
263 ZONE* zone = static_cast<ZONE*>( aItem );
264
265 if( aCol == 0 )
266 return zone->GetZoneName();
267 else if( aCol == 1 )
268 return UnescapeString( zone->GetNetname() );
269 else if( aCol == 2 )
270 {
271 wxArrayString layers;
272 BOARD* board = m_frame->GetBoard();
273 // Make sure we don't show layers from Rule Areas that aren't actually on the board,
274 // since they have all copper areas by default.
275 LSET dialogLayers = LSET::AllNonCuMask()
277
278 for( PCB_LAYER_ID layer : dialogLayers.UIOrder() )
279 {
280 if( zone->IsOnLayer( layer ) )
281 layers.Add( board->GetLayerName( layer ) );
282 }
283
284 return wxJoin( layers, ',' );
285 }
286 else if( aCol == 3 )
287 return wxString::Format( "%d", zone->GetAssignedPriority() );
288 else if( aCol == 4 )
289 return m_frame->MessageTextFromCoord( zone->GetX(), ORIGIN_TRANSFORMS::ABS_X_COORD );
290 else if( aCol == 5 )
291 return m_frame->MessageTextFromCoord( zone->GetY(), ORIGIN_TRANSFORMS::ABS_Y_COORD );
292 else if( aCol == 6 )
293 {
294 return m_frame->MessageTextFromValue( zone->GetIsRuleArea() ? zone->GetOutlineArea() : zone->GetFilledArea(),
295 true, EDA_DATA_TYPE::AREA );
296 }
297
298
299 return wxEmptyString;
300}
301
302
304 PCB_SEARCH_HANDLER( _HKI( "Text" ), aFrame )
305{
306 m_columns.emplace_back( _HKI( "Type" ), 2, wxLIST_FORMAT_LEFT );
307 m_columns.emplace_back( _HKI( "Text" ), 12, wxLIST_FORMAT_LEFT );
308 m_columns.emplace_back( _HKI( "Layer" ), 3, wxLIST_FORMAT_CENTER );
309 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
310 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
311}
312
313
314int TEXT_SEARCH_HANDLER::Search( const wxString& aQuery )
315{
316 m_hitlist.clear();
317 BOARD* board = m_frame->GetBoard();
318
320 EDA_SEARCH_DATA frp;
321
323 frp.searchMetadata = settings.search_metadata;
324 frp.findString = aQuery;
325
326 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
328
329 for( BOARD_ITEM* item : board->Drawings() )
330 {
331 if( item->Type() == PCB_TEXT_T
332 || BaseType( item->Type() ) == PCB_DIMENSION_T
333 || item->Type() == PCB_TEXTBOX_T
334 || item->Type() == PCB_TABLECELL_T )
335 {
336 if( frp.findString.IsEmpty() || item->Matches( frp, nullptr ) )
337 m_hitlist.push_back( item );
338 }
339 }
340
341 return (int) m_hitlist.size();
342}
343
344
346{
347 if( aCol == 0 )
348 {
349 if( PCB_TEXT::ClassOf( aItem ) )
350 return _( "Text" );
351 else if( PCB_TEXTBOX::ClassOf( aItem ) )
352 return _( "Textbox" );
353 else if( dynamic_cast<PCB_DIMENSION_BASE*>( aItem ) )
354 return _( "Dimension" );
355 }
356 else if( aCol == 1 )
357 {
358 if( PCB_TEXT::ClassOf( aItem ) )
359 return UnescapeString( static_cast<PCB_TEXT*>( aItem )->GetText() );
360 else if( PCB_TEXTBOX::ClassOf( aItem ) )
361 return UnescapeString( static_cast<PCB_TEXTBOX*>( aItem )->GetText() );
362 else if( PCB_DIMENSION_BASE* dimension = dynamic_cast<PCB_DIMENSION_BASE*>( aItem ) )
363 return UnescapeString( dimension->GetText() );
364 }
365 else if( aCol == 2 )
366 return aItem->GetLayerName();
367 else if( aCol == 3 )
368 return m_frame->MessageTextFromCoord( aItem->GetX(), ORIGIN_TRANSFORMS::ABS_X_COORD );
369 else if( aCol == 4 )
370 return m_frame->MessageTextFromCoord( aItem->GetY(), ORIGIN_TRANSFORMS::ABS_Y_COORD );
371
372 return wxEmptyString;
373}
374
375
377 PCB_SEARCH_HANDLER( _HKI( "Groups" ), aFrame )
378{
379 m_columns.emplace_back( _HKI( "Type" ), 2, wxLIST_FORMAT_LEFT );
380 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
381 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
382 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
383}
384
385
386int GROUP_SEARCH_HANDLER::Search( const wxString& aQuery )
387{
388 m_hitlist.clear();
389 BOARD* board = m_frame->GetBoard();
390
392 EDA_SEARCH_DATA frp;
393
395 frp.searchMetadata = settings.search_metadata;
396 frp.findString = aQuery;
397
398 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
400
401 for( BOARD_ITEM* item : board->Groups() )
402 {
403 // Skip generators, they are for internal use, not user-facing grouping
404 if( item->Type() == PCB_GENERATOR_T )
405 continue;
406
407 if( frp.findString.IsEmpty() || item->Matches( frp, nullptr ) )
408 m_hitlist.push_back( item );
409 }
410
411 return (int) m_hitlist.size();
412}
413
414
416{
417 if( aCol == 0 )
418 {
419 if( aItem->Type() == PCB_GROUP_T )
420 return _( "Group" );
421 else if( aItem->Type() == PCB_GENERATOR_T )
422 return _( "Generator" );
423 }
424 else if( aCol == 1 )
425 return static_cast<PCB_GROUP*>( aItem )->GetName();
426 else if( aCol == 2 )
427 return m_frame->MessageTextFromCoord( aItem->GetX(), ORIGIN_TRANSFORMS::ABS_X_COORD );
428 else if( aCol == 3 )
429 return m_frame->MessageTextFromCoord( aItem->GetY(), ORIGIN_TRANSFORMS::ABS_Y_COORD );
430
431 return wxEmptyString;
432}
433
434
436 PCB_SEARCH_HANDLER( _HKI( "Nets" ), aFrame )
437{
438 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
439 m_columns.emplace_back( _HKI( "Class" ), 6, wxLIST_FORMAT_LEFT );
440}
441
442
443int NETS_SEARCH_HANDLER::Search( const wxString& aQuery )
444{
445 m_hitlist.clear();
446
447 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
448 EDA_SEARCH_DATA frp;
449
451 frp.searchMetadata = settings.search_metadata;
452 frp.findString = aQuery;
453
454 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
456
457 BOARD* board = m_frame->GetBoard();
458
459 for( NETINFO_ITEM* net : board->GetNetInfo() )
460 {
461 if( net && ( aQuery.IsEmpty() || net->Matches( frp, nullptr ) ) )
462 m_hitlist.push_back( net );
463 }
464
465 return (int) m_hitlist.size();
466}
467
468
470{
471 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aItem );
472
473 if( net->GetNetCode() == 0 )
474 {
475 if( aCol == 0 )
476 return _( "No Net" );
477 else if( aCol == 1 )
478 return wxT( "" );
479 }
480
481 if( aCol == 0 )
482 return UnescapeString( net->GetNetname() );
483 else if( aCol == 1 )
484 return net->GetNetClass()->GetName();
485
486 return wxEmptyString;
487}
488
489
490void NETS_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
491{
492 RENDER_SETTINGS* ps = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
493 ps->SetHighlight( false );
494
495 std::vector<NETINFO_ITEM*> selectedItems;
496
497 for( long row : aItemRows )
498 {
499 if( row >= 0 && row < (long) m_hitlist.size() )
500 {
501 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( m_hitlist[row] );
502
503 ps->SetHighlight( true, net->GetNetCode(), true );
504 }
505 }
506
507 m_frame->GetCanvas()->GetView()->UpdateAllLayersColor();
508 m_frame->GetCanvas()->Refresh();
509}
510
511
513{
514 m_frame->ShowBoardSetupDialog( _( "Net Classes" ) );
515}
516
517
519 PCB_SEARCH_HANDLER( _HKI( "Ratsnest" ), aFrame )
520{
521 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
522 m_columns.emplace_back( _HKI( "Class" ), 6, wxLIST_FORMAT_LEFT );
523}
524
525
526int RATSNEST_SEARCH_HANDLER::Search( const wxString& aQuery )
527{
528 m_hitlist.clear();
529
530 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
531 EDA_SEARCH_DATA frp;
532
534 frp.searchMetadata = settings.search_metadata;
535 frp.findString = aQuery;
536
537 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
539
540 BOARD* board = m_frame->GetBoard();
541
542 for( NETINFO_ITEM* net : board->GetNetInfo() )
543 {
544 if( net == nullptr || !net->Matches( frp, nullptr ) )
545 continue;
546
547 RN_NET* rn = board->GetConnectivity()->GetRatsnestForNet( net->GetNetCode() );
548
549 if( rn && !rn->GetEdges().empty() )
550 m_hitlist.push_back( net );
551 }
552
553 return (int) m_hitlist.size();
554}
555
556
558{
559 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aItem );
560
561 if( net->GetNetCode() == 0 )
562 {
563 if( aCol == 0 )
564 return _( "No Net" );
565 else if( aCol == 1 )
566 return wxT( "" );
567 }
568
569 if( aCol == 0 )
570 return UnescapeString( net->GetNetname() );
571 else if( aCol == 1 )
572 return net->GetNetClass()->GetName();
573
574 return wxEmptyString;
575}
576
577
578void RATSNEST_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
579{
580 RENDER_SETTINGS* ps = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
581 ps->SetHighlight( false );
582
583 std::vector<NETINFO_ITEM*> selectedItems;
584
585 for( long row : aItemRows )
586 {
587 if( row >= 0 && row < (long) m_hitlist.size() )
588 {
589 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( m_hitlist[row] );
590
591 ps->SetHighlight( true, net->GetNetCode(), true );
592 }
593 }
594
595 m_frame->GetCanvas()->GetView()->UpdateAllLayersColor();
596 m_frame->GetCanvas()->Refresh();
597}
598
599
601{
602 m_frame->ShowBoardSetupDialog( _( "Net Classes" ) );
603}
604
605
607 PCB_SEARCH_HANDLER( _HKI( "Drills" ), aFrame ),
608 m_frame( aFrame )
609{
610 m_columns.emplace_back( _HKI( "Count" ), 2, wxLIST_FORMAT_RIGHT );
611 m_columns.emplace_back( _HKI( "Shape" ), 3, wxLIST_FORMAT_LEFT );
612 m_columns.emplace_back( _HKI( "X Size" ), 3, wxLIST_FORMAT_CENTER );
613 m_columns.emplace_back( _HKI( "Y Size" ), 3, wxLIST_FORMAT_CENTER );
614 m_columns.emplace_back( _HKI( "Plated" ), 2, wxLIST_FORMAT_CENTER );
615 m_columns.emplace_back( _HKI( "Via/Pad" ), 2, wxLIST_FORMAT_CENTER );
616 m_columns.emplace_back( _HKI( "Start Layer" ), 4, wxLIST_FORMAT_CENTER );
617 m_columns.emplace_back( _HKI( "Stop Layer" ), 4, wxLIST_FORMAT_CENTER );
618}
619
620
621int DRILL_SEARCH_HANDLER::Search( const wxString& aQuery )
622{
623 BOARD* board = m_frame->GetBoard();
624
625 m_drills.clear();
626 m_ptrToDrill.clear();
627 m_hitlist.clear();
628
629 auto addEntryOrIncrement = [&]( const DRILL_LINE_ITEM& d, BOARD_ITEM* rep )
630 {
631 for( DRILL_ROW& g : m_drills )
632 {
633 if( g.entry == d )
634 {
635 g.entry.m_Qty++;
636 return;
637 }
638 }
639
640 DRILL_ROW g = { .entry = d, .item = rep, };
641 g.entry.m_Qty = 1;
642
643 m_drills.push_back( g );
644 };
645
646 // Collect from pads
647 for( FOOTPRINT* fp : board->Footprints() )
648 {
649 for( PAD* pad : fp->Pads() )
650 {
651 if( !pad->HasHole() )
652 continue;
653
654 int xs = pad->GetDrillSize().x;
655 int ys = pad->GetDrillSize().y;
656 if( xs <= 0 || ys <= 0 )
657 continue;
658
659 PCB_LAYER_ID top, bottom;
660
661 if( pad->GetLayerSet().CuStack().empty() )
662 {
664 bottom = UNDEFINED_LAYER;
665 }
666 else
667 {
668 top = pad->GetLayerSet().CuStack().front();
669 bottom = pad->GetLayerSet().CuStack().back();
670 }
671
672 DRILL_LINE_ITEM d( xs, ys, pad->GetDrillShape(),
673 pad->GetAttribute() != PAD_ATTRIB::NPTH,
674 true, top, bottom );
675
676 addEntryOrIncrement( d, pad );
677 }
678 }
679
680 // Collect from vias
681 for( PCB_TRACK* t : board->Tracks() )
682 {
683 if( t->Type() != PCB_VIA_T )
684 continue;
685
686 PCB_VIA* via = static_cast<PCB_VIA*>( t );
687 int dmm = via->GetDrillValue();
688 if( dmm <= 0 )
689 continue;
690
691 DRILL_LINE_ITEM d( dmm, dmm, PAD_DRILL_SHAPE::CIRCLE, true,
692 false, via->TopLayer(), via->BottomLayer() );
693 addEntryOrIncrement( d, via );
694 }
695
696 std::sort( m_drills.begin(), m_drills.end(),
697 []( const DRILL_ROW& a, const DRILL_ROW& b )
698 {
699 DRILL_LINE_ITEM::COMPARE cmp( DRILL_LINE_ITEM::COL_COUNT, false );
700 return cmp( a.entry, b.entry );
701 } );
702
703 // Apply filter and populate display list
704 for( size_t i = 0; i < m_drills.size(); ++i )
705 {
706 if( aQuery.IsEmpty() || rowMatchesQuery( m_drills[i].entry, aQuery.Lower() ) )
707 {
708 m_hitlist.push_back( m_drills[i].item );
709 m_ptrToDrill[m_drills[i].item] = (int) i;
710 }
711 }
712
713 return (int) m_hitlist.size();
714}
715
716
718{
719 auto it = m_ptrToDrill.find( aItem );
720
721 if( it == m_ptrToDrill.end() )
722 return wxEmptyString;
723
724 const auto& e = m_drills[it->second].entry;
725
726 return cellText( e, aCol );
727}
728
729
730void DRILL_SEARCH_HANDLER::Sort( int aCol, bool aAscending, std::vector<long>* aSelection )
731{
732 // Preserve current selection pointers
733 std::vector<BOARD_ITEM*> selPtrs;
734
735 if( aSelection )
736 {
737 for( long row : *aSelection )
738 {
739 if( row >= 0 && row < (long) m_hitlist.size() )
740 selPtrs.push_back( m_hitlist[row] );
741 }
742 }
743
744 auto cmpPtr = [&]( BOARD_ITEM* pa, BOARD_ITEM* pb )
745 {
746 auto itA = m_ptrToDrill.find( pa );
747 auto itB = m_ptrToDrill.find( pb );
748
749 bool validA = ( itA != m_ptrToDrill.end() && itA->second >= 0
750 && itA->second < static_cast<int>( m_drills.size() ) );
751 bool validB = ( itB != m_ptrToDrill.end() && itB->second >= 0
752 && itB->second < static_cast<int>( m_drills.size() ) );
753
754 if( !validA || !validB )
755 {
756 if( validA != validB )
757 return validA;
758
759 return pa < pb;
760 }
761
762 const auto& a = m_drills[itA->second].entry;
763 const auto& b = m_drills[itB->second].entry;
764
765 int col = aCol < 0 ? 0 : aCol;
766 DRILL_LINE_ITEM::COMPARE cmp( static_cast<DRILL_LINE_ITEM::COL_ID>( col ), aAscending );
767
768 return cmp( a, b );
769 };
770
771 std::sort( m_hitlist.begin(), m_hitlist.end(), cmpPtr );
772
773 // Rebuild selection rows from pointers
774 if( aSelection )
775 {
776 aSelection->clear();
777
778 for( long row = 0; row < (long) m_hitlist.size(); ++row )
779 {
780 if( alg::contains( selPtrs, m_hitlist[row] ) )
781 aSelection->push_back( row );
782 }
783 }
784}
785
786
787void DRILL_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
788{
789 BOARD* board = m_frame->GetBoard();
790 std::vector<EDA_ITEM*> selectedItems;
791 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
792
793 // Collect matching items
794 for( long row : aItemRows )
795 {
796 if( row < 0 || row >= (long) m_hitlist.size() )
797 continue;
798
799 BOARD_ITEM* rep = m_hitlist[row];
800 auto it = m_ptrToDrill.find( rep );
801
802 if( it == m_ptrToDrill.end() )
803 continue;
804
805 const auto* target = &m_drills[it->second].entry;
806
807 // Pads
808 for( FOOTPRINT* fp : board->Footprints() )
809 {
810 for( PAD* pad : fp->Pads() )
811 {
812 if( !pad->HasHole() )
813 continue;
814
815 int xs = pad->GetDrillSize().x;
816 int ys = pad->GetDrillSize().y;
817 PCB_LAYER_ID top, bottom;
818
819 if( pad->GetLayerSet().CuStack().empty() )
820 {
822 bottom = UNDEFINED_LAYER;
823 }
824 else
825 {
826 top = pad->GetLayerSet().CuStack().front();
827 bottom = pad->GetLayerSet().CuStack().back();
828 }
829
830 DRILL_LINE_ITEM e( xs, ys, pad->GetDrillShape(), pad->GetAttribute() != PAD_ATTRIB::NPTH, true,
831 top, bottom );
832
833 if( e == *target )
834 selectedItems.push_back( pad );
835 }
836 }
837
838 // Vias
839 for( PCB_TRACK* t : board->Tracks() )
840 {
841 if( t->Type() != PCB_VIA_T )
842 continue;
843
844 PCB_VIA* via = static_cast<PCB_VIA*>( t );
845 DRILL_LINE_ITEM e( via->GetDrillValue(), via->GetDrillValue(), PAD_DRILL_SHAPE::CIRCLE, true,
846 false, via->TopLayer(), via->BottomLayer() );
847
848 if( e == *target )
849 selectedItems.push_back( via );
850 }
851 }
852
853
854 m_frame->GetToolManager()->RunAction( ACTIONS::selectionClear );
855
856 if( selectedItems.size() )
857 {
858 m_frame->GetToolManager()->RunAction( ACTIONS::selectItems, &selectedItems );
859
860 switch( settings.selection_zoom )
861 {
863 m_frame->GetToolManager()->RunAction( ACTIONS::centerSelection );
864 break;
866 m_frame->GetToolManager()->RunAction( ACTIONS::zoomFitSelection );
867 break;
869 break;
870 }
871 }
872
873 m_frame->GetCanvas()->Refresh( false );
874}
875
876
877wxString DRILL_SEARCH_HANDLER::cellText( const DRILL_LINE_ITEM& e, int col ) const
878{
879 BOARD* board = m_frame->GetBoard();
880
881 switch( col )
882 {
883 case 0: return wxString::Format( "%d", e.m_Qty );
884 case 1: return e.shape == PAD_DRILL_SHAPE::CIRCLE ? _( "Round" ) : _( "Slot" );
885 case 2: return m_frame->MessageTextFromValue( e.xSize );
886 case 3: return m_frame->MessageTextFromValue( e.ySize );
887 case 4: return e.isPlated ? _( "PTH" ) : _( "NPTH" );
888 case 5: return e.isPad ? _( "Pad" ) : _( "Via" );
889 case 6: return ( e.startLayer == UNDEFINED_LAYER ) ? _( "N/A" ) : board->GetLayerName( e.startLayer );
890 case 7: return ( e.stopLayer == UNDEFINED_LAYER ) ? _( "N/A" ) : board->GetLayerName( e.stopLayer );
891 default: return wxEmptyString;
892 }
893}
894
895
896bool DRILL_SEARCH_HANDLER::rowMatchesQuery( const DRILL_LINE_ITEM& e, const wxString& aQuery ) const
897{
898 if( aQuery.IsEmpty() )
899 return true;
900
901 for( int col = 0; col < 8; ++col )
902 {
903 if( cellText( e, col ).Lower().Contains( aQuery ) )
904 return true;
905 }
906
907 return false;
908}
static TOOL_ACTION zoomFitSelection
Definition actions.h:144
static TOOL_ACTION centerSelection
Definition actions.h:150
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:224
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:232
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:84
int GetY() const
Definition board_item.h:106
int GetX() const
Definition board_item.h:100
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:322
const NETINFO_LIST & GetNetInfo() const
Definition board.h:996
const ZONES & Zones() const
Definition board.h:367
const GROUPS & Groups() const
The groups must maintain the following invariants.
Definition board.h:396
int GetCopperLayerCount() const
Definition board.cpp:920
const FOOTPRINTS & Footprints() const
Definition board.h:363
const TRACKS & Tracks() const
Definition board.h:361
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:729
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition board.h:563
const DRAWINGS & Drawings() const
Definition board.h:365
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:111
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:368
const LIB_ID & GetFPID() const
Definition footprint.h:351
const wxString & GetValue() const
Definition footprint.h:773
const wxString & GetReference() const
Definition footprint.h:751
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
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:608
LSEQ UIOrder() const
Return the copper, technical and user layers in the order shown in layer widget.
Definition lset.cpp:743
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition lset.cpp:627
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:328
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:55
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)
wxString GetResultCell(int aRow, int aCol) override
void Sort(int aCol, bool aAscending, std::vector< long > *aSelection) override
void SelectItems(std::vector< long > &aItemRows) override
std::vector< BOARD_ITEM * > m_hitlist
virtual wxString getResultCell(BOARD_ITEM *aItem, int aCol)=0
static bool ClassOf(const EDA_ITEM *aItem)
Definition pcb_textbox.h:48
static bool ClassOf(const EDA_ITEM *aItem)
Definition pcb_text.h:52
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:73
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:719
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 bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition zone.cpp:644
unsigned GetAssignedPriority() const
Definition zone.h:125
#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:103
#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
KIBIS top(path, &reporter)
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
Definition typeinfo.h:254
@ 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:111
@ 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