KiCad PCB EDA Suite
Loading...
Searching...
No Matches
db_lib_preview_panel.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
21
22#include <wx/choice.h>
23#include <wx/sizer.h>
24#include <wx/splitter.h>
25#include <wx/stattext.h>
26
28#include <generate_alias_info.h>
29#include <ki_exception.h>
30#include <kiplatform/ui.h>
31#include <lib_symbol.h>
33#include <widgets/lib_tree.h>
35
36
42{
43public:
45 std::function<const LIB_SYMBOL*( const LIB_ID& )> aLookup ) :
46 LIB_TREE_MODEL_ADAPTER( aFrame, wxEmptyString, aSettings ),
47 m_lookup( std::move( aLookup ) )
48 {
49 }
50
51 void SetLibrary( const wxString& aNickname, const std::vector<LIB_TREE_ITEM*>& aItems )
52 {
53 // The tree control still holds rows for the nodes about to be freed
54 ResetTreeView resetGuard( *this );
56
57 m_tree.Clear();
58
59 if( !aItems.empty() )
60 DoAddLibrary( aNickname, wxEmptyString, aItems, false, false );
61 }
62
63 wxString GenerateInfo( const LIB_ID& aLibId, int aUnit ) override
64 {
65 const LIB_SYMBOL* symbol = m_lookup( aLibId );
66 return symbol ? GenerateAliasInfo( symbol, aUnit ) : wxString();
67 }
68
69 bool CanPinLibraries() const override { return false; }
70
71protected:
73
74private:
75 std::function<const LIB_SYMBOL*( const LIB_ID& )> m_lookup;
76};
77
78
80 EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvasType ) :
81 wxPanel( aParent ),
82 m_footprintPreview( nullptr ),
83 m_kiway( aKiway ),
84 m_footprintLoadRetry( [this]()
85 {
86 showFootprint( m_footprintChoice->GetStringSelection() );
87 },
88 250 )
89{
90 m_adapter = new DB_LIB_PREVIEW_TREE_ADAPTER( aFrame, m_treeSettings,
91 [this]( const LIB_ID& aLibId )
92 {
93 return findSymbol( aLibId );
94 } );
95
96 wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
97 wxSplitterWindow* splitter = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
98 wxSP_LIVE_UPDATE | wxSP_3D );
99
100 wxPanel* treePanel = new wxPanel( splitter );
101 wxBoxSizer* treeSizer = new wxBoxSizer( wxVERTICAL );
102
103 m_tree = new LIB_TREE( treePanel, wxT( "database_preview" ), m_adapter, LIB_TREE::ALL_WIDGETS );
104 treeSizer->Add( m_tree, 1, wxEXPAND, 0 );
105
106 m_status = new wxStaticText( treePanel, wxID_ANY, wxEmptyString );
107 treeSizer->Add( m_status, 0, wxEXPAND | wxALL, 5 );
108
109 treePanel->SetSizer( treeSizer );
110
111 wxPanel* previewPanel = new wxPanel( splitter );
112 wxBoxSizer* previewSizer = new wxBoxSizer( wxVERTICAL );
113
114 m_symbolPreview = new SYMBOL_PREVIEW_WIDGET( previewPanel, aKiway, true, aCanvasType );
115 previewSizer->Add( m_symbolPreview, 11, wxEXPAND | wxALL, 5 );
116
117 m_footprintChoice = new wxChoice( previewPanel, wxID_ANY );
118 m_footprintChoice->SetToolTip( _( "Footprints offered by the selected row" ) );
119 previewSizer->Add( m_footprintChoice, 0, wxEXPAND | wxLEFT | wxRIGHT, 5 );
120
121 if( aKiway )
122 {
123 m_footprintPreview = new FOOTPRINT_PREVIEW_WIDGET( previewPanel, *aKiway );
124 previewSizer->Add( m_footprintPreview, 10, wxEXPAND | wxALL, 5 );
125
126 // Nothing else may have loaded the footprint libraries, e.g. when opened from the library table
128 }
129
130 previewPanel->SetSizer( previewSizer );
131
132 splitter->SetSashGravity( 0.5 );
133 splitter->SetMinimumPaneSize( 80 );
134 splitter->SplitHorizontally( treePanel, previewPanel );
135
136 sizer->Add( splitter, 1, wxEXPAND, 0 );
137 SetSizer( sizer );
138
139 m_adapter->FinishTreeInitialization();
140
141 Bind( EVT_LIBITEM_SELECTED, &DB_LIB_PREVIEW_PANEL::onSymbolSelected, this );
142 m_footprintChoice->Bind( wxEVT_CHOICE, &DB_LIB_PREVIEW_PANEL::onFootprintSelected, this );
143
144 showSymbol( nullptr, 1 );
145}
146
147
149{
150 Unbind( EVT_LIBITEM_SELECTED, &DB_LIB_PREVIEW_PANEL::onSymbolSelected, this );
151 m_footprintChoice->Unbind( wxEVT_CHOICE, &DB_LIB_PREVIEW_PANEL::onFootprintSelected, this );
152 m_footprintLoadRetry.Cancel();
153}
154
155
156void DB_LIB_PREVIEW_PANEL::SetSymbols( const wxString& aLibNickname,
157 std::vector<std::unique_ptr<LIB_SYMBOL>> aSymbols )
158{
159 int unit = 0;
160 LIB_ID selected = m_tree->GetSelectedLibId( &unit );
161
162 m_tree->Unselect();
163
164 std::map<wxString, std::unique_ptr<LIB_SYMBOL>> symbols;
165 std::vector<LIB_TREE_ITEM*> items;
166
167 for( std::unique_ptr<LIB_SYMBOL>& symbol : aSymbols )
168 {
169 LIB_ID id = symbol->GetLibId();
170 id.SetLibNickname( aLibNickname );
171 id.SetLibItemName( symbol->GetName() );
172 symbol->SetLibId( id );
173
174 symbols[symbol->GetName()] = std::move( symbol );
175 }
176
177 // Keys that sanitize to the same name collapse to one symbol, so take pointers after the map settles
178 for( const auto& [name, symbol] : symbols )
179 items.push_back( symbol.get() );
180
181 // The tree selects asynchronously after a rebuild, so carry the selection through its preselect,
182 // which matches nodes by nickname and name only
183 LIB_ID preselect;
184
185 if( selected.IsValid() && symbols.contains( selected.GetLibItemName().wx_str() ) )
186 preselect = LIB_ID( aLibNickname, selected.GetLibItemName() );
187
188 m_adapter->SetPreselectNode( preselect, preselect.IsValid() ? unit : 0 );
189
190 static_cast<DB_LIB_PREVIEW_TREE_ADAPTER*>( m_adapter.get() )->SetLibrary( aLibNickname, items );
191
192 // Tree nodes copied what they need, so the old symbols can go now
193 m_symbols = std::move( symbols );
194 m_nickname = aLibNickname;
195
196 m_tree->Regenerate( false );
197
198 if( !m_nickname.IsEmpty() )
199 m_adapter->OpenLibs( { m_nickname } );
200}
201
202
203void DB_LIB_PREVIEW_PANEL::SetStatus( const wxString& aText )
204{
205 m_status->SetLabel( aText );
206
207 // The splitter does not lay out its panes again when only their contents change
208 m_status->GetParent()->Layout();
209 Layout();
210}
211
212
213void DB_LIB_PREVIEW_PANEL::SelectSymbol( const wxString& aSymbolName )
214{
215 if( !m_symbols.contains( aSymbolName ) )
216 return;
217
218 LIB_ID id( m_nickname, aSymbolName );
219
220 m_tree->SelectLibId( id );
221 m_tree->CenterLibId( id );
222}
223
224
226{
227 auto it = m_symbols.find( aLibId.GetLibItemName().wx_str() );
228 return it == m_symbols.end() ? nullptr : it->second.get();
229}
230
231
232void DB_LIB_PREVIEW_PANEL::onSymbolSelected( wxCommandEvent& aEvent )
233{
234 int unit = 0;
235 LIB_ID id = m_tree->GetSelectedLibId( &unit );
236
237 showSymbol( findSymbol( id ), std::max( unit, 1 ) );
238}
239
240
241void DB_LIB_PREVIEW_PANEL::showSymbol( const LIB_SYMBOL* aSymbol, int aUnit )
242{
243 m_footprintChoice->Clear();
244
245 if( !aSymbol )
246 {
247 // Clear without the status overlay; a GL canvas hidden since creation lays out wrongly on GTK
248 m_symbolPreview->DisplayPart( nullptr, 0 );
249 m_footprintChoice->Disable();
250 showFootprint( wxEmptyString );
251 return;
252 }
253
254 // The loader leaves the source unset when the row's symbols column did not resolve
255 if( !aSymbol->GetSourceLibId().IsValid() )
256 {
257 m_symbolPreview->SetStatusText( _( "Symbol not found; check the symbols column" ) );
258 }
259 else
260 {
261 try
262 {
263 m_symbolPreview->DisplayPart( aSymbol->IsDerived() ? aSymbol->Flatten().get() : aSymbol, aUnit );
264 }
265 catch( const IO_ERROR& )
266 {
267 // A derived symbol whose parent is gone still shows its own items
268 m_symbolPreview->DisplayPart( aSymbol, aUnit );
269 }
270 }
271
272 // The database loader lists every footprint of the row in the footprint filters
273 for( const wxString& footprint : aSymbol->GetFPFilters() )
274 {
275 if( footprint.Contains( wxS( ":" ) ) && !footprint.Contains( wxS( "*" ) ) && !footprint.Contains( wxS( "?" ) ) )
276 m_footprintChoice->Append( footprint );
277 }
278
279 m_footprintChoice->Enable( m_footprintChoice->GetCount() > 1 );
280
281 if( m_footprintChoice->GetCount() > 0 )
282 {
283 m_footprintChoice->SetSelection( 0 );
284 showFootprint( m_footprintChoice->GetString( 0 ) );
285 }
286 else
287 {
288 showFootprint( wxEmptyString );
289 }
290}
291
292
293void DB_LIB_PREVIEW_PANEL::onFootprintSelected( wxCommandEvent& aEvent )
294{
295 showFootprint( m_footprintChoice->GetStringSelection() );
296}
297
298
299void DB_LIB_PREVIEW_PANEL::showFootprint( const wxString& aFootprint )
300{
301 if( !m_footprintPreview || !m_footprintPreview->IsInitialized() )
302 return;
303
304 LIB_ID id;
305
306 if( aFootprint.IsEmpty() )
307 {
308 m_footprintPreview->SetStatusText( _( "No footprint specified" ) );
309 }
310 else if( m_kiway && GetFootprintLibrariesLoadProgress( *m_kiway ) < 1.0f )
311 {
312 m_footprintPreview->SetStatusText( _( "Loading footprint libraries..." ) );
313 m_footprintLoadRetry.Restart();
314 }
315 else if( id.Parse( aFootprint ) == -1 && id.IsValid() )
316 {
317 m_footprintPreview->ClearStatus();
318 m_footprintPreview->DisplayFootprint( id );
319 }
320 else
321 {
322 m_footprintPreview->SetStatusText( _( "Invalid footprint specified" ) );
323 }
324}
const char * name
void onFootprintSelected(wxCommandEvent &aEvent)
const LIB_SYMBOL * findSymbol(const LIB_ID &aLibId) const
void showSymbol(const LIB_SYMBOL *aSymbol, int aUnit)
void showFootprint(const wxString &aFootprint)
void onSymbolSelected(wxCommandEvent &aEvent)
WX_DEBOUNCED_ACTION m_footprintLoadRetry
Polls the footprint library load, which DisplayFootprint() needs finished.
FOOTPRINT_PREVIEW_WIDGET * m_footprintPreview
void SelectSymbol(const wxString &aSymbolName)
wxObjectDataPtr< LIB_TREE_MODEL_ADAPTER > m_adapter
void SetSymbols(const wxString &aLibNickname, std::vector< std::unique_ptr< LIB_SYMBOL > > aSymbols)
Replaces the previewed library, keeping the selected symbol when it still exists.
DB_LIB_PREVIEW_PANEL(wxWindow *aParent, EDA_BASE_FRAME *aFrame, KIWAY *aKiway, EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvasType)
SYMBOL_PREVIEW_WIDGET * m_symbolPreview
void SetStatus(const wxString &aText)
Shows a one-line status below the library tree.
std::map< wxString, std::unique_ptr< LIB_SYMBOL > > m_symbols
Tree model over symbols the preview panel owns.
wxString GenerateInfo(const LIB_ID &aLibId, int aUnit) override
bool CanPinLibraries() const override
Pinning writes to the project, so trees of libraries outside it must opt out.
std::function< const LIB_SYMBOL *(const LIB_ID &)> m_lookup
void SetLibrary(const wxString &aNickname, const std::vector< LIB_TREE_ITEM * > &aItems)
DB_LIB_PREVIEW_TREE_ADAPTER(EDA_BASE_FRAME *aFrame, APP_SETTINGS_BASE::LIB_TREE &aSettings, std::function< const LIB_SYMBOL *(const LIB_ID &)> aLookup)
PROJECT::LIB_TYPE_T getLibType() override
The base frame for deriving all KiCad main window classes.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:348
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
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition lib_id.cpp:113
const UTF8 & GetLibItemName() const
Definition lib_id.h:98
Define a library symbol object.
Definition lib_symbol.h:114
bool IsDerived() const
Definition lib_symbol.h:241
LIB_ID GetSourceLibId() const
Definition lib_symbol.h:193
wxArrayString GetFPFilters() const
Definition lib_symbol.h:252
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
RAII guard that detaches the GtkTreeView from the model across a tree rebuild so a deferred frame-clo...
LIB_TREE_MODEL_ADAPTER(EDA_BASE_FRAME *aParent, const wxString &aPinnedKey, APP_SETTINGS_BASE::LIB_TREE &aSettingsStruct)
Create the adapter.
LIB_TREE_NODE_LIBRARY & DoAddLibrary(const wxString &aNodeName, const wxString &aDesc, const std::vector< LIB_TREE_ITEM * > &aItemList, bool aPinned, bool aPresorted)
Add the given list of symbols by alias.
Widget displaying a tree of symbols with optional search text control and description panel.
Definition lib_tree.h:44
@ ALL_WIDGETS
Definition lib_tree.h:53
@ SYMBOL_LIB
Definition project.h:191
wxString wx_str() const
Definition utf8.cpp:41
#define _(s)
float GetFootprintLibrariesLoadProgress(KIWAY &aKiway)
Return how far the background load of the footprint libraries has got.
bool StartFootprintLibrariesLoad(KIWAY &aKiway)
Start loading the footprint libraries in the background.
wxString GenerateAliasInfo(SYMBOL_LIBRARY_ADAPTER *aLibs, LIB_ID const &aLibId, int aUnit)
Return an HTML page describing a LIB_ID in a SYMBOL_LIBRARY_ADAPTER.
void CancelPendingScroll(wxDataViewCtrl *aCtrl)
Cancel any pending scroll-to-item request on aCtrl.
Definition wxgtk/ui.cpp:649
STL namespace.
static LIB_SYMBOL * findSymbol(const wxString &aName, LEGACY_SYMBOL_LIBS *aLibs, bool aCached)
Search the libraries for the first symbol with a given name.