diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index ce319cd899..b0b3b66ffc 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -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 ) diff --git a/common/widgets/footprint_preview_panel.cpp b/common/widgets/footprint_preview_panel.cpp deleted file mode 100644 index bf6169bb2e..0000000000 --- a/common/widgets/footprint_preview_panel.cpp +++ /dev/null @@ -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 - * - * 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 . - */ - -#include -#include -#include - - -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( - 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; -} diff --git a/common/widgets/footprint_preview_widget.cpp b/common/widgets/footprint_preview_widget.cpp new file mode 100644 index 0000000000..a30520d1c4 --- /dev/null +++ b/common/widgets/footprint_preview_widget.cpp @@ -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 + * + * 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 . + */ + +#include +#include +#include +#include + + +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( window ); + + if( window && !panel ) + delete window; + } catch( ... ) + {} + + return panel; +} diff --git a/eeschema/dialogs/dialog_choose_component.cpp b/eeschema/dialogs/dialog_choose_component.cpp index 02b8ae537f..0f6e4cdae4 100644 --- a/eeschema/dialogs/dialog_choose_component.cpp +++ b/eeschema/dialogs/dialog_choose_component.cpp @@ -45,7 +45,7 @@ #include #include -#include +#include #include #include #include @@ -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; } diff --git a/eeschema/dialogs/dialog_choose_component.h b/eeschema/dialogs/dialog_choose_component.h index f54863f171..d0aee6945e 100644 --- a/eeschema/dialogs/dialog_choose_component.h +++ b/eeschema/dialogs/dialog_choose_component.h @@ -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; diff --git a/include/widgets/footprint_preview_panel.h b/include/widgets/footprint_preview_panel.h deleted file mode 100644 index 9b56ba2041..0000000000 --- a/include/widgets/footprint_preview_panel.h +++ /dev/null @@ -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 - * Copyright (C) 2016 Tomasz Wlostowski - * - * 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 . - */ - -#ifndef __FOOTPRINT_PREVIEW_PANEL_H -#define __FOOTPRINT_PREVIEW_PANEL_H - -#include - -#include -#include - -#include -#include -#include -#include -#include - -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 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 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 m_loaderQueue; - std::map 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 m_iface; - - std::unique_ptr m_dummyBoard; - - LIB_ID m_currentFPID; - bool m_footprintDisplayed; - - wxStaticText* m_label; - wxSizer* m_hidesizer; -}; - -#endif diff --git a/include/widgets/footprint_preview_widget.h b/include/widgets/footprint_preview_widget.h new file mode 100644 index 0000000000..d5d06085fa --- /dev/null +++ b/include/widgets/footprint_preview_widget.h @@ -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 + * + * 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 . + */ + +#ifndef __FOOTPRINT_PREVIEW_WIDGET_H +#define __FOOTPRINT_PREVIEW_WIDGET_H + +#include +#include +#include + +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 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 diff --git a/pcbnew/footprint_preview_panel.cpp b/pcbnew/footprint_preview_panel.cpp index 06b0c5d97d..a91bcebd87 100644 --- a/pcbnew/footprint_preview_panel.cpp +++ b/pcbnew/footprint_preview_panel.cpp @@ -19,7 +19,7 @@ * with this program. If not, see . */ -#include +#include #include #include @@ -36,65 +36,164 @@ #include + + +/** + * 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 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 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 m_loaderQueue; + std::map 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 m_iface; + std::shared_ptr m_iface; public: FP_LOADER_THREAD( FOOTPRINT_PREVIEW_PANEL* aParent, - std::shared_ptr const& aIface ): + std::shared_ptr 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::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::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(); + m_iface = std::make_shared(); 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( this ); } diff --git a/pcbnew/footprint_preview_panel.h b/pcbnew/footprint_preview_panel.h new file mode 100644 index 0000000000..d44313d539 --- /dev/null +++ b/pcbnew/footprint_preview_panel.h @@ -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 + * Copyright (C) 2016 Tomasz Wlostowski + * + * 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 . + */ + +#ifndef __FOOTPRINT_PREVIEW_PANEL_H +#define __FOOTPRINT_PREVIEW_PANEL_H + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +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 m_iface; + FOOTPRINT_STATUS_HANDLER m_handler; + std::unique_ptr m_dummyBoard; + + LIB_ID m_currentFPID; + bool m_footprintDisplayed; +}; + +#endif diff --git a/include/pcb_draw_panel_gal.h b/pcbnew/pcb_draw_panel_gal.h similarity index 100% rename from include/pcb_draw_panel_gal.h rename to pcbnew/pcb_draw_panel_gal.h diff --git a/pcbnew/pcbnew.cpp b/pcbnew/pcbnew.cpp index 1eed6bfecb..deaf30274a 100644 --- a/pcbnew/pcbnew.cpp +++ b/pcbnew/pcbnew.cpp @@ -57,7 +57,7 @@ #include #include #include -#include +#include #include extern bool IsWxPythonLoaded();