KiCad PCB EDA Suite
footprint_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 (C) 2016-2019 KiCad Developers, see AUTHORS.txt for contributors.
5  * Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
6  * Copyright (C) 2016 Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
7  *
8  * This program is free software: you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the
10  * Free Software Foundation, either version 3 of the License, or (at your
11  * option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <memory>
23 #include <mutex>
24 #include <utility>
25 
26 #include "pcbnew_settings.h"
27 #include <class_board.h>
28 #include <class_module.h>
29 #include <eda_draw_frame.h>
31 #include <fp_lib_table.h>
32 #include <id.h>
33 #include <io_mgr.h>
34 #include <kiface_i.h>
35 #include <kiway.h>
36 #include <math/box2.h>
37 #include <painter.h>
38 #include <pcb_draw_panel_gal.h>
39 #include <pcb_edit_frame.h>
40 #include <pgm_base.h>
42 #include <view/view.h>
43 #include <wx/stattext.h>
44 
49 {
51 
52  public:
53  FP_THREAD_IFACE() : m_panel( nullptr )
54  {
55  }
56 
59  {
60  std::lock_guard<std::mutex> lock( m_lock );
61  auto it = m_cachedFootprints.find( aFPID );
62 
63  if( it != m_cachedFootprints.end() )
64  return it->second;
65  else
66  return NULLOPT;
67  }
68 
73  CACHE_ENTRY AddToQueue( const LIB_ID& aEntry )
74  {
75  std::lock_guard<std::mutex> lock( m_lock );
76 
77  CACHE_ENTRY ent = { aEntry, nullptr, FPS_LOADING };
78  m_cachedFootprints[aEntry] = ent;
79  m_loaderQueue.push_back( ent );
80 
81  return ent;
82  }
83 
86  {
87  std::lock_guard<std::mutex> lock( m_lock );
88 
89  if( m_loaderQueue.empty() )
90  {
91  return NULLOPT;
92  }
93  else
94  {
95  auto ent = m_loaderQueue.front();
96  m_loaderQueue.pop_front();
97  return ent;
98  }
99  }
100 
102  void AddToCache( const CACHE_ENTRY& aEntry )
103  {
104  std::lock_guard<std::mutex> lock( m_lock );
105  m_cachedFootprints[aEntry.fpid] = aEntry;
106  }
107 
112  {
113  std::lock_guard<std::mutex> lock( m_lock );
114  m_current_fp = std::move( aFp );
115  }
116 
121  {
122  std::lock_guard<std::mutex> lock( m_lock );
123  return m_current_fp;
124  }
125 
130  {
131  std::lock_guard<std::mutex> lock( m_lock );
132  m_panel = aPanel;
133  }
134 
139  {
140  std::lock_guard<std::mutex> lock( m_lock );
141  return m_panel;
142  }
143 
148  bool QueueEvent( const wxEvent& aEvent )
149  {
150  std::lock_guard<std::mutex> lock( m_lock );
151 
152  if( m_panel )
153  {
154  m_panel->GetEventHandler()->QueueEvent( aEvent.Clone() );
155  return true;
156  }
157  else
158  {
159  return false;
160  }
161  }
162 
167  {
168  std::lock_guard<std::mutex> lock( m_lock );
169  return m_panel ? m_panel->Prj().PcbFootprintLibs() : nullptr;
170  }
171 
172  private:
173  std::deque<CACHE_ENTRY> m_loaderQueue;
174  std::map<LIB_ID, CACHE_ENTRY> m_cachedFootprints;
177  std::mutex m_lock;
178 };
179 
180 
185 class FP_LOADER_THREAD : public wxThread
186 {
188 
189  std::shared_ptr<FP_THREAD_IFACE> m_iface;
190 
191 public:
192  FP_LOADER_THREAD( const std::shared_ptr<FP_THREAD_IFACE>& aIface )
193  : wxThread( wxTHREAD_DETACHED ), m_iface( aIface )
194  {
195  }
196 
197 
199  {
200  }
201 
202 
203  void ProcessEntry( CACHE_ENTRY& aEntry )
204  {
205  FP_LIB_TABLE* fptbl = m_iface->GetTable();
206 
207  if( !fptbl )
208  return;
209 
210  try
211  {
212  aEntry.module.reset( fptbl->FootprintLoadWithOptionalNickname( aEntry.fpid ) );
213 
214  if( !aEntry.module )
215  aEntry.status = FPS_NOT_FOUND;
216  }
217  catch( const IO_ERROR& )
218  {
219  aEntry.status = FPS_NOT_FOUND;
220  }
221 
222  if( aEntry.status != FPS_NOT_FOUND )
223  aEntry.status = FPS_READY;
224 
225  m_iface->AddToCache( aEntry );
226 
227  if( aEntry.fpid == m_iface->GetCurrentFootprint() )
228  {
229  wxCommandEvent evt( wxEVT_COMMAND_TEXT_UPDATED, 1 );
230  m_iface->QueueEvent( evt );
231  }
232  }
233 
234 
235  virtual void* Entry() override
236  {
237  while( m_iface->GetPanel() )
238  {
239  auto ent = m_iface->PopFromQueue();
240 
241  if( ent )
242  ProcessEntry( *ent );
243  else
244  wxMilliSleep( 100 );
245  }
246 
247  return nullptr;
248  }
249 };
250 
251 
253  std::unique_ptr<KIGFX::GAL_DISPLAY_OPTIONS> aOpts, GAL_TYPE aGalType )
254  : PCB_DRAW_PANEL_GAL( aParent, -1, wxPoint( 0, 0 ), wxSize( 200, 200 ), *aOpts, aGalType ),
255  KIWAY_HOLDER( aKiway, KIWAY_HOLDER::PANEL ),
256  m_displayOptions( std::move( aOpts ) ),
257  m_currentModule( nullptr ),
258  m_footprintDisplayed( true )
259 {
260  m_iface = std::make_shared<FP_THREAD_IFACE>();
261  m_iface->SetPanel( this );
263  m_loader->Run();
264 
265  SetStealsFocus( false );
266  ShowScrollbars( wxSHOW_SB_NEVER, wxSHOW_SB_NEVER );
267  EnableScrolling( false, false ); // otherwise Zoom Auto disables GAL canvas
268 
269  m_dummyBoard = std::make_unique<BOARD>();
270  UpdateColors();
272 
273  Raise();
274  Show( true );
275  StartDrawing();
276 
277  Connect( wxEVT_COMMAND_TEXT_UPDATED,
278  wxCommandEventHandler( FOOTPRINT_PREVIEW_PANEL::OnLoaderThreadUpdate ), NULL, this );
279 }
280 
281 
283 {
284  if( m_currentModule )
285  {
286  GetView()->Remove( m_currentModule.get() );
287  GetView()->Clear();
288  m_currentModule->SetParent( nullptr );
289  }
290 
291  m_iface->SetPanel( nullptr );
292 }
293 
294 
296 {
297  auto opt_ent = m_iface->GetFromCache( aFPID );
298 
299  if( opt_ent )
300  return *opt_ent;
301  else
302  return m_iface->AddToQueue( aFPID );
303 }
304 
305 
306 // This is separate to avoid having to export CACHE_ENTRY to the global namespace
308 {
309  (void) CacheAndReturn( aFPID );
310 }
311 
312 
313 void FOOTPRINT_PREVIEW_PANEL::renderFootprint( std::shared_ptr<MODULE> aModule )
314 {
315  if( m_currentModule )
316  {
317  GetView()->Remove( m_currentModule.get() );
318  GetView()->Clear();
319  m_currentModule->SetParent( nullptr );
320  }
321 
322  aModule->SetParent( m_dummyBoard.get() );
323 
324  GetView()->Add( aModule.get() );
325  GetView()->SetVisible( aModule.get(), true );
326  GetView()->Update( aModule.get(), KIGFX::ALL );
327 
328  // Save a reference to the module's shared pointer to say we are using it in the
329  // preview panel
330  m_currentModule = aModule;
331 
332  BOX2I bbox = aModule->ViewBBox();
333  bbox.Merge( aModule->Value().ViewBBox() );
334  bbox.Merge( aModule->Reference().ViewBBox() );
335 
336  if( bbox.GetSize().x > 0 && bbox.GetSize().y > 0 )
337  {
338  // Autozoom
339  GetView()->SetViewport( BOX2D( bbox.GetOrigin(), bbox.GetSize() ) );
340 
341  // Add a margin
342  GetView()->SetScale( GetView()->GetScale() * 0.7 );
343 
344  Refresh();
345  }
346 }
347 
348 
350 {
351  m_currentFPID = aFPID;
352  m_iface->SetCurrentFootprint( aFPID );
353  m_footprintDisplayed = false;
354 
356 
357  if( m_handler )
358  m_handler( fpe.status );
359 
360  if( fpe.status == FPS_READY )
361  {
362  if( !m_footprintDisplayed )
363  {
364  renderFootprint( fpe.module );
365  m_footprintDisplayed = true;
366  Refresh();
367  }
368  }
369 }
370 
371 
372 void FOOTPRINT_PREVIEW_PANEL::OnLoaderThreadUpdate( wxCommandEvent& aEvent )
373 {
375 }
376 
377 
379 {
380  m_handler = aHandler;
381 }
382 
383 
385 {
386  return static_cast<wxWindow*>( this );
387 }
388 
389 
391 {
392  PCB_EDIT_FRAME* pcbnew =
393  static_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR, false ) );
394 
395  PCBNEW_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<PCBNEW_SETTINGS>();
396 
397  // Fetch grid & display settings from PCBNew if it's running; otherwise fetch them
398  // from PCBNew's config settings.
399  // We need a copy with a lifetime that matches the panel
400  std::unique_ptr<KIGFX::GAL_DISPLAY_OPTIONS> gal_opts;
401 
402  if( pcbnew )
403  {
404  // Copy the existing Pcbnew options
405  // REVIEW: This also copies the current subscription list of the options
406  // to the new options. This is probably not what is intended, but because
407  // this widget doesn't change the options it should be OK.
408  gal_opts = std::make_unique<KIGFX::GAL_DISPLAY_OPTIONS>( pcbnew->GetGalDisplayOptions() );
409  }
410  else
411  {
412 
413  // Make and populate a new one from config
414  gal_opts = std::make_unique<KIGFX::GAL_DISPLAY_OPTIONS>();
415  gal_opts->ReadConfig( *Pgm().GetCommonSettings(), cfg->m_Window, aParent );
416  }
417 
418  auto canvasType = static_cast<EDA_DRAW_PANEL_GAL::GAL_TYPE>( cfg->m_Graphics.canvas_type );
419  auto panel = new FOOTPRINT_PREVIEW_PANEL( aKiway, aParent, std::move( gal_opts ), canvasType );
420 
421  if( pcbnew )
422  {
423  panel->GetGAL()->SetGridVisibility( pcbnew->IsGridVisible() );
424  panel->GetGAL()->SetGridSize( VECTOR2D( pcbnew->GetScreen()->GetGridSize() ) );
425 
426  // Grid color (among other things):
427  KIGFX::PAINTER* pcbnew_painter = pcbnew->GetCanvas()->GetView()->GetPainter();
428  panel->GetView()->GetPainter()->ApplySettings( pcbnew_painter->GetSettings() );
429  }
430  else
431  {
432  panel->GetGAL()->SetGridVisibility( cfg->m_Window.grid.show );
433 
434  // Read grid size:
435  std::unique_ptr<PCB_SCREEN> temp_screen = std::make_unique<PCB_SCREEN>( wxSize() );
436  temp_screen->SetGrid( ID_POPUP_GRID_LEVEL_1000 + cfg->m_Window.grid.last_size );
437  panel->GetGAL()->SetGridSize( VECTOR2D( temp_screen->GetGridSize() ) );
438  }
439 
440  return panel;
441 }
KIWAY_HOLDER is a mix in class which holds the location of a wxWindow's KIWAY.
Definition: kiway_holder.h:39
LIB_ID fpid
Footprint loader thread to prevent footprint loading from locking the UI.
const wxRealPoint & GetGridSize() const
Return the grid size of the currently selected grid.
Definition: base_screen.h:279
FOOTPRINT_STATUS status
void SetViewport(const BOX2D &aViewport)
Function SetViewport() Sets the visible area of the VIEW.
Definition: view.cpp:550
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:103
KIGFX::GAL_DISPLAY_OPTIONS & GetGalDisplayOptions()
Return a reference to the gal rendering options used by GAL for rendering.
virtual bool IsGridVisible() const override
Function IsGridVisible()
virtual void Update(VIEW_ITEM *aItem, int aUpdateFlags) override
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: pcb_view.cpp:91
bool QueueEvent(const wxEvent &aEvent)
Post an event to the panel, if the panel still exists.
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOX2< VECTOR2D > BOX2D
Definition: box2.h:522
std::shared_ptr< FP_THREAD_IFACE > m_iface
Template specialization to enable wxStrings for certain containers (e.g. unordered_map)
Definition: bitmap.cpp:56
virtual void * Entry() override
LIB_ID GetCurrentFootprint()
Threadsafe accessor to get the current footprint.
OPT< CACHE_ENTRY > PopFromQueue()
Pop an entry from the queue, or empty option if none is available.
void ProcessEntry(CACHE_ENTRY &aEntry)
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
Item needs to be redrawn.
Definition: view_item.h:61
virtual void DisplayFootprint(const LIB_ID &aFPID) override
Set the currently displayed footprint.
virtual void Remove(VIEW_ITEM *aItem) override
Function Remove() Removes a VIEW_ITEM from the view.
Definition: pcb_view.cpp:74
virtual void ApplySettings(const RENDER_SETTINGS *aSettings)=0
Function ApplySettings Loads colors and display modes settings that are going to be used when drawing...
PAINTER * GetPainter() const
Function GetPainter() Returns the painter object used by the view for drawing VIEW_ITEMS.
Definition: view.h:199
Panel that renders a single footprint via Cairo GAL, meant to be exported through Kiface.
FP_LIB_TABLE * GetTable()
Get an FP_LIB_TABLE, or null if the panel is dead.
std::shared_ptr< MODULE > module
CACHE_ENTRY AddToQueue(const LIB_ID &aEntry)
Push an entry to the loading queue and a placeholder to the cache; return the placeholder.
FOOTPRINT_PREVIEW_PANEL * GetPanel()
Get the associated panel.
PAINTER contains all the knowledge about how to draw graphical object onto any particular output devi...
Definition: painter.h:308
virtual wxWindow * GetWindow() override
Get the underlying wxWindow.
std::shared_ptr< MODULE > m_currentModule
const auto NULLOPT
Definition: optional.h:9
#define NULL
VECTOR2< double > VECTOR2D
Definition: vector2d.h:593
std::unique_ptr< BOARD > m_dummyBoard
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:341
Threadsafe interface class between loader thread and panel class.
void Clear()
Function Clear() Removes all items from the view.
Definition: view.cpp:1111
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
void SetStealsFocus(bool aStealsFocus)
Set whether focus is taken on certain events (mouseover, keys, etc).
virtual void SetStatusHandler(FOOTPRINT_STATUS_HANDLER aHandler) override
Set the callback to receive status updates.
virtual void CacheFootprint(const LIB_ID &aFPID) override
Preload a footprint into the cache.
static FOOTPRINT_PREVIEW_PANEL * New(KIWAY *aKiway, wxWindow *aParent)
KIWAY is a minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the s...
Definition: kiway.h:273
FOOTPRINT_PREVIEW_PANEL(KIWAY *aKiway, wxWindow *aParent, std::unique_ptr< KIGFX::GAL_DISPLAY_OPTIONS > aOpts, GAL_TYPE aGalType)
Create a new panel.
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Function Merge modifies the position and size of the rectangle in order to contain aRect.
Definition: box2.h:385
void SyncLayersVisibility(const BOARD *aBoard)
Function SyncLayersVisibility Updates "visibility" property of each layer of a given BOARD.
void renderFootprint(std::shared_ptr< MODULE > aModule)
virtual KIGFX::PCB_VIEW * GetView() const override
Function GetView() Returns a pointer to the VIEW instance used in the panel.
void SetCurrentFootprint(LIB_ID aFp)
Threadsafe accessor to set the current footprint.
void StartDrawing()
Function StartDrawing() Begins drawing if it was stopped previously.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=NULL) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
void UpdateColors()
Updates the color settings in the painter and GAL.
std::map< LIB_ID, CACHE_ENTRY > m_cachedFootprints
VTBL_ENTRY FP_LIB_TABLE * PcbFootprintLibs(KIWAY &aKiway)
Return the table of footprint libraries.
Definition: project.cpp:427
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Function SetScale() Sets the scaling factor, zooming around a given anchor point.
Definition: view.cpp:578
virtual RENDER_SETTINGS * GetSettings()=0
Function GetSettings Returns pointer to current settings that are going to be used when drawing items...
void SetPanel(FOOTPRINT_PREVIEW_PANEL *aPanel)
Set the associated panel, for QueueEvent() and GetTable().
see class PGM_BASE
void OnLoaderThreadUpdate(wxCommandEvent &aEvent)
FOOTPRINT_STATUS_HANDLER m_handler
virtual CACHE_ENTRY CacheAndReturn(const LIB_ID &aFPID)
PCB_EDIT_FRAME is the main frame for Pcbnew.
std::shared_ptr< FP_THREAD_IFACE > m_iface
FP_LOADER_THREAD(const std::shared_ptr< FP_THREAD_IFACE > &aIface)
OPT< CACHE_ENTRY > GetFromCache(const LIB_ID &aFPID)
Retrieve a cache entry by LIB_ID.
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
boost::optional< T > OPT
Definition: optional.h:7
std::deque< CACHE_ENTRY > m_loaderQueue
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Sets the item visibility.
Definition: view.cpp:1486
MODULE * FootprintLoadWithOptionalNickname(const LIB_ID &aFootprintId)
Function FootprintLoadWithOptionalNickname loads a footprint having aFootprintId with possibly an emp...
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1) override
Function Add() Adds a VIEW_ITEM to the view.
Definition: pcb_view.cpp:58
const Vec & GetSize() const
Definition: box2.h:188
Module description (excepted pads)
const Vec & GetOrigin() const
Definition: box2.h:192
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
FOOTPRINT_PREVIEW_PANEL * m_panel
void AddToCache(const CACHE_ENTRY &aEntry)
Add an entry to the cache.
std::function< void(FOOTPRINT_STATUS)> FOOTPRINT_STATUS_HANDLER