KiCad PCB EDA Suite
Loading...
Searching...
No Matches
footprint_select_widget.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <eda_draw_frame.h>
21#include <kiway.h>
22#include <kiface_ids.h>
25#include <json_common.h>
26#include <set>
27#include <wx/wupdlock.h>
28
29
30wxDEFINE_EVENT( EVT_FOOTPRINT_SELECTED, wxCommandEvent );
31
33 int aMaxItems ) :
34 wxPanel( aParent ),
35 m_max_items( aMaxItems ),
36 m_pin_count( 0 ),
37 m_zero_filter( true ),
38 m_kiway( nullptr )
39{
40 m_sizer = new wxBoxSizer( wxVERTICAL );
41 m_fp_sel_ctrl = new FOOTPRINT_CHOICE( this, wxID_ANY );
42 m_sizer->Add( m_fp_sel_ctrl, 1, wxEXPAND, 5 );
43
44 SetSizer( m_sizer );
45 Layout();
46 m_sizer->Fit( this );
47
48 m_fp_sel_ctrl->Bind( wxEVT_COMBOBOX, &FOOTPRINT_SELECT_WIDGET::OnComboBox, this );
49}
50
51
53{
54 m_kiway = &aKiway;
55}
56
57
58void FOOTPRINT_SELECT_WIDGET::OnComboBox( wxCommandEvent& aEvent )
59{
60 wxCommandEvent evt( EVT_FOOTPRINT_SELECTED );
61 int sel = m_fp_sel_ctrl->GetSelection();
62
63 if( sel == wxNOT_FOUND )
64 return;
65
66 wxStringClientData* clientdata = static_cast<wxStringClientData*>( m_fp_sel_ctrl->GetClientObject( sel ) );
67 wxASSERT( clientdata );
68
69 evt.SetString( clientdata->GetData() );
70 wxPostEvent( this, evt );
71}
72
73
75{
76 m_pin_count = 0;
77 m_filters.Clear();
78 m_default_footprint.Clear();
79 m_zero_filter = false;
80 m_always_included.clear();
81}
82
83
85{
86 if( !aFootprintId.IsValid() )
87 return;
88
89 for( const LIB_ID& existing : m_always_included )
90 {
91 if( existing == aFootprintId )
92 return;
93 }
94
95 m_always_included.push_back( aFootprintId );
96}
97
98
100{
101 m_pin_count = aPinCount;
102}
103
104
105void FOOTPRINT_SELECT_WIDGET::FilterByFootprintFilters( wxArrayString const& aFilters,
106 bool aZeroFilters )
107{
108 m_zero_filter = ( aZeroFilters && aFilters.size() == 0 );
109 m_filters = aFilters;
110}
111
112
114{
116}
117
118
120{
121 if( !m_kiway )
122 return false;
123
124 wxWindowUpdateLocker lock( m_fp_sel_ctrl );
125 m_fp_sel_ctrl->Clear();
126
127 // Add the default footprint entry at the top
128 wxString defaultLabel = m_default_footprint.IsEmpty()
129 ? _( "No default footprint" )
130 : wxS( "[" ) + _( "Default" ) + wxS( "] " ) + m_default_footprint;
131
132 m_fp_sel_ctrl->Append( defaultLabel, new wxStringClientData( m_default_footprint ) );
133
134 // Explicitly associated footprints are listed first and always shown, bypassing the
135 // pin-count and glob filters (issue #2282). Track their names so the filtered results below
136 // can be deduplicated against them.
137 std::set<wxString> alwaysIncludedNames;
138
139 for( const LIB_ID& fpId : m_always_included )
140 {
141 wxString fpName = fpId.Format().wx_str();
142
143 if( alwaysIncludedNames.insert( fpName ).second )
144 m_fp_sel_ctrl->Append( fpName, new wxStringClientData( fpName ) );
145 }
146
147 // If zero_filter is set and we have no filters, show only the always-included footprints
148 if( m_zero_filter && m_filters.IsEmpty() && m_pin_count == 0 )
149 {
151 return true;
152 }
153
154 // Build JSON request for pcbnew
155 using json = nlohmann::json;
156 json request;
157 request["pin_count"] = m_pin_count;
158 request["zero_filters"] = m_zero_filter;
159 request["max_results"] = m_max_items;
160
161 json filtersArray = json::array();
162
163 for( const wxString& filter : m_filters )
164 filtersArray.push_back( filter.ToStdString() );
165
166 request["filters"] = filtersArray;
167
168 // Get the filter function from pcbnew via KIWAY
169 try
170 {
171 KIFACE* kiface = m_kiway->KiFACE( KIWAY::FACE_PCB );
172
173 if( !kiface )
174 {
176 return true;
177 }
178
179 void* funcPtr = kiface->IfaceOrAddress( KIFACE_FILTER_FOOTPRINTS );
180
181 if( !funcPtr )
182 {
184 return true;
185 }
186
187 // Call the filter function
188 using FilterFunc = wxString ( * )( const wxString& );
189 FilterFunc filterFootprints = reinterpret_cast<FilterFunc>( funcPtr );
190
191 wxString requestStr = wxString::FromUTF8( request.dump() );
192 wxString responseStr = filterFootprints( requestStr );
193
194 // Parse the response
195 json response = json::parse( responseStr.ToStdString() );
196
197 if( response.is_array() )
198 {
199 for( const auto& item : response )
200 {
201 if( item.is_string() )
202 {
203 wxString fpName = wxString::FromUTF8( item.get<std::string>() );
204
205 if( alwaysIncludedNames.count( fpName ) )
206 continue;
207
208 m_fp_sel_ctrl->Append( fpName, new wxStringClientData( fpName ) );
209 }
210 }
211 }
212 }
213 catch( const std::exception& )
214 {
215 // JSON parsing or other error - just show default
216 }
217
219 return true;
220}
221
222
224{
225 m_fp_sel_ctrl->SetSelection( 0 );
226}
227
228
230{
231 return m_fp_sel_ctrl->Enable( aEnable );
232}
The base class for create windows for drawing purpose.
Customized combo box for footprint selection.
virtual bool Enable(bool aEnable=true) override
Enable or disable the control for input.
std::vector< LIB_ID > m_always_included
void OnComboBox(wxCommandEvent &aEvent)
void AddAlwaysIncludedFootprint(const LIB_ID &aFootprintId)
Add a footprint that is always listed regardless of the pin-count and glob filters (issue #2282).
void FilterByFootprintFilters(const wxArrayString &aFilters, bool aZeroFilters)
Filter by footprint filter list.
void SetDefaultFootprint(const wxString &aFp)
Set the default footprint for a part.
FOOTPRINT_SELECT_WIDGET(EDA_DRAW_FRAME *aFrame, wxWindow *aParent, int aMaxItems=400)
Construct a footprint selector widget.
void FilterByPinCount(int aPinCount)
Filter by pin count.
void SelectDefault()
Set current selection to the default footprint.
bool UpdateList()
Update the contents of the list by fetching filtered footprints from pcbnew.
void ClearFilters()
Clear all filters.
void Load(KIWAY &aKiway, PROJECT &aProject)
Initialize the widget with a KIWAY for cross-module communication.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:311
@ FACE_PCB
pcbnew DSO
Definition kiway.h:319
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:168
Container for project specific data.
Definition project.h:63
#define _(s)
wxDEFINE_EVENT(EVT_FOOTPRINT_SELECTED, wxCommandEvent)
nlohmann::json json
Definition gerbview.cpp:50
@ KIFACE_FILTER_FOOTPRINTS
Function pointer type: wxString (*)(const wxString& aFilterJson) Input JSON: {"pin_count": N,...
Definition kiface_ids.h:35
static wxString filterFootprints(const wxString &aFilterJson)
Filter footprints based on criteria passed as JSON.
Definition pcbnew.cpp:111
Implement a participant in the KIWAY alchemy.
Definition kiway.h:152
IFACE KIFACE_BASE kiface("pcb_test_frame", KIWAY::FACE_PCB)