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-2017 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 
23 #include <pcb_draw_panel_gal.h>
24 
25 #include <kiway.h>
26 #include <io_mgr.h>
27 #include <fp_lib_table.h>
28 #include <view/view.h>
29 #include <math/box2.h>
30 #include <class_module.h>
31 #include <class_board.h>
32 #include <ki_mutex.h>
33 
34 #include <boost/bind.hpp>
35 #include <make_unique.h>
36 
37 #include <wx/stattext.h>
38 
39 
44 {
46 
47  public:
50  {
51  MUTLOCK lock( m_lock );
52  auto it = m_cachedFootprints.find( aFPID );
53 
54  if( it != m_cachedFootprints.end() )
55  return it->second;
56  else
57  return boost::none;
58  }
59 
64  CACHE_ENTRY AddToQueue( LIB_ID const & aEntry )
65  {
66  MUTLOCK lock( m_lock );
67 
68  CACHE_ENTRY ent = { aEntry, NULL, FPS_LOADING };
69  m_cachedFootprints[aEntry] = ent;
70  m_loaderQueue.push_back( ent );
71 
72  return ent;
73  }
74 
77  {
78  MUTLOCK lock( m_lock );
79 
80  if( m_loaderQueue.empty() )
81  {
82  return boost::none;
83  }
84  else
85  {
86  auto ent = m_loaderQueue.front();
87  m_loaderQueue.pop_front();
88  return ent;
89  }
90  }
91 
93  void AddToCache( CACHE_ENTRY const & aEntry )
94  {
95  MUTLOCK lock( m_lock );
96  m_cachedFootprints[aEntry.fpid] = aEntry;
97  }
98 
103  {
104  MUTLOCK lock( m_lock );
105  m_current_fp = aFp;
106  }
107 
112  {
113  MUTLOCK lock( m_lock );
114  return m_current_fp;
115  }
116 
121  {
122  MUTLOCK lock( m_lock );
123  m_panel = aPanel;
124  }
125 
130  {
131  MUTLOCK lock( m_lock );
132  return m_panel;
133  }
134 
139  bool QueueEvent( wxEvent const& aEvent )
140  {
141  MUTLOCK lock( m_lock );
142 
143  if( m_panel )
144  {
145  m_panel->GetEventHandler()->QueueEvent( aEvent.Clone() );
146  return true;
147  }
148  else
149  {
150  return false;
151  }
152  }
153 
158  {
159  MUTLOCK locK( m_lock );
160  return m_panel ? m_panel->Prj().PcbFootprintLibs() : nullptr;
161  }
162 
163  private:
164  std::deque<CACHE_ENTRY> m_loaderQueue;
165  std::map<LIB_ID, CACHE_ENTRY> m_cachedFootprints;
169 };
170 
171 
176 class FP_LOADER_THREAD: public wxThread
177 {
179 
180  std::shared_ptr<FP_THREAD_IFACE> m_iface;
181 
182 public:
183  FP_LOADER_THREAD( std::shared_ptr<FP_THREAD_IFACE> const& aIface ):
184  wxThread( wxTHREAD_DETACHED ),
185  m_iface( aIface )
186  {}
187 
188 
190  {}
191 
192 
193  void ProcessEntry( CACHE_ENTRY& aEntry )
194  {
195  FP_LIB_TABLE* fptbl = m_iface->GetTable();
196 
197  if( !fptbl )
198  return;
199 
200  aEntry.module = NULL;
201 
202  try {
203  aEntry.module = fptbl->FootprintLoadWithOptionalNickname( aEntry.fpid );
204 
205  if( !aEntry.module )
206  aEntry.status = FPS_NOT_FOUND;
207 
208  } catch( const IO_ERROR& )
209  {
210  aEntry.status = FPS_NOT_FOUND;
211  }
212 
213 
214  if( aEntry.status != FPS_NOT_FOUND )
215  aEntry.status = FPS_READY;
216 
217  m_iface->AddToCache( aEntry );
218 
219  if( aEntry.fpid == m_iface->GetCurrentFootprint() )
220  {
221  wxCommandEvent evt( wxEVT_COMMAND_TEXT_UPDATED, 1 );
222  m_iface->QueueEvent( evt );
223  }
224  }
225 
226 
227  virtual void* Entry() override
228  {
229  while( m_iface->GetPanel() )
230  {
231  auto ent = m_iface->PopFromQueue();
232 
233  if( ent )
234  ProcessEntry( *ent );
235  else
236  wxMilliSleep( 100 );
237  }
238 
239  return nullptr;
240  }
241 };
242 
243 
245  KIWAY* aKiway, wxWindow* aParent, KIGFX::GAL_DISPLAY_OPTIONS& aOpts, GAL_TYPE aGalType )
246  : PCB_DRAW_PANEL_GAL ( aParent, -1, wxPoint( 0, 0 ), wxSize(200, 200), aOpts, aGalType ),
247  KIWAY_HOLDER( aKiway ),
248  m_footprintDisplayed( true )
249 {
250 
251  m_iface = std::make_shared<FP_THREAD_IFACE>();
252  m_iface->SetPanel( this );
254  m_loader->Run();
255 
256  SetStealsFocus( false );
257  ShowScrollbars( wxSHOW_SB_NEVER, wxSHOW_SB_NEVER );
258  EnableScrolling( false, false ); // otherwise Zoom Auto disables GAL canvas
259 
260  m_dummyBoard = std::make_unique<BOARD>();
261 
262  UseColorScheme( m_dummyBoard->GetColorsSettings() );
264 
265  Raise();
266  Show(true);
267  StartDrawing();
268 
269  Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( FOOTPRINT_PREVIEW_PANEL::OnLoaderThreadUpdate ), NULL, this );
270 }
271 
272 
274 {
275  m_iface->SetPanel( nullptr );
276 }
277 
278 
280 {
281  auto opt_ent = m_iface->GetFromCache( aFPID );
282 
283  if( opt_ent )
284  return *opt_ent;
285  else
286  return m_iface->AddToQueue( aFPID );
287 }
288 
289 
290 // This is separate to avoid having to export CACHE_ENTRY to the global namespace
292 {
293  (void) CacheAndReturn( aFPID );
294 }
295 
296 
298 {
299  GetView()->Clear();
300  module->SetParent ( &*m_dummyBoard );
301  module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, GetView(), _1, -1 ) );
302 
303  GetView()->Add ( module );
304 
305  GetView()->SetVisible( module, true );
306  GetView()->Update( module, KIGFX::ALL );
307 
308  BOX2I bbox = module->ViewBBox();
309  bbox.Merge ( module->Value().ViewBBox() );
310  bbox.Merge ( module->Reference().ViewBBox() );
311 
312  if( bbox.GetSize().x > 0 && bbox.GetSize().y > 0 )
313  {
314  // Autozoom
315  GetView()->SetViewport( BOX2D( bbox.GetOrigin(), bbox.GetSize() ) );
316 
317  // Add a margin
318  GetView()->SetScale( GetView()->GetScale() * 0.7 );
319 
320  Refresh();
321  }
322 }
323 
324 
326 {
327  m_currentFPID = aFPID;
328  m_iface->SetCurrentFootprint( aFPID );
329  m_footprintDisplayed = false;
330 
332 
333  if( m_handler )
334  m_handler( fpe.status );
335 
336  if( fpe.status == FPS_READY )
337  {
338  if ( !m_footprintDisplayed )
339  {
340  renderFootprint( fpe.module );
341  m_footprintDisplayed = true;
342  Refresh();
343  }
344  }
345 }
346 
347 
349 {
351 }
352 
353 
355 {
356  m_handler = aHandler;
357 }
358 
359 
361 {
362  return static_cast<wxWindow*>( this );
363 }
364 
365 
367 {
369 
370  return new FOOTPRINT_PREVIEW_PANEL(
371  aKiway, aParent, gal_opts, EDA_DRAW_PANEL_GAL::GAL_TYPE_CAIRO );
372 }
const Vec & GetOrigin() const
Definition: box2.h:181
Class KIWAY_HOLDER is a mix in class which holds the location of a wxWindow's KIWAY.
Definition: kiway_player.h:48
LIB_ID fpid
Footprint loader thread to prevent footprint loading from locking the UI.
void RunOnChildren(std::function< void(BOARD_ITEM *)> aFunction)
Function RunOnChildren.
bool QueueEvent(wxEvent const &aEvent)
Post an event to the panel, if the panel still exists.
TEXTE_MODULE & Reference()
Definition: class_module.h:463
FOOTPRINT_STATUS status
void SetViewport(const BOX2D &aViewport)
Function SetViewport() Sets the visible area of the VIEW.
Definition: view.cpp:513
virtual const BOX2I ViewBBox() const override
Function ViewBBox() returns the bounding box of the item covering all its layers. ...
Class BOARD to handle a board.
void renderFootprint(MODULE *module)
BOX2< VECTOR2D > BOX2D
Definition: box2.h:469
virtual CACHE_ENTRY CacheAndReturn(LIB_ID const &aFPID)
std::shared_ptr< FP_THREAD_IFACE > m_iface
boost::interprocess::interprocess_mutex MUTEX
Establish KiCad MUTEX choices here in this file: typedef MUTEX and typedef MUTLOCK.
Definition: ki_mutex.h:42
virtual void * Entry() override
LIB_ID GetCurrentFootprint()
Threadsafe accessor to get the current footprint.
KIGFX::VIEW * GetView() const
Function GetView() Returns a pointer to the VIEW instance used in the panel.
void ProcessEntry(CACHE_ENTRY &aEntry)
Class LIB_ID.
Definition: lib_id.h:56
Layers have changed.
Definition: view_item.h:59
const Vec & GetSize() const
Definition: box2.h:177
void SetScale(double aScale)
Function SetScale() Sets the scaling factor.
Definition: view.h:247
Panel that renders a single footprint via Cairo GAL, meant to be exported through Kiface...
CACHE_ENTRY AddToQueue(LIB_ID const &aEntry)
Push an entry to the loading queue and a placeholder to the cache; return the placeholder.
FP_LIB_TABLE * GetTable()
Get an FP_LIB_TABLE, or null if the panel is dead.
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
FOOTPRINT_PREVIEW_PANEL * GetPanel()
Get the associated panel.
virtual wxWindow * GetWindow() override
Get the underlying wxWindow.
std::unique_ptr< BOARD > m_dummyBoard
Threadsafe interface class between loader thread and panel class.
void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:213
void Clear()
Function Clear() Removes all items from the view.
Definition: view.cpp:982
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:462
void AddToCache(CACHE_ENTRY const &aEntry)
Add an entry to the cache.
boost::optional< CACHE_ENTRY > GetFromCache(LIB_ID const &aFPID)
Retrieve a cache entry by LIB_ID.
virtual const BOX2I ViewBBox() const override
Function ViewBBox() returns the bounding box of the item covering all its layers. ...
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.
static FOOTPRINT_PREVIEW_PANEL * New(KIWAY *aKiway, wxWindow *aParent)
Class KIWAY is a minimalistic software bus for communications between various DLLs/DSOs (DSOs) within...
Definition: kiway.h:257
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:350
void SyncLayersVisibility(const BOARD *aBoard)
Function SyncLayersVisibility Updates "visibility" property of each layer of a given BOARD...
void Update(VIEW_ITEM *aItem, int aUpdateFlags)
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: view.cpp:1385
void SetCurrentFootprint(LIB_ID aFp)
Threadsafe accessor to set the current footprint.
void StartDrawing()
Function StartDrawing() Begins drawing if it was stopped previously.
void Refresh(bool aEraseBackground=true, const wxRect *aRect=NULL) override
void UseColorScheme(const COLORS_DESIGN_SETTINGS *aSettings)
Function UseColorScheme Applies layer color settings.
std::map< LIB_ID, CACHE_ENTRY > m_cachedFootprints
VTBL_ENTRY FP_LIB_TABLE * PcbFootprintLibs(KIWAY &aKiway)
Return the table of footprint libraries.
boost::interprocess::scoped_lock< MUTEX > MUTLOCK
Definition: ki_mutex.h:43
FP_LOADER_THREAD(std::shared_ptr< FP_THREAD_IFACE > const &aIface)
void SetPanel(FOOTPRINT_PREVIEW_PANEL *aPanel)
Set the associated panel, for QueueEvent() and GetTable().
virtual void CacheFootprint(LIB_ID const &aFPID) override
Preload a footprint into the cache.
Implementation of std::make_unique for pre C++14 compilation environments.
void OnLoaderThreadUpdate(wxCommandEvent &aEvent)
boost::optional< CACHE_ENTRY > PopFromQueue()
Pop an entry from the queue, or empty option if none is available.
FOOTPRINT_STATUS_HANDLER m_handler
MODULE * module
std::shared_ptr< FP_THREAD_IFACE > m_iface
std::deque< CACHE_ENTRY > m_loaderQueue
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Sets the item visibility.
Definition: view.cpp:1331
MODULE * FootprintLoadWithOptionalNickname(const LIB_ID &aFootprintId)
Function FootprintLoadWithOptionalNickname loads a footprint having aFootprintId with possibly an emp...
void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Function Add() Adds a VIEW_ITEM to the view.
Definition: view.cpp:311
virtual void DisplayFootprint(LIB_ID const &aFPID) override
Set the currently displayed footprint.
Module description (excepted pads)
FOOTPRINT_PREVIEW_PANEL(KIWAY *aKiway, wxWindow *aParent, KIGFX::GAL_DISPLAY_OPTIONS &aOpts, GAL_TYPE aGalType)
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:47
FOOTPRINT_PREVIEW_PANEL * m_panel
std::function< void(FOOTPRINT_STATUS)> FOOTPRINT_STATUS_HANDLER