From 381cb92f0a95b98abbb82adc737c5410aaa9225b Mon Sep 17 00:00:00 2001 From: Pieter Hijma Date: Sat, 5 Apr 2025 13:47:00 +0200 Subject: [PATCH] [Core] Add visibility toggling to ViewProvider With this extension of the API, view providers can indicate whether document objects should be able to be toggled for visibility. There is both a C++ and Python interface, idiomatic for FreeCAD code. --- src/Gui/FreeCADGuiInit.py | 7 ++++++- src/Gui/Tree.cpp | 4 +++- src/Gui/ViewProvider.cpp | 1 + src/Gui/ViewProvider.h | 27 +++++++++++++++++++++++++++ src/Gui/ViewProvider.pyi | 10 ++++++++++ src/Gui/ViewProviderPyImp.cpp | 31 +++++++++++++++++++++++++++++++ 6 files changed, 78 insertions(+), 2 deletions(-) diff --git a/src/Gui/FreeCADGuiInit.py b/src/Gui/FreeCADGuiInit.py index 97f4910d43..5c027d838e 100644 --- a/src/Gui/FreeCADGuiInit.py +++ b/src/Gui/FreeCADGuiInit.py @@ -29,7 +29,7 @@ # imports the one and only import FreeCAD, FreeCADGui -from enum import IntEnum +from enum import IntEnum, Enum # shortcuts Gui = FreeCADGui @@ -52,6 +52,11 @@ class SelectionStyle(IntEnum): NormalSelection = 0 GreedySelection = 1 +# The values must match with that of the Python enum class in ViewProvider.pyi +class ToggleVisibilityMode(Enum): + CanToggleVisibility = "CanToggleVisibility" + NoToggleVisibility = "NoToggleVisibility" + Gui.Selection.SelectionStyle = SelectionStyle # Important definitions diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index 77adeb35ee..4cedaba752 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -5534,7 +5534,9 @@ void DocumentObjectItem::testStatus(bool resetStatus, QIcon& icon1, QIcon& icon2 QPainter pt; pt.begin(&px); pt.setPen(Qt::NoPen); - pt.drawPixmap(0, 0, px_org.width(), px_org.height(), (currentStatus & Status::Visible) ? pxVisible : pxInvisible); + if (object()->canToggleVisibility()) { + pt.drawPixmap(0, 0, px_org.width(), px_org.height(), (currentStatus & Status::Visible) ? pxVisible : pxInvisible); + } pt.drawPixmap(px_org.width() + spacing, 0, px_org.width(), px_org.height(), px_org); pt.end(); diff --git a/src/Gui/ViewProvider.cpp b/src/Gui/ViewProvider.cpp index 2acaebea60..15a30b7adf 100644 --- a/src/Gui/ViewProvider.cpp +++ b/src/Gui/ViewProvider.cpp @@ -93,6 +93,7 @@ PROPERTY_SOURCE_ABSTRACT(Gui::ViewProvider, App::TransactionalObject) ViewProvider::ViewProvider() : overrideMode("As Is") + , toggleVisibilityMode(ToggleVisibilityMode::CanToggleVisibility) { setStatus(UpdateData, true); diff --git a/src/Gui/ViewProvider.h b/src/Gui/ViewProvider.h index fd1aeb3d06..a376491ebe 100644 --- a/src/Gui/ViewProvider.h +++ b/src/Gui/ViewProvider.h @@ -121,6 +121,11 @@ class GuiExport ViewProvider : public App::TransactionalObject PROPERTY_HEADER_WITH_OVERRIDE(Gui::ViewProvider); public: + enum class ToggleVisibilityMode : bool { + CanToggleVisibility = true, + NoToggleVisibility = false + }; + /// constructor. ViewProvider(); @@ -247,6 +252,22 @@ public: /// deliver the icon shown in the tree view virtual QIcon getIcon() const; + /** + * @brief Whether the viewprovider should allow to toggle the visibility. + * + * Some document objects are not rendered and for those document objects, + * it makes no sense to be able to toggle the visibility. Examples are + * VarSet and Spreadsheet. + * + * Note that "rendered" should be seen broadly here. Objects such as + * TechDraw pages, templates, views, and dimensions are not rendered by + * Coin but are "rendered" on the TechDraw page and hence this function can + * return true for those items. + */ + bool canToggleVisibility() const { + return toggleVisibilityMode == ToggleVisibilityMode::CanToggleVisibility; + } + /** @name Methods used by the Tree * If you want to take control over the * viewprovider specific overlay icons that will be drawn with color @@ -571,6 +592,8 @@ protected: /// Turn on mode switch virtual void setModeSwitch(); + void setToggleVisibility(ToggleVisibilityMode mode) { toggleVisibilityMode = mode; } + protected: /// The root Separator of the ViewProvider SoSeparator *pcRoot; @@ -584,6 +607,10 @@ protected: ViewProviderPy* pyViewObject{nullptr}; std::string overrideMode; std::bitset<32> StatusBits; + /// whether visibility can toggled + ToggleVisibilityMode toggleVisibilityMode; + + friend class ViewProviderPy; private: int _iActualMode{-1}; diff --git a/src/Gui/ViewProvider.pyi b/src/Gui/ViewProvider.pyi index 5d651e9893..46d8ec4e9e 100644 --- a/src/Gui/ViewProvider.pyi +++ b/src/Gui/ViewProvider.pyi @@ -2,6 +2,7 @@ from Base.Metadata import constmethod from Base.BoundBox import BoundBox from App.ExtensionContainer import ExtensionContainer from typing import Any, Final, List, Optional +import enum class ViewProvider(ExtensionContainer): @@ -12,6 +13,11 @@ class ViewProvider(ExtensionContainer): Licence: LGPL """ + class ToggleVisibilityMode(enum.Enum): + CanToggleVisibility = "CanToggleVisibility" + NoToggleVisibility = "NoToggleVisibility" + + def addProperty( self, type: str, @@ -367,3 +373,7 @@ class ViewProvider(ExtensionContainer): DropPrefix: Final[str] = "" """Subname referencing the sub-object for holding dropped object.""" + + ToggleVisibility: ToggleVisibilityMode = ToggleVisibilityMode.CanToggleVisibility + """Get/set whether the viewprovider can toggle the visibility of + the object.""" diff --git a/src/Gui/ViewProviderPyImp.cpp b/src/Gui/ViewProviderPyImp.cpp index e3a9f5f5a0..a38d9b0b88 100644 --- a/src/Gui/ViewProviderPyImp.cpp +++ b/src/Gui/ViewProviderPyImp.cpp @@ -706,3 +706,34 @@ Py::String ViewProviderPy::getDropPrefix() const { return {getViewProviderPtr()->getDropPrefix()}; } + +void ViewProviderPy::setToggleVisibility(Py::Object arg) +{ + std::string val; + + if (PyObject_HasAttrString(arg.ptr(), "value")) { + // we are dealing with the enum + val = Py::String(arg.getAttr("value")); + } + else { + // we are dealing with a string + val = Py::String(arg); + } + + if (val == "CanToggleVisibility") { + getViewProviderPtr()->setToggleVisibility(ViewProvider::ToggleVisibilityMode::CanToggleVisibility); + } + else if (val == "NoToggleVisibility") { + getViewProviderPtr()->setToggleVisibility(ViewProvider::ToggleVisibilityMode::NoToggleVisibility); + } + else { + throw Py::ValueError("Invalid ToggleVisibility mode. Use 'CanToggleVisibility' or 'NoToggleVisibility'."); + } +} + +Py::Object ViewProviderPy::getToggleVisibility() const +{ + bool canToggleVisibility = getViewProviderPtr()->canToggleVisibility(); + + return Py::String(canToggleVisibility ? "CanToggleVisibility" : "NoToggleVisibility"); +}