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 <kiway.h>
35 #include <math/box2.h>
36 #include <pcb_painter.h>
37 #include <pcb_draw_panel_gal.h>
38 #include <pcb_edit_frame.h>
39 #include <pgm_base.h>
41 #include <view/view.h>
42 #include <wx/stattext.h>
43 
48 {
50 
51  public:
52  FP_THREAD_IFACE() : m_panel( nullptr )
53  {
54  }
55 
58  {
59  std::lock_guard<std::mutex> lock( m_lock );
60  auto it = m_cachedFootprints.find( aFPID );
61 
62  if( it != m_cachedFootprints.end() )
63  return it->second;
64  else
65  return NULLOPT;
66  }
67 
72  CACHE_ENTRY AddToQueue( const LIB_ID& aEntry )
73  {
74  std::lock_guard<std::mutex> lock( m_lock );
75 
76  CACHE_ENTRY ent = { aEntry, nullptr, FPS_LOADING };
77  m_cachedFootprints[aEntry] = ent;
78  m_loaderQueue.push_back( ent );
79 
80  return ent;
81  }
82 
85  {
86  std::lock_guard<std::mutex> lock( m_lock );
87 
88  if( m_loaderQueue.empty() )
89  {
90  return NULLOPT;
91  }
92  else
93  {
94  auto ent = m_loaderQueue.front();
95  m_loaderQueue.pop_front();
96  return ent;
97  }
98  }
99 
101  void AddToCache( const CACHE_ENTRY& aEntry )
102  {
103  std::lock_guard<std::mutex> lock( m_lock );
104  m_cachedFootprints[aEntry.fpid] = aEntry;
105  }
106 
111  {
112  std::lock_guard<std::mutex> lock( m_lock );
113  m_current_fp = std::move( aFp );
114  }
115 
120  {
121  std::lock_guard<std::mutex> lock( m_lock );
122  return m_current_fp;
123  }
124 
129  {
130  std::lock_guard<std::mutex> lock( m_lock );
131  m_panel = aPanel;
132  }
133 
138  {
139  std::lock_guard<std::mutex> lock( m_lock );
140  return m_panel;
141  }
142 
147  bool QueueEvent( const wxEvent& aEvent )
148  {
149  std::lock_guard<std::mutex> lock( m_lock );
150 
151  if( m_panel )
152  {
153  m_panel->GetEventHandler()->QueueEvent( aEvent.Clone() );
154  return true;
155  }
156  else
157  {
158  return false;
159  }
160  }
161 
166  {
167  std::lock_guard<std::mutex> lock( m_lock );
168  return m_panel ? m_panel->Prj().PcbFootprintLibs() : nullptr;
169  }
170 
171  private:
172  std::deque<CACHE_ENTRY> m_loaderQueue;
173  std::map<LIB_ID, CACHE_ENTRY> m_cachedFootprints;
176  std::mutex m_lock;
177 };
178 
179 
184 class FP_LOADER_THREAD : public wxThread
185 {
187 
188  std::shared_ptr<FP_THREAD_IFACE> m_iface;
189 
190 public:
191  FP_LOADER_THREAD( const std::shared_ptr<FP_THREAD_IFACE>& aIface )
192  : wxThread( wxTHREAD_DETACHED ), m_iface( aIface )
193  {
194  }
195 
196 
198  {
199  }
200 
201 
202  void ProcessEntry( CACHE_ENTRY& aEntry )
203  {
204  FP_LIB_TABLE* fptbl = m_iface->GetTable();
205 
206  if( !fptbl )
207  return;
208 
209  try
210  {
211  aEntry.module.reset( fptbl->FootprintLoadWithOptionalNickname( aEntry.fpid ) );
212 
213  if( !aEntry.module )
214  aEntry.status = FPS_NOT_FOUND;
215  }
216  catch( const IO_ERROR& )
217  {
218  aEntry.status = FPS_NOT_FOUND;
219  }
220 
221  if( aEntry.status != FPS_NOT_FOUND )
222  aEntry.status = FPS_READY;
223 
224  m_iface->AddToCache( aEntry );
225 
226  if( aEntry.fpid == m_iface->GetCurrentFootprint() )
227  {
228  wxCommandEvent evt( wxEVT_COMMAND_TEXT_UPDATED, 1 );
229  m_iface->QueueEvent( evt );
230  }
231  }
232 
233 
234  virtual void* Entry() override
235  {
236  while( m_iface->GetPanel() )
237  {
238  auto ent = m_iface->PopFromQueue();
239 
240  if( ent )
241  ProcessEntry( *ent );
242  else
243  wxMilliSleep( 100 );
244  }
245 
246  return nullptr;
247  }
248 };
249 
250 
252  std::unique_ptr<KIGFX::GAL_DISPLAY_OPTIONS> aOpts, GAL_TYPE aGalType )
253  : PCB_DRAW_PANEL_GAL( aParent, -1, wxPoint( 0, 0 ), wxSize( 200, 200 ), *aOpts, aGalType ),
254  KIWAY_HOLDER( aKiway, KIWAY_HOLDER::PANEL ),
255  m_displayOptions( std::move( aOpts ) ),
256  m_currentModule( nullptr ),
257  m_footprintDisplayed( true )
258 {
259  m_iface = std::make_shared<FP_THREAD_IFACE>();
260  m_iface->SetPanel( this );
262  m_loader->Run();
263 
264  SetStealsFocus( false );
265  ShowScrollbars( wxSHOW_SB_NEVER, wxSHOW_SB_NEVER );
266  EnableScrolling( false, false ); // otherwise Zoom Auto disables GAL canvas
267 
268  m_dummyBoard = std::make_unique<BOARD>();
269  UpdateColors();
271 
272  Raise();
273  Show( true );
274  StartDrawing();
275 
276  Connect( wxEVT_COMMAND_TEXT_UPDATED,
277  wxCommandEventHandler( FOOTPRINT_PREVIEW_PANEL::OnLoaderThreadUpdate ), NULL, this );
278 }
279 
280 
282 {
283  if( m_currentModule )
284  {
285  GetView()->Remove( m_currentModule.get() );
286  GetView()->Clear();
287  m_currentModule->SetParent( nullptr );
288  }
289 
290  m_iface->SetPanel( nullptr );
291 }
292 
293 
295 {
296  auto opt_ent = m_iface->GetFromCache( aFPID );
297 
298  if( opt_ent )
299  return *opt_ent;
300  else
301  return m_iface->AddToQueue( aFPID );
302 }
303 
304 
305 // This is separate to avoid having to export CACHE_ENTRY to the global namespace
307 {
308  (void) CacheAndReturn( aFPID );
309 }
310 
311 
312 void FOOTPRINT_PREVIEW_PANEL::renderFootprint( std::shared_ptr<MODULE> aModule )
313 {
314  if( m_currentModule )
315  {
316  GetView()->Remove( m_currentModule.get() );
317  GetView()->Clear();
318  m_currentModule->SetParent( nullptr );
319  }
320 
321  aModule->SetParent( m_dummyBoard.get() );
322 
323  // Ensure we are not using the high contrast mode to display the selected footprint
324  KIGFX::PAINTER* painter = GetView()->GetPainter();
325  auto settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( painter->GetSettings() );
326  settings->SetContrastModeDisplay( HIGH_CONTRAST_MODE::NORMAL );
327 
328  GetView()->Add( aModule.get() );
329  GetView()->SetVisible( aModule.get(), true );
330  GetView()->Update( aModule.get(), KIGFX::ALL );
331 
332  // Save a reference to the module's shared pointer to say we are using it in the
333  // preview panel
334  m_currentModule = aModule;
335 
336  BOX2I bbox = aModule->ViewBBox();
337  bbox.Merge( aModule->Value().ViewBBox() );
338  bbox.Merge( aModule->Reference().ViewBBox() );
339 
340  if( bbox.GetSize().x > 0 && bbox.GetSize().y > 0 )
341  {
342  // Autozoom
343  GetView()->SetViewport( BOX2D( bbox.GetOrigin(), bbox.GetSize() ) );
344 
345  // Add a margin
346  GetView()->SetScale( GetView()->GetScale() * 0.7 );
347 
348  Refresh();
349  }
350 }
351 
352 
354 {
355  m_currentFPID = aFPID;
356  m_iface->SetCurrentFootprint( aFPID );
357  m_footprintDisplayed = false;
358 
360 
361  if( m_handler )
362  m_handler( fpe.status );
363 
364  if( fpe.status == FPS_READY )
365  {
366  if( !m_footprintDisplayed )
367  {
368  renderFootprint( fpe.module );
369  m_footprintDisplayed = true;
370  Refresh();
371  }
372  }
373 }
374 
375 
376 void FOOTPRINT_PREVIEW_PANEL::OnLoaderThreadUpdate( wxCommandEvent& aEvent )
377 {
379 }
380 
381 
383 {
384  m_handler = aHandler;
385 }
386 
387 
389 {
390  return static_cast<wxWindow*>( this );
391 }
392 
393 
395 {
396  PCBNEW_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<PCBNEW_SETTINGS>();
397 
398  if( cfg->m_Window.grid.sizes.empty() )
399  {
400  cfg->m_Window.grid.sizes = { "1000 mil",
401  "500 mil",
402  "250 mil",
403  "200 mil",
404  "100 mil",
405  "50 mil",
406  "25 mil",
407  "20 mil",
408  "10 mil",
409  "5 mil",
410  "2 mil",
411  "1 mil",
412  "5.0 mm",
413  "2.5 mm",
414  "1.0 mm",
415  "0.5 mm",
416  "0.25 mm",
417  "0.2 mm",
418  "0.1 mm",
419  "0.05 mm",
420  "0.025 mm",
421  "0.01 mm" };
422  }
423 
424  if( cfg->m_Window.zoom_factors.empty() )
425  {
426  cfg->m_Window.zoom_factors = { 0.035,
427  0.05,
428  0.08,
429  0.13,
430  0.22,
431  0.35,
432  0.6,
433  1.0,
434  1.5,
435  2.2,
436  3.5,
437  5.0,
438  8.0,
439  13.0,
440  20.0,
441  35.0,
442  50.0,
443  80.0,
444  130.0,
445  220.0,
446  300.0 };
447  }
448 
449  for( double& factor : cfg->m_Window.zoom_factors )
450  factor = std::min( factor, MAX_ZOOM_FACTOR );
451 
452  std::unique_ptr<KIGFX::GAL_DISPLAY_OPTIONS> gal_opts;
453 
454  gal_opts = std::make_unique<KIGFX::GAL_DISPLAY_OPTIONS>();
455  gal_opts->ReadConfig( *Pgm().GetCommonSettings(), cfg->m_Window, aParent );
456 
457  auto canvasType = static_cast<EDA_DRAW_PANEL_GAL::GAL_TYPE>( cfg->m_Graphics.canvas_type );
458  auto panel = new FOOTPRINT_PREVIEW_PANEL( aKiway, aParent, std::move( gal_opts ), canvasType );
459 
460  panel->UpdateColors();
461 
462  const GRID_SETTINGS& gridCfg = cfg->m_Window.grid;
463 
464  panel->GetGAL()->SetGridVisibility( gridCfg.show );
465 
466  //Bounds checking cannot include number of elements as an index!
467  int gridIdx = std::max( 0, std::min( gridCfg.last_size_idx, (int) gridCfg.sizes.size() - 1 ) );
468  int gridSize = (int) ValueFromString( EDA_UNITS::INCHES, gridCfg.sizes[ gridIdx ], true );
469  panel->GetGAL()->SetGridSize( VECTOR2D( gridSize, gridSize ) );
470 
471  return panel;
472 }
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.
FOOTPRINT_STATUS status
void SetViewport(const BOX2D &aViewport)
Function SetViewport() Sets the visible area of the VIEW.
Definition: view.cpp:554
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:104
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:92
bool QueueEvent(const wxEvent &aEvent)
Post an event to the panel, if the panel still exists.
BOX2< VECTOR2D > BOX2D
Definition: box2.h:523
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:63
virtual void DisplayFootprint(const LIB_ID &aFPID) override
Set the currently displayed footprint.
std::vector< double > zoom_factors
Definition: app_settings.h:79
virtual void Remove(VIEW_ITEM *aItem) override
Function Remove() Removes a VIEW_ITEM from the view.
Definition: pcb_view.cpp:75
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:58
virtual wxWindow * GetWindow() override
Get the underlying wxWindow.
std::vector< wxString > sizes
Definition: app_settings.h:52
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
Threadsafe interface class between loader thread and panel class.
void Clear()
Function Clear() Removes all items from the view.
Definition: view.cpp:1115
GRID_SETTINGS grid
Definition: app_settings.h:82
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.
#define MAX_ZOOM_FACTOR
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:386
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:291
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Function SetScale() Sets the scaling factor, zooming around a given anchor point.
Definition: view.cpp:582
virtual RENDER_SETTINGS * GetSettings()=0
Function GetAdapter Returns pointer to current settings that are going to be used when drawing items.
WINDOW_SETTINGS m_Window
Definition: app_settings.h:154
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)
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.
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:1490
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:189
const Vec & GetOrigin() const
Definition: box2.h:193
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.
long long int ValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, bool aUseMils, EDA_DATA_TYPE aType)
Function ValueFromString converts aTextValue in aUnits to internal units used by the application.
Definition: base_units.cpp:471
std::function< void(FOOTPRINT_STATUS)> FOOTPRINT_STATUS_HANDLER
Common grid settings, available to every frame.
Definition: app_settings.h:49