KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_selection_filter.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) 2020 Jon Evans <[email protected]>
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
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <pcb_base_edit_frame.h>
22#include <tool/tool_manager.h>
25#include <wx/settings.h>
26#include <wx/dcbuffer.h>
27
28
29wxDEFINE_EVENT( EVT_PCB_SELECTION_FILTER_FLASH, PCB_SELECTION_FILTER_EVENT );
30
33 m_frame( dynamic_cast<PCB_BASE_EDIT_FRAME*>( aParent ) ),
34 m_onlyCheckbox( nullptr )
35{
36 wxFont font = KIUI::GetInfoFont( this );
37 m_cbLockedItems->SetFont( font );
38 m_cbFootprints->SetFont( font );
39 m_cbText->SetFont( font );
40 m_cbTracks->SetFont( font );
41 m_cbVias->SetFont( font );
42 m_cbPads->SetFont( font );
43 m_cbGraphics->SetFont( font );
44 m_cbZones->SetFont( font );
45 m_cbKeepouts->SetFont( font );
46 m_cbDimensions->SetFont( font );
47 m_cbPoints->SetFont( font );
48 m_cbGridItems->SetFont( font );
49 m_cbOtherItems->SetFont( font );
50 m_cbAllItems->SetFont( font );
51
52 SetBorders( true, false, false, false );
53
54 wxASSERT( m_frame );
55 m_tool = m_frame->GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
56 wxASSERT( m_tool );
57
58 PCB_SELECTION_FILTER_OPTIONS& opts = m_tool->GetFilter();
60
61 m_cbFootprints->Bind( wxEVT_RIGHT_DOWN, &PANEL_SELECTION_FILTER::onRightClick, this );
62 m_cbText->Bind( wxEVT_RIGHT_DOWN, &PANEL_SELECTION_FILTER::onRightClick, this );
63 m_cbTracks->Bind( wxEVT_RIGHT_DOWN, &PANEL_SELECTION_FILTER::onRightClick, this );
64 m_cbVias->Bind( wxEVT_RIGHT_DOWN, &PANEL_SELECTION_FILTER::onRightClick, this );
65 m_cbPads->Bind( wxEVT_RIGHT_DOWN, &PANEL_SELECTION_FILTER::onRightClick, this );
66 m_cbGraphics->Bind( wxEVT_RIGHT_DOWN, &PANEL_SELECTION_FILTER::onRightClick, this );
67 m_cbZones->Bind( wxEVT_RIGHT_DOWN, &PANEL_SELECTION_FILTER::onRightClick, this );
68 m_cbKeepouts->Bind( wxEVT_RIGHT_DOWN, &PANEL_SELECTION_FILTER::onRightClick, this );
69 m_cbDimensions->Bind( wxEVT_RIGHT_DOWN, &PANEL_SELECTION_FILTER::onRightClick, this );
70 m_cbPoints->Bind( wxEVT_RIGHT_DOWN, &PANEL_SELECTION_FILTER::onRightClick, this );
71 m_cbGridItems->Bind( wxEVT_RIGHT_DOWN, &PANEL_SELECTION_FILTER::onRightClick, this );
72 m_cbOtherItems->Bind( wxEVT_RIGHT_DOWN, &PANEL_SELECTION_FILTER::onRightClick, this );
73
74 m_frame->Bind( EDA_LANG_CHANGED, &PANEL_SELECTION_FILTER::OnLanguageChanged, this );
75
76 SetMinSize( GetBestSize() );
77
78 m_flashSteps = 10;
79 m_flashTimer.SetOwner( this );
80 Bind( wxEVT_TIMER, &PANEL_SELECTION_FILTER::onFlashTimer, this );
81 aParent->Bind( EVT_PCB_SELECTION_FILTER_FLASH, &PANEL_SELECTION_FILTER::OnFlashEvent, this );
82}
83
84
86{
87 // Stop any active flashing
88 m_flashTimer.Stop();
89
90#ifndef __WXMSW__
91 if( !m_flashCounters.empty() )
92 {
93 Unbind( wxEVT_PAINT, &PANEL_SELECTION_FILTER::onPanelPaint, this );
94 }
95#endif
96
97 m_flashCounters.clear();
98
99 m_frame->Unbind( EDA_LANG_CHANGED, &PANEL_SELECTION_FILTER::OnLanguageChanged, this );
100 m_frame->Unbind( EVT_PCB_SELECTION_FILTER_FLASH, &PANEL_SELECTION_FILTER::OnFlashEvent, this );
101}
102
103
105{
106 Freeze();
107
108 m_cbLockedItems->SetValue( aOptions.lockedItems );
109 m_cbFootprints->SetValue( aOptions.footprints );
110 m_cbText->SetValue( aOptions.text );
111 m_cbTracks->SetValue( aOptions.tracks );
112 m_cbVias->SetValue( aOptions.vias );
113 m_cbPads->SetValue( aOptions.pads );
114 m_cbGraphics->SetValue( aOptions.graphics );
115 m_cbZones->SetValue( aOptions.zones );
116 m_cbKeepouts->SetValue( aOptions.keepouts );
117 m_cbDimensions->SetValue( aOptions.dimensions );
118 m_cbPoints->SetValue( aOptions.points );
119 m_cbGridItems->SetValue( aOptions.gridItems );
120 m_cbOtherItems->SetValue( aOptions.otherItems );
121
122 m_cbAllItems->SetValue( aOptions.All() );
123
124 Thaw();
125}
126
127
128void PANEL_SELECTION_FILTER::OnFilterChanged( wxCommandEvent& aEvent )
129{
130 if( aEvent.GetEventObject() == m_cbAllItems )
131 {
132 bool newState = m_cbAllItems->GetValue();
133
134 m_cbFootprints->SetValue( newState );
135 m_cbText->SetValue( newState );
136 m_cbTracks->SetValue( newState );
137 m_cbVias->SetValue( newState );
138 m_cbPads->SetValue( newState );
139 m_cbGraphics->SetValue( newState );
140 m_cbZones->SetValue( newState );
141 m_cbKeepouts->SetValue( newState );
142 m_cbDimensions->SetValue( newState );
143 m_cbPoints->SetValue( newState );
144 m_cbGridItems->SetValue( newState );
145 m_cbOtherItems->SetValue( newState );
146 }
147
148 PCB_SELECTION_FILTER_OPTIONS& opts = m_tool->GetFilter();
149
150 // If any of the other checkboxes turned off, turn off the All Items checkbox
151 bool allChecked = setFilterFromCheckboxes( opts );
152 m_cbAllItems->SetValue( allChecked );
153}
154
155
157{
158 aOptions.lockedItems = m_cbLockedItems->GetValue();
159 aOptions.footprints = m_cbFootprints->GetValue();
160 aOptions.text = m_cbText->GetValue();
161 aOptions.tracks = m_cbTracks->GetValue();
162 aOptions.vias = m_cbVias->GetValue();
163 aOptions.pads = m_cbPads->GetValue();
164 aOptions.graphics = m_cbGraphics->GetValue();
165 aOptions.zones = m_cbZones->GetValue();
166 aOptions.keepouts = m_cbKeepouts->GetValue();
167 aOptions.dimensions = m_cbDimensions->GetValue();
168 aOptions.points = m_cbPoints->GetValue();
169 aOptions.gridItems = m_cbGridItems->GetValue();
170 aOptions.otherItems = m_cbOtherItems->GetValue();
171
172 return aOptions.All();
173}
174
175
176void PANEL_SELECTION_FILTER::onRightClick( wxMouseEvent& aEvent )
177{
178 wxMenu menu;
179
180 wxCheckBox* cb = dynamic_cast<wxCheckBox*>( aEvent.GetEventObject() );
181
182 if( !cb )
183 return;
184
185 m_onlyCheckbox = cb;
186
187 wxString label;
188 label.Printf( _( "Only %s" ), cb->GetLabel().Lower() );
189
190 menu.Append( new wxMenuItem( &menu, wxID_ANY, label, wxEmptyString, wxITEM_NORMAL ) );
191
192 menu.Bind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_SELECTION_FILTER::onPopupSelection, this );
193
194 PopupMenu( &menu );
195}
196
197
198void PANEL_SELECTION_FILTER::onPopupSelection( wxCommandEvent& aEvent )
199{
200 if( !m_onlyCheckbox )
201 return;
202
203 m_cbAllItems->SetValue( false );
204 m_cbFootprints->SetValue( false );
205 m_cbText->SetValue( false );
206 m_cbTracks->SetValue( false );
207 m_cbVias->SetValue( false );
208 m_cbPads->SetValue( false );
209 m_cbGraphics->SetValue( false );
210 m_cbZones->SetValue( false );
211 m_cbKeepouts->SetValue( false );
212 m_cbDimensions->SetValue( false );
213 m_cbPoints->SetValue( false );
214 m_cbGridItems->SetValue( false );
215 m_cbOtherItems->SetValue( false );
216
217 m_onlyCheckbox->SetValue( true );
218 m_onlyCheckbox = nullptr;
219
220 wxCommandEvent dummy;
222}
223
224
225void PANEL_SELECTION_FILTER::OnLanguageChanged( wxCommandEvent& aEvent )
226{
227 m_cbAllItems->SetLabel( _( "All items" ) );
228 m_cbLockedItems->SetLabel( _( "Locked items" ) );
229 m_cbLockedItems->SetToolTip( _( "Allow selection of locked items" ) );
230 m_cbFootprints->SetLabel( _( "Footprints" ) );
231 m_cbText->SetLabel( _( "Text" ) );
232 m_cbTracks->SetLabel( _( "Tracks" ) );
233 m_cbVias->SetLabel( _( "Vias" ) );
234 m_cbPads->SetLabel( _( "Pads" ) );
235 m_cbGraphics->SetLabel( _( "Graphics" ) );
236 m_cbZones->SetLabel( _( "Zones" ) );
237 m_cbKeepouts->SetLabel( _( "Rule Areas" ) );
238 m_cbDimensions->SetLabel( _( "Dimensions" ) );
239 m_cbPoints->SetLabel( _( "Points" ) );
240 m_cbGridItems->SetLabel( _( "Grid Items" ) );
241 m_cbOtherItems->SetLabel( _( "Other items" ) );
242
243 m_cbAllItems->GetParent()->Layout();
244
245 aEvent.Skip();
246}
247
248
250{
251 if( !aBox )
252 return;
253
254#ifdef __WXMSW__
255 // Native MSW checkboxes paint over the panel, so tint the box itself
257 aBox->SetBackgroundColour( flashColour( m_flashSteps ) );
258 aBox->Refresh();
259#else
260 // Bind paint event to this panel if not already bound
261 if( m_flashCounters.empty() )
262 {
263 Bind( wxEVT_PAINT, &PANEL_SELECTION_FILTER::onPanelPaint, this );
264 }
265
267 Refresh();
268#endif
269}
270
271
272wxColour PANEL_SELECTION_FILTER::flashColour( int aStep ) const
273{
274 // Blend from the panel, never from a box that may still carry a flash colour
275 wxColour highlight = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT );
276 wxColour bg = GetBackgroundColour();
277
278 return wxColour( ( highlight.Red() * aStep + bg.Red() * ( m_flashSteps - aStep ) ) / m_flashSteps,
279 ( highlight.Green() * aStep + bg.Green() * ( m_flashSteps - aStep ) ) / m_flashSteps,
280 ( highlight.Blue() * aStep + bg.Blue() * ( m_flashSteps - aStep ) ) / m_flashSteps );
281}
282
283
284void PANEL_SELECTION_FILTER::onFlashTimer( wxTimerEvent& aEvent )
285{
286 for( auto it = m_flashCounters.begin(); it != m_flashCounters.end(); )
287 {
288 int step = --( it->second );
289
290#ifdef __WXMSW__
291 // wxNullColour drops the override so the box inherits the panel colour again
292 it->first->SetBackgroundColour( step > 0 ? flashColour( step ) : wxNullColour );
293 it->first->Refresh();
294#endif
295
296 if( step <= 0 )
297 it = m_flashCounters.erase( it );
298 else
299 ++it;
300 }
301
302 if( m_flashCounters.empty() )
303 {
304 m_flashTimer.Stop();
305
306#ifndef __WXMSW__
307 // Unbind paint event when no more flashing
308 Unbind( wxEVT_PAINT, &PANEL_SELECTION_FILTER::onPanelPaint, this );
309#endif
310 }
311
312#ifndef __WXMSW__
313 Refresh();
314#endif
315}
316
317
318void PANEL_SELECTION_FILTER::onPanelPaint( wxPaintEvent& aEvent )
319{
320 wxPaintDC dc( this );
321
322 // First, let the default painting happen
323 aEvent.Skip();
324
325 // Then draw our highlights on top
326 for( auto& pair : m_flashCounters )
327 {
328 wxCheckBox* checkbox = pair.first;
329 int step = pair.second;
330
331 if( step > 0 )
332 {
333 // Get the checkbox position relative to this panel
334 wxPoint checkboxPos = checkbox->GetPosition();
335 wxSize checkboxSize = checkbox->GetSize();
336 wxRect checkboxRect( checkboxPos, checkboxSize );
337
338 // Calculate blended color based on current flash step
339 wxColour blend = flashColour( step );
340
341 // Draw semi-transparent overlay
342 wxColour overlayColor( blend.Red(), blend.Green(), blend.Blue(), 128 );
343 dc.SetBrush( wxBrush( overlayColor ) );
344 dc.SetPen( wxPen( overlayColor ) );
345 dc.DrawRectangle( checkboxRect );
346 }
347 }
348}
349
350
352{
353 const PCB_SELECTION_FILTER_OPTIONS& aOptions = aEvent.m_options;
354
355 if( aOptions.lockedItems )
357
358 if( aOptions.footprints )
360
361 if( aOptions.text )
363
364 if( aOptions.tracks )
366
367 if( aOptions.vias )
369
370 if( aOptions.pads )
372
373 if( aOptions.graphics )
375
376 if( aOptions.zones )
378
379 if( aOptions.keepouts )
381
382 if( aOptions.dimensions )
384
385 if( aOptions.points )
387
388 if( aOptions.gridItems )
390
391 if( aOptions.otherItems )
393
394 // Restarting a running timer on every event would stall the fade
395 if( !m_flashCounters.empty() && !m_flashTimer.IsRunning() )
396 m_flashTimer.Start( 50 );
397}
PANEL_SELECTION_FILTER_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
PCB_BASE_EDIT_FRAME * m_frame
void onPopupSelection(wxCommandEvent &aEvent)
std::map< wxCheckBox *, int > m_flashCounters
void flashCheckbox(wxCheckBox *aBox)
PCB_SELECTION_TOOL * m_tool
bool setFilterFromCheckboxes(PCB_SELECTION_FILTER_OPTIONS &aOptions)
PANEL_SELECTION_FILTER(wxWindow *aParent)
void OnFlashEvent(PCB_SELECTION_FILTER_EVENT &aEvent)
void SetCheckboxesFromFilter(PCB_SELECTION_FILTER_OPTIONS &aOptions)
void onFlashTimer(wxTimerEvent &aEvent)
wxColour flashColour(int aStep) const
void OnLanguageChanged(wxCommandEvent &aEvent)
void OnFilterChanged(wxCommandEvent &aEvent) override
void onRightClick(wxMouseEvent &aEvent)
void onPanelPaint(wxPaintEvent &aEvent)
Common, abstract interface for edit frames.
PCB_SELECTION_FILTER_OPTIONS m_options
The selection tool: currently supports:
void SetBorders(bool aLeft, bool aRight, bool aTop, bool aBottom)
Definition wx_panel.h:35
#define _(s)
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
wxDEFINE_EVENT(EVT_PCB_SELECTION_FILTER_FLASH, PCB_SELECTION_FILTER_EVENT)
std::vector< FAB_LAYER_COLOR > dummy
This file contains data structures that are saved in the project file or project local settings file ...
bool otherItems
Anything not fitting one of the above categories.
bool graphics
Graphic lines, shapes, polygons.
bool footprints
Allow selecting entire footprints.
bool text
Text (free or attached to a footprint)
bool lockedItems
Allow selecting locked items.