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 <class_board.h>
27 #include <class_module.h>
28 #include <colors_design_settings.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>
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  m_colorsSettings = std::make_unique<COLORS_DESIGN_SETTINGS>( FRAME_FOOTPRINT_PREVIEW );
270  m_colorsSettings->Load( Kiface().KifaceSettings() );
271 
274 
275  Raise();
276  Show( true );
277  StartDrawing();
278 
279  Connect( wxEVT_COMMAND_TEXT_UPDATED,
280  wxCommandEventHandler( FOOTPRINT_PREVIEW_PANEL::OnLoaderThreadUpdate ), NULL, this );
281 }
282 
283 
285 {
286  if( m_currentModule )
287  {
288  GetView()->Remove( m_currentModule.get() );
289  GetView()->Clear();
290  m_currentModule->SetParent( nullptr );
291  }
292 
293  m_iface->SetPanel( nullptr );
294 }
295 
296 
298 {
299  auto opt_ent = m_iface->GetFromCache( aFPID );
300 
301  if( opt_ent )
302  return *opt_ent;
303  else
304  return m_iface->AddToQueue( aFPID );
305 }
306 
307 
308 // This is separate to avoid having to export CACHE_ENTRY to the global namespace
310 {
311  (void) CacheAndReturn( aFPID );
312 }
313 
314 
315 void FOOTPRINT_PREVIEW_PANEL::renderFootprint( std::shared_ptr<MODULE> aModule )
316 {
317  if( m_currentModule )
318  {
319  GetView()->Remove( m_currentModule.get() );
320  GetView()->Clear();
321  m_currentModule->SetParent( nullptr );
322  }
323 
324  aModule->SetParent( m_dummyBoard.get() );
325 
326  GetView()->Add( aModule.get() );
327  GetView()->SetVisible( aModule.get(), true );
328  GetView()->Update( aModule.get(), KIGFX::ALL );
329 
330  // Save a reference to the module's shared pointer to say we are using it in the
331  // preview panel
332  m_currentModule = aModule;
333 
334  BOX2I bbox = aModule->ViewBBox();
335  bbox.Merge( aModule->Value().ViewBBox() );
336  bbox.Merge( aModule->Reference().ViewBBox() );
337 
338  if( bbox.GetSize().x > 0 && bbox.GetSize().y > 0 )
339  {
340  // Autozoom
341  GetView()->SetViewport( BOX2D( bbox.GetOrigin(), bbox.GetSize() ) );
342 
343  // Add a margin
344  GetView()->SetScale( GetView()->GetScale() * 0.7 );
345 
346  Refresh();
347  }
348 }
349 
350 
352 {
353  m_currentFPID = aFPID;
354  m_iface->SetCurrentFootprint( aFPID );
355  m_footprintDisplayed = false;
356 
358 
359  if( m_handler )
360  m_handler( fpe.status );
361 
362  if( fpe.status == FPS_READY )
363  {
364  if( !m_footprintDisplayed )
365  {
366  renderFootprint( fpe.module );
367  m_footprintDisplayed = true;
368  Refresh();
369  }
370  }
371 }
372 
373 
374 void FOOTPRINT_PREVIEW_PANEL::OnLoaderThreadUpdate( wxCommandEvent& aEvent )
375 {
377 }
378 
379 
381 {
382  m_handler = aHandler;
383 }
384 
385 
387 {
388  return static_cast<wxWindow*>( this );
389 }
390 
391 
393 {
394  PCB_EDIT_FRAME* pcbnew =
395  static_cast<PCB_EDIT_FRAME*>( aKiway->Player( FRAME_PCB_EDITOR, false ) );
396  wxConfigBase* cfg = Kiface().KifaceSettings();
397  wxConfigBase* commonCfg = Pgm().CommonSettings();
398  bool btemp;
399  int itemp;
400  wxString msg;
401  COLOR4D ctemp;
402 
403  // Fetch grid & display settings from PCBNew if it's running; otherwise fetch them
404  // from PCBNew's config settings.
405  // We need a copy with a lifetime that matches the panel
406  std::unique_ptr<KIGFX::GAL_DISPLAY_OPTIONS> gal_opts;
407 
408  if( pcbnew )
409  {
410  // Copy the existing Pcbnew options
411  // REVIEW: This also copies the current subscription list of the options
412  // to the new options. This is probably not what is intended, but because
413  // this widget doesn't change the options it should be OK.
414  gal_opts = std::make_unique<KIGFX::GAL_DISPLAY_OPTIONS>( pcbnew->GetGalDisplayOptions() );
415  }
416  else
417  {
418  // Make and populate a new one from config
419  gal_opts = std::make_unique<KIGFX::GAL_DISPLAY_OPTIONS>();
420 
421  gal_opts->ReadConfig( *commonCfg, *cfg, wxString( PCB_EDIT_FRAME_NAME ), aParent );
422  }
423 
424 #ifdef __WXMAC__
425  // Cairo renderer doesn't handle Retina displays so default to OpenGL
428 #else
431 #endif
432 
433  auto panel = new FOOTPRINT_PREVIEW_PANEL( aKiway, aParent, std::move( gal_opts ), canvasType );
434 
435  if( pcbnew )
436  {
437  panel->GetGAL()->SetGridVisibility( pcbnew->IsGridVisible() );
438  panel->GetGAL()->SetGridSize( VECTOR2D( pcbnew->GetScreen()->GetGridSize() ) );
439 
440  // Grid color (among other things):
441  KIGFX::PAINTER* pcbnew_painter = pcbnew->GetCanvas()->GetView()->GetPainter();
442  panel->GetView()->GetPainter()->ApplySettings( pcbnew_painter->GetSettings() );
443  }
444  else
445  {
446  btemp = cfg->ReadBool( wxString( PCB_EDIT_FRAME_NAME ) + ShowGridEntryKeyword, true );
447  panel->GetGAL()->SetGridVisibility( btemp );
448 
449  // Read grid size:
450  std::unique_ptr<PCB_SCREEN> temp_screen = std::make_unique<PCB_SCREEN>( wxSize() );
451  cfg->Read( wxString( PCB_EDIT_FRAME_NAME ) + LastGridSizeIdKeyword, &itemp, 0L );
452  temp_screen->SetGrid( itemp + ID_POPUP_GRID_LEVEL_1000 );
453  panel->GetGAL()->SetGridSize( VECTOR2D( temp_screen->GetGridSize() ) );
454 
455  // Read grid color:
456  msg = cfg->Read( wxString( PCB_EDIT_FRAME_NAME ) + GridColorEntryKeyword, wxT( "NONE" ) );
457  ctemp.SetFromWxString( msg );
458  panel->GetGAL()->SetGridColor( ctemp );
459  }
460 
461  return panel;
462 }
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:98
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()
#define LastGridSizeIdKeyword
Most recently used grid size (suffix)
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
Handle colors used to draw all items or layers.
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.
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:103
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:55
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
#define CanvasTypeKeyBase
The key to store the canvas type in config.
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:313
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.
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
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:274
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 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.
Definition: project.cpp:400
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)
#define ShowGridEntryKeyword
Nonzero to show grid (suffix)
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
#define PCB_EDIT_FRAME_NAME
const Vec & GetSize() const
Definition: box2.h:188
Module description (excepted pads)
const Vec & GetOrigin() const
Definition: box2.h:192
#define GridColorEntryKeyword
Grid color ID (suffix)
std::unique_ptr< COLORS_DESIGN_SETTINGS > m_colorsSettings
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
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39