diff --git a/3d-viewer/3d_navlib/nl_3d_viewer_plugin_impl.cpp b/3d-viewer/3d_navlib/nl_3d_viewer_plugin_impl.cpp index ebe967278c..5a4965c816 100644 --- a/3d-viewer/3d_navlib/nl_3d_viewer_plugin_impl.cpp +++ b/3d-viewer/3d_navlib/nl_3d_viewer_plugin_impl.cpp @@ -44,35 +44,6 @@ */ const wxChar* NL_3D_VIEWER_PLUGIN_IMPL::m_logTrace = wxT( "KI_TRACE_NL_3D_VIEWER_PLUGIN" ); -/** - * Template to compare two floating point values for equality within a required epsilon. - * - * @param aFirst value to compare. - * @param aSecond value to compare. - * @param aEpsilon allowed error. - * @return true if the values considered equal within the specified epsilon, otherwise false. - */ -template -bool equals( T aFirst, T aSecond, T aEpsilon = static_cast( FLT_EPSILON ) ) -{ - T diff = fabs( aFirst - aSecond ); - - if( diff < aEpsilon ) - { - return true; - } - - aFirst = fabs( aFirst ); - aSecond = fabs( aSecond ); - T largest = aFirst > aSecond ? aFirst : aSecond; - - if( diff <= largest * aEpsilon ) - { - return true; - } - - return false; -} /** * Template to compare two glm::mat values for equality within a required epsilon. @@ -245,13 +216,13 @@ void NL_3D_VIEWER_PLUGIN_IMPL::exportCommandsAndImages() streamBuffer->GetBufferSize() ), 0 ); - wxLogTrace( m_logTrace, "Adding image for : %s", name ); + wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name ); vImages.push_back( std::move( tdxImage ) ); } } - wxLogTrace( m_logTrace, "Inserting command: %s, description: %s, in category: %s", name, - description, iter->first ); + 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 ) ) ); @@ -681,7 +652,7 @@ long NL_3D_VIEWER_PLUGIN_IMPL::GetFrontView( navlib::matrix_t& matrix ) const long NL_3D_VIEWER_PLUGIN_IMPL::GetCoordinateSystem( navlib::matrix_t& matrix ) const { // Use the right-handed coordinate system X-right, Z-up, Y-in (row vectors) - matrix = { 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1 }; + matrix = { 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1 }; return 0; } diff --git a/3d-viewer/3d_viewer/eda_3d_viewer_frame.cpp b/3d-viewer/3d_viewer/eda_3d_viewer_frame.cpp index 0eb05b8fc5..2afa0078f4 100644 --- a/3d-viewer/3d_viewer/eda_3d_viewer_frame.cpp +++ b/3d-viewer/3d_viewer/eda_3d_viewer_frame.cpp @@ -255,6 +255,19 @@ void EDA_3D_VIEWER_FRAME::setupUIConditions() } +void EDA_3D_VIEWER_FRAME::handleIconizeEvent( wxIconizeEvent& aEvent ) +{ + KIWAY_PLAYER::handleIconizeEvent( aEvent ); + +#if defined( KICAD_USE_3DCONNEXION ) + if( m_spaceMouse != nullptr && aEvent.IsIconized() ) + { + m_spaceMouse->SetFocus( false ); + } +#endif +} + + void EDA_3D_VIEWER_FRAME::ReloadRequest() { // This will schedule a request to load later diff --git a/3d-viewer/3d_viewer/eda_3d_viewer_frame.h b/3d-viewer/3d_viewer/eda_3d_viewer_frame.h index c78c652967..a3dbe5cef8 100644 --- a/3d-viewer/3d_viewer/eda_3d_viewer_frame.h +++ b/3d-viewer/3d_viewer/eda_3d_viewer_frame.h @@ -120,6 +120,8 @@ public: protected: void setupUIConditions() override; + void handleIconizeEvent( wxIconizeEvent& aEvent ) override; + private: /// Called when user press the File->Exit void Exit3DFrame( wxCommandEvent& event ); diff --git a/LICENSE.APACHE-2.0 b/LICENSE.APACHE-2.0 new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/LICENSE.APACHE-2.0 @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/LICENSE.README b/LICENSE.README index 8a2ba54da7..7614cf1782 100644 --- a/LICENSE.README +++ b/LICENSE.README @@ -8,6 +8,8 @@ KiCad EDA suite by the KiCad project or any third party, e.g. Linux distributor. You are free to use the *sources* under the terms of their respective licenses. +Licensed under Apache License, Version 2.0 + - portions of code in libs/kimath/include/math/util.h Licensed under BOOSTv1: - libcontext [https://github.com/boostorg/context] in thirdparty/libcontext - clipper in thirdparty/clipper diff --git a/common/eda_base_frame.cpp b/common/eda_base_frame.cpp index bec446103a..bcf4d984a5 100644 --- a/common/eda_base_frame.cpp +++ b/common/eda_base_frame.cpp @@ -107,6 +107,7 @@ BEGIN_EVENT_TABLE( EDA_BASE_FRAME, wxFrame ) EVT_MAXIMIZE( EDA_BASE_FRAME::OnMaximize ) EVT_SYS_COLOUR_CHANGED( EDA_BASE_FRAME::onSystemColorChange ) + EVT_ICONIZE( EDA_BASE_FRAME::onIconize ) END_EVENT_TABLE() @@ -1325,6 +1326,16 @@ void EDA_BASE_FRAME::onSystemColorChange( wxSysColourChangedEvent& aEvent ) } +void EDA_BASE_FRAME::onIconize( wxIconizeEvent& aEvent ) +{ + // Call the handler + handleIconizeEvent( aEvent ); + + // Skip the event. + aEvent.Skip(); +} + + #ifdef _WIN32 WXLRESULT EDA_BASE_FRAME::MSWWindowProc( WXUINT message, WXWPARAM wParam, WXLPARAM lParam ) { diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index 05ea6a241a..afcb7db477 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -435,6 +435,13 @@ if( KICAD_SPICE ) ) endif() +if( KICAD_USE_3DCONNEXION ) + message( STATUS "Including 3Dconnexion SpaceMouse navigation support in eeschema" ) + add_subdirectory( ./navlib ) + target_link_libraries( eeschema_kiface PRIVATE eeschema_navlib) +endif() + + set_target_properties( eeschema_kiface PROPERTIES # Decorate OUTPUT_NAME with PREFIX and SUFFIX, creating something like # _eeschema.so, _eeschema.dll, or _eeschema.kiface diff --git a/eeschema/navlib/CMakeLists.txt b/eeschema/navlib/CMakeLists.txt new file mode 100644 index 0000000000..bd2e8bb458 --- /dev/null +++ b/eeschema/navlib/CMakeLists.txt @@ -0,0 +1,30 @@ +if( KICAD_USE_3DCONNEXION ) + add_library(eeschema_navlib STATIC + "nl_schematic_plugin.cpp" + "nl_schematic_plugin_impl.cpp" + ) + + # eeschema_navlib depends on make_lexer outputs in common + add_dependencies( eeschema_navlib common ) + + # Find the 3DxWare SDK component 3DxWare::NlClient + # find_package(TDxWare_SDK 4.0 REQUIRED COMPONENTS 3DxWare::Navlib) + target_compile_definitions(eeschema_navlib PRIVATE + $ + ) + target_compile_options(eeschema_navlib PRIVATE + $ + ) + target_include_directories(eeschema_navlib PRIVATE + $ + $ + ) + target_link_libraries(eeschema_navlib + $ + 3DxWare::Navlib + ) +else() + add_library(eeschema_navlib STATIC + "nl_schematic_plugin.cpp" + ) +endif(KICAD_USE_3DCONNEXION) diff --git a/eeschema/navlib/nl_schematic_plugin.cpp b/eeschema/navlib/nl_schematic_plugin.cpp new file mode 100644 index 0000000000..0f6621653e --- /dev/null +++ b/eeschema/navlib/nl_schematic_plugin.cpp @@ -0,0 +1,69 @@ +/* + * 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 . + */ + +#include "nl_schematic_plugin.h" +#if defined( KICAD_USE_3DCONNEXION ) + +#include "nl_schematic_plugin_impl.h" + + +NL_SCHEMATIC_PLUGIN::NL_SCHEMATIC_PLUGIN() : m_impl( new NL_SCHEMATIC_PLUGIN_IMPL() ) +{ +} + + +NL_SCHEMATIC_PLUGIN::~NL_SCHEMATIC_PLUGIN() +{ + delete m_impl; +} + + +void NL_SCHEMATIC_PLUGIN::SetFocus( bool focus ) +{ + m_impl->SetFocus( focus ); +} + + +void NL_SCHEMATIC_PLUGIN::SetCanvas( EDA_DRAW_PANEL_GAL* aViewport ) +{ + m_impl->SetCanvas( aViewport ); +} +#else + + +NL_SCHEMATIC_PLUGIN::NL_SCHEMATIC_PLUGIN( EDA_DRAW_PANEL_GAL* aViewport ) +{ +} + + +void NL_SCHEMATIC_PLUGIN::SetFocus( bool focus ) +{ +} + + +void NL_SCHEMATIC_PLUGIN::SetCanvas( EDA_DRAW_PANEL_GAL* aViewport ) +{ +} + + +NL_SCHEMATIC_PLUGIN::~NL_SCHEMATIC_PLUGIN() +{ +} +#endif diff --git a/eeschema/navlib/nl_schematic_plugin.h b/eeschema/navlib/nl_schematic_plugin.h new file mode 100644 index 0000000000..39c74aa353 --- /dev/null +++ b/eeschema/navlib/nl_schematic_plugin.h @@ -0,0 +1,67 @@ +/* + * 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 . + */ + +/** + * @file nl_schematic_plugin.h + * @brief Declaration of the NL_SCHEMATIC_PLUGIN class + */ + +#ifndef NL_SCHEMATIC_PLUGIN_H_ +#define NL_SCHEMATIC_PLUGIN_H_ + +// Forward declarations. +class EDA_DRAW_PANEL_GAL; +class NL_SCHEMATIC_PLUGIN_IMPL; + +/** + * The class that implements the public interface to the SpaceMouse plug-in. + */ +class NL_SCHEMATIC_PLUGIN +{ +public: + /** + * Initializes a new instance of the NL_SCHEMATIC_PLUGIN. + */ + NL_SCHEMATIC_PLUGIN(); + + virtual ~NL_SCHEMATIC_PLUGIN(); + + + /** + * Sets the viewport controlled by the SpaceMouse. + * + * @param aViewport is the viewport to be navigated. + */ + void SetCanvas( EDA_DRAW_PANEL_GAL* aViewport ); + + + /** + * Set the connection to the 3Dconnexion driver to the focus state so that + * 3DMouse data is routed to this connexion. + * + * @param aFocus is true to set the connexion active. + */ + void SetFocus( bool aFocus ); + +private: + NL_SCHEMATIC_PLUGIN_IMPL* m_impl; +}; + +#endif // NL_SCHEMATIC_PLUGIN_H_ diff --git a/eeschema/navlib/nl_schematic_plugin_impl.cpp b/eeschema/navlib/nl_schematic_plugin_impl.cpp new file mode 100644 index 0000000000..044832fdae --- /dev/null +++ b/eeschema/navlib/nl_schematic_plugin_impl.cpp @@ -0,0 +1,608 @@ +/* + * 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 . + */ + +#include "nl_schematic_plugin_impl.h" + +// KiCAD includes +#include +#include +#include +#include +#include +#include +#include +#include + +// stdlib +#include +#include +#include +#include +#include +#include + +#include +#include + + +/** + * 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_isMoving( false ) +{ + 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( 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 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 categoryNode = + std::make_unique( 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 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 vImages; + + // add the action set to the category_store + categoryStore.insert( categoryStore.end(), CATEGORY_STORE::value_type( ".", &commandSet ) ); + + std::list::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( + 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( 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( 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( 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( box.GetOrigin().x ), + static_cast( box.GetOrigin().y ), + -half_depth, + static_cast( box.GetEnd().x ), + static_cast( 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 actions = ACTION_MANAGER::GetActionList(); + TOOL_ACTION* context = nullptr; + + for( std::list::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( 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, true ); + } + } + 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 ); +} diff --git a/eeschema/navlib/nl_schematic_plugin_impl.h b/eeschema/navlib/nl_schematic_plugin_impl.h new file mode 100644 index 0000000000..1ff4c4e0a4 --- /dev/null +++ b/eeschema/navlib/nl_schematic_plugin_impl.h @@ -0,0 +1,147 @@ +/* + * 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 . + */ + +/** + * @file nl_schematic_plugin_impl.h + * @brief Declaration of the NL_SCHEMATIC_PLUGIN_IMPL class + */ + +#ifndef NL_SCHEMATIC_PLUGIN_IMPL_H_ +#define NL_SCHEMATIC_PLUGIN_IMPL_H_ + +#if _WIN32 +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0603 +#endif +#endif + +// TDxWare SDK. +#include + +// wx +#include + +// KiCAD +#include + +// stdlib +#include + +// Forward declarations. +class EDA_DRAW_PANEL_GAL; +namespace KIGFX +{ +class SCH_VIEW; +} + +// Convenience typedef. +typedef TDx::SpaceMouse::Navigation3D::CNavigation3D NAV_3D; + +/** + * The class that implements the accessors and mutators required for + * 3D navigation in an PCB_DRAW_PANEL_GAL using a SpaceMouse. + */ +class NL_SCHEMATIC_PLUGIN_IMPL : public NAV_3D +{ +public: + /** + * Initializes a new instance of the NL_SCHEMATIC_PLUGIN_IMPL. + */ + NL_SCHEMATIC_PLUGIN_IMPL(); + + + virtual ~NL_SCHEMATIC_PLUGIN_IMPL(); + + + /** + * Sets the viewport controlled by the SpaceMouse. + * + * @param aViewport is the viewport to be navigated. + */ + void SetCanvas( EDA_DRAW_PANEL_GAL* aViewport ); + + + /** + * Set the connection to the 3Dconnexion driver to the focus state so that + * 3DMouse data is routed here. + * + * @param aFocus is true to set the connection active. + */ + void SetFocus( bool aFocus ); + +private: + /** + * Export the invocable actions and images to the 3Dconnexion UI. + */ + void exportCommandsAndImages(); + + long GetCameraMatrix( navlib::matrix_t& aMatrix ) const override; + long GetPointerPosition( navlib::point_t& aPosition ) const override; + long GetViewExtents( navlib::box_t& aExtents ) const override; + long GetViewFOV( double& aFov ) const override; + long GetViewFrustum( navlib::frustum_t& aFrustum ) const override; + long GetIsViewPerspective( navlib::bool_t& aPerspective ) const override; + long SetCameraMatrix( const navlib::matrix_t& aMatrix ) override; + long SetViewExtents( const navlib::box_t& aExtents ) override; + long SetViewFOV( double aFov ) override; + long SetViewFrustum( const navlib::frustum_t& aFrustum ) override; + long GetModelExtents( navlib::box_t& aExtents ) const override; + long GetSelectionExtents( navlib::box_t& aExtents ) const override; + long GetSelectionTransform( navlib::matrix_t& aTransform ) const override; + long GetIsSelectionEmpty( navlib::bool_t& aEmpty ) const override; + long SetSelectionTransform( const navlib::matrix_t& aMatrix ) override; + long GetPivotPosition( navlib::point_t& aPosition ) const override; + long IsUserPivot( navlib::bool_t& aUserPivot ) const override; + long SetPivotPosition( const navlib::point_t& aPosition ) override; + long GetPivotVisible( navlib::bool_t& aVisible ) const override; + long SetPivotVisible( bool aVisible ) override; + long GetHitLookAt( navlib::point_t& aPosition ) const override; + long SetHitAperture( double aAperture ) override; + long SetHitDirection( const navlib::vector_t& aDirection ) override; + long SetHitLookFrom( const navlib::point_t& aPosition ) override; + long SetHitSelectionOnly( bool aSelectionOnly ) override; + long SetActiveCommand( std::string aCommandId ) override; + + long SetSettingsChanged( long aChangeNumber ) override; + long SetMotionFlag( bool aValue ) override; + long SetTransaction( long aValue ) override; + long SetCameraTarget( const navlib::point_t& aPosition ) override; + + long GetFrontView( navlib::matrix_t& aMatrix ) const override; + long GetCoordinateSystem( navlib::matrix_t& aMatrix ) const override; + long GetIsViewRotatable( navlib::bool_t& isRotatable ) const override; + +private: + EDA_DRAW_PANEL_GAL* m_viewport2D; + KIGFX::SCH_VIEW* m_view; + bool m_isMoving; + mutable double m_viewportWidth; + mutable VECTOR2D m_viewPosition; + + /** + * Trace mask used to enable or disable the trace output of this class. + * The debug output can be turned on by setting the WXTRACE environment variable to + * "KI_TRACE_NL_SCHEMATIC_PLUGIN". See the wxWidgets documentation on wxLogTrace for + * more information. + */ + static const wxChar* m_logTrace; +}; + +#endif // NL_SCHEMATIC_PLUGIN_IMPL diff --git a/eeschema/sch_base_frame.cpp b/eeschema/sch_base_frame.cpp index 2a0f5c9447..aae4e28175 100644 --- a/eeschema/sch_base_frame.cpp +++ b/eeschema/sch_base_frame.cpp @@ -42,6 +42,9 @@ #include #include +#if defined( KICAD_USE_3DCONNEXION ) +#include +#endif LIB_SYMBOL* SchGetLibSymbol( const LIB_ID& aLibId, SYMBOL_LIB_TABLE* aLibTable, SYMBOL_LIB* aCacheLib, wxWindow* aParent, bool aShowErrorMsg ) @@ -81,8 +84,9 @@ LIB_SYMBOL* SchGetLibSymbol( const LIB_ID& aLibId, SYMBOL_LIB_TABLE* aLibTable, SCH_BASE_FRAME::SCH_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aWindowType, const wxString& aTitle, const wxPoint& aPosition, const wxSize& aSize, long aStyle, const wxString& aFrameName ) : - EDA_DRAW_FRAME( aKiway, aParent, aWindowType, aTitle, aPosition, aSize, aStyle, aFrameName ), - m_base_frame_defaults( nullptr, "base_Frame_defaults" ) + EDA_DRAW_FRAME( aKiway, aParent, aWindowType, aTitle, aPosition, aSize, aStyle, + aFrameName ), + m_base_frame_defaults( nullptr, "base_Frame_defaults" ) { createCanvas(); @@ -300,6 +304,28 @@ void SCH_BASE_FRAME::createCanvas() } +void SCH_BASE_FRAME::ActivateGalCanvas() +{ + EDA_DRAW_FRAME::ActivateGalCanvas(); + +#if defined( KICAD_USE_3DCONNEXION ) + try + { + if( !m_spaceMouse ) + { + m_spaceMouse = std::make_unique(); + } + + m_spaceMouse->SetCanvas( GetCanvas() ); + } + catch( const std::system_error& e ) + { + wxLogTrace( wxT( "KI_TRACE_NAVLIB" ), e.what() ); + } +#endif +} + + void SCH_BASE_FRAME::UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete, bool aUpdateRtree ) { EDA_ITEM* parent = aItem->GetParent(); @@ -471,3 +497,28 @@ COLOR4D SCH_BASE_FRAME::GetDrawBgColor() const return GetColorSettings()->GetColor( LAYER_SCHEMATIC_BACKGROUND ); } + +void SCH_BASE_FRAME::handleActivateEvent( wxActivateEvent& aEvent ) +{ + EDA_DRAW_FRAME::handleActivateEvent( aEvent ); + +#if defined( KICAD_USE_3DCONNEXION ) + if( m_spaceMouse ) + { + m_spaceMouse->SetFocus( aEvent.GetActive() ); + } +#endif +} + + +void SCH_BASE_FRAME::handleIconizeEvent( wxIconizeEvent& aEvent ) +{ + EDA_DRAW_FRAME::handleIconizeEvent( aEvent ); + +#if defined( KICAD_USE_3DCONNEXION ) + if( m_spaceMouse && aEvent.IsIconized() ) + { + m_spaceMouse->SetFocus( false ); + } +#endif +} diff --git a/eeschema/sch_base_frame.h b/eeschema/sch_base_frame.h index 30b0fe5082..7f7481ebce 100644 --- a/eeschema/sch_base_frame.h +++ b/eeschema/sch_base_frame.h @@ -58,6 +58,10 @@ class SYMBOL_LIB_TABLE; class EESCHEMA_SETTINGS; class SYMBOL_EDITOR_SETTINGS; +#if defined( KICAD_USE_3DCONNEXION ) +class NL_SCHEMATIC_PLUGIN; +#endif + /** * Load symbol from symbol library table. * @@ -241,7 +245,13 @@ public: COLOR_SETTINGS* GetColorSettings( bool aForceRefresh = false ) const override; + void ActivateGalCanvas() override; + protected: + void handleActivateEvent( wxActivateEvent& aEvent ) override; + + void handleIconizeEvent( wxIconizeEvent& aEvent ) override; + /** * Save Symbol Library Tables to disk. * @@ -254,6 +264,11 @@ protected: /// These are only used by symbol_editor. Eeschema should be using the one inside /// the SCHEMATIC. SCHEMATIC_SETTINGS m_base_frame_defaults; + +private: +#if defined( KICAD_USE_3DCONNEXION ) + std::unique_ptr m_spaceMouse; +#endif }; #endif // SCH_BASE_FRAME_H_ diff --git a/include/eda_base_frame.h b/include/eda_base_frame.h index 3a7457c27a..5b671ad8d6 100644 --- a/include/eda_base_frame.h +++ b/include/eda_base_frame.h @@ -606,6 +606,15 @@ protected: */ void onAutoSaveTimer( wxTimerEvent& aEvent ); + + /** + * Handle a window iconize event. + * + * @param aEvent is the data for the event. + */ + virtual void handleIconizeEvent( wxIconizeEvent& aEvent ) {} + void onIconize( wxIconizeEvent& aEvent ); + /** * Return the auto save status of the application. * diff --git a/include/pcb_base_frame.h b/include/pcb_base_frame.h index c655b30515..0ff0a6a07f 100644 --- a/include/pcb_base_frame.h +++ b/include/pcb_base_frame.h @@ -392,6 +392,8 @@ protected: void handleActivateEvent( wxActivateEvent& aEvent ) override; + void handleIconizeEvent( wxIconizeEvent& aEvent ) override; + /** * Attempts to load \a aFootprintId from the footprint library table. * diff --git a/libs/kimath/include/math/util.h b/libs/kimath/include/math/util.h index c9407c2086..0aee29bd46 100644 --- a/libs/kimath/include/math/util.h +++ b/libs/kimath/include/math/util.h @@ -7,6 +7,11 @@ * * @author Tomasz Wlostowski * + * The equals() method to compare two floating point values adapted from + * AlmostEqualRelativeAndAbs() on + * https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ + * (C) Bruce Dawson subject to the Apache 2.0 license. + * * 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 2 @@ -32,6 +37,7 @@ #include #include #include +#include /** * Helper to avoid directly including wx/log.h for the templated functions in kimath @@ -113,4 +119,37 @@ int rescale( int aNumerator, int aValue, int aDenominator ); template <> int64_t rescale( int64_t aNumerator, int64_t aValue, int64_t aDenominator ); + +/** + * Template to compare two floating point values for equality within a required epsilon. + * + * @param aFirst value to compare. + * @param aSecond value to compare. + * @param aEpsilon allowed error. + * @return true if the values considered equal within the specified epsilon, otherwise false. + */ +template +typename std::enable_if::is_integer, bool>::type +equals( T aFirst, T aSecond, T aEpsilon = std::numeric_limits::epsilon() ) +{ + T diff = fabs( aFirst - aSecond ); + + if( diff < aEpsilon ) + { + return true; + } + + aFirst = fabs( aFirst ); + aSecond = fabs( aSecond ); + T largest = aFirst > aSecond ? aFirst : aSecond; + + if( diff <= largest * aEpsilon ) + { + return true; + } + + return false; +} + + #endif // UTIL_H diff --git a/libs/kimath/include/math/vector2d.h b/libs/kimath/include/math/vector2d.h index 1ae3d51a7c..811da14ef2 100644 --- a/libs/kimath/include/math/vector2d.h +++ b/libs/kimath/include/math/vector2d.h @@ -573,6 +573,28 @@ const int LexicographicalCompare( const VECTOR2& aA, const VECTOR2& aB ) } +/** + * Template to compare two VECTOR2 values for equality within a required epsilon. + * + * @param aFirst value to compare. + * @param aSecond value to compare. + * @param aEpsilon allowed error. + * @return true if the values considered equal within the specified epsilon, otherwise false. + */ +template +typename std::enable_if::is_integer, bool>::type +equals( VECTOR2 const& aFirst, VECTOR2 const& aSecond, + T aEpsilon = std::numeric_limits::epsilon() ) +{ + if( !equals( aFirst.x, aSecond.x, aEpsilon ) ) + { + return false; + } + + return equals( aFirst.y, aSecond.y, aEpsilon ); +} + + template std::ostream& operator<<( std::ostream& aStream, const VECTOR2& aVector ) { diff --git a/pcbnew/navlib/nl_pcbnew_plugin_impl.cpp b/pcbnew/navlib/nl_pcbnew_plugin_impl.cpp index b29d327d57..adf9c7ca05 100644 --- a/pcbnew/navlib/nl_pcbnew_plugin_impl.cpp +++ b/pcbnew/navlib/nl_pcbnew_plugin_impl.cpp @@ -42,55 +42,6 @@ #include #include -/** - * Template to compare two floating point values for equality within a required epsilon. - * - * @param aFirst value to compare. - * @param aSecond value to compare. - * @param aEpsilon allowed error. - * @return true if the values considered equal within the specified epsilon, otherwise false. - */ -template -bool equals( T aFirst, T aSecond, T aEpsilon = static_cast( FLT_EPSILON ) ) -{ - T diff = fabs( aFirst - aSecond ); - - if( diff < aEpsilon ) - { - return true; - } - - aFirst = fabs( aFirst ); - aSecond = fabs( aSecond ); - T largest = aFirst > aSecond ? aFirst : aSecond; - - if( diff <= largest * aEpsilon ) - { - return true; - } - - return false; -} - -/** - * Template to compare two VECTOR2 values for equality within a required epsilon. - * - * @param aFirst value to compare. - * @param aSecond value to compare. - * @param aEpsilon allowed error. - * @return true if the values considered equal within the specified epsilon, otherwise false. - */ -template -bool equals( VECTOR2 const& aFirst, VECTOR2 const& aSecond, - T aEpsilon = static_cast( FLT_EPSILON ) ) -{ - if( !equals( aFirst.x, aSecond.x, aEpsilon ) ) - { - return false; - } - - return equals( aFirst.y, aSecond.y, aEpsilon ); -} /** * Flag to enable the NL_PCBNEW_PLUGIN debug tracing. @@ -129,7 +80,7 @@ NL_PCBNEW_PLUGIN_IMPL::~NL_PCBNEW_PLUGIN_IMPL() void NL_PCBNEW_PLUGIN_IMPL::SetFocus( bool aFocus ) { - wxLogTrace( m_logTrace, "NL_PCBNEW_PLUGIN_IMPL::SetFocus %d", aFocus ); + wxLogTrace( m_logTrace, wxT( "NL_PCBNEW_PLUGIN_IMPL::SetFocus %d" ), aFocus ); NAV_3D::Write( navlib::focus_k, aFocus ); } @@ -178,7 +129,7 @@ static CATEGORY_STORE::iterator add_category( std::string aCategoryPath, void NL_PCBNEW_PLUGIN_IMPL::exportCommandsAndImages() { - wxLogTrace( m_logTrace, "NL_PCBNEW_PLUGIN_IMPL::exportCommandsAndImages" ); + wxLogTrace( m_logTrace, wxT( "NL_PCBNEW_PLUGIN_IMPL::exportCommandsAndImages" ) ); std::list actions = ACTION_MANAGER::GetActionList(); @@ -253,13 +204,13 @@ void NL_PCBNEW_PLUGIN_IMPL::exportCommandsAndImages() streamBuffer->GetBufferSize() ), 0 ); - wxLogTrace( m_logTrace, "Adding image for : %s", name ); + wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name ); vImages.push_back( std::move( tdxImage ) ); } } - wxLogTrace( m_logTrace, "Inserting command: %s, description: %s, in category: %s", name, - description, iter->first ); + 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 ) ) ); @@ -349,7 +300,8 @@ long NL_PCBNEW_PLUGIN_IMPL::SetCameraMatrix( const navlib::matrix_t& matrix ) long result = 0; VECTOR2D viewPos( matrix.m4x4[3][0], matrix.m4x4[3][1] ); - if( !equals( m_view->GetCenter(), m_viewPosition ) ) + if( !equals( m_view->GetCenter(), m_viewPosition, + static_cast( FLT_EPSILON ) ) ) { m_view->SetCenter( viewPos + m_view->GetCenter() - m_viewPosition ); result = navlib::make_result_code( navlib::navlib_errc::error ); @@ -385,7 +337,7 @@ long NL_PCBNEW_PLUGIN_IMPL::SetViewExtents( const navlib::box_t& extents ) double scale = width / m_viewportWidth * m_view->GetScale(); m_view->SetScale( scale, m_view->GetCenter() ); - if( !equals( m_view->GetScale(), scale ) ) + if( !equals( m_view->GetScale(), scale, static_cast( FLT_EPSILON ) ) ) { result = navlib::make_result_code( navlib::navlib_errc::error ); } diff --git a/pcbnew/pcb_base_frame.cpp b/pcbnew/pcb_base_frame.cpp index 6d4db2404e..7ad253341e 100644 --- a/pcbnew/pcb_base_frame.cpp +++ b/pcbnew/pcb_base_frame.cpp @@ -119,6 +119,19 @@ void PCB_BASE_FRAME::handleActivateEvent( wxActivateEvent& aEvent ) } +void PCB_BASE_FRAME::handleIconizeEvent( wxIconizeEvent& aEvent ) +{ + EDA_DRAW_FRAME::handleIconizeEvent( aEvent ); + +#if defined( KICAD_USE_3DCONNEXION ) + if( m_spaceMouse != nullptr && aEvent.IsIconized() ) + { + m_spaceMouse->SetFocus( false ); + } +#endif +} + + EDA_3D_VIEWER_FRAME* PCB_BASE_FRAME::Get3DViewerFrame() { wxWindow* frame = FindWindowByName( QUALIFIED_VIEWER3D_FRAMENAME( this ) );