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& ioe )
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:456
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
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:455
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
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)
Function Update() For dynamic VIEWs, informs the associated VIEW that the graphical representation of...
Definition: view.cpp:1379
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)
Function SetVisible() 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