Refactor FOOTPRINT_PREVIEW_PANEL

- Pull out compound widget bits into FOOTPRINT_PREVIEW_WIDGET
- Move all pcbnew-specific bits *inside* pcbnew; implementation should
  be private for users
- Make a few class members and inner types private
This commit is contained in:
Chris Pavlina 2017-03-10 14:11:41 -05:00
parent de30dc9f5d
commit bbaa29fbc4
11 changed files with 541 additions and 405 deletions

View File

@ -169,7 +169,7 @@ set( COMMON_WIDGET_SRCS
widgets/mathplot.cpp
widgets/widget_hotkey_list.cpp
widgets/two_column_tree_list.cpp
widgets/footprint_preview_panel.cpp
widgets/footprint_preview_widget.cpp
widgets/indicator_icon.cpp
)

View File

@ -1,66 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <widgets/footprint_preview_panel.h>
#include <wx/stattext.h>
#include <kiway.h>
FOOTPRINT_PREVIEW_PANEL* FOOTPRINT_PREVIEW_PANEL::InstallOnPanel(
KIWAY& aKiway, wxPanel* aPanel, bool aStatus )
{
FOOTPRINT_PREVIEW_PANEL* fpp = NULL;
try {
KIFACE* kiface = aKiway.KiFACE( KIWAY::FACE_PCB );
if( !kiface )
return NULL;
fpp = static_cast<FOOTPRINT_PREVIEW_PANEL*>(
kiface->CreateWindow( aPanel, FRAME_PCB_FOOTPRINT_PREVIEW, &aKiway ) );
} catch( ... )
{
return NULL;
}
aPanel->SetBackgroundColour( *wxBLACK );
aPanel->SetForegroundColour( *wxWHITE );
auto sizer = new wxBoxSizer( wxVERTICAL );
sizer->Add( fpp, 1, wxALL | wxEXPAND, 0 );
if( aStatus )
{
auto label = new wxStaticText( aPanel, -1, wxEmptyString );
auto sizer2 = new wxBoxSizer( wxVERTICAL );
sizer2->Add( 0, 0, 1 );
sizer2->Add( label, 0, wxALL | wxALIGN_CENTER, 0 );
sizer2->Add( 0, 0, 1 );
sizer->Add( sizer2, 1, wxALL | wxALIGN_CENTER, 0 );
sizer2->ShowItems( false );
fpp->LinkErrorLabel( label );
fpp->SetHideSizer( sizer2 );
}
aPanel->SetSizer( sizer );
return fpp;
}

View File

@ -0,0 +1,129 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <widgets/footprint_preview_widget.h>
#include <wx/stattext.h>
#include <wx/sizer.h>
#include <kiway.h>
FOOTPRINT_PREVIEW_WIDGET::FOOTPRINT_PREVIEW_WIDGET( wxWindow* aParent, KIWAY& aKiway ):
wxPanel( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxFULL_REPAINT_ON_RESIZE | wxSUNKEN_BORDER | wxTAB_TRAVERSAL ),
m_prev_panel( nullptr ),
m_status_label( nullptr ),
m_sizer( nullptr )
{
m_prev_panel = FOOTPRINT_PREVIEW_PANEL_BASE::Create( this, aKiway );
if( !m_prev_panel )
return;
SetBackgroundColour( *wxBLACK );
SetForegroundColour( *wxWHITE );
m_status_label = new wxStaticText( this, -1, wxEmptyString );
m_sizer = new wxBoxSizer( wxVERTICAL );
m_sizer->Add( 0, 0, 1 );
m_sizer->Add( m_status_label, 0, wxALL | wxALIGN_CENTER, 0 );
m_sizer->Add( 0, 0, 1 );
auto outer_sizer = new wxBoxSizer( wxVERTICAL );
outer_sizer->Add( m_prev_panel->GetWindow(), 1, wxALL | wxEXPAND, 0 );
outer_sizer->Add( m_sizer, 1, wxALL | wxALIGN_CENTER, 0 );
m_sizer->ShowItems( false );
m_prev_panel->SetStatusHandler( [this]( FOOTPRINT_STATUS s ){ this->OnStatusChange( s ); } );
SetSizer( outer_sizer );
}
void FOOTPRINT_PREVIEW_WIDGET::SetStatusText( wxString const& aText )
{
m_status_label->SetLabel( aText );
m_sizer->ShowItems( true );
m_prev_panel->GetWindow()->Hide();
Layout();
}
void FOOTPRINT_PREVIEW_WIDGET::ClearStatus()
{
m_status_label->SetLabel( wxEmptyString );
m_prev_panel->GetWindow()->Show();
m_sizer->ShowItems( false );
Layout();
}
void FOOTPRINT_PREVIEW_WIDGET::CacheFootprint( const LIB_ID& aFPID )
{
if( m_prev_panel )
(void) m_prev_panel->CacheFootprint( aFPID );
}
void FOOTPRINT_PREVIEW_WIDGET::DisplayFootprint( const LIB_ID& aFPID )
{
if( m_prev_panel )
(void) m_prev_panel->DisplayFootprint( aFPID );
}
void FOOTPRINT_PREVIEW_WIDGET::OnStatusChange( FOOTPRINT_STATUS aStatus )
{
switch( aStatus )
{
case FPS_NOT_FOUND:
SetStatusText( _( "Footprint not found" ) );
break;
case FPS_LOADING:
SetStatusText( _( "Loading..." ) );
break;
case FPS_READY:
ClearStatus();
}
Refresh();
}
FOOTPRINT_PREVIEW_PANEL_BASE* FOOTPRINT_PREVIEW_PANEL_BASE::Create(
wxWindow* aParent, KIWAY& aKiway )
{
FOOTPRINT_PREVIEW_PANEL_BASE* panel = nullptr;
try {
KIFACE* kiface = aKiway.KiFACE( KIWAY::FACE_PCB );
auto window = kiface->CreateWindow( aParent, FRAME_PCB_FOOTPRINT_PREVIEW, &aKiway );
panel = dynamic_cast<FOOTPRINT_PREVIEW_PANEL_BASE*>( window );
if( window && !panel )
delete window;
} catch( ... )
{}
return panel;
}

View File

@ -45,7 +45,7 @@
#include <class_library.h>
#include <sch_base_frame.h>
#include <widgets/footprint_preview_panel.h>
#include <widgets/footprint_preview_widget.h>
#include <widgets/two_column_tree_list.h>
#include <template_fieldnames.h>
#include <generate_alias_info.h>
@ -61,7 +61,6 @@ DIALOG_CHOOSE_COMPONENT::DIALOG_CHOOSE_COMPONENT(
CMP_TREE_MODEL_ADAPTER::PTR& aAdapter, int aDeMorganConvert ):
DIALOG_SHIM( aParent, wxID_ANY, aTitle, wxDefaultPosition,
wxSize( 800, 650 ), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
m_fp_viewer( nullptr ),
m_parent( aParent ),
m_adapter( aAdapter ),
m_deMorganConvert( aDeMorganConvert >= 0 ? aDeMorganConvert : 0 ),
@ -158,11 +157,7 @@ wxPanel* DIALOG_CHOOSE_COMPONENT::ConstructRightPanel( wxWindow* aParent )
m_fp_sel_ctrl = new wxChoice( panel, wxID_ANY );
m_fp_sel_ctrl->SetSelection( 0 );
m_fp_view_ctrl = new wxPanel( panel, wxID_ANY,
wxDefaultPosition, wxSize( -1,-1 ),
wxFULL_REPAINT_ON_RESIZE | wxSUNKEN_BORDER | wxTAB_TRAVERSAL );
m_fp_viewer = FOOTPRINT_PREVIEW_PANEL::InstallOnPanel( Kiway(), m_fp_view_ctrl, true );
m_fp_view_ctrl = new FOOTPRINT_PREVIEW_WIDGET( panel, Kiway() );
sizer->Add( m_sch_view_ctrl, 1, wxEXPAND | wxALL, 5 );
sizer->Add( m_fp_sel_ctrl, 0, wxEXPAND | wxALL, 5 );
@ -188,10 +183,10 @@ void DIALOG_CHOOSE_COMPONENT::OnInitDialog( wxInitDialogEvent& aEvent )
m_query_ctrl->SetFocus();
m_query_ctrl->SetValue( wxEmptyString );
if( m_fp_viewer )
if( m_fp_view_ctrl->IsInitialized() )
{
// This hides the GAL panel and shows the status label
m_fp_viewer->SetStatusText( wxEmptyString );
m_fp_view_ctrl->SetStatusText( wxEmptyString );
}
}
@ -280,8 +275,8 @@ void DIALOG_CHOOSE_COMPONENT::OnTreeSelect( wxDataViewEvent& aEvent )
{
m_details_ctrl->SetPage( wxEmptyString );
if( m_fp_viewer )
m_fp_viewer->SetStatusText( wxEmptyString );
if( m_fp_view_ctrl->IsInitialized() )
m_fp_view_ctrl->SetStatusText( wxEmptyString );
}
}
@ -322,7 +317,7 @@ void DIALOG_CHOOSE_COMPONENT::OnSchViewDClick( wxMouseEvent& aEvent )
void DIALOG_CHOOSE_COMPONENT::ShowFootprintFor( LIB_ALIAS* aAlias )
{
if( !m_fp_viewer )
if( !m_fp_view_ctrl->IsInitialized() )
return;
LIB_FIELDS fields;
@ -335,13 +330,13 @@ void DIALOG_CHOOSE_COMPONENT::ShowFootprintFor( LIB_ALIAS* aAlias )
wxString fpname = field.GetFullText();
if( fpname == wxEmptyString )
{
m_fp_viewer->SetStatusText( _( "No footprint specified" ) );
m_fp_view_ctrl->SetStatusText( _( "No footprint specified" ) );
}
else
{
m_fp_viewer->ClearStatus();
m_fp_viewer->CacheFootprint( LIB_ID( fpname ) );
m_fp_viewer->DisplayFootprint( LIB_ID( fpname ) );
m_fp_view_ctrl->ClearStatus();
m_fp_view_ctrl->CacheFootprint( LIB_ID( fpname ) );
m_fp_view_ctrl->DisplayFootprint( LIB_ID( fpname ) );
}
break;
}

View File

@ -39,7 +39,7 @@ class wxChoice;
class wxButton;
class wxTimer;
class FOOTPRINT_PREVIEW_PANEL;
class FOOTPRINT_PREVIEW_WIDGET;
class LIB_ALIAS;
class LIB_PART;
class SCH_BASE_FRAME;
@ -169,9 +169,8 @@ protected:
wxHtmlWindow* m_details_ctrl;
wxPanel* m_sch_view_ctrl;
wxChoice* m_fp_sel_ctrl;
wxPanel* m_fp_view_ctrl;
FOOTPRINT_PREVIEW_PANEL* m_fp_viewer;
FOOTPRINT_PREVIEW_WIDGET* m_fp_view_ctrl;
SCH_BASE_FRAME* m_parent;
CMP_TREE_MODEL_ADAPTER::PTR m_adapter;

View File

@ -1,168 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016-2017 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
* Copyright (C) 2016 Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FOOTPRINT_PREVIEW_PANEL_H
#define __FOOTPRINT_PREVIEW_PANEL_H
#include <wx/wx.h>
#include <map>
#include <deque>
#include <pcb_draw_panel_gal.h>
#include <gal/gal_display_options.h>
#include <lib_id.h>
#include <kiway_player.h>
#include <boost/optional.hpp>
class MODULE;
class KIWAY;
class IO_MGR;
class BOARD;
class wxStaticText;
class FP_LOADER_THREAD;
enum FOOTPRINT_STATUS {
FPS_NOT_FOUND = 0,
FPS_READY = 1,
FPS_LOADING = 2
};
class FOOTPRINT_PREVIEW_PANEL : public PCB_DRAW_PANEL_GAL, public KIWAY_HOLDER
{
friend class FP_LOADER_THREAD;
public:
struct CACHE_ENTRY {
LIB_ID fpid;
MODULE *module;
FOOTPRINT_STATUS status;
};
virtual ~FOOTPRINT_PREVIEW_PANEL( );
virtual CACHE_ENTRY CacheFootprint ( const LIB_ID& aFPID );
virtual void DisplayFootprint ( const LIB_ID& aFPID );
/**
* Link to a label for displaying error and status messages. Can be NULL to
* unlink. This does not take ownership of the wx object.
*
* TODO if we ever require wx >= 3.1: use wxActivityIndicator for "Loading"
* status
*/
virtual void LinkErrorLabel( wxStaticText* aLabel );
/**
* Set a sizer to be automatically hidden when the status text is cleared.
* This is useful to have a status message take the place of the footprint display
* instead of displaying next to it.
*/
virtual void SetHideSizer( wxSizer* aSizer );
/**
* Set the contents of the status label, and display it if autohide is enabled.
*/
virtual void SetStatusText( wxString const & aText );
/**
* Clear the contents of the status label, and hide it if autohide is enabled.
*/
virtual void ClearStatus();
#ifdef PCBNEW
static FOOTPRINT_PREVIEW_PANEL* New( KIWAY* aKiway, wxWindow* aParent );
#endif
/**
* Get a preview panel via Kiway and add it to a blank wxPanel. May return
* NULL in the event of a kiway error.
*
* @param aKiway - an active Kiway instance
* @param aPanel - a blank panel to receive the previewer
* @param aStatus - if true, also add indicator elements to display status and errors.
*/
static FOOTPRINT_PREVIEW_PANEL* InstallOnPanel( KIWAY& aKiway, wxPanel* aPanel, bool aStatus );
protected:
class IFACE
{
public:
/**
* Threadsafe accessor to retrieve an entry from the cache.
*/
boost::optional<CACHE_ENTRY> GetFromCache( LIB_ID const & aFPID );
/**
* Threadsafe accessor to push an entry to the queue to be loaded.
* Also adds a placeholder to the cache and returns it.
*/
CACHE_ENTRY AddToQueue( LIB_ID const & aEntry );
/**
* Threadsafe accessor to pop from the loader queue. Returns a
* cache entry or an empty option if there is none.
*/
boost::optional<CACHE_ENTRY> PopFromQueue();
/**
* Threadsafe accessor to add an entry to the cache. Puts it into
* both the footprint cache and the loader queue.
*/
void AddToCache( CACHE_ENTRY const & aEntry );
private:
/* DO NOT access directly unless you are an accessor function.
* USE THE ACCESSOR FUNCTIONS.
*/
std::deque<CACHE_ENTRY> m_loaderQueue;
std::map<LIB_ID, CACHE_ENTRY> m_cachedFootprints;
wxMutex m_loaderLock;
};
FOOTPRINT_PREVIEW_PANEL(
KIWAY* aKiway, wxWindow* aParent,
KIGFX::GAL_DISPLAY_OPTIONS& aOpts, GAL_TYPE aGalType );
private:
void OnPaint( wxPaintEvent& event );
void OnLoaderThreadUpdate( wxCommandEvent& aEvent );
void renderFootprint( MODULE *module );
FP_LOADER_THREAD* m_loader;
std::shared_ptr<IFACE> m_iface;
std::unique_ptr<BOARD> m_dummyBoard;
LIB_ID m_currentFPID;
bool m_footprintDisplayed;
wxStaticText* m_label;
wxSizer* m_hidesizer;
};
#endif

View File

@ -0,0 +1,139 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FOOTPRINT_PREVIEW_WIDGET_H
#define __FOOTPRINT_PREVIEW_WIDGET_H
#include <wx/panel.h>
#include <functional>
#include <import_export.h>
class FOOTPRINT_LOAD_EVENT;
class FOOTPRINT_PREVIEW_PANEL_BASE;
class LIB_ID;
class KIWAY;
class wxStaticText;
class wxSizer;
enum FOOTPRINT_STATUS {
FPS_NOT_FOUND = 0,
FPS_READY = 1,
FPS_LOADING = 2
};
class FOOTPRINT_PREVIEW_WIDGET: public wxPanel
{
public:
/**
* Construct a footprint preview widget.
*
* @param aParent - parent window
* @param aKiway - an active Kiway instance
*/
FOOTPRINT_PREVIEW_WIDGET( wxWindow* aParent, KIWAY& aKiway );
/**
* Return whether the widget initialized properly. This could return false
* if Kiway is not available. If this returns false, no other methods should
* be called.
*/
bool IsInitialized() const { return !! m_prev_panel; }
/**
* Set the contents of the status label and display it.
*/
void SetStatusText( wxString const& aText );
/**
* Clear the contents of the status label and hide it.
*/
void ClearStatus();
/**
* Preload a footprint into the cache. This must be called prior to
* DisplayFootprint, and may be called early.
*/
void CacheFootprint( const LIB_ID& aFPID );
/**
* Set the currently displayed footprint. Any footprint passed in here
* must have been passed to CacheFootprint before.
*/
void DisplayFootprint( const LIB_ID& aFPID );
private:
/**
* Callback from the FOOTPRINT_PREVIEW_PANEL
*/
void OnStatusChange( FOOTPRINT_STATUS aStatus );
FOOTPRINT_PREVIEW_PANEL_BASE* m_prev_panel;
wxStaticText* m_status_label;
wxSizer* m_sizer;
};
typedef std::function<void( FOOTPRINT_STATUS )> FOOTPRINT_STATUS_HANDLER;
/**
* Base class for the actual viewer panel. The implementation is in
* pcbnew/footprint_preview_panel.cpp, accessed via kiface.
*/
class APIEXPORT FOOTPRINT_PREVIEW_PANEL_BASE
{
public:
virtual ~FOOTPRINT_PREVIEW_PANEL_BASE() {}
/**
* Preload a footprint into the cache. This must be called prior to
* DisplayFootprint, and may be called early.
*/
virtual void CacheFootprint( LIB_ID const& aFPID ) = 0;
/**
* Set the currently displayed footprint. Any footprint passed in here
* must have been passed to CacheFootprint before.
*/
virtual void DisplayFootprint( LIB_ID const& aFPID ) = 0;
/**
* Set the callback to receive status updates.
*/
virtual void SetStatusHandler( FOOTPRINT_STATUS_HANDLER aHandler ) = 0;
/**
* Get the underlying wxWindow.
*/
virtual wxWindow* GetWindow() = 0;
/**
* Return a footprint preview panel instance via Kiface. May return null
* if Kiway is not available or there is any error on load.
*/
static FOOTPRINT_PREVIEW_PANEL_BASE* Create( wxWindow* aParent, KIWAY& aKiway );
};
#endif // __FOOTPRINT_PREVIEW_WIDGET_H

View File

@ -19,7 +19,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <widgets/footprint_preview_panel.h>
#include <footprint_preview_panel.h>
#include <pcb_draw_panel_gal.h>
#include <kiway.h>
@ -36,65 +36,164 @@
#include <wx/stattext.h>
/**
* Threadsafe interface class between loader thread and panel class.
*/
class FP_THREAD_IFACE
{
using CACHE_ENTRY = FOOTPRINT_PREVIEW_PANEL::CACHE_ENTRY;
public:
/// Retrieve a cache entry by LIB_ID
boost::optional<CACHE_ENTRY> GetFromCache( LIB_ID const & aFPID )
{
wxMutexLocker lock( m_lock );
auto it = m_cachedFootprints.find( aFPID );
if( it != m_cachedFootprints.end() )
return it->second;
else
return boost::none;
}
/**
* Push an entry to the loading queue and a placeholder to the cache;
* return the placeholder.
*/
CACHE_ENTRY AddToQueue( LIB_ID const & aEntry )
{
wxMutexLocker lock( m_lock );
CACHE_ENTRY ent = { aEntry, NULL, FPS_LOADING };
m_cachedFootprints[aEntry] = ent;
m_loaderQueue.push_back( ent );
return ent;
}
/// Pop an entry from the queue, or empty option if none is available.
boost::optional<CACHE_ENTRY> PopFromQueue()
{
wxMutexLocker lock( m_lock );
if( m_loaderQueue.empty() )
{
return boost::none;
}
else
{
auto ent = m_loaderQueue.front();
m_loaderQueue.pop_front();
return ent;
}
}
/// Add an entry to the cache.
void AddToCache( CACHE_ENTRY const & aEntry )
{
wxMutexLocker lock( m_lock );
m_cachedFootprints[aEntry.fpid] = aEntry;
}
/**
* Threadsafe accessor to set the current footprint.
*/
void SetCurrentFootprint( LIB_ID aFp )
{
wxMutexLocker lock( m_lock );
m_current_fp = aFp;
}
/**
* Threadsafe accessor to get the current footprint.
*/
LIB_ID GetCurrentFootprint()
{
wxMutexLocker lock( m_lock );
return m_current_fp;
}
private:
std::deque<CACHE_ENTRY> m_loaderQueue;
std::map<LIB_ID, CACHE_ENTRY> m_cachedFootprints;
LIB_ID m_current_fp;
wxMutex m_lock;
};
/**
* Footprint loader thread to prevent footprint loading from locking the UI.
* Interface is via a FP_THREAD_IFACE.
*/
class FP_LOADER_THREAD: public wxThread
{
using CACHE_ENTRY = FOOTPRINT_PREVIEW_PANEL::CACHE_ENTRY;
FOOTPRINT_PREVIEW_PANEL* m_parent;
std::shared_ptr<FOOTPRINT_PREVIEW_PANEL::IFACE> m_iface;
std::shared_ptr<FP_THREAD_IFACE> m_iface;
public:
FP_LOADER_THREAD( FOOTPRINT_PREVIEW_PANEL* aParent,
std::shared_ptr<FOOTPRINT_PREVIEW_PANEL::IFACE> const& aIface ):
std::shared_ptr<FP_THREAD_IFACE> const& aIface ):
wxThread( wxTHREAD_DETACHED ),
m_parent( aParent ),
m_iface( aIface )
{}
~FP_LOADER_THREAD()
{}
void ProcessEntry( CACHE_ENTRY& aEntry )
{
FP_LIB_TABLE* fptbl = m_parent->Prj().PcbFootprintLibs();
if( !fptbl )
return;
aEntry.module = NULL;
try {
aEntry.module = fptbl->FootprintLoadWithOptionalNickname( aEntry.fpid );
if( !aEntry.module )
aEntry.status = FPS_NOT_FOUND;
} catch( const IO_ERROR& ioe )
{
aEntry.status = FPS_NOT_FOUND;
}
if( aEntry.status != FPS_NOT_FOUND )
aEntry.status = FPS_READY;
m_iface->AddToCache( aEntry );
if( aEntry.fpid == m_iface->GetCurrentFootprint() )
{
auto handler = m_parent->GetEventHandler();
if( handler )
handler->QueueEvent( new wxCommandEvent( wxEVT_COMMAND_TEXT_UPDATED, 1 ) );
}
}
virtual void* Entry() override
{
while(!TestDestroy())
while( !TestDestroy() )
{
auto ent = m_iface->PopFromQueue();
if( ent )
{
FP_LIB_TABLE* fptbl = m_parent->Prj().PcbFootprintLibs();
if(!fptbl)
continue;
ent->module = NULL;
try {
ent->module = fptbl->FootprintLoadWithOptionalNickname( ent->fpid );
if(ent->module == NULL)
ent->status = FPS_NOT_FOUND;
} catch( const IO_ERROR& ioe )
{
ent->status = FPS_NOT_FOUND;
}
if(ent->status != FPS_NOT_FOUND )
ent->status = FPS_READY;
m_iface->AddToCache( *ent );
if( ent->fpid == m_parent->m_currentFPID )
{
auto handler = m_parent->GetEventHandler();
if( handler )
handler->QueueEvent( new wxCommandEvent( wxEVT_COMMAND_TEXT_UPDATED, 1 ) );
}
} else {
wxMilliSleep(100);
}
ProcessEntry( *ent );
else
wxMilliSleep( 100 );
}
return NULL;
@ -102,69 +201,14 @@ public:
};
boost::optional<FOOTPRINT_PREVIEW_PANEL::CACHE_ENTRY>
FOOTPRINT_PREVIEW_PANEL::IFACE::PopFromQueue()
{
wxMutexLocker lock( m_loaderLock );
if( m_loaderQueue.empty() )
{
return boost::none;
}
else
{
auto ent = m_loaderQueue.front();
m_loaderQueue.pop_front();
return ent;
}
}
FOOTPRINT_PREVIEW_PANEL::CACHE_ENTRY
FOOTPRINT_PREVIEW_PANEL::IFACE::AddToQueue( LIB_ID const & aEntry )
{
wxMutexLocker lock( m_loaderLock );
CACHE_ENTRY ent = { aEntry, NULL, FPS_LOADING };
m_cachedFootprints[aEntry] = ent;
m_loaderQueue.push_back( ent );
return ent;
}
void FOOTPRINT_PREVIEW_PANEL::IFACE::AddToCache(
FOOTPRINT_PREVIEW_PANEL::CACHE_ENTRY const & aEntry )
{
wxMutexLocker lock( m_loaderLock );
m_cachedFootprints[aEntry.fpid] = aEntry;
}
boost::optional<FOOTPRINT_PREVIEW_PANEL::CACHE_ENTRY>
FOOTPRINT_PREVIEW_PANEL::IFACE::GetFromCache( LIB_ID const & aFPID )
{
wxMutexLocker lock( m_loaderLock );
auto it = m_cachedFootprints.find( aFPID );
if( it != m_cachedFootprints.end() )
return it->second;
else
return boost::none;
}
FOOTPRINT_PREVIEW_PANEL::FOOTPRINT_PREVIEW_PANEL(
KIWAY* aKiway, wxWindow* aParent, KIGFX::GAL_DISPLAY_OPTIONS& aOpts, GAL_TYPE aGalType )
: PCB_DRAW_PANEL_GAL ( aParent, -1, wxPoint( 0, 0 ), wxSize(200, 200), aOpts, aGalType ),
KIWAY_HOLDER( aKiway ),
m_footprintDisplayed( true ),
m_label( NULL ),
m_hidesizer( NULL )
m_footprintDisplayed( true )
{
m_iface = std::make_shared<IFACE>();
m_iface = std::make_shared<FP_THREAD_IFACE>();
m_loader = new FP_LOADER_THREAD( this, m_iface );
m_loader->Run();
@ -182,7 +226,6 @@ FOOTPRINT_PREVIEW_PANEL::FOOTPRINT_PREVIEW_PANEL(
StartDrawing();
Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( FOOTPRINT_PREVIEW_PANEL::OnLoaderThreadUpdate ), NULL, this );
}
@ -192,8 +235,7 @@ FOOTPRINT_PREVIEW_PANEL::~FOOTPRINT_PREVIEW_PANEL( )
}
FOOTPRINT_PREVIEW_PANEL::CACHE_ENTRY
FOOTPRINT_PREVIEW_PANEL::CacheFootprint ( const LIB_ID& aFPID )
FOOTPRINT_PREVIEW_PANEL::CACHE_ENTRY FOOTPRINT_PREVIEW_PANEL::CacheAndReturn( const LIB_ID& aFPID )
{
auto opt_ent = m_iface->GetFromCache( aFPID );
@ -204,6 +246,13 @@ FOOTPRINT_PREVIEW_PANEL::CacheFootprint ( const LIB_ID& aFPID )
}
// This is separate to avoid having to export CACHE_ENTRY to the global namespace
void FOOTPRINT_PREVIEW_PANEL::CacheFootprint( LIB_ID const& aFPID )
{
(void) CacheAndReturn( aFPID );
}
void FOOTPRINT_PREVIEW_PANEL::renderFootprint( MODULE *module )
{
GetView()->Clear();
@ -235,24 +284,18 @@ void FOOTPRINT_PREVIEW_PANEL::renderFootprint( MODULE *module )
void FOOTPRINT_PREVIEW_PANEL::DisplayFootprint ( const LIB_ID& aFPID )
{
m_currentFPID = aFPID;
m_iface->SetCurrentFootprint( aFPID );
m_footprintDisplayed = false;
CACHE_ENTRY fpe = CacheFootprint ( m_currentFPID );
CACHE_ENTRY fpe = CacheAndReturn ( m_currentFPID );
switch( fpe.status )
if( m_handler )
m_handler( fpe.status );
if( fpe.status == FPS_READY )
{
case FPS_NOT_FOUND:
SetStatusText( _( "Footprint not found" ) );
break;
case FPS_LOADING:
SetStatusText( _( "Loading..." ) );
break;
case FPS_READY:
if ( !m_footprintDisplayed )
{
ClearStatus();
renderFootprint( fpe.module );
m_footprintDisplayed = true;
Refresh();
@ -261,55 +304,21 @@ void FOOTPRINT_PREVIEW_PANEL::DisplayFootprint ( const LIB_ID& aFPID )
}
void FOOTPRINT_PREVIEW_PANEL::LinkErrorLabel( wxStaticText* aLabel )
{
m_label = aLabel;
}
void FOOTPRINT_PREVIEW_PANEL::SetHideSizer( wxSizer* aSizer )
{
m_hidesizer = aSizer;
}
void FOOTPRINT_PREVIEW_PANEL::OnLoaderThreadUpdate( wxCommandEvent& event )
{
DisplayFootprint( m_currentFPID );
}
void FOOTPRINT_PREVIEW_PANEL::SetStatusText( wxString const & aText )
void FOOTPRINT_PREVIEW_PANEL::SetStatusHandler( FOOTPRINT_STATUS_HANDLER aHandler )
{
if( m_label )
{
m_label->SetLabel( aText );
}
if( m_hidesizer )
{
m_hidesizer->ShowItems( true );
Hide();
}
GetParent()->Layout();
m_handler = aHandler;
}
void FOOTPRINT_PREVIEW_PANEL::ClearStatus()
wxWindow* FOOTPRINT_PREVIEW_PANEL::GetWindow()
{
if( m_label )
{
m_label->SetLabel( wxEmptyString );
}
if( m_hidesizer )
{
Show();
m_hidesizer->ShowItems( false );
}
GetParent()->Layout();
return static_cast<wxWindow*>( this );
}

View File

@ -0,0 +1,99 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016-2017 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
* Copyright (C) 2016 Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FOOTPRINT_PREVIEW_PANEL_H
#define __FOOTPRINT_PREVIEW_PANEL_H
#include <wx/wx.h>
#include <map>
#include <deque>
#include <functional>
#include <pcb_draw_panel_gal.h>
#include <gal/gal_display_options.h>
#include <lib_id.h>
#include <kiway_player.h>
#include <boost/optional.hpp>
#include <widgets/footprint_preview_widget.h>
class MODULE;
class KIWAY;
class IO_MGR;
class BOARD;
class FP_LOADER_THREAD;
class FP_THREAD_IFACE;
/**
* Panel that renders a single footprint via Cairo GAL, meant to be exported
* through Kiface.
*/
class FOOTPRINT_PREVIEW_PANEL :
public PCB_DRAW_PANEL_GAL, public KIWAY_HOLDER, public FOOTPRINT_PREVIEW_PANEL_BASE
{
friend class FP_THREAD_IFACE;
friend class FP_LOADER_THREAD;
public:
virtual ~FOOTPRINT_PREVIEW_PANEL( );
virtual void CacheFootprint( LIB_ID const& aFPID ) override;
virtual void DisplayFootprint ( LIB_ID const& aFPID ) override;
virtual void SetStatusHandler( FOOTPRINT_STATUS_HANDLER aHandler ) override;
virtual wxWindow* GetWindow() override;
static FOOTPRINT_PREVIEW_PANEL* New( KIWAY* aKiway, wxWindow* aParent );
private:
struct CACHE_ENTRY {
LIB_ID fpid;
MODULE *module;
FOOTPRINT_STATUS status;
};
FOOTPRINT_PREVIEW_PANEL(
KIWAY* aKiway, wxWindow* aParent,
KIGFX::GAL_DISPLAY_OPTIONS& aOpts, GAL_TYPE aGalType );
virtual CACHE_ENTRY CacheAndReturn ( LIB_ID const& aFPID );
void OnLoaderThreadUpdate( wxCommandEvent& aEvent );
void renderFootprint( MODULE *module );
FP_LOADER_THREAD* m_loader;
std::shared_ptr<FP_THREAD_IFACE> m_iface;
FOOTPRINT_STATUS_HANDLER m_handler;
std::unique_ptr<BOARD> m_dummyBoard;
LIB_ID m_currentFPID;
bool m_footprintDisplayed;
};
#endif

View File

@ -57,7 +57,7 @@
#include <module_editor_frame.h>
#include <modview_frame.h>
#include <footprint_wizard_frame.h>
#include <widgets/footprint_preview_panel.h>
#include <footprint_preview_panel.h>
#include <gl_context_mgr.h>
extern bool IsWxPythonLoaded();