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 
97  m_cachedFootprints[aEntry.fpid] = aEntry;
98  }
99 
104  {
105  MUTLOCK lock( m_lock );
106  m_current_fp = aFp;
107  }
108 
113  {
114  MUTLOCK lock( m_lock );
115  return m_current_fp;
116  }
117 
118  private:
119  std::deque<CACHE_ENTRY> m_loaderQueue;
120  std::map<LIB_ID, CACHE_ENTRY> m_cachedFootprints;
123 };
124 
125 
130 class FP_LOADER_THREAD: public wxThread
131 {
133 
135  std::shared_ptr<FP_THREAD_IFACE> m_iface;
136 
137 public:
139  std::shared_ptr<FP_THREAD_IFACE> const& aIface ):
140  wxThread( wxTHREAD_DETACHED ),
141  m_parent( aParent ),
142  m_iface( aIface )
143  {}
144 
145 
147  {}
148 
149 
150  void ProcessEntry( CACHE_ENTRY& aEntry )
151  {
152  FP_LIB_TABLE* fptbl = m_parent->Prj().PcbFootprintLibs();
153 
154  if( !fptbl )
155  return;
156 
157  aEntry.module = NULL;
158 
159  try {
160  aEntry.module = fptbl->FootprintLoadWithOptionalNickname( aEntry.fpid );
161 
162  if( !aEntry.module )
163  aEntry.status = FPS_NOT_FOUND;
164 
165  } catch( const IO_ERROR& ioe )
166  {
167  aEntry.status = FPS_NOT_FOUND;
168  }
169 
170 
171  if( aEntry.status != FPS_NOT_FOUND )
172  aEntry.status = FPS_READY;
173 
174  m_iface->AddToCache( aEntry );
175 
176  if( aEntry.fpid == m_iface->GetCurrentFootprint() )
177  {
178  auto handler = m_parent->GetEventHandler();
179 
180  if( handler )
181  handler->QueueEvent( new wxCommandEvent( wxEVT_COMMAND_TEXT_UPDATED, 1 ) );
182  }
183  }
184 
185 
186  virtual void* Entry() override
187  {
188  while( !TestDestroy() )
189  {
190  auto ent = m_iface->PopFromQueue();
191 
192  if( ent )
193  ProcessEntry( *ent );
194  else
195  wxMilliSleep( 100 );
196  }
197 
198  return NULL;
199  }
200 };
201 
202 
204  KIWAY* aKiway, wxWindow* aParent, KIGFX::GAL_DISPLAY_OPTIONS& aOpts, GAL_TYPE aGalType )
205  : PCB_DRAW_PANEL_GAL ( aParent, -1, wxPoint( 0, 0 ), wxSize(200, 200), aOpts, aGalType ),
206  KIWAY_HOLDER( aKiway ),
207  m_footprintDisplayed( true )
208 {
209 
210  m_iface = std::make_shared<FP_THREAD_IFACE>();
211  m_loader = new FP_LOADER_THREAD( this, m_iface );
212  m_loader->Run();
213 
214  SetStealsFocus( false );
215  ShowScrollbars( wxSHOW_SB_NEVER, wxSHOW_SB_NEVER );
216  EnableScrolling( false, false ); // otherwise Zoom Auto disables GAL canvas
217 
218  m_dummyBoard = std::make_unique<BOARD>();
219 
220  UseColorScheme( m_dummyBoard->GetColorsSettings() );
222 
223  Raise();
224  Show(true);
225  StartDrawing();
226 
227  Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( FOOTPRINT_PREVIEW_PANEL::OnLoaderThreadUpdate ), NULL, this );
228 }
229 
230 
232 {
233  m_loader->Delete();
234 }
235 
236 
238 {
239  auto opt_ent = m_iface->GetFromCache( aFPID );
240 
241  if( opt_ent )
242  return *opt_ent;
243  else
244  return m_iface->AddToQueue( aFPID );
245 }
246 
247 
248 // This is separate to avoid having to export CACHE_ENTRY to the global namespace
250 {
251  (void) CacheAndReturn( aFPID );
252 }
253 
254 
256 {
257  GetView()->Clear();
258  module->SetParent ( &*m_dummyBoard );
259  module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, GetView(), _1, -1 ) );
260 
261  GetView()->Add ( module );
262 
263  GetView()->SetVisible( module, true );
264  GetView()->Update( module, KIGFX::ALL );
265 
266  BOX2I bbox = module->ViewBBox();
267  bbox.Merge ( module->Value().ViewBBox() );
268  bbox.Merge ( module->Reference().ViewBBox() );
269 
270  if( bbox.GetSize().x > 0 && bbox.GetSize().y > 0 )
271  {
272  // Autozoom
273  GetView()->SetViewport( BOX2D( bbox.GetOrigin(), bbox.GetSize() ) );
274 
275  // Add a margin
276  GetView()->SetScale( GetView()->GetScale() * 0.7 );
277 
278  Refresh();
279  }
280 }
281 
282 
284 {
285  m_currentFPID = aFPID;
286  m_iface->SetCurrentFootprint( aFPID );
287  m_footprintDisplayed = false;
288 
290 
291  if( m_handler )
292  m_handler( fpe.status );
293 
294  if( fpe.status == FPS_READY )
295  {
296  if ( !m_footprintDisplayed )
297  {
298  renderFootprint( fpe.module );
299  m_footprintDisplayed = true;
300  Refresh();
301  }
302  }
303 }
304 
305 
307 {
309 }
310 
311 
313 {
314  m_handler = aHandler;
315 }
316 
317 
319 {
320  return static_cast<wxWindow*>( this );
321 }
322 
323 
325 {
327 
328  return new FOOTPRINT_PREVIEW_PANEL(
329  aKiway, aParent, gal_opts, EDA_DRAW_PANEL_GAL::GAL_TYPE_CAIRO );
330 }
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.
TEXTE_MODULE & Reference()
Definition: class_module.h:455
FOOTPRINT_STATUS status
void SetViewport(const BOX2D &aViewport)
Function SetViewport() Sets the visible area of the VIEW.
Definition: view.cpp:512
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.
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
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:981
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:454
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:1378
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
FOOTPRINT_PREVIEW_PANEL * m_parent
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:1330
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:310
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
FP_LOADER_THREAD(FOOTPRINT_PREVIEW_PANEL *aParent, std::shared_ptr< FP_THREAD_IFACE > const &aIface)
std::function< void(FOOTPRINT_STATUS)> FOOTPRINT_STATUS_HANDLER