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 The 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 if( parent_iter != aCategoryStore.end() )
149 parent_iter->second->push_back( std::move( categoryNode ) );
150}
151
152
161static void try_add_category( const std::string& aCategoryPath, CATEGORY_STORE& aCategoryStore )
162{
163 if( !aCategoryStore.contains( aCategoryPath ) )
164 {
165 add_category( aCategoryPath, aCategoryStore );
166 }
167}
168
169
171{
172 wxLogTrace( m_logTrace, wxT( "NL_PL_EDITOR_PLUGIN_IMPL::exportCommandsAndImages" ) );
173
174 std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
175
176 if( actions.empty() )
177 return;
178
179 using TDx::SpaceMouse::CCommand;
180 using TDx::SpaceMouse::CCommandSet;
181
182 // The root action set node
183 CCommandSet commandSet( "PL_EDITOR", "Drawing Sheet Editor" );
184
185 // Activate the command set
186 NAV_3D::PutActiveCommands( commandSet.GetId() );
187
188 // temporary store for the categories initialized with action set
189 CATEGORY_STORE categoryStore{ CATEGORY_STORE::value_type( ".", &commandSet ) };
190
191 std::vector<TDx::CImage> vImages;
192
193 for( const auto action : actions )
194 {
195 std::string label = action->GetMenuLabel().ToStdString();
196
197 if( label.empty() )
198 continue;
199
200 std::string name = action->GetName();
201
202 // Do no export commands for the 3DViewer app.
203
204 if( name.rfind( "3DViewer.", 0 ) == 0 )
205 continue;
206
207 std::string strCategory = action->GetToolName();
208 std::string description = action->GetDescription().ToStdString();
209
210 try_add_category( strCategory, categoryStore );
211 CATEGORY_STORE::iterator iter = categoryStore.find( strCategory );
212
213 wxCHECK2( iter != categoryStore.end(), continue );
214
215 // Arbitrary 8-bit data stream
216 wxMemoryOutputStream imageStream;
217
218 if( action->GetIcon() != BITMAPS::INVALID_BITMAP )
219 {
220 wxImage image = KiBitmap( action->GetIcon() ).ConvertToImage();
221 image.SaveFile( imageStream, wxBitmapType::wxBITMAP_TYPE_PNG );
222 image.Destroy();
223
224 if( imageStream.GetSize() )
225 {
226 const wxStreamBuffer* streamBuffer = imageStream.GetOutputStreamBuffer();
227 TDx::CImage tdxImage = TDx::CImage::FromData( "", 0, name.c_str() );
228 tdxImage.AssignImage(
229 std::string( std::bit_cast<const char*>( streamBuffer->GetBufferStart() ),
230 streamBuffer->GetBufferSize() ),
231 0 );
232
233 wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name );
234 vImages.push_back( std::move( tdxImage ) );
235 }
236 }
237
238 wxLogTrace( m_logTrace, wxT( "Inserting command: %s, description: %s, in category: %s" ),
239 name, description, iter->first );
240
241 iter->second->push_back( CCommand( std::move( name ), std::move( label ),
242 std::move( description ) ) );
243 }
244
245 NAV_3D::AddCommandSet( commandSet );
246 NAV_3D::AddImages( vImages );
247}
248
249
250long NL_PL_EDITOR_PLUGIN_IMPL::GetCameraMatrix( navlib::matrix_t& matrix ) const
251{
252 if( m_view == nullptr )
253 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
254
256
257 double x = m_view->IsMirroredX() ? -1 : 1;
258 double y = m_view->IsMirroredY() ? 1 : -1;
259
260 // x * y * z = 1 for a right-handed coordinate system.
261 double z = x * y;
262
263 // Note: the connexion has been configured as row vectors, the coordinate system is defined in
264 // NL_PL_EDITOR_PLUGIN_IMPL::GetCoordinateSystem and the front view in NL_PL_EDITOR_PLUGIN_IMPL::GetFrontView.
265 matrix = { { { x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, m_viewPosition.x, m_viewPosition.y, 0,
266 1 } } };
267 return 0;
268}
269
270
271long NL_PL_EDITOR_PLUGIN_IMPL::GetPointerPosition( navlib::point_t& position ) const
272{
273 if( m_view == nullptr )
274 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
275
277
278 position.x = mouse_pointer.x;
279 position.y = mouse_pointer.y;
280 position.z = 0;
281
282 return 0;
283}
284
285
286long NL_PL_EDITOR_PLUGIN_IMPL::GetViewExtents( navlib::box_t& extents ) const
287{
288 if( m_view == nullptr )
289 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
290
291 double scale = m_viewport2D->GetGAL()->GetWorldScale();
292 BOX2D box = m_view->GetViewport();
293
295
296 extents.min_x = -box.GetWidth() / 2.0;
297 extents.min_y = -box.GetHeight() / 2.0;
298 extents.min_z = m_viewport2D->GetGAL()->GetMinDepth() / scale;
299 extents.max_x = box.GetWidth() / 2.0;
300 extents.max_y = box.GetHeight() / 2.0;
301 extents.max_z = m_viewport2D->GetGAL()->GetMaxDepth() / scale;
302 return 0;
303}
304
305
306long NL_PL_EDITOR_PLUGIN_IMPL::GetIsViewPerspective( navlib::bool_t& perspective ) const
307{
308 perspective = false;
309
310 return 0;
311}
312
313
314long NL_PL_EDITOR_PLUGIN_IMPL::SetCameraMatrix( const navlib::matrix_t& matrix )
315{
316 if( m_view == nullptr )
317 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
318
319 long result = 0;
320 VECTOR2D viewPos( matrix.m4x4[3][0], matrix.m4x4[3][1] );
321
323 static_cast<VECTOR2D::coord_type>( FLT_EPSILON ) ) )
324 {
326 result = navlib::make_result_code( navlib::navlib_errc::error );
327 }
328 else
329 {
330 m_view->SetCenter( viewPos );
331 }
332
333 m_viewPosition = viewPos;
334
335 return result;
336}
337
338
339long NL_PL_EDITOR_PLUGIN_IMPL::SetViewExtents( const navlib::box_t& extents )
340{
341 if( m_view == nullptr )
342 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
343
344 long result = 0;
345
347 result = navlib::make_result_code( navlib::navlib_errc::error );
348
349 double width = m_viewportWidth;
350 m_viewportWidth = extents.max_x - extents.min_x;
351
352 double scale = width / m_viewportWidth * m_view->GetScale();
354
355 if( !equals( m_view->GetScale(), scale, static_cast<double>( FLT_EPSILON ) ) )
356 result = navlib::make_result_code( navlib::navlib_errc::error );
357
358 return result;
359}
360
361
363{
364 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
365}
366
367
368long NL_PL_EDITOR_PLUGIN_IMPL::SetViewFrustum( const navlib::frustum_t& frustum )
369{
370 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
371}
372
373
374long NL_PL_EDITOR_PLUGIN_IMPL::GetModelExtents( navlib::box_t& extents ) const
375{
376 if( m_view == nullptr )
377 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
378
379 BOX2I box = static_cast<PL_EDITOR_FRAME*>( m_viewport2D->GetParent() )->GetDocumentExtents();
380 box.Normalize();
381
382 double half_depth = 0.1 / m_viewport2D->GetGAL()->GetWorldScale();
383
384 if( box.GetWidth() == 0 && box.GetHeight() == 0 )
385 half_depth = 0;
386
387 extents.min_x = static_cast<double>( box.GetOrigin().x );
388 extents.min_y = static_cast<double>( box.GetOrigin().y );
389 extents.min_z = -half_depth;
390 extents.max_x = static_cast<double>( box.GetEnd().x );
391 extents.max_y = static_cast<double>( box.GetEnd().y );
392 extents.max_z = half_depth;
393
394 return 0;
395}
396
397
398long NL_PL_EDITOR_PLUGIN_IMPL::GetCoordinateSystem( navlib::matrix_t& matrix ) const
399{
400 // The coordinate system is defined as x to the right, y down and z into the screen.
401 matrix = { { { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 } } };
402 return 0;
403}
404
405
406long NL_PL_EDITOR_PLUGIN_IMPL::GetFrontView( navlib::matrix_t& matrix ) const
407{
408 matrix = { { { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 } } };
409 return 0;
410}
411
412
414{
415 empty = true;
416 return 0;
417}
418
419
420long NL_PL_EDITOR_PLUGIN_IMPL::GetIsViewRotatable( navlib::bool_t& isRotatable ) const
421{
422 isRotatable = false;
423 return 0;
424}
425
426
428{
429 if( commandId.empty() )
430 return 0;
431
432 if( m_viewport2D == nullptr )
433 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
434
435 wxWindow* parent = m_viewport2D->GetParent();
436
437 // Only allow command execution if the window is enabled. i.e. there is not a modal dialog
438 // currently active.
439 if( !parent || !parent->IsEnabled() )
440 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
441
442 TOOLS_HOLDER* tools_holder = dynamic_cast<TOOLS_HOLDER*>( parent );
443 TOOL_MANAGER* tool_manager = tools_holder ? tools_holder->GetToolManager() : nullptr;
444
445 // Only allow for command execution if the tool manager is accessible.
446 if( !tool_manager )
447 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
448
449 for( std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList(); const auto action : actions )
450 {
451 if( action == nullptr )
452 continue;
453
454 if( commandId == action->GetName() )
455 {
456 // Get the selection to use to test if the action is enabled
457 const SELECTION& sel = tool_manager->GetToolHolder()->GetCurrentSelection();
458
459 const ACTION_CONDITIONS* aCond = tool_manager->GetActionManager()->GetCondition( *action );
460
461 if( aCond == nullptr )
462 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
463
464 aCond->enableCondition( sel );
465 tool_manager->RunAction( *action );
466 break;
467 }
468 }
469
470 return 0;
471}
472
473
475{
476 return 0;
477}
478
479
481{
482 m_isMoving = value;
483
484 return 0;
485}
486
487
489{
490 if( value == 0L )
492
493 return 0;
494}
495
496
498{
499 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
500}
501
502
503long NL_PL_EDITOR_PLUGIN_IMPL::GetViewFrustum( navlib::frustum_t& frustum ) const
504{
505 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
506}
507
508
509long NL_PL_EDITOR_PLUGIN_IMPL::GetSelectionExtents( navlib::box_t& extents ) const
510{
511 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
512}
513
514
515long NL_PL_EDITOR_PLUGIN_IMPL::GetSelectionTransform( navlib::matrix_t& transform ) const
516{
517 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
518}
519
520
521long NL_PL_EDITOR_PLUGIN_IMPL::SetSelectionTransform( const navlib::matrix_t& matrix )
522{
523 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
524}
525
526
527long NL_PL_EDITOR_PLUGIN_IMPL::GetPivotPosition( navlib::point_t& position ) const
528{
529 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
530}
531
532
533long NL_PL_EDITOR_PLUGIN_IMPL::IsUserPivot( navlib::bool_t& userPivot ) const
534{
535 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
536}
537
538
539long NL_PL_EDITOR_PLUGIN_IMPL::SetPivotPosition( const navlib::point_t& position )
540{
541 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
542}
543
544
545long NL_PL_EDITOR_PLUGIN_IMPL::GetPivotVisible( navlib::bool_t& visible ) const
546{
547 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
548}
549
550
552{
553 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
554}
555
556
557long NL_PL_EDITOR_PLUGIN_IMPL::GetHitLookAt( navlib::point_t& position ) const
558{
559 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
560}
561
562
564{
565 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
566}
567
568
569long NL_PL_EDITOR_PLUGIN_IMPL::SetHitDirection( const navlib::vector_t& direction )
570{
571 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
572}
573
574
575long NL_PL_EDITOR_PLUGIN_IMPL::SetHitLookFrom( const navlib::point_t& eye )
576{
577 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
578}
579
580
582{
583 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
584}
585
586
587long NL_PL_EDITOR_PLUGIN_IMPL::SetCameraTarget( const navlib::point_t& position )
588{
589 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
590}
const char * name
Definition: DXF_plotter.cpp:62
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:276
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:530
const VECTOR2D & GetCenter() const
Return the center point of this VIEW (in world space coordinates).
Definition: view.h:346
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:570
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:250
bool IsMirroredY() const
Return true if view is flipped across the Y axis.
Definition: view.h:258
const BOX2D & GetBoundary() const
Definition: view.h:305
void SetCenter(const VECTOR2D &aCenter)
Set the center point of the VIEW (i.e.
Definition: view.cpp:596
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.
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
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:406
ACTION_MANAGER * GetActionManager() const
Definition: tool_manager.h:306
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.