/* * 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include FOOTPRINT_PREVIEW_PANEL::LOADER_THREAD::LOADER_THREAD ( FOOTPRINT_PREVIEW_PANEL* aParent ) : wxThread ( wxTHREAD_JOINABLE ), m_parent( aParent ) { } FOOTPRINT_PREVIEW_PANEL::LOADER_THREAD::~LOADER_THREAD () { } boost::optional FOOTPRINT_PREVIEW_PANEL::LOADER_THREAD::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::LOADER_THREAD::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::LOADER_THREAD::AddToCache( FOOTPRINT_PREVIEW_PANEL::CACHE_ENTRY const & aEntry ) { wxMutexLocker lock( m_loaderLock ); m_cachedFootprints[aEntry.fpid] = aEntry; } boost::optional FOOTPRINT_PREVIEW_PANEL::LOADER_THREAD::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; } void* FOOTPRINT_PREVIEW_PANEL::LOADER_THREAD::Entry() { while(!TestDestroy()) { auto ent = 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; AddToCache( *ent ); if( ent->fpid == m_parent->m_currentFPID ) { wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, 1 ); m_parent->GetEventHandler()->AddPendingEvent ( event ); } } else { wxMilliSleep(100); } } return NULL; } 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_loader = std::make_unique( this ); m_loader->Run(); ShowScrollbars( wxSHOW_SB_NEVER, wxSHOW_SB_NEVER ); EnableScrolling( false, false ); // otherwise Zoom Auto disables GAL canvas m_dummyBoard = std::make_unique(); UseColorScheme( m_dummyBoard->GetColorsSettings() ); SyncLayersVisibility( &*m_dummyBoard ); Raise(); Show(true); StartDrawing(); Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( FOOTPRINT_PREVIEW_PANEL::OnLoaderThreadUpdate ), NULL, this ); } FOOTPRINT_PREVIEW_PANEL::~FOOTPRINT_PREVIEW_PANEL( ) { m_loader->Delete(); } FOOTPRINT_PREVIEW_PANEL::CACHE_ENTRY FOOTPRINT_PREVIEW_PANEL::CacheFootprint ( const LIB_ID& aFPID ) { auto opt_ent = m_loader->GetFromCache( aFPID ); if( opt_ent ) return *opt_ent; else return m_loader->AddToQueue( aFPID ); } void FOOTPRINT_PREVIEW_PANEL::renderFootprint( MODULE *module ) { Freeze(); GetView()->Clear(); module->SetParent ( &*m_dummyBoard ); module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, GetView(), _1 ) ); GetView()->Add ( module ); GetView()->SetVisible( module, true ); GetView()->Update( module, KIGFX::ALL ); BOX2I bbox = module->ViewBBox(); bbox.Merge ( module->Value().ViewBBox() ); bbox.Merge ( module->Reference().ViewBBox() ); if( bbox.GetSize().x > 0 && bbox.GetSize().y > 0 ) { // Autozoom GetView()->SetViewport( BOX2D( bbox.GetOrigin(), bbox.GetSize() ) ); // Add a margin GetView()->SetScale( GetView()->GetScale() * 0.7 ); Refresh(); } Thaw(); } void FOOTPRINT_PREVIEW_PANEL::DisplayFootprint ( const LIB_ID& aFPID ) { m_currentFPID = aFPID; m_footprintDisplayed = false; CACHE_ENTRY fpe = CacheFootprint ( m_currentFPID ); switch( fpe.status ) { 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(); } } } 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 ) { Freeze(); if( m_label ) { m_label->SetLabel( aText ); } if( m_hidesizer ) { m_hidesizer->ShowItems( true ); Hide(); } GetParent()->Layout(); Thaw(); } void FOOTPRINT_PREVIEW_PANEL::ClearStatus() { Freeze(); if( m_label ) { m_label->SetLabel( wxEmptyString ); } if( m_hidesizer ) { Show(); m_hidesizer->ShowItems( false ); } GetParent()->Layout(); Thaw(); } FOOTPRINT_PREVIEW_PANEL* FOOTPRINT_PREVIEW_PANEL::New( KIWAY* aKiway, wxWindow* aParent ) { KIGFX::GAL_DISPLAY_OPTIONS gal_opts; return new FOOTPRINT_PREVIEW_PANEL( aKiway, aParent, gal_opts, EDA_DRAW_PANEL_GAL::GAL_TYPE_CAIRO ); }