mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 10:13:19 +02:00
Using a boolean argument just leads to a lot of trailing booleans in the function calls and is not user friendly. Instead, introduce PostAction() to send an action that runs after the coroutine (equivalent to passing false or the default argument), and leave RunAction as the immediate execution function.
613 lines
17 KiB
C++
613 lines
17 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2022 3Dconnexion
|
|
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* 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 "nl_schematic_plugin_impl.h"
|
|
|
|
// KiCAD includes
|
|
#include <sch_base_frame.h>
|
|
#include <bitmaps.h>
|
|
#include <class_draw_panel_gal.h>
|
|
#include <view/view.h>
|
|
#include <view/wx_view_controls.h>
|
|
#include <tool/action_manager.h>
|
|
#include <tool/tool_action.h>
|
|
#include <tool/tool_manager.h>
|
|
|
|
// stdlib
|
|
#include <list>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <utility>
|
|
#include <vector>
|
|
#include <cfloat>
|
|
|
|
#include <wx/log.h>
|
|
#include <wx/mstream.h>
|
|
|
|
|
|
/**
|
|
* Flag to enable the NL_SCHEMATIC_PLUGIN debug tracing.
|
|
*
|
|
* Use "KI_TRACE_NL_SCHEMATIC_PLUGIN" to enable.
|
|
*
|
|
* @ingroup trace_env_vars
|
|
*/
|
|
const wxChar* NL_SCHEMATIC_PLUGIN_IMPL::m_logTrace = wxT( "KI_TRACE_NL_SCHEMATIC_PLUGIN" );
|
|
|
|
|
|
NL_SCHEMATIC_PLUGIN_IMPL::NL_SCHEMATIC_PLUGIN_IMPL() :
|
|
CNavigation3D( false, false ),
|
|
m_viewport2D( nullptr ),
|
|
m_view( nullptr ),
|
|
m_isMoving( false ),
|
|
m_viewportWidth( 0.0 )
|
|
{
|
|
PutProfileHint( "KiCAD Eeschema" );
|
|
}
|
|
|
|
|
|
NL_SCHEMATIC_PLUGIN_IMPL::~NL_SCHEMATIC_PLUGIN_IMPL()
|
|
{
|
|
EnableNavigation( false );
|
|
}
|
|
|
|
|
|
void NL_SCHEMATIC_PLUGIN_IMPL::SetCanvas( EDA_DRAW_PANEL_GAL* aViewport )
|
|
{
|
|
bool init = m_viewport2D == nullptr;
|
|
|
|
m_viewport2D = aViewport;
|
|
|
|
if( m_viewport2D != nullptr )
|
|
{
|
|
m_view = static_cast<KIGFX::SCH_VIEW*>( m_viewport2D->GetView() );
|
|
m_viewportWidth = m_view->GetBoundary().GetWidth();
|
|
|
|
if( init )
|
|
{
|
|
// Use the default settings for the connexion to the 3DMouse navigation
|
|
// They are use a single-threaded threading model and row vectors.
|
|
EnableNavigation( true );
|
|
|
|
// Use the SpaceMouse internal timing source for the frame rate.
|
|
PutFrameTimingSource( TimingSource::SpaceMouse );
|
|
|
|
exportCommandsAndImages();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void NL_SCHEMATIC_PLUGIN_IMPL::SetFocus( bool aFocus )
|
|
{
|
|
wxLogTrace( m_logTrace, wxT( "NL_SCHEMATIC_PLUGIN_IMPL::SetFocus %d" ), aFocus );
|
|
NAV_3D::Write( navlib::focus_k, aFocus );
|
|
}
|
|
|
|
// temporary store for the command categories
|
|
typedef std::map<std::string, TDx::CCommandTreeNode*> CATEGORY_STORE;
|
|
|
|
|
|
/**
|
|
* Add a category to the store.
|
|
*
|
|
* The function adds category paths of the format "A.B" where B is a sub-category of A.
|
|
*
|
|
* @param aCategoryPath is the std::string representation of the category.
|
|
* @param aCategoryStore is the CATEGORY_STORE instance to add to.
|
|
* @return a CATEGORY_STORE::iterator where the category was added.
|
|
*/
|
|
static CATEGORY_STORE::iterator add_category( std::string aCategoryPath,
|
|
CATEGORY_STORE& aCategoryStore )
|
|
{
|
|
using TDx::SpaceMouse::CCategory;
|
|
|
|
CATEGORY_STORE::iterator parent_iter = aCategoryStore.begin();
|
|
std::string::size_type pos = aCategoryPath.find_last_of( '.' );
|
|
|
|
if( pos != std::string::npos )
|
|
{
|
|
std::string parentPath = aCategoryPath.substr( 0, pos );
|
|
parent_iter = aCategoryStore.find( parentPath );
|
|
|
|
if( parent_iter == aCategoryStore.end() )
|
|
{
|
|
parent_iter = add_category( parentPath, aCategoryStore );
|
|
}
|
|
}
|
|
|
|
std::string name = aCategoryPath.substr( pos + 1 );
|
|
std::unique_ptr<CCategory> categoryNode =
|
|
std::make_unique<CCategory>( aCategoryPath.c_str(), name.c_str() );
|
|
|
|
CATEGORY_STORE::iterator iter = aCategoryStore.insert(
|
|
aCategoryStore.end(), CATEGORY_STORE::value_type( aCategoryPath, categoryNode.get() ) );
|
|
|
|
parent_iter->second->push_back( std::move( categoryNode ) );
|
|
return iter;
|
|
}
|
|
|
|
|
|
void NL_SCHEMATIC_PLUGIN_IMPL::exportCommandsAndImages()
|
|
{
|
|
wxLogTrace( m_logTrace, wxT( "NL_SCHEMATIC_PLUGIN_IMPL::exportCommandsAndImages" ) );
|
|
|
|
std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
|
|
|
|
if( actions.size() == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
using TDx::SpaceMouse::CCommand;
|
|
using TDx::SpaceMouse::CCommandSet;
|
|
|
|
// The root action set node
|
|
CCommandSet commandSet( "SCHEMATIC_EDITOR", "Schematic Editor" );
|
|
|
|
// Activate the command set
|
|
NAV_3D::PutActiveCommands( commandSet.GetId() );
|
|
|
|
// temporary store for the categories
|
|
CATEGORY_STORE categoryStore;
|
|
|
|
std::vector<TDx::CImage> vImages;
|
|
|
|
// add the action set to the category_store
|
|
categoryStore.insert( categoryStore.end(), CATEGORY_STORE::value_type( ".", &commandSet ) );
|
|
|
|
std::list<TOOL_ACTION*>::const_iterator it;
|
|
|
|
for( it = actions.begin(); it != actions.end(); ++it )
|
|
{
|
|
const TOOL_ACTION* action = *it;
|
|
std::string label = action->GetLabel().ToStdString();
|
|
|
|
if( label.empty() )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
std::string name = action->GetName();
|
|
|
|
// Do no export commands for the 3DViewer app.
|
|
|
|
if( name.rfind( "3DViewer.", 0 ) == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
std::string strCategory = action->GetToolName();
|
|
CATEGORY_STORE::iterator iter = categoryStore.find( strCategory );
|
|
|
|
if( iter == categoryStore.end() )
|
|
{
|
|
iter = add_category( std::move( strCategory ), categoryStore );
|
|
}
|
|
|
|
std::string description = action->GetDescription().ToStdString();
|
|
|
|
// Arbitrary 8-bit data stream
|
|
wxMemoryOutputStream imageStream;
|
|
|
|
if( action->GetIcon() != BITMAPS::INVALID_BITMAP )
|
|
{
|
|
wxImage image = KiBitmap( action->GetIcon() ).ConvertToImage();
|
|
image.SaveFile( imageStream, wxBitmapType::wxBITMAP_TYPE_PNG );
|
|
image.Destroy();
|
|
|
|
if( imageStream.GetSize() )
|
|
{
|
|
wxStreamBuffer* streamBuffer = imageStream.GetOutputStreamBuffer();
|
|
TDx::CImage tdxImage = TDx::CImage::FromData( "", 0, name.c_str() );
|
|
tdxImage.AssignImage( std::string( reinterpret_cast<const char*>(
|
|
streamBuffer->GetBufferStart() ),
|
|
streamBuffer->GetBufferSize() ),
|
|
0 );
|
|
|
|
wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name );
|
|
vImages.push_back( std::move( tdxImage ) );
|
|
}
|
|
}
|
|
|
|
wxLogTrace( m_logTrace, wxT( "Inserting command: %s, description: %s, in category: %s" ),
|
|
name, description, iter->first );
|
|
|
|
iter->second->push_back(
|
|
CCommand( std::move( name ), std::move( label ), std::move( description ) ) );
|
|
}
|
|
|
|
NAV_3D::AddCommandSet( commandSet );
|
|
NAV_3D::AddImages( vImages );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::GetCameraMatrix( navlib::matrix_t& matrix ) const
|
|
{
|
|
if( m_view == nullptr )
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
|
|
}
|
|
|
|
m_viewPosition = m_view->GetCenter();
|
|
|
|
double x = m_view->IsMirroredX() ? -1 : 1;
|
|
double y = m_view->IsMirroredY() ? 1 : -1;
|
|
|
|
// x * y * z = 1 for a right-handed coordinate system.
|
|
double z = x * y;
|
|
|
|
// Note: the connexion has been configured as row vectors, the coordinate system is defined in
|
|
// NL_SCHEMATIC_PLUGIN_IMPL::GetCoordinateSystem and the front view in NL_SCHEMATIC_PLUGIN_IMPL::GetFrontView.
|
|
matrix = { x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, m_viewPosition.x, m_viewPosition.y, 0, 1 };
|
|
return 0;
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::GetPointerPosition( navlib::point_t& position ) const
|
|
{
|
|
if( m_view == nullptr )
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
|
|
}
|
|
|
|
VECTOR2D mouse_pointer = m_viewport2D->GetViewControls()->GetMousePosition();
|
|
|
|
position.x = mouse_pointer.x;
|
|
position.y = mouse_pointer.y;
|
|
position.z = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::GetViewExtents( navlib::box_t& extents ) const
|
|
{
|
|
if( m_view == nullptr )
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
|
|
}
|
|
|
|
double scale = m_viewport2D->GetGAL()->GetWorldScale();
|
|
BOX2D box = m_view->GetViewport();
|
|
|
|
m_viewportWidth = box.GetWidth();
|
|
|
|
extents = navlib::box_t{ -box.GetWidth() / 2.0,
|
|
-box.GetHeight() / 2.0,
|
|
m_viewport2D->GetGAL()->GetMinDepth() / scale,
|
|
box.GetWidth() / 2.0,
|
|
box.GetHeight() / 2.0,
|
|
m_viewport2D->GetGAL()->GetMaxDepth() / scale };
|
|
return 0;
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::GetIsViewPerspective( navlib::bool_t& perspective ) const
|
|
{
|
|
perspective = false;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::SetCameraMatrix( const navlib::matrix_t& matrix )
|
|
{
|
|
if( m_view == nullptr )
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
|
|
long result = 0;
|
|
VECTOR2D viewPos( matrix.m4x4[3][0], matrix.m4x4[3][1] );
|
|
|
|
if( !equals( m_view->GetCenter(), m_viewPosition,
|
|
static_cast<VECTOR2D::coord_type>( FLT_EPSILON ) ) )
|
|
{
|
|
m_view->SetCenter( viewPos + m_view->GetCenter() - m_viewPosition );
|
|
result = navlib::make_result_code( navlib::navlib_errc::error );
|
|
}
|
|
else
|
|
{
|
|
m_view->SetCenter( viewPos );
|
|
}
|
|
|
|
m_viewPosition = viewPos;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::SetViewExtents( const navlib::box_t& extents )
|
|
{
|
|
if( m_view == nullptr )
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
|
|
long result = 0;
|
|
|
|
if( m_viewportWidth != m_view->GetViewport().GetWidth() )
|
|
{
|
|
result = navlib::make_result_code( navlib::navlib_errc::error );
|
|
}
|
|
|
|
double width = m_viewportWidth;
|
|
m_viewportWidth = extents.max_x - extents.min_x;
|
|
|
|
double scale = width / m_viewportWidth * m_view->GetScale();
|
|
m_view->SetScale( scale, m_view->GetCenter() );
|
|
|
|
if( !equals( m_view->GetScale(), scale, static_cast<double>( FLT_EPSILON ) ) )
|
|
{
|
|
result = navlib::make_result_code( navlib::navlib_errc::error );
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::SetViewFOV( double fov )
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::SetViewFrustum( const navlib::frustum_t& frustum )
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::GetModelExtents( navlib::box_t& extents ) const
|
|
{
|
|
if( m_view == nullptr )
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
|
|
}
|
|
|
|
BOX2I box = static_cast<SCH_BASE_FRAME*>( m_viewport2D->GetParent() )->GetDocumentExtents();
|
|
box.Normalize();
|
|
|
|
double half_depth = 0.1 / m_viewport2D->GetGAL()->GetWorldScale();
|
|
|
|
if( box.GetWidth() == 0 && box.GetHeight() == 0 )
|
|
{
|
|
half_depth = 0;
|
|
}
|
|
|
|
extents = { static_cast<double>( box.GetOrigin().x ),
|
|
static_cast<double>( box.GetOrigin().y ),
|
|
-half_depth,
|
|
static_cast<double>( box.GetEnd().x ),
|
|
static_cast<double>( box.GetEnd().y ),
|
|
half_depth };
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::GetCoordinateSystem( navlib::matrix_t& matrix ) const
|
|
{
|
|
// The coordinate system is defined as x to the right, y down and z into the screen.
|
|
matrix = { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 };
|
|
return 0;
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::GetFrontView( navlib::matrix_t& matrix ) const
|
|
{
|
|
matrix = { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 };
|
|
return 0;
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::GetIsSelectionEmpty( navlib::bool_t& empty ) const
|
|
{
|
|
empty = true;
|
|
return 0;
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::GetIsViewRotatable( navlib::bool_t& isRotatable ) const
|
|
{
|
|
isRotatable = false;
|
|
return 0;
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::SetActiveCommand( std::string commandId )
|
|
{
|
|
if( commandId.empty() )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
|
|
TOOL_ACTION* context = nullptr;
|
|
|
|
for( std::list<TOOL_ACTION*>::const_iterator it = actions.begin(); it != actions.end(); it++ )
|
|
{
|
|
TOOL_ACTION* action = *it;
|
|
std::string nm = action->GetName();
|
|
|
|
if( commandId == nm )
|
|
{
|
|
context = action;
|
|
}
|
|
}
|
|
|
|
if( context != nullptr )
|
|
{
|
|
wxWindow* parent = m_viewport2D->GetParent();
|
|
|
|
// Only allow command execution if the window is enabled. i.e. there is not a modal dialog
|
|
// currently active.
|
|
|
|
if( parent->IsEnabled() )
|
|
{
|
|
TOOL_MANAGER* tool_manager = static_cast<SCH_BASE_FRAME*>( parent )->GetToolManager();
|
|
|
|
// Get the selection to use to test if the action is enabled
|
|
SELECTION& sel = tool_manager->GetToolHolder()->GetCurrentSelection();
|
|
|
|
bool runAction = true;
|
|
|
|
if( const ACTION_CONDITIONS* aCond =
|
|
tool_manager->GetActionManager()->GetCondition( *context ) )
|
|
{
|
|
runAction = aCond->enableCondition( sel );
|
|
}
|
|
|
|
if( runAction )
|
|
{
|
|
tool_manager->RunAction( *context );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::SetSettingsChanged( long change )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::SetMotionFlag( bool value )
|
|
{
|
|
m_isMoving = value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::SetTransaction( long value )
|
|
{
|
|
if( value == 0L )
|
|
{
|
|
m_viewport2D->ForceRefresh();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::GetViewFOV( double& fov ) const
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::GetViewFrustum( navlib::frustum_t& frustum ) const
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::GetSelectionExtents( navlib::box_t& extents ) const
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::GetSelectionTransform( navlib::matrix_t& transform ) const
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::SetSelectionTransform( const navlib::matrix_t& matrix )
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::GetPivotPosition( navlib::point_t& position ) const
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::IsUserPivot( navlib::bool_t& userPivot ) const
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::SetPivotPosition( const navlib::point_t& position )
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::GetPivotVisible( navlib::bool_t& visible ) const
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::SetPivotVisible( bool visible )
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::GetHitLookAt( navlib::point_t& position ) const
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::SetHitAperture( double aperture )
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::SetHitDirection( const navlib::vector_t& direction )
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::SetHitLookFrom( const navlib::point_t& eye )
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::SetHitSelectionOnly( bool onlySelection )
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|
|
|
|
|
|
long NL_SCHEMATIC_PLUGIN_IMPL::SetCameraTarget( const navlib::point_t& position )
|
|
{
|
|
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
|
|
}
|