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 wxCHECK2( field, continue );
164
165 if( field->Matches( frp, nullptr ) )
166 {
167 found = true;
168 break;
169 }
170 }
171 }
172
173 if( found )
174 m_hitlist.push_back( fp );
175 }
176
177 return (int) m_hitlist.size();
178}
179
180
182{
183 FOOTPRINT* fp = static_cast<FOOTPRINT*>( aItem );
184
185 if( aCol == 0 )
186 return fp->GetReference();
187 else if( aCol == 1 )
188 return UnescapeString( fp->GetValue() );
189 else if( aCol == 2 )
190 return fp->GetLayerName();
191 else if( aCol == 3 )
192 return m_frame->MessageTextFromCoord( fp->GetX(), ORIGIN_TRANSFORMS::ABS_X_COORD );
193 else if( aCol == 4 )
194 return m_frame->MessageTextFromCoord( fp->GetY(), ORIGIN_TRANSFORMS::ABS_Y_COORD );
195 else if( aCol == 5 )
196 return fp->GetFPID().Format();
197 else if( aCol == 6 )
198 return fp->GetLibDescription();
199
200 return wxEmptyString;
201}
202
203
205 PCB_SEARCH_HANDLER( _HKI( "Zones" ), aFrame )
206{
207 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
208 m_columns.emplace_back( _HKI( "Net" ), 6, wxLIST_FORMAT_LEFT);
209 m_columns.emplace_back( _HKI( "Layer" ), 3, wxLIST_FORMAT_CENTER );
210 m_columns.emplace_back( _HKI( "Priority" ), 2, wxLIST_FORMAT_CENTER );
211 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
212 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
213 m_columns.emplace_back( _HKI( "Area" ), 3, wxLIST_FORMAT_RIGHT );
214}
215
216
217int ZONE_SEARCH_HANDLER::Search( const wxString& aQuery )
218{
219 m_hitlist.clear();
220 BOARD* board = m_frame->GetBoard();
221
222 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
223 EDA_SEARCH_DATA frp;
224
226 frp.searchMetadata = settings.search_metadata;
227 frp.findString = aQuery;
228
229 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
231
232 for( BOARD_ITEM* item : board->Zones() )
233 {
234 if( frp.findString.IsEmpty() || item->Matches( frp, nullptr ) )
235 m_hitlist.push_back( item );
236 }
237
238 return (int) m_hitlist.size();
239}
240
241
243{
244 ZONE* zone = static_cast<ZONE*>( aItem );
245
246 if( aCol == 0 )
247 return zone->GetZoneName();
248 else if( aCol == 1 )
249 return UnescapeString( zone->GetNetname() );
250 else if( aCol == 2 )
251 {
252 wxArrayString layers;
253 BOARD* board = m_frame->GetBoard();
254 // Make sure we don't show layers from Rule Areas that aren't actually on the board,
255 // since they have all copper areas by default.
256 LSET dialogLayers = LSET::AllNonCuMask()
258
259 for( PCB_LAYER_ID layer : dialogLayers.UIOrder() )
260 {
261 if( zone->IsOnLayer( layer ) )
262 layers.Add( board->GetLayerName( layer ) );
263 }
264
265 return wxJoin( layers, ',' );
266 }
267 else if( aCol == 3 )
268 return wxString::Format( "%d", zone->GetAssignedPriority() );
269 else if( aCol == 4 )
270 return m_frame->MessageTextFromCoord( zone->GetX(), ORIGIN_TRANSFORMS::ABS_X_COORD );
271 else if( aCol == 5 )
272 return m_frame->MessageTextFromCoord( zone->GetY(), ORIGIN_TRANSFORMS::ABS_Y_COORD );
273 else if( aCol == 6 )
274 {
275 return m_frame->MessageTextFromValue( zone->GetIsRuleArea() ? zone->GetOutlineArea() : zone->GetFilledArea(),
276 true, EDA_DATA_TYPE::AREA );
277 }
278
279
280 return wxEmptyString;
281}
282
283
285 PCB_SEARCH_HANDLER( _HKI( "Text" ), aFrame )
286{
287 m_columns.emplace_back( _HKI( "Type" ), 2, wxLIST_FORMAT_LEFT );
288 m_columns.emplace_back( _HKI( "Text" ), 12, wxLIST_FORMAT_LEFT );
289 m_columns.emplace_back( _HKI( "Layer" ), 3, wxLIST_FORMAT_CENTER );
290 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
291 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
292}
293
294
295int TEXT_SEARCH_HANDLER::Search( const wxString& aQuery )
296{
297 m_hitlist.clear();
298 BOARD* board = m_frame->GetBoard();
299
301 EDA_SEARCH_DATA frp;
302
304 frp.searchMetadata = settings.search_metadata;
305 frp.findString = aQuery;
306
307 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
309
310 for( BOARD_ITEM* item : board->Drawings() )
311 {
312 if( item->Type() == PCB_TEXT_T
313 || BaseType( item->Type() ) == PCB_DIMENSION_T
314 || item->Type() == PCB_TEXTBOX_T
315 || item->Type() == PCB_TABLECELL_T )
316 {
317 if( frp.findString.IsEmpty() || item->Matches( frp, nullptr ) )
318 m_hitlist.push_back( item );
319 }
320 }
321
322 return (int) m_hitlist.size();
323}
324
325
327{
328 if( aCol == 0 )
329 {
330 if( PCB_TEXT::ClassOf( aItem ) )
331 return _( "Text" );
332 else if( PCB_TEXTBOX::ClassOf( aItem ) )
333 return _( "Textbox" );
334 else if( dynamic_cast<PCB_DIMENSION_BASE*>( aItem ) )
335 return _( "Dimension" );
336 }
337 else if( aCol == 1 )
338 {
339 if( PCB_TEXT::ClassOf( aItem ) )
340 return UnescapeString( static_cast<PCB_TEXT*>( aItem )->GetText() );
341 else if( PCB_TEXTBOX::ClassOf( aItem ) )
342 return UnescapeString( static_cast<PCB_TEXTBOX*>( aItem )->GetText() );
343 else if( PCB_DIMENSION_BASE* dimension = dynamic_cast<PCB_DIMENSION_BASE*>( aItem ) )
344 return UnescapeString( dimension->GetText() );
345 }
346 else if( aCol == 2 )
347 return aItem->GetLayerName();
348 else if( aCol == 3 )
349 return m_frame->MessageTextFromCoord( aItem->GetX(), ORIGIN_TRANSFORMS::ABS_X_COORD );
350 else if( aCol == 4 )
351 return m_frame->MessageTextFromCoord( aItem->GetY(), ORIGIN_TRANSFORMS::ABS_Y_COORD );
352
353 return wxEmptyString;
354}
355
356
358 PCB_SEARCH_HANDLER( _HKI( "Groups" ), aFrame )
359{
360 m_columns.emplace_back( _HKI( "Type" ), 2, wxLIST_FORMAT_LEFT );
361 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
362 m_columns.emplace_back( wxT( "X" ), 3, wxLIST_FORMAT_CENTER );
363 m_columns.emplace_back( wxT( "Y" ), 3, wxLIST_FORMAT_CENTER );
364}
365
366
367int GROUP_SEARCH_HANDLER::Search( const wxString& aQuery )
368{
369 m_hitlist.clear();
370 BOARD* board = m_frame->GetBoard();
371
373 EDA_SEARCH_DATA frp;
374
376 frp.searchMetadata = settings.search_metadata;
377 frp.findString = aQuery;
378
379 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
381
382 for( BOARD_ITEM* item : board->Groups() )
383 {
384 // Skip generators, they are for internal use, not user-facing grouping
385 if( item->Type() == PCB_GENERATOR_T )
386 continue;
387
388 if( frp.findString.IsEmpty() || item->Matches( frp, nullptr ) )
389 m_hitlist.push_back( item );
390 }
391
392 return (int) m_hitlist.size();
393}
394
395
397{
398 if( aCol == 0 )
399 {
400 if( aItem->Type() == PCB_GROUP_T )
401 return _( "Group" );
402 else if( aItem->Type() == PCB_GENERATOR_T )
403 return _( "Generator" );
404 }
405 else if( aCol == 1 )
406 return static_cast<PCB_GROUP*>( aItem )->GetName();
407 else if( aCol == 2 )
408 return m_frame->MessageTextFromCoord( aItem->GetX(), ORIGIN_TRANSFORMS::ABS_X_COORD );
409 else if( aCol == 3 )
410 return m_frame->MessageTextFromCoord( aItem->GetY(), ORIGIN_TRANSFORMS::ABS_Y_COORD );
411
412 return wxEmptyString;
413}
414
415
417 PCB_SEARCH_HANDLER( _HKI( "Nets" ), aFrame )
418{
419 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
420 m_columns.emplace_back( _HKI( "Class" ), 6, wxLIST_FORMAT_LEFT );
421}
422
423
424int NETS_SEARCH_HANDLER::Search( const wxString& aQuery )
425{
426 m_hitlist.clear();
427
428 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
429 EDA_SEARCH_DATA frp;
430
432 frp.searchMetadata = settings.search_metadata;
433 frp.findString = aQuery;
434
435 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
437
438 BOARD* board = m_frame->GetBoard();
439
440 for( NETINFO_ITEM* net : board->GetNetInfo() )
441 {
442 if( net && ( aQuery.IsEmpty() || net->Matches( frp, nullptr ) ) )
443 m_hitlist.push_back( net );
444 }
445
446 return (int) m_hitlist.size();
447}
448
449
451{
452 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aItem );
453
454 if( net->GetNetCode() == 0 )
455 {
456 if( aCol == 0 )
457 return _( "No Net" );
458 else if( aCol == 1 )
459 return wxT( "" );
460 }
461
462 if( aCol == 0 )
463 return UnescapeString( net->GetNetname() );
464 else if( aCol == 1 )
465 return net->GetNetClass()->GetName();
466
467 return wxEmptyString;
468}
469
470
471void NETS_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
472{
473 RENDER_SETTINGS* ps = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
474 ps->SetHighlight( false );
475
476 std::vector<NETINFO_ITEM*> selectedItems;
477
478 for( long row : aItemRows )
479 {
480 if( row >= 0 && row < (long) m_hitlist.size() )
481 {
482 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( m_hitlist[row] );
483
484 ps->SetHighlight( true, net->GetNetCode(), true );
485 }
486 }
487
488 m_frame->GetCanvas()->GetView()->UpdateAllLayersColor();
489 m_frame->GetCanvas()->Refresh();
490}
491
492
494{
495 m_frame->ShowBoardSetupDialog( _( "Net Classes" ) );
496}
497
498
500 PCB_SEARCH_HANDLER( _HKI( "Ratsnest" ), aFrame )
501{
502 m_columns.emplace_back( _HKI( "Name" ), 6, wxLIST_FORMAT_LEFT );
503 m_columns.emplace_back( _HKI( "Class" ), 6, wxLIST_FORMAT_LEFT );
504}
505
506
507int RATSNEST_SEARCH_HANDLER::Search( const wxString& aQuery )
508{
509 m_hitlist.clear();
510
511 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
512 EDA_SEARCH_DATA frp;
513
515 frp.searchMetadata = settings.search_metadata;
516 frp.findString = aQuery;
517
518 // Try to handle whatever the user throws at us (substring, wildcards, regex, etc.)
520
521 BOARD* board = m_frame->GetBoard();
522
523 for( NETINFO_ITEM* net : board->GetNetInfo() )
524 {
525 if( net == nullptr || !net->Matches( frp, nullptr ) )
526 continue;
527
528 RN_NET* rn = board->GetConnectivity()->GetRatsnestForNet( net->GetNetCode() );
529
530 if( rn && !rn->GetEdges().empty() )
531 m_hitlist.push_back( net );
532 }
533
534 return (int) m_hitlist.size();
535}
536
537
539{
540 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aItem );
541
542 if( net->GetNetCode() == 0 )
543 {
544 if( aCol == 0 )
545 return _( "No Net" );
546 else if( aCol == 1 )
547 return wxT( "" );
548 }
549
550 if( aCol == 0 )
551 return UnescapeString( net->GetNetname() );
552 else if( aCol == 1 )
553 return net->GetNetClass()->GetName();
554
555 return wxEmptyString;
556}
557
558
559void RATSNEST_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
560{
561 RENDER_SETTINGS* ps = m_frame->GetCanvas()->GetView()->GetPainter()->GetSettings();
562 ps->SetHighlight( false );
563
564 std::vector<NETINFO_ITEM*> selectedItems;
565
566 for( long row : aItemRows )
567 {
568 if( row >= 0 && row < (long) m_hitlist.size() )
569 {
570 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( m_hitlist[row] );
571
572 ps->SetHighlight( true, net->GetNetCode(), true );
573 }
574 }
575
576 m_frame->GetCanvas()->GetView()->UpdateAllLayersColor();
577 m_frame->GetCanvas()->Refresh();
578}
579
580
582{
583 m_frame->ShowBoardSetupDialog( _( "Net Classes" ) );
584}
585
586
588 PCB_SEARCH_HANDLER( _HKI( "Drills" ), aFrame ),
589 m_frame( aFrame )
590{
591 m_columns.emplace_back( _HKI( "Count" ), 2, wxLIST_FORMAT_RIGHT );
592 m_columns.emplace_back( _HKI( "Shape" ), 3, wxLIST_FORMAT_LEFT );
593 m_columns.emplace_back( _HKI( "X Size" ), 3, wxLIST_FORMAT_CENTER );
594 m_columns.emplace_back( _HKI( "Y Size" ), 3, wxLIST_FORMAT_CENTER );
595 m_columns.emplace_back( _HKI( "Plated" ), 2, wxLIST_FORMAT_CENTER );
596 m_columns.emplace_back( _HKI( "Via/Pad" ), 2, wxLIST_FORMAT_CENTER );
597 m_columns.emplace_back( _HKI( "Start Layer" ), 4, wxLIST_FORMAT_CENTER );
598 m_columns.emplace_back( _HKI( "Stop Layer" ), 4, wxLIST_FORMAT_CENTER );
599}
600
601
602int DRILL_SEARCH_HANDLER::Search( const wxString& aQuery )
603{
604 BOARD* board = m_frame->GetBoard();
605
606 m_drills.clear();
607 m_ptrToDrill.clear();
608 m_hitlist.clear();
609
610 auto addEntryOrIncrement = [&]( const DRILL_LINE_ITEM& d, BOARD_ITEM* rep )
611 {
612 for( DRILL_ROW& g : m_drills )
613 {
614 if( g.entry == d )
615 {
616 g.entry.m_Qty++;
617 return;
618 }
619 }
620
621 DRILL_ROW g = { .entry = d, .item = rep, };
622 g.entry.m_Qty = 1;
623
624 m_drills.push_back( g );
625 };
626
627 // Collect from pads
628 for( FOOTPRINT* fp : board->Footprints() )
629 {
630 for( PAD* pad : fp->Pads() )
631 {
632 if( !pad->HasHole() )
633 continue;
634
635 int xs = pad->GetDrillSize().x;
636 int ys = pad->GetDrillSize().y;
637 if( xs <= 0 || ys <= 0 )
638 continue;
639
640 PCB_LAYER_ID top, bottom;
641
642 if( pad->GetLayerSet().CuStack().empty() )
643 {
645 bottom = UNDEFINED_LAYER;
646 }
647 else
648 {
649 top = pad->GetLayerSet().CuStack().front();
650 bottom = pad->GetLayerSet().CuStack().back();
651 }
652
653 DRILL_LINE_ITEM d( xs, ys, pad->GetDrillShape(),
654 pad->GetAttribute() != PAD_ATTRIB::NPTH,
655 true, top, bottom );
656
657 addEntryOrIncrement( d, pad );
658 }
659 }
660
661 // Collect from vias
662 for( PCB_TRACK* t : board->Tracks() )
663 {
664 if( t->Type() != PCB_VIA_T )
665 continue;
666
667 PCB_VIA* via = static_cast<PCB_VIA*>( t );
668 int dmm = via->GetDrillValue();
669 if( dmm <= 0 )
670 continue;
671
672 DRILL_LINE_ITEM d( dmm, dmm, PAD_DRILL_SHAPE::CIRCLE, true,
673 false, via->TopLayer(), via->BottomLayer() );
674 addEntryOrIncrement( d, via );
675 }
676
677 std::sort( m_drills.begin(), m_drills.end(),
678 []( const DRILL_ROW& a, const DRILL_ROW& b )
679 {
680 DRILL_LINE_ITEM::COMPARE cmp( DRILL_LINE_ITEM::COL_COUNT, false );
681 return cmp( a.entry, b.entry );
682 } );
683
684 // Apply filter and populate display list
685 for( size_t i = 0; i < m_drills.size(); ++i )
686 {
687 if( aQuery.IsEmpty() || rowMatchesQuery( m_drills[i].entry, aQuery.Lower() ) )
688 {
689 m_hitlist.push_back( m_drills[i].item );
690 m_ptrToDrill[m_drills[i].item] = (int) i;
691 }
692 }
693
694 return (int) m_hitlist.size();
695}
696
697
699{
700 auto it = m_ptrToDrill.find( aItem );
701
702 if( it == m_ptrToDrill.end() )
703 return wxEmptyString;
704
705 const auto& e = m_drills[it->second].entry;
706
707 return cellText( e, aCol );
708}
709
710
711void DRILL_SEARCH_HANDLER::Sort( int aCol, bool aAscending, std::vector<long>* aSelection )
712{
713 // Preserve current selection pointers
714 std::vector<BOARD_ITEM*> selPtrs;
715
716 if( aSelection )
717 {
718 for( long row : *aSelection )
719 {
720 if( row >= 0 && row < (long) m_hitlist.size() )
721 selPtrs.push_back( m_hitlist[row] );
722 }
723 }
724
725 auto cmpPtr = [&]( BOARD_ITEM* pa, BOARD_ITEM* pb )
726 {
727 auto itA = m_ptrToDrill.find( pa );
728 auto itB = m_ptrToDrill.find( pb );
729
730 bool validA = ( itA != m_ptrToDrill.end() && itA->second >= 0
731 && itA->second < static_cast<int>( m_drills.size() ) );
732 bool validB = ( itB != m_ptrToDrill.end() && itB->second >= 0
733 && itB->second < static_cast<int>( m_drills.size() ) );
734
735 if( !validA || !validB )
736 {
737 if( validA != validB )
738 return validA;
739
740 return pa < pb;
741 }
742
743 const auto& a = m_drills[itA->second].entry;
744 const auto& b = m_drills[itB->second].entry;
745
746 int col = aCol < 0 ? 0 : aCol;
747 DRILL_LINE_ITEM::COMPARE cmp( static_cast<DRILL_LINE_ITEM::COL_ID>( col ), aAscending );
748
749 return cmp( a, b );
750 };
751
752 std::sort( m_hitlist.begin(), m_hitlist.end(), cmpPtr );
753
754 // Rebuild selection rows from pointers
755 if( aSelection )
756 {
757 aSelection->clear();
758
759 for( long row = 0; row < (long) m_hitlist.size(); ++row )
760 {
761 if( alg::contains( selPtrs, m_hitlist[row] ) )
762 aSelection->push_back( row );
763 }
764 }
765}
766
767
768void DRILL_SEARCH_HANDLER::SelectItems( std::vector<long>& aItemRows )
769{
770 BOARD* board = m_frame->GetBoard();
771 std::vector<EDA_ITEM*> selectedItems;
772 APP_SETTINGS_BASE::SEARCH_PANE& settings = m_frame->config()->m_SearchPane;
773
774 // Collect matching items
775 for( long row : aItemRows )
776 {
777 if( row < 0 || row >= (long) m_hitlist.size() )
778 continue;
779
780 BOARD_ITEM* rep = m_hitlist[row];
781 auto it = m_ptrToDrill.find( rep );
782
783 if( it == m_ptrToDrill.end() )
784 continue;
785
786 const auto* target = &m_drills[it->second].entry;
787
788 // Pads
789 for( FOOTPRINT* fp : board->Footprints() )
790 {
791 for( PAD* pad : fp->Pads() )
792 {
793 if( !pad->HasHole() )
794 continue;
795
796 int xs = pad->GetDrillSize().x;
797 int ys = pad->GetDrillSize().y;
798 PCB_LAYER_ID top, bottom;
799
800 if( pad->GetLayerSet().CuStack().empty() )
801 {
803 bottom = UNDEFINED_LAYER;
804 }
805 else
806 {
807 top = pad->GetLayerSet().CuStack().front();
808 bottom = pad->GetLayerSet().CuStack().back();
809 }
810
811 DRILL_LINE_ITEM e( xs, ys, pad->GetDrillShape(), pad->GetAttribute() != PAD_ATTRIB::NPTH, true,
812 top, bottom );
813
814 if( e == *target )
815 selectedItems.push_back( pad );
816 }
817 }
818
819 // Vias
820 for( PCB_TRACK* t : board->Tracks() )
821 {
822 if( t->Type() != PCB_VIA_T )
823 continue;
824
825 PCB_VIA* via = static_cast<PCB_VIA*>( t );
826 DRILL_LINE_ITEM e( via->GetDrillValue(), via->GetDrillValue(), PAD_DRILL_SHAPE::CIRCLE, true,
827 false, via->TopLayer(), via->BottomLayer() );
828
829 if( e == *target )
830 selectedItems.push_back( via );
831 }
832 }
833
834
835 m_frame->GetToolManager()->RunAction( ACTIONS::selectionClear );
836
837 if( selectedItems.size() )
838 {
839 m_frame->GetToolManager()->RunAction( ACTIONS::selectItems, &selectedItems );
840
841 switch( settings.selection_zoom )
842 {
844 m_frame->GetToolManager()->RunAction( ACTIONS::centerSelection );
845 break;
847 m_frame->GetToolManager()->RunAction( ACTIONS::zoomFitSelection );
848 break;
850 break;
851 }
852 }
853
854 m_frame->GetCanvas()->Refresh( false );
855}
856
857
858wxString DRILL_SEARCH_HANDLER::cellText( const DRILL_LINE_ITEM& e, int col ) const
859{
860 BOARD* board = m_frame->GetBoard();
861
862 switch( col )
863 {
864 case 0: return wxString::Format( "%d", e.m_Qty );
865 case 1: return e.shape == PAD_DRILL_SHAPE::CIRCLE ? _( "Round" ) : _( "Slot" );
866 case 2: return m_frame->MessageTextFromValue( e.xSize );
867 case 3: return m_frame->MessageTextFromValue( e.ySize );
868 case 4: return e.isPlated ? _( "PTH" ) : _( "NPTH" );
869 case 5: return e.isPad ? _( "Pad" ) : _( "Via" );
870 case 6: return ( e.startLayer == UNDEFINED_LAYER ) ? _( "N/A" ) : board->GetLayerName( e.startLayer );
871 case 7: return ( e.stopLayer == UNDEFINED_LAYER ) ? _( "N/A" ) : board->GetLayerName( e.stopLayer );
872 default: return wxEmptyString;
873 }
874}
875
876
877bool DRILL_SEARCH_HANDLER::rowMatchesQuery( const DRILL_LINE_ITEM& e, const wxString& aQuery ) const
878{
879 if( aQuery.IsEmpty() )
880 return true;
881
882 for( int col = 0; col < 8; ++col )
883 {
884 if( cellText( e, col ).Lower().Contains( aQuery ) )
885 return true;
886 }
887
888 return false;
889}
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:919
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:728
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
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
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:608
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)
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: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