KiCad PCB EDA Suite
Loading...
Searching...
No Matches
nl_pl_editor_plugin_impl.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2024 3Dconnexion
5 * Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
22
23// KiCAD includes
25#include <pl_editor_frame.h>
26#include <bitmaps.h>
28#include <view/view.h>
30#include <tool/action_manager.h>
31#include <tool/tool_action.h>
32#include <tool/tool_manager.h>
33
34// stdlib
35#include <list>
36#include <map>
37#include <memory>
38#include <utility>
39#include <vector>
40#include <cfloat>
41
42#include <wx/log.h>
43#include <wx/mstream.h>
44
45
53const wxChar* NL_PL_EDITOR_PLUGIN_IMPL::m_logTrace = wxT( "KI_TRACE_NL_PL_EDITOR_PLUGIN" );
54
55
57{
58 PutProfileHint( "KiCAD Datasheet Editor" );
59}
60
61
63{
64 std::error_code m_errCode;
65 EnableNavigation( false, m_errCode );
66 if( m_errCode.value() != 0 )
67 {
68 wxLogTrace( wxT( "KI_TRACE_NAVLIB" ),
69 wxT( "Error occured when calling EnableNavigation. Error code: %d" ),
70 m_errCode.value() );
71 }
72}
73
74
76{
77 m_viewport2D = aViewport;
78
79 if( m_viewport2D == nullptr )
80 {
81 return;
82 }
83
85
86 if( m_view == nullptr )
87 {
88 return;
89 }
90
92
93 if( !IsEnabled() )
94 {
95 // Use the default settings for the connexion to the 3DMouse navigation
96 // They are use a single-threaded threading model and row vectors.
97 EnableNavigation( true );
98
99 // Use the SpaceMouse internal timing source for the frame rate.
100 PutFrameTimingSource( TimingSource::SpaceMouse );
101
103 }
104}
105
106
108{
109 wxLogTrace( m_logTrace, wxT( "NL_PL_EDITOR_PLUGIN_IMPL::SetFocus %d" ), aFocus );
110 NAV_3D::Write( navlib::focus_k, aFocus );
111}
112
113// temporary store for the command categories
114using CATEGORY_STORE = std::map<std::string, TDx::CCommandTreeNode*, std::less<>>;
115
116
125static void add_category( const std::string& aCategoryPath, CATEGORY_STORE& aCategoryStore )
126{
127 using TDx::SpaceMouse::CCategory;
128
129 auto parent_iter = aCategoryStore.begin();
130 std::string::size_type pos = aCategoryPath.find_last_of( '.' );
131
132 if( pos != std::string::npos )
133 {
134 std::string parentPath = aCategoryPath.substr( 0, pos );
135
136 if( !aCategoryStore.contains( parentPath ) )
137 {
138 add_category( parentPath, aCategoryStore );
139 parent_iter = aCategoryStore.find( parentPath );
140 }
141 }
142
143 std::string name = aCategoryPath.substr( pos + 1 );
144 auto categoryNode = std::make_unique<CCategory>( aCategoryPath.c_str(), name.c_str() );
145
146 aCategoryStore.try_emplace( aCategoryStore.end(), aCategoryPath, categoryNode.get() );
147
148 parent_iter->second->push_back( std::move( categoryNode ) );
149}
150
151
160static void try_add_category( const std::string& aCategoryPath, CATEGORY_STORE& aCategoryStore )
161{
162 if( !aCategoryStore.contains( aCategoryPath ) )
163 {
164 add_category( aCategoryPath, aCategoryStore );
165 }
166}
167
168
170{
171 wxLogTrace( m_logTrace, wxT( "NL_PL_EDITOR_PLUGIN_IMPL::exportCommandsAndImages" ) );
172
173 std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
174
175 if( actions.empty() )
176 return;
177
178 using TDx::SpaceMouse::CCommand;
179 using TDx::SpaceMouse::CCommandSet;
180
181 // The root action set node
182 CCommandSet commandSet( "PL_EDITOR", "Drawing Sheet Editor" );
183
184 // Activate the command set
185 NAV_3D::PutActiveCommands( commandSet.GetId() );
186
187 // temporary store for the categories initialized with action set
188 CATEGORY_STORE categoryStore{ CATEGORY_STORE::value_type( ".", &commandSet ) };
189
190 std::vector<TDx::CImage> vImages;
191
192 for( const auto action : actions )
193 {
194 std::string label = action->GetMenuLabel().ToStdString();
195
196 if( label.empty() )
197 continue;
198
199 std::string name = action->GetName();
200
201 // Do no export commands for the 3DViewer app.
202
203 if( name.rfind( "3DViewer.", 0 ) == 0 )
204 continue;
205
206 std::string strCategory = action->GetToolName();
207 std::string description = action->GetDescription().ToStdString();
208
209 try_add_category( strCategory, categoryStore );
210 CATEGORY_STORE::iterator iter = categoryStore.find( strCategory );
211
212 // Arbitrary 8-bit data stream
213 wxMemoryOutputStream imageStream;
214
215 if( action->GetIcon() != BITMAPS::INVALID_BITMAP )
216 {
217 wxImage image = KiBitmap( action->GetIcon() ).ConvertToImage();
218 image.SaveFile( imageStream, wxBitmapType::wxBITMAP_TYPE_PNG );
219 image.Destroy();
220
221 if( imageStream.GetSize() )
222 {
223 const wxStreamBuffer* streamBuffer = imageStream.GetOutputStreamBuffer();
224 TDx::CImage tdxImage = TDx::CImage::FromData( "", 0, name.c_str() );
225 tdxImage.AssignImage(
226 std::string( std::bit_cast<const char*>( streamBuffer->GetBufferStart() ),
227 streamBuffer->GetBufferSize() ),
228 0 );
229
230 wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name );
231 vImages.push_back( std::move( tdxImage ) );
232 }
233 }
234
235 wxLogTrace( m_logTrace, wxT( "Inserting command: %s, description: %s, in category: %s" ),
236 name, description, iter->first );
237
238 iter->second->push_back(
239 CCommand( std::move( name ), std::move( label ), std::move( description ) ) );
240 }
241
242 NAV_3D::AddCommandSet( commandSet );
243 NAV_3D::AddImages( vImages );
244}
245
246
247long NL_PL_EDITOR_PLUGIN_IMPL::GetCameraMatrix( navlib::matrix_t& matrix ) const
248{
249 if( m_view == nullptr )
250 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
251
253
254 double x = m_view->IsMirroredX() ? -1 : 1;
255 double y = m_view->IsMirroredY() ? 1 : -1;
256
257 // x * y * z = 1 for a right-handed coordinate system.
258 double z = x * y;
259
260 // Note: the connexion has been configured as row vectors, the coordinate system is defined in
261 // NL_PL_EDITOR_PLUGIN_IMPL::GetCoordinateSystem and the front view in NL_PL_EDITOR_PLUGIN_IMPL::GetFrontView.
262 matrix = { { { x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, m_viewPosition.x, m_viewPosition.y, 0,
263 1 } } };
264 return 0;
265}
266
267
268long NL_PL_EDITOR_PLUGIN_IMPL::GetPointerPosition( navlib::point_t& position ) const
269{
270 if( m_view == nullptr )
271 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
272
274
275 position.x = mouse_pointer.x;
276 position.y = mouse_pointer.y;
277 position.z = 0;
278
279 return 0;
280}
281
282
283long NL_PL_EDITOR_PLUGIN_IMPL::GetViewExtents( navlib::box_t& extents ) const
284{
285 if( m_view == nullptr )
286 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
287
288 double scale = m_viewport2D->GetGAL()->GetWorldScale();
289 BOX2D box = m_view->GetViewport();
290
292
293 extents.min_x = -box.GetWidth() / 2.0;
294 extents.min_y = -box.GetHeight() / 2.0;
295 extents.min_z = m_viewport2D->GetGAL()->GetMinDepth() / scale;
296 extents.max_x = box.GetWidth() / 2.0;
297 extents.max_y = box.GetHeight() / 2.0;
298 extents.max_z = m_viewport2D->GetGAL()->GetMaxDepth() / scale;
299 return 0;
300}
301
302
303long NL_PL_EDITOR_PLUGIN_IMPL::GetIsViewPerspective( navlib::bool_t& perspective ) const
304{
305 perspective = false;
306
307 return 0;
308}
309
310
311long NL_PL_EDITOR_PLUGIN_IMPL::SetCameraMatrix( const navlib::matrix_t& matrix )
312{
313 if( m_view == nullptr )
314 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
315
316 long result = 0;
317 VECTOR2D viewPos( matrix.m4x4[3][0], matrix.m4x4[3][1] );
318
320 static_cast<VECTOR2D::coord_type>( FLT_EPSILON ) ) )
321 {
323 result = navlib::make_result_code( navlib::navlib_errc::error );
324 }
325 else
326 {
327 m_view->SetCenter( viewPos );
328 }
329
330 m_viewPosition = viewPos;
331
332 return result;
333}
334
335
336long NL_PL_EDITOR_PLUGIN_IMPL::SetViewExtents( const navlib::box_t& extents )
337{
338 if( m_view == nullptr )
339 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
340
341 long result = 0;
342
344 result = navlib::make_result_code( navlib::navlib_errc::error );
345
346 double width = m_viewportWidth;
347 m_viewportWidth = extents.max_x - extents.min_x;
348
349 double scale = width / m_viewportWidth * m_view->GetScale();
351
352 if( !equals( m_view->GetScale(), scale, static_cast<double>( FLT_EPSILON ) ) )
353 result = navlib::make_result_code( navlib::navlib_errc::error );
354
355 return result;
356}
357
358
360{
361 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
362}
363
364
365long NL_PL_EDITOR_PLUGIN_IMPL::SetViewFrustum( const navlib::frustum_t& frustum )
366{
367 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
368}
369
370
371long NL_PL_EDITOR_PLUGIN_IMPL::GetModelExtents( navlib::box_t& extents ) const
372{
373 if( m_view == nullptr )
374 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
375
376 BOX2I box = static_cast<PL_EDITOR_FRAME*>( m_viewport2D->GetParent() )->GetDocumentExtents();
377 box.Normalize();
378
379 double half_depth = 0.1 / m_viewport2D->GetGAL()->GetWorldScale();
380
381 if( box.GetWidth() == 0 && box.GetHeight() == 0 )
382 half_depth = 0;
383
384 extents.min_x = static_cast<double>( box.GetOrigin().x );
385 extents.min_y = static_cast<double>( box.GetOrigin().y );
386 extents.min_z = -half_depth;
387 extents.max_x = static_cast<double>( box.GetEnd().x );
388 extents.max_y = static_cast<double>( box.GetEnd().y );
389 extents.max_z = half_depth;
390
391 return 0;
392}
393
394
395long NL_PL_EDITOR_PLUGIN_IMPL::GetCoordinateSystem( navlib::matrix_t& matrix ) const
396{
397 // The coordinate system is defined as x to the right, y down and z into the screen.
398 matrix = { { { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 } } };
399 return 0;
400}
401
402
403long NL_PL_EDITOR_PLUGIN_IMPL::GetFrontView( navlib::matrix_t& matrix ) const
404{
405 matrix = { { { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 } } };
406 return 0;
407}
408
409
411{
412 empty = true;
413 return 0;
414}
415
416
417long NL_PL_EDITOR_PLUGIN_IMPL::GetIsViewRotatable( navlib::bool_t& isRotatable ) const
418{
419 isRotatable = false;
420 return 0;
421}
422
423
425{
426 if( commandId.empty() )
427 return 0;
428
429 if(m_viewport2D == nullptr)
430 {
431 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
432 }
433
434 wxWindow* parent = m_viewport2D->GetParent();
435
436 // Only allow command execution if the window is enabled. i.e. there is not a modal dialog
437 // currently active.
438 if( parent == nullptr || !parent->IsEnabled() )
439 {
440 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
441 }
442
443 TOOL_MANAGER* tool_manager = dynamic_cast<TOOLS_HOLDER*>( parent )->GetToolManager();
444
445 // Only allow for command execution if the tool manager is accessible.
446 if( tool_manager == nullptr )
447 {
448 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
449 }
450
451 for( std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
452 const auto action : actions )
453 {
454 if( action == nullptr )
455 {
456 continue;
457 }
458
459 if( commandId == action->GetName() )
460 {
461 // Get the selection to use to test if the action is enabled
462 const SELECTION& sel = tool_manager->GetToolHolder()->GetCurrentSelection();
463
464 const ACTION_CONDITIONS* aCond =
465 tool_manager->GetActionManager()->GetCondition( *action );
466
467 if( aCond == nullptr )
468 {
469 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
470 }
471
472 aCond->enableCondition( sel );
473 tool_manager->RunAction( *action );
474 break;
475 }
476 }
477
478 return 0;
479}
480
481
483{
484 return 0;
485}
486
487
489{
490 m_isMoving = value;
491
492 return 0;
493}
494
495
497{
498 if( value == 0L )
500
501 return 0;
502}
503
504
506{
507 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
508}
509
510
511long NL_PL_EDITOR_PLUGIN_IMPL::GetViewFrustum( navlib::frustum_t& frustum ) const
512{
513 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
514}
515
516
517long NL_PL_EDITOR_PLUGIN_IMPL::GetSelectionExtents( navlib::box_t& extents ) const
518{
519 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
520}
521
522
523long NL_PL_EDITOR_PLUGIN_IMPL::GetSelectionTransform( navlib::matrix_t& transform ) const
524{
525 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
526}
527
528
529long NL_PL_EDITOR_PLUGIN_IMPL::SetSelectionTransform( const navlib::matrix_t& matrix )
530{
531 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
532}
533
534
535long NL_PL_EDITOR_PLUGIN_IMPL::GetPivotPosition( navlib::point_t& position ) const
536{
537 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
538}
539
540
541long NL_PL_EDITOR_PLUGIN_IMPL::IsUserPivot( navlib::bool_t& userPivot ) const
542{
543 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
544}
545
546
547long NL_PL_EDITOR_PLUGIN_IMPL::SetPivotPosition( const navlib::point_t& position )
548{
549 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
550}
551
552
553long NL_PL_EDITOR_PLUGIN_IMPL::GetPivotVisible( navlib::bool_t& visible ) const
554{
555 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
556}
557
558
560{
561 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
562}
563
564
565long NL_PL_EDITOR_PLUGIN_IMPL::GetHitLookAt( navlib::point_t& position ) const
566{
567 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
568}
569
570
572{
573 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
574}
575
576
577long NL_PL_EDITOR_PLUGIN_IMPL::SetHitDirection( const navlib::vector_t& direction )
578{
579 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
580}
581
582
583long NL_PL_EDITOR_PLUGIN_IMPL::SetHitLookFrom( const navlib::point_t& eye )
584{
585 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
586}
587
588
590{
591 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
592}
593
594
595long NL_PL_EDITOR_PLUGIN_IMPL::SetCameraTarget( const navlib::point_t& position )
596{
597 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
598}
const char * name
Definition: DXF_plotter.cpp:57
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:104
const ACTION_CONDITIONS * GetCondition(const TOOL_ACTION &aAction) const
Get the conditions to use for a specific tool action.
static std::list< TOOL_ACTION * > & GetActionList()
Return list of TOOL_ACTIONs.
constexpr const Vec GetEnd() const
Definition: box2.h:212
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:146
constexpr size_type GetWidth() const
Definition: box2.h:214
constexpr size_type GetHeight() const
Definition: box2.h:215
constexpr const Vec & GetOrigin() const
Definition: box2.h:210
KIGFX::VIEW_CONTROLS * GetViewControls() const
Return a pointer to the #VIEW_CONTROLS instance used in the panel.
virtual KIGFX::VIEW * GetView() const
Return a pointer to the #VIEW instance used in the panel.
void ForceRefresh()
Force a redraw.
KIGFX::GAL * GetGAL() const
Return a pointer to the GAL instance used in the panel.
double GetMaxDepth() const
double GetMinDepth() const
double GetWorldScale() const
Get the world scale.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
double GetScale() const
Definition: view.h:277
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:547
const VECTOR2D & GetCenter() const
Return the center point of this VIEW (in world space coordinates).
Definition: view.h:347
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:587
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:251
bool IsMirroredY() const
Return true if view is flipped across the Y axis.
Definition: view.h:259
const BOX2D & GetBoundary() const
Definition: view.h:306
void SetCenter(const VECTOR2D &aCenter)
Set the center point of the VIEW (i.e.
Definition: view.cpp:613
long SetViewExtents(const navlib::box_t &aExtents) override
long GetPivotPosition(navlib::point_t &aPosition) const override
long GetViewFOV(double &aFov) const override
long SetCameraTarget(const navlib::point_t &aPosition) override
long SetPivotPosition(const navlib::point_t &aPosition) override
long GetCameraMatrix(navlib::matrix_t &aMatrix) const override
long GetViewFrustum(navlib::frustum_t &aFrustum) const override
long SetHitDirection(const navlib::vector_t &aDirection) override
long SetHitLookFrom(const navlib::point_t &aPosition) override
long SetHitSelectionOnly(bool aSelectionOnly) override
long SetPivotVisible(bool aVisible) override
void SetCanvas(EDA_DRAW_PANEL_GAL *aViewport)
Sets the viewport controlled by the SpaceMouse.
long SetActiveCommand(std::string aCommandId) override
long SetCameraMatrix(const navlib::matrix_t &aMatrix) override
long SetSelectionTransform(const navlib::matrix_t &aMatrix) override
long GetViewExtents(navlib::box_t &aExtents) const override
long SetSettingsChanged(long aChangeNumber) override
long SetHitAperture(double aAperture) override
long GetHitLookAt(navlib::point_t &aPosition) const override
long GetPointerPosition(navlib::point_t &aPosition) const override
void exportCommandsAndImages()
Export the invocable actions and images to the 3Dconnexion UI.
void SetFocus(bool aFocus)
Set the connection to the 3Dconnexion driver to the focus state so that 3DMouse data is routed here.
long SetViewFrustum(const navlib::frustum_t &aFrustum) override
long GetIsSelectionEmpty(navlib::bool_t &aEmpty) const override
long GetIsViewRotatable(navlib::bool_t &isRotatable) const override
long GetFrontView(navlib::matrix_t &aMatrix) const override
long SetViewFOV(double aFov) override
long SetMotionFlag(bool aValue) override
long GetSelectionTransform(navlib::matrix_t &aTransform) const override
long IsUserPivot(navlib::bool_t &aUserPivot) const override
long GetModelExtents(navlib::box_t &aExtents) const override
long GetCoordinateSystem(navlib::matrix_t &aMatrix) const override
long GetPivotVisible(navlib::bool_t &aVisible) const override
long SetTransaction(long aValue) override
long GetSelectionExtents(navlib::box_t &aExtents) const override
NL_PL_EDITOR_PLUGIN_IMPL()
Initializes a new instance of the NL_PL_EDITOR_PLUGIN_IMPL.
long GetIsViewPerspective(navlib::bool_t &aPerspective) const override
The main window used in the drawing sheet editor.
virtual SELECTION & GetCurrentSelection()
Get the current selection from the canvas area.
Definition: tools_holder.h:98
Master controller class:
Definition: tool_manager.h:62
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
TOOLS_HOLDER * GetToolHolder() const
Definition: tool_manager.h:402
ACTION_MANAGER * GetActionManager() const
Definition: tool_manager.h:302
double coord_type
Definition: vector2d.h:74
static bool empty(const wxTextEntryBase *aCtrl)
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
bool equals(glm::mat< L, C, T, Q > const &aFirst, glm::mat< L, C, T, Q > const &aSecond, T aEpsilon=static_cast< T >(FLT_EPSILON *10))
Template to compare two glm::mat<T> values for equality within a required epsilon.
std::map< std::string, TDx::CCommandTreeNode * > CATEGORY_STORE
static void try_add_category(const std::string &aCategoryPath, CATEGORY_STORE &aCategoryStore)
add_category wrapper.
static void try_add_category(const std::string &aCategoryPath, CATEGORY_STORE &aCategoryStore)
add_category wrapper.
static void add_category(const std::string &aCategoryPath, CATEGORY_STORE &aCategoryStore)
Add a category to the store.
const int scale
Functors that can be used to figure out how the action controls should be displayed in the UI and if ...
SELECTION_CONDITION enableCondition
Returns true if the UI control should be enabled.
WX_VIEW_CONTROLS class definition.