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