ViewProvider(DocumentObject): new APIs for context aware selection
Context aware selection makes it possible to select the same Coin3D node in different hierarchies (i.e. context) without ambiguity. New/modified APIs in ViewProvider (the first two are the most crucial APIs for context aware selection to work): * getElementPicked(), supercedes getElement(). Given a Coin3D pick point, this function returns a dot separated subname reference as a path leads to the selected object. * getDetailPath(), supercedes getDetail(). Given a subname reference, this function returns an SoFullPath leads to the Coin3D node of the selected object or sub-element (with SoDetail). * (has)HiddenMarker(), check/return a special text marker for context aware override of object visibility. * partialRender(), render only part of the object based on given subname references. It can render, e.g. some faces of a solid, or some children of a container. It uses the 'secondary' extension of SoSelectionElementAction to select which elements to render or hide. The actually rendering functionality will be added in the following patch. * update()/onChanged(), modified to sync Visibility property from DocumentObject. * useNewSelectionModel(), modified to return the default true view parameter. This is for test in the early stage of Link development, probably not needed anymore. * getBoundingBox(), a convenience function to obtain the bounding box of a sub-object/element regardless of object's visibility. It uses getDetailPath() and SoGetBoundingBoxAction to obtain bounding box through Coin3D. It will be used in later sub-element box selection functionality. New/modified APIs in ViewProviderDocumentObject: * getElementPicked()/getDetailPath() provides actual implementation to support container like (sub)object selection without ambiguity. It relies on DocumentObject::getSubObject() to walk the path. * reattach(), called when undo deleteion * forceUpdate()/isUpdateForced(), force update even if object is invisible. These are used by Link to force update the visual of a linked object regardless of its visibility. * getLinkedViewProvider(), return the linked view provider with hierarchy. ViewProviderDocumentObjectPy: * Object attribute is made writtable. Assigning it is equaivalant of calling ViewProviderDocumentObject::attach() in Python.
This commit is contained in:
@@ -30,12 +30,14 @@
|
||||
# include <Inventor/SoPickedPoint.h>
|
||||
# include <Inventor/nodes/SoSeparator.h>
|
||||
# include <Inventor/nodes/SoSwitch.h>
|
||||
# include <Inventor/details/SoDetail.h>
|
||||
# include <Inventor/nodes/SoTransform.h>
|
||||
# include <Inventor/nodes/SoCamera.h>
|
||||
# include <Inventor/events/SoMouseButtonEvent.h>
|
||||
# include <Inventor/events/SoLocation2Event.h>
|
||||
# include <Inventor/actions/SoGetMatrixAction.h>
|
||||
# include <Inventor/actions/SoSearchAction.h>
|
||||
# include <Inventor/actions/SoGetBoundingBoxAction.h>
|
||||
#endif
|
||||
|
||||
/// Here the FreeCAD includes sorted by Base,App,Gui......
|
||||
@@ -55,6 +57,7 @@
|
||||
#include "View3DInventorViewer.h"
|
||||
#include "SoFCDB.h"
|
||||
#include "ViewProviderExtension.h"
|
||||
#include "ViewParams.h"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
@@ -883,6 +886,87 @@ std::vector< App::DocumentObject* > ViewProvider::claimChildren3D(void) const
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
bool ViewProvider::getElementPicked(const SoPickedPoint *pp, std::string &subname) const {
|
||||
if(!isSelectable()) return false;
|
||||
auto vector = getExtensionsDerivedFromType<Gui::ViewProviderExtension>();
|
||||
for(Gui::ViewProviderExtension* ext : vector)
|
||||
if(ext->extensionGetElementPicked(pp,subname))
|
||||
return true;
|
||||
subname = getElement(pp?pp->getDetail():0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ViewProvider::getDetailPath(const char *subname, SoFullPath *pPath, bool append, SoDetail *&det) const {
|
||||
if(pcRoot->findChild(pcModeSwitch) < 0) {
|
||||
// this is possible in case of editing, where the switch node
|
||||
// of the linked view object is temporarily removed from its root
|
||||
// if(append)
|
||||
// pPath->append(pcRoot);
|
||||
return false;
|
||||
}
|
||||
if(append) {
|
||||
pPath->append(pcRoot);
|
||||
pPath->append(pcModeSwitch);
|
||||
}
|
||||
auto vector = getExtensionsDerivedFromType<Gui::ViewProviderExtension>();
|
||||
for(Gui::ViewProviderExtension* ext : vector)
|
||||
if(ext->extensionGetDetailPath(subname,pPath,det))
|
||||
return true;
|
||||
det = getDetail(subname);
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::string &ViewProvider::hiddenMarker() {
|
||||
return App::DocumentObject::hiddenMarker();
|
||||
}
|
||||
|
||||
const char *ViewProvider::hasHiddenMarker(const char *subname) {
|
||||
return App::DocumentObject::hasHiddenMarker(subname);
|
||||
}
|
||||
|
||||
int ViewProvider::partialRender(const std::vector<std::string> &elements, bool clear) {
|
||||
if(elements.empty()) {
|
||||
auto node = pcModeSwitch->getChild(_iActualMode);
|
||||
if(node) {
|
||||
FC_LOG("partial render clear");
|
||||
SoSelectionElementAction action(SoSelectionElementAction::None,true);
|
||||
action.apply(node);
|
||||
}
|
||||
}
|
||||
int count = 0;
|
||||
SoFullPath *path = static_cast<SoFullPath*>(new SoPath);
|
||||
path->ref();
|
||||
SoSelectionElementAction action;
|
||||
action.setSecondary(true);
|
||||
for(auto element : elements) {
|
||||
bool hidden = hasHiddenMarker(element.c_str());
|
||||
if(hidden)
|
||||
element.resize(element.size()-hiddenMarker().size());
|
||||
path->truncate(0);
|
||||
SoDetail *det = 0;
|
||||
if(getDetailPath(element.c_str(),path,false,det)) {
|
||||
if(!hidden && !det) {
|
||||
FC_LOG("partial render element not found: " << element);
|
||||
continue;
|
||||
}
|
||||
FC_LOG("partial render (" << path->getLength() << "): " << element);
|
||||
if(!hidden)
|
||||
action.setType(clear?SoSelectionElementAction::Remove:SoSelectionElementAction::Append);
|
||||
else
|
||||
action.setType(clear?SoSelectionElementAction::Show:SoSelectionElementAction::Hide);
|
||||
action.setElement(det);
|
||||
action.apply(path);
|
||||
++count;
|
||||
}
|
||||
delete det;
|
||||
}
|
||||
path->unref();
|
||||
return count;
|
||||
}
|
||||
|
||||
bool ViewProvider::useNewSelectionModel() const {
|
||||
return ViewParams::instance()->getUseNewSelection();
|
||||
}
|
||||
|
||||
void ViewProvider::beforeDelete() {
|
||||
auto vector = getExtensionsDerivedFromType<Gui::ViewProviderExtension>();
|
||||
@@ -890,6 +974,67 @@ void ViewProvider::beforeDelete() {
|
||||
ext->extensionBeforeDelete();
|
||||
}
|
||||
|
||||
Base::BoundBox3d ViewProvider::getBoundingBox(const char *subname, bool transform, MDIView *view) const {
|
||||
if(!pcRoot || !pcModeSwitch || pcRoot->findChild(pcModeSwitch)<0)
|
||||
return Base::BoundBox3d();
|
||||
|
||||
if(!view)
|
||||
view = Application::Instance->activeView();
|
||||
auto iview = dynamic_cast<View3DInventor*>(view);
|
||||
if(!iview) {
|
||||
auto doc = Application::Instance->activeDocument();
|
||||
if(doc) {
|
||||
auto views = doc->getMDIViewsOfType(View3DInventor::getClassTypeId());
|
||||
if(views.size())
|
||||
iview = dynamic_cast<View3DInventor*>(views.front());
|
||||
}
|
||||
if(!iview) {
|
||||
FC_ERR("no view");
|
||||
return Base::BoundBox3d();
|
||||
}
|
||||
}
|
||||
|
||||
View3DInventorViewer* viewer = iview->getViewer();
|
||||
SoGetBoundingBoxAction bboxAction(viewer->getSoRenderManager()->getViewportRegion());
|
||||
|
||||
auto mode = pcModeSwitch->whichChild.getValue();
|
||||
if(mode < 0)
|
||||
pcModeSwitch->whichChild = getDefaultMode();
|
||||
|
||||
SoTempPath path(20);
|
||||
path.ref();
|
||||
if(subname && subname[0]) {
|
||||
SoDetail *det=0;
|
||||
if(!getDetailPath(subname,&path,true,det)) {
|
||||
if(mode < 0)
|
||||
pcModeSwitch->whichChild = mode;
|
||||
path.unrefNoDelete();
|
||||
return Base::BoundBox3d();
|
||||
}
|
||||
delete det;
|
||||
}
|
||||
SoTempPath resetPath(3);
|
||||
resetPath.ref();
|
||||
if(!transform) {
|
||||
resetPath.append(pcRoot);
|
||||
resetPath.append(pcModeSwitch);
|
||||
bboxAction.setResetPath(&resetPath,true,SoGetBoundingBoxAction::TRANSFORM);
|
||||
}
|
||||
if(path.getLength())
|
||||
bboxAction.apply(&path);
|
||||
else
|
||||
bboxAction.apply(pcRoot);
|
||||
if(mode < 0)
|
||||
pcModeSwitch->whichChild = mode;
|
||||
resetPath.unrefNoDelete();
|
||||
path.unrefNoDelete();
|
||||
auto bbox = bboxAction.getBoundingBox();
|
||||
float minX,minY,minZ,maxX,maxY,maxZ;
|
||||
bbox.getMax().getValue(maxX,maxY,maxZ);
|
||||
bbox.getMin().getValue(minX,minY,minZ);
|
||||
return Base::BoundBox3d(minX,minY,minZ,maxX,maxY,maxZ);
|
||||
}
|
||||
|
||||
bool ViewProvider::isLinkVisible() const {
|
||||
auto ext = getExtensionByType<ViewProviderLinkObserver>(true);
|
||||
if(!ext)
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <App/TransactionalObject.h>
|
||||
#include <App/Material.h>
|
||||
#include <Base/Vector3D.h>
|
||||
#include <Base/BoundBox.h>
|
||||
|
||||
class SbVec2s;
|
||||
class SbVec3f;
|
||||
@@ -48,6 +49,7 @@ class SbMatrix;
|
||||
class SoEventCallback;
|
||||
class SoPickedPoint;
|
||||
class SoDetail;
|
||||
class SoFullPath;
|
||||
class QString;
|
||||
class QMenu;
|
||||
class QObject;
|
||||
@@ -151,12 +153,44 @@ public:
|
||||
//@{
|
||||
|
||||
/// indicates if the ViewProvider use the new Selection model
|
||||
virtual bool useNewSelectionModel(void) const {return false;}
|
||||
/// indicates if the ViewProvider can be selected
|
||||
virtual bool useNewSelectionModel(void) const;
|
||||
virtual bool isSelectable(void) const {return true;}
|
||||
/// return a hit element given the picked point which contains the full node path
|
||||
virtual bool getElementPicked(const SoPickedPoint *, std::string &subname) const;
|
||||
/// return a hit element to the selection path or 0
|
||||
virtual std::string getElement(const SoDetail *) const { return std::string(); }
|
||||
virtual SoDetail* getDetail(const char*) const { return 0; }
|
||||
/// return the coin node detail of the subelement
|
||||
virtual SoDetail* getDetail(const char *) const { return 0; }
|
||||
|
||||
/** return the coin node detail and path to the node of the subelement
|
||||
*
|
||||
* @param subname: dot separated string reference to the sub element
|
||||
* @param pPath: output coin path leading to the returned element detail
|
||||
* @param append: If true, pPath will be first appended with the root node and
|
||||
* the mode switch node of this view provider.
|
||||
*
|
||||
* @return the coint detail of the subelement
|
||||
*
|
||||
* If this view provider links to other view provider, then the
|
||||
* implementation of getDetailPath() shall also append all intermediate
|
||||
* nodes starting just after the mode switch node up till the mode switch of
|
||||
* the linked view provider.
|
||||
*/
|
||||
virtual bool getDetailPath(const char *subname, SoFullPath *pPath, bool append, SoDetail *&det) const;
|
||||
|
||||
/** partial rendering setup
|
||||
*
|
||||
* @param subelements: a list of dot separated string refer to the sub element
|
||||
* @param clear: if true, remove the the subelement from partial rendering.
|
||||
* If else, add the subelement for rendering.
|
||||
*
|
||||
* @return Return the number of subelement found
|
||||
*
|
||||
* Partial rendering only works if there is at least one SoFCSelectRoot node
|
||||
* in this view provider
|
||||
*/
|
||||
int partialRender(const std::vector<std::string> &subelements, bool clear);
|
||||
|
||||
virtual std::vector<Base::Vector3d> getModelPoints(const SoPickedPoint *) const;
|
||||
/// return the highlight lines for a given element or the whole shape
|
||||
virtual std::vector<Base::Vector3d> getSelectionShape(const char* Element) const {
|
||||
@@ -164,6 +198,13 @@ public:
|
||||
return std::vector<Base::Vector3d>();
|
||||
}
|
||||
|
||||
/** Return the bound box of this view object
|
||||
*
|
||||
* This method shall work regardless whether the current view object is
|
||||
* visible or not.
|
||||
*/
|
||||
Base::BoundBox3d getBoundingBox(const char *subname=0, bool transform=true, MDIView *view=0) const;
|
||||
|
||||
/**
|
||||
* Get called if the object is about to get deleted.
|
||||
* Here you can delete other objects, switch their visibility or prevent the deletion of the object.
|
||||
@@ -346,6 +387,19 @@ public:
|
||||
const std::string getOverrideMode();
|
||||
//@}
|
||||
|
||||
/** @name Color mangement methods
|
||||
*/
|
||||
//@{
|
||||
virtual std::map<std::string, App::Color> getElementColors(const char *element=0) const {
|
||||
(void)element;
|
||||
return {};
|
||||
}
|
||||
virtual void setElementColors(const std::map<std::string, App::Color> &colors) {
|
||||
(void)colors;
|
||||
}
|
||||
static const std::string &hiddenMarker();
|
||||
static const char *hasHiddenMarker(const char *subname);
|
||||
//@}
|
||||
|
||||
/** @name Edit methods
|
||||
* if the Viewprovider goes in edit mode
|
||||
@@ -441,7 +495,7 @@ public:
|
||||
void setDefaultMode(int);
|
||||
int getDefaultMode() const;
|
||||
//@}
|
||||
|
||||
|
||||
protected:
|
||||
/** Helper method to check that the node is valid, i.e. it must not cause
|
||||
* and infinite recursion.
|
||||
|
||||
@@ -30,22 +30,34 @@
|
||||
# include <Inventor/nodes/SoDrawStyle.h>
|
||||
# include <Inventor/nodes/SoMaterial.h>
|
||||
# include <Inventor/nodes/SoSeparator.h>
|
||||
# include <Inventor/nodes/SoSwitch.h>
|
||||
# include <Inventor/nodes/SoTransform.h>
|
||||
# include <Inventor/SoPickedPoint.h>
|
||||
# include <Inventor/SoFullPath.h>
|
||||
# include <Inventor/misc/SoChildList.h>
|
||||
# include <Inventor/details/SoDetail.h>
|
||||
#endif
|
||||
|
||||
/// Here the FreeCAD includes sorted by Base,App,Gui......
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/BoundBox.h>
|
||||
#include <App/Material.h>
|
||||
#include <App/DocumentObjectGroup.h>
|
||||
#include <App/DocumentObserver.h>
|
||||
#include <App/Origin.h>
|
||||
#include "Application.h"
|
||||
#include "Document.h"
|
||||
#include "Selection.h"
|
||||
#include "MainWindow.h"
|
||||
#include "MDIView.h"
|
||||
#include "View3DInventor.h"
|
||||
#include "View3DInventorViewer.h"
|
||||
#include "TaskView/TaskAppearance.h"
|
||||
#include "ViewProviderDocumentObject.h"
|
||||
#include "ViewProviderExtension.h"
|
||||
#include "Tree.h"
|
||||
#include <Gui/ViewProviderDocumentObjectPy.h>
|
||||
|
||||
FC_LOG_LEVEL_INIT("Gui",true,true)
|
||||
@@ -61,6 +73,15 @@ ViewProviderDocumentObject::ViewProviderDocumentObject()
|
||||
{
|
||||
ADD_PROPERTY(DisplayMode,((long)0));
|
||||
ADD_PROPERTY(Visibility,(true));
|
||||
ADD_PROPERTY(ShowInTree,(true));
|
||||
|
||||
static const char* OnTopEnum[]= {"Disabled","Enabled","Object","Element",NULL};
|
||||
ADD_PROPERTY(OnTopWhenSelected,((long int)0));
|
||||
ADD_PROPERTY_TYPE(OnTopWhenSelected,((long int)0), "Base", App::Prop_None,
|
||||
"Enabled: Display the object on top of any other object when selected\n"
|
||||
"Object: On top only if the whole object is selected\n"
|
||||
"Element: On top only if some sub-element of the object is selected");
|
||||
OnTopWhenSelected.setEnums(OnTopEnum);
|
||||
|
||||
sPixmap = "Feature";
|
||||
}
|
||||
@@ -79,10 +100,16 @@ void ViewProviderDocumentObject::getTaskViewContent(std::vector<Gui::TaskView::T
|
||||
void ViewProviderDocumentObject::startRestoring()
|
||||
{
|
||||
hide();
|
||||
auto vector = getExtensionsDerivedFromType<Gui::ViewProviderExtension>();
|
||||
for(Gui::ViewProviderExtension* ext : vector)
|
||||
ext->extensionStartRestoring();
|
||||
}
|
||||
|
||||
void ViewProviderDocumentObject::finishRestoring()
|
||||
{
|
||||
auto vector = getExtensionsDerivedFromType<Gui::ViewProviderExtension>();
|
||||
for(Gui::ViewProviderExtension* ext : vector)
|
||||
ext->extensionFinishRestoring();
|
||||
}
|
||||
|
||||
bool ViewProviderDocumentObject::isAttachedToDocument() const
|
||||
@@ -100,6 +127,10 @@ const char* ViewProviderDocumentObject::detachFromDocument()
|
||||
|
||||
bool ViewProviderDocumentObject::removeDynamicProperty(const char* name)
|
||||
{
|
||||
App::Property* prop = getDynamicPropertyByName(name);
|
||||
if(!prop || prop->testStatus(App::Property::LockDynamic))
|
||||
return false;
|
||||
|
||||
// transactions of view providers are also managed in App::Document.
|
||||
App::DocumentObject* docobject = getObject();
|
||||
App::Document* document = docobject ? docobject->getDocument() : nullptr;
|
||||
@@ -147,6 +178,8 @@ void ViewProviderDocumentObject::onChanged(const App::Property* prop)
|
||||
Visibility.getValue() ? show() : hide();
|
||||
Visibility.setStatus(App::Property::User2, false);
|
||||
}
|
||||
if(getObject() && getObject()->Visibility.getValue()!=Visibility.getValue())
|
||||
getObject()->Visibility.setValue(Visibility.getValue());
|
||||
}
|
||||
|
||||
if (pcDocument && !pcDocument->isModified()) {
|
||||
@@ -160,13 +193,13 @@ void ViewProviderDocumentObject::onChanged(const App::Property* prop)
|
||||
|
||||
void ViewProviderDocumentObject::hide(void)
|
||||
{
|
||||
ViewProvider::hide();
|
||||
// use this bit to check whether 'Visibility' must be adjusted
|
||||
if (Visibility.testStatus(App::Property::User2) == false) {
|
||||
Visibility.setStatus(App::Property::User2, true);
|
||||
Visibility.setValue(false);
|
||||
Visibility.setStatus(App::Property::User2, false);
|
||||
}
|
||||
ViewProvider::hide();
|
||||
}
|
||||
|
||||
void ViewProviderDocumentObject::show(void)
|
||||
@@ -182,7 +215,7 @@ void ViewProviderDocumentObject::show(void)
|
||||
|
||||
void ViewProviderDocumentObject::updateView()
|
||||
{
|
||||
if(testStatus(ViewStatus::UpdatingView))
|
||||
if(!pcObject || testStatus(ViewStatus::UpdatingView))
|
||||
return;
|
||||
|
||||
Base::ObjectStatusLocker<ViewStatus,ViewProviderDocumentObject> lock(ViewStatus::UpdatingView,this);
|
||||
@@ -196,7 +229,7 @@ void ViewProviderDocumentObject::updateView()
|
||||
for (std::map<std::string, App::Property*>::iterator it = Map.begin(); it != Map.end(); ++it) {
|
||||
updateData(it->second);
|
||||
}
|
||||
if (vis) ViewProvider::show();
|
||||
if (vis && Visibility.getValue()) ViewProvider::show();
|
||||
}
|
||||
|
||||
void ViewProviderDocumentObject::attach(App::DocumentObject *pcObj)
|
||||
@@ -204,6 +237,10 @@ void ViewProviderDocumentObject::attach(App::DocumentObject *pcObj)
|
||||
// save Object pointer
|
||||
pcObject = pcObj;
|
||||
|
||||
if(pcObj && pcObj->getNameInDocument() &&
|
||||
Visibility.getValue()!=pcObj->Visibility.getValue())
|
||||
pcObj->Visibility.setValue(Visibility.getValue());
|
||||
|
||||
// Retrieve the supported display modes of the view provider
|
||||
aDisplayModesArray = this->getDisplayModes();
|
||||
|
||||
@@ -229,19 +266,35 @@ void ViewProviderDocumentObject::attach(App::DocumentObject *pcObj)
|
||||
ext->extensionAttach(pcObj);
|
||||
}
|
||||
|
||||
void ViewProviderDocumentObject::updateData(const App::Property* prop)
|
||||
void ViewProviderDocumentObject::reattach(App::DocumentObject *pcObj) {
|
||||
auto vector = getExtensionsDerivedFromType<Gui::ViewProviderExtension>();
|
||||
for (Gui::ViewProviderExtension* ext : vector)
|
||||
ext->extensionReattach(pcObj);
|
||||
}
|
||||
|
||||
void ViewProviderDocumentObject::update(const App::Property* prop)
|
||||
{
|
||||
ViewProvider::updateData(prop);
|
||||
// bypass view provider update to always allow changing visibility from
|
||||
// document object
|
||||
if(prop == &getObject()->Visibility) {
|
||||
if(!isRestoring() && Visibility.getValue()!=getObject()->Visibility.getValue())
|
||||
Visibility.setValue(!Visibility.getValue());
|
||||
}else
|
||||
ViewProvider::update(prop);
|
||||
}
|
||||
|
||||
Gui::Document* ViewProviderDocumentObject::getDocument() const
|
||||
{
|
||||
if(!pcObject)
|
||||
throw Base::RuntimeError("View provider detached");
|
||||
App::Document* pAppDoc = pcObject->getDocument();
|
||||
return Gui::Application::Instance->getDocument(pAppDoc);
|
||||
}
|
||||
|
||||
Gui::MDIView* ViewProviderDocumentObject::getActiveView() const
|
||||
{
|
||||
if(!pcObject)
|
||||
throw Base::RuntimeError("View provider detached");
|
||||
App::Document* pAppDoc = pcObject->getDocument();
|
||||
Gui::Document* pGuiDoc = Gui::Application::Instance->getDocument(pAppDoc);
|
||||
return pGuiDoc->getActiveView();
|
||||
@@ -249,6 +302,8 @@ Gui::MDIView* ViewProviderDocumentObject::getActiveView() const
|
||||
|
||||
Gui::MDIView* ViewProviderDocumentObject::getEditingView() const
|
||||
{
|
||||
if(!pcObject)
|
||||
throw Base::RuntimeError("View provider detached");
|
||||
App::Document* pAppDoc = pcObject->getDocument();
|
||||
Gui::Document* pGuiDoc = Gui::Application::Instance->getDocument(pAppDoc);
|
||||
return pGuiDoc->getEditingViewOfViewProvider(const_cast<ViewProviderDocumentObject*>(this));
|
||||
@@ -256,6 +311,8 @@ Gui::MDIView* ViewProviderDocumentObject::getEditingView() const
|
||||
|
||||
Gui::MDIView* ViewProviderDocumentObject::getInventorView() const
|
||||
{
|
||||
if(!pcObject)
|
||||
throw Base::RuntimeError("View provider detached");
|
||||
App::Document* pAppDoc = pcObject->getDocument();
|
||||
Gui::Document* pGuiDoc = Gui::Application::Instance->getDocument(pAppDoc);
|
||||
|
||||
@@ -269,6 +326,8 @@ Gui::MDIView* ViewProviderDocumentObject::getInventorView() const
|
||||
|
||||
Gui::MDIView* ViewProviderDocumentObject::getViewOfNode(SoNode* node) const
|
||||
{
|
||||
if(!pcObject)
|
||||
throw Base::RuntimeError("View provider detached");
|
||||
App::Document* pAppDoc = pcObject->getDocument();
|
||||
Gui::Document* pGuiDoc = Gui::Application::Instance->getDocument(pAppDoc);
|
||||
return pGuiDoc->getViewOfNode(node);
|
||||
@@ -276,6 +335,8 @@ Gui::MDIView* ViewProviderDocumentObject::getViewOfNode(SoNode* node) const
|
||||
|
||||
SoNode* ViewProviderDocumentObject::findFrontRootOfType(const SoType& type) const
|
||||
{
|
||||
if(!pcObject)
|
||||
return 0;
|
||||
// first get the document this object is part of and get its GUI counterpart
|
||||
App::Document* pAppDoc = pcObject->getDocument();
|
||||
Gui::Document* pGuiDoc = Gui::Application::Instance->getDocument(pAppDoc);
|
||||
@@ -336,6 +397,160 @@ PyObject* ViewProviderDocumentObject::getPyObject()
|
||||
return pyViewObject;
|
||||
}
|
||||
|
||||
bool ViewProviderDocumentObject::canDropObjectEx(App::DocumentObject* obj, App::DocumentObject *owner,
|
||||
const char *subname, const std::vector<std::string> &elements) const
|
||||
{
|
||||
auto vector = getExtensionsDerivedFromType<Gui::ViewProviderExtension>();
|
||||
for(Gui::ViewProviderExtension* ext : vector){
|
||||
if(ext->extensionCanDropObjectEx(obj,owner,subname,elements))
|
||||
return true;
|
||||
}
|
||||
if(obj && obj->getDocument()!=getObject()->getDocument())
|
||||
return false;
|
||||
return canDropObject(obj);
|
||||
}
|
||||
|
||||
int ViewProviderDocumentObject::replaceObject(
|
||||
App::DocumentObject *oldObj, App::DocumentObject *newObj)
|
||||
{
|
||||
if(!oldObj || !oldObj->getNameInDocument()
|
||||
|| !newObj || !newObj->getNameInDocument())
|
||||
{
|
||||
FC_THROWM(Base::RuntimeError,"Invalid object");
|
||||
}
|
||||
|
||||
auto obj = getObject();
|
||||
if(!obj || !obj->getNameInDocument())
|
||||
FC_THROWM(Base::RuntimeError,"View provider not attached");
|
||||
|
||||
int res = ViewProvider::replaceObject(oldObj,newObj);
|
||||
if(res>=0)
|
||||
return res;
|
||||
|
||||
std::vector<std::pair<App::DocumentObjectT, std::unique_ptr<App::Property> > > propChanges;
|
||||
std::vector<App::Property*> props;
|
||||
obj->getPropertyList(props);
|
||||
for(auto prop : props) {
|
||||
auto linkProp = Base::freecad_dynamic_cast<App::PropertyLinkBase>(prop);
|
||||
if(!linkProp)
|
||||
continue;
|
||||
std::unique_ptr<App::Property> copy(linkProp->CopyOnLinkReplace(obj, oldObj,newObj));
|
||||
if(!copy)
|
||||
continue;
|
||||
propChanges.emplace_back(prop,std::move(copy));
|
||||
}
|
||||
|
||||
if(propChanges.empty())
|
||||
return 0;
|
||||
|
||||
// Global search for affected links
|
||||
for(auto doc : App::GetApplication().getDocuments()) {
|
||||
for(auto o : doc->getObjects()) {
|
||||
if(o == obj)
|
||||
continue;
|
||||
std::vector<App::Property*> props;
|
||||
o->getPropertyList(props);
|
||||
for(auto prop : props) {
|
||||
auto linkProp = Base::freecad_dynamic_cast<App::PropertyLinkBase>(prop);
|
||||
if(!linkProp)
|
||||
continue;
|
||||
std::unique_ptr<App::Property> copy(linkProp->CopyOnLinkReplace(obj,oldObj,newObj));
|
||||
if(!copy)
|
||||
continue;
|
||||
propChanges.emplace_back(App::DocumentObjectT(prop),std::move(copy));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &v : propChanges) {
|
||||
auto prop = v.first.getProperty();
|
||||
if(prop)
|
||||
prop->Paste(*v.second.get());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool ViewProviderDocumentObject::showInTree() const {
|
||||
return ShowInTree.getValue();
|
||||
}
|
||||
|
||||
bool ViewProviderDocumentObject::getElementPicked(const SoPickedPoint *pp, std::string &subname) const
|
||||
{
|
||||
if(!isSelectable()) return false;
|
||||
auto vector = getExtensionsDerivedFromType<Gui::ViewProviderExtension>();
|
||||
for(Gui::ViewProviderExtension* ext : vector)
|
||||
if(ext->extensionGetElementPicked(pp,subname))
|
||||
return true;
|
||||
|
||||
auto childRoot = getChildRoot();
|
||||
int idx;
|
||||
if(!childRoot ||
|
||||
(idx=pcModeSwitch->whichChild.getValue())<0 ||
|
||||
pcModeSwitch->getChild(idx)!=childRoot)
|
||||
{
|
||||
return ViewProvider::getElementPicked(pp,subname);
|
||||
}
|
||||
|
||||
SoPath* path = pp->getPath();
|
||||
idx = path->findNode(childRoot);
|
||||
if(idx<0 || idx+1>=path->getLength())
|
||||
return false;
|
||||
auto vp = getDocument()->getViewProvider(path->getNode(idx+1));
|
||||
if(!vp) return false;
|
||||
auto obj = vp->getObject();
|
||||
if(!obj || !obj->getNameInDocument())
|
||||
return false;
|
||||
std::ostringstream str;
|
||||
str << obj->getNameInDocument() << '.';
|
||||
if(vp->getElementPicked(pp,subname))
|
||||
str << subname;
|
||||
subname = str.str();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ViewProviderDocumentObject::getDetailPath(const char *subname, SoFullPath *path, bool append, SoDetail *&det) const
|
||||
{
|
||||
auto len = path->getLength();
|
||||
if(!append && len>=2)
|
||||
len -= 2;
|
||||
if(ViewProvider::getDetailPath(subname,path,append,det)) {
|
||||
if(det || !subname || !*subname)
|
||||
return true;
|
||||
}
|
||||
|
||||
if(det) {
|
||||
delete det;
|
||||
det = 0;
|
||||
}
|
||||
|
||||
const char *dot = strchr(subname,'.');
|
||||
if(!dot) return false;
|
||||
auto obj = getObject();
|
||||
if(!obj || !obj->getNameInDocument()) return false;
|
||||
auto sobj = obj->getSubObject(std::string(subname,dot-subname+1).c_str());
|
||||
if(!sobj) return false;
|
||||
auto vp = Application::Instance->getViewProvider(sobj);
|
||||
if(!vp) return false;
|
||||
|
||||
auto childRoot = getChildRoot();
|
||||
if(!childRoot)
|
||||
path->truncate(len);
|
||||
else {
|
||||
auto idx = pcModeSwitch->whichChild.getValue();
|
||||
if(idx < 0 || pcModeSwitch->getChild(idx)!=childRoot)
|
||||
return false;
|
||||
path->append(childRoot);
|
||||
}
|
||||
bool ret = false;
|
||||
if(path->getLength()) {
|
||||
SoNode * tail = path->getTail();
|
||||
const SoChildList * children = tail->getChildren();
|
||||
if(children && children->find(vp->getRoot())>=0)
|
||||
ret = vp->getDetailPath(dot+1,path,true,det);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ViewProviderDocumentObject::onPropertyStatusChanged(
|
||||
const App::Property &prop, unsigned long oldStatus)
|
||||
{
|
||||
@@ -344,6 +559,23 @@ void ViewProviderDocumentObject::onPropertyStatusChanged(
|
||||
pcObject->getDocument()->signalChangePropertyEditor(*pcObject->getDocument(),prop);
|
||||
}
|
||||
|
||||
ViewProviderDocumentObject *ViewProviderDocumentObject::getLinkedViewProvider(
|
||||
std::string *subname, bool recursive) const
|
||||
{
|
||||
(void)subname;
|
||||
auto self = const_cast<ViewProviderDocumentObject*>(this);
|
||||
if(!pcObject || !pcObject->getNameInDocument())
|
||||
return self;
|
||||
auto linked = pcObject->getLinkedObject(recursive);
|
||||
if(!linked || linked == pcObject)
|
||||
return self;
|
||||
auto res = Base::freecad_dynamic_cast<ViewProviderDocumentObject>(
|
||||
Application::Instance->getViewProvider(linked));
|
||||
if(!res)
|
||||
res = self;
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string ViewProviderDocumentObject::getFullName() const {
|
||||
if(pcObject)
|
||||
return pcObject->getFullName() + ".ViewObject";
|
||||
|
||||
@@ -24,9 +24,10 @@
|
||||
#ifndef GUI_VIEWPROVIDER_DOCUMENTOBJECT_H
|
||||
#define GUI_VIEWPROVIDER_DOCUMENTOBJECT_H
|
||||
|
||||
#include <Inventor/SoType.h>
|
||||
|
||||
#include "ViewProvider.h"
|
||||
#include <App/DocumentObject.h>
|
||||
#include <Inventor/SoType.h>
|
||||
|
||||
class SoMaterial;
|
||||
class SoDrawStyle;
|
||||
@@ -59,9 +60,12 @@ public:
|
||||
// Display properties
|
||||
App::PropertyEnumeration DisplayMode;
|
||||
App::PropertyBool Visibility;
|
||||
App::PropertyBool ShowInTree;
|
||||
App::PropertyEnumeration OnTopWhenSelected;
|
||||
|
||||
virtual void attach(App::DocumentObject *pcObject);
|
||||
virtual void updateData(const App::Property*);
|
||||
virtual void reattach(App::DocumentObject *);
|
||||
virtual void update(const App::Property*) override;
|
||||
/// Set the active mode, i.e. the first item of the 'Display' property.
|
||||
void setActiveMode();
|
||||
/// Hide the object in the view
|
||||
@@ -69,6 +73,13 @@ public:
|
||||
/// Show the object in the view
|
||||
virtual void show(void);
|
||||
|
||||
virtual bool canDropObjectEx(App::DocumentObject *, App::DocumentObject *,
|
||||
const char *, const std::vector<std::string> &) const override;
|
||||
|
||||
virtual int replaceObject(App::DocumentObject*, App::DocumentObject*) override;
|
||||
|
||||
virtual bool showInTree() const;
|
||||
|
||||
/// Get a list of TaskBoxes associated with this object
|
||||
virtual void getTaskViewContent(std::vector<Gui::TaskView::TaskContent*>&) const;
|
||||
|
||||
@@ -83,6 +94,22 @@ public:
|
||||
/// Get the python wrapper for that ViewProvider
|
||||
PyObject* getPyObject();
|
||||
|
||||
/// return a hit element given the picked point which contains the full node path
|
||||
virtual bool getElementPicked(const SoPickedPoint *, std::string &subname) const override;
|
||||
/// return the coin node detail and path to the node of the subname
|
||||
virtual bool getDetailPath(const char *subname, SoFullPath *pPath, bool append, SoDetail *&det) const override;
|
||||
|
||||
/* Force update visual
|
||||
*
|
||||
* These method exists because some view provider skips visual update when
|
||||
* hidden (e.g. PartGui::ViewProviderPartExt). Call this function to force
|
||||
* visual update.
|
||||
*/
|
||||
//@{
|
||||
virtual void forceUpdate(bool enable = true) {(void)enable;}
|
||||
virtual bool isUpdateForced() const {return false;}
|
||||
//@}
|
||||
|
||||
/** @name Restoring view provider from document load */
|
||||
//@{
|
||||
virtual void startRestoring();
|
||||
@@ -96,6 +123,20 @@ public:
|
||||
const char* group=0, const char* doc=0,
|
||||
short attr=0, bool ro=false, bool hidden=false) override;
|
||||
|
||||
/** Return the linked view object
|
||||
*
|
||||
* This function is mainly used for GUI navigation (e.g.
|
||||
* StdCmdLinkSelectLinked).
|
||||
*
|
||||
* @param subname: output as the subname referencing the linked object
|
||||
* @param recursive: whether to follow the link recursively
|
||||
*
|
||||
* @return Returns the linked view provider. If none, it shall return
|
||||
* itself.
|
||||
*/
|
||||
virtual ViewProviderDocumentObject *getLinkedViewProvider(
|
||||
std::string *subname=0, bool recursive=false) const;
|
||||
|
||||
virtual std::string getFullName() const override;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -18,12 +18,18 @@
|
||||
<UserDocu>Update the view representation of the object</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="Object" ReadOnly="true">
|
||||
<Attribute Name="Object">
|
||||
<Documentation>
|
||||
<UserDocu>Return the associated data object</UserDocu>
|
||||
<UserDocu>Set/Get the associated data object</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Object" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="ForceUpdate">
|
||||
<Documentation>
|
||||
<UserDocu>Reference count to force update visual</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="ForceUpdate" Type="Boolean" />
|
||||
</Attribute>
|
||||
<Attribute Name="Document" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Return the document the view provider is part of</UserDocu>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
#include <Gui/ViewProviderDocumentObject.h>
|
||||
#include <Gui/Document.h>
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/DocumentObjectPy.h>
|
||||
|
||||
// inclusion of the generated files (generated out of ViewProviderDocumentObjectPy.xml)
|
||||
#include "ViewProviderDocumentObjectPy.h"
|
||||
@@ -62,6 +62,27 @@ Py::Object ViewProviderDocumentObjectPy::getObject(void) const
|
||||
return Py::Object(obj->getPyObject(), true); // do not inc'ref twice
|
||||
}
|
||||
|
||||
void ViewProviderDocumentObjectPy::setObject(Py::Object pyobj)
|
||||
{
|
||||
if(!PyObject_TypeCheck(*pyobj,&App::DocumentObjectPy::Type))
|
||||
throw Py::TypeError("Expect document object");
|
||||
App::DocumentObject* obj = getViewProviderDocumentObjectPtr()->getObject();
|
||||
if(obj)
|
||||
throw Py::RuntimeError("View object already attached");
|
||||
getViewProviderDocumentObjectPtr()->attach(
|
||||
static_cast<App::DocumentObjectPy*>(*pyobj)->getDocumentObjectPtr());
|
||||
}
|
||||
|
||||
Py::Boolean ViewProviderDocumentObjectPy::getForceUpdate() const
|
||||
{
|
||||
return Py::Boolean(getViewProviderDocumentObjectPtr()->isUpdateForced());
|
||||
}
|
||||
|
||||
void ViewProviderDocumentObjectPy::setForceUpdate(Py::Boolean arg)
|
||||
{
|
||||
getViewProviderDocumentObjectPtr()->forceUpdate(arg);
|
||||
}
|
||||
|
||||
Py::Object ViewProviderDocumentObjectPy::getDocument(void) const
|
||||
{
|
||||
Document* doc = getViewProviderDocumentObjectPtr()->getDocument();
|
||||
|
||||
@@ -120,11 +120,66 @@ Returns 1 if succeed, 0 if not found, -1 if not supported
|
||||
<UserDocu>Returns list of objects that are to be grouped in tree under this object.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="partialRender">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
partialRender(sub=None,clear=False): render only part of the object
|
||||
|
||||
sub: string or list of string refer to the subelement. If it is None then
|
||||
reset the partial rendering.
|
||||
clear: true to add, or false to remove the subelement(s) for rendering.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getElementColors">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
getElementColors(elementName=None) -> dict(elementName:color)
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setElementColors">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
setElementColors(colors): set element colors
|
||||
|
||||
colors: color dictonary of type elementName:(r,g,b,a)
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getElementPicked" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>getElementPicked(pickPoint): return the picked subelement</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getDetailPath" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
getDetailPath(subname,path,append=True): return Coin detail and path of an subelement
|
||||
|
||||
subelement: dot separated string reference to the sub element
|
||||
pPath: output coin path leading to the returned element detail
|
||||
append: If true, path will be first appended with the root node and the mode
|
||||
switch node of this view provider.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="signalChangeIcon" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>Trigger icon changed signal</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getBoundingBox">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
getBoundingBox(subname=None, transform=True, view=None): obtain the bounding box of this view object
|
||||
|
||||
* subname: the optional subname referring a sub-object
|
||||
* transform: whether to apply the transformation matrix of this view provider
|
||||
* view: the MDIView, default to active view
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="Annotation" ReadOnly="false">
|
||||
<Documentation>
|
||||
<UserDocu>A pivy Separator to add a custom scene graph to this ViewProvider</UserDocu>
|
||||
|
||||
@@ -377,6 +377,135 @@ PyObject* ViewProviderPy::claimChildren(PyObject* args)
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
|
||||
PyObject* ViewProviderPy::partialRender(PyObject* args)
|
||||
{
|
||||
PyObject *value = Py_None;
|
||||
PyObject *clear = Py_False;
|
||||
if (!PyArg_ParseTuple(args, "|OO",&value,&clear))
|
||||
return NULL; // NULL triggers exception
|
||||
|
||||
std::vector<std::string> values;
|
||||
if(value != Py_None) {
|
||||
PyObject *item = 0;
|
||||
Py_ssize_t nSize;
|
||||
if (PyList_Check(value) || PyTuple_Check(value))
|
||||
nSize = PySequence_Size(value);
|
||||
else {
|
||||
item = value;
|
||||
value = 0;
|
||||
nSize = 1;
|
||||
}
|
||||
values.resize(nSize);
|
||||
for (Py_ssize_t i = 0; i < nSize; ++i) {
|
||||
if(value) item = PySequence_GetItem(value, i);
|
||||
if (PyUnicode_Check(item)) {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
values[i] = PyUnicode_AsUTF8(item);
|
||||
#else
|
||||
PyObject* unicode = PyUnicode_AsUTF8String(item);
|
||||
values[i] = PyString_AsString(unicode);
|
||||
Py_DECREF(unicode);
|
||||
#endif
|
||||
}
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
else if (PyString_Check(item)) {
|
||||
values[i] = PyString_AsString(item);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
std::string error = std::string("type must be str or unicode");
|
||||
if(item) {
|
||||
error += " not, ";
|
||||
error += item->ob_type->tp_name;
|
||||
}
|
||||
throw Base::TypeError(error + item->ob_type->tp_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Py::Int ret(getViewProviderPtr()->partialRender(values,PyObject_IsTrue(clear)));
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
|
||||
PyObject* ViewProviderPy::getElementColors(PyObject* args)
|
||||
{
|
||||
const char *element = 0;
|
||||
if (!PyArg_ParseTuple(args, "|s", &element))
|
||||
return 0;
|
||||
|
||||
Py::Dict dict;
|
||||
for(auto &v : getViewProviderPtr()->getElementColors(element)) {
|
||||
auto &c = v.second;
|
||||
dict.setItem(Py::String(v.first),
|
||||
Py::TupleN(Py::Float(c.r),Py::Float(c.g),Py::Float(c.b),Py::Float(c.a)));
|
||||
}
|
||||
return Py::new_reference_to(dict);
|
||||
}
|
||||
|
||||
PyObject* ViewProviderPy::setElementColors(PyObject* args)
|
||||
{
|
||||
PyObject *pyObj;
|
||||
if (!PyArg_ParseTuple(args, "O", &pyObj))
|
||||
return 0;
|
||||
|
||||
if(!PyDict_Check(pyObj))
|
||||
throw Py::TypeError("Expect a dict");
|
||||
|
||||
std::map<std::string,App::Color> colors;
|
||||
Py::Dict dict(pyObj);
|
||||
for(auto it=dict.begin();it!=dict.end();++it) {
|
||||
const auto &value = *it;
|
||||
if(!value.first.isString() || !value.second.isSequence())
|
||||
throw Py::TypeError("Expect the dictonary contain items of type elementName:(r,g,b,a)");
|
||||
|
||||
App::PropertyColor prop;
|
||||
prop.setPyObject(value.second.ptr());
|
||||
colors[value.first.as_string()] = prop.getValue();
|
||||
}
|
||||
getViewProviderPtr()->setElementColors(colors);
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* ViewProviderPy::getElementPicked(PyObject* args)
|
||||
{
|
||||
PyObject *obj;
|
||||
if (!PyArg_ParseTuple(args, "O",&obj))
|
||||
return NULL;
|
||||
void *ptr = 0;
|
||||
Base::Interpreter().convertSWIGPointerObj("pivy.coin", "_p_SoPickedPoint", obj, &ptr, 0);
|
||||
SoPickedPoint *pp = reinterpret_cast<SoPickedPoint*>(ptr);
|
||||
if(!pp)
|
||||
throw Base::TypeError("type must be of coin.SoPickedPoint");
|
||||
std::string name;
|
||||
if(!getViewProviderPtr()->getElementPicked(pp,name))
|
||||
Py_Return;
|
||||
return Py::new_reference_to(Py::String(name));
|
||||
}
|
||||
|
||||
PyObject* ViewProviderPy::getDetailPath(PyObject* args)
|
||||
{
|
||||
const char *sub;
|
||||
PyObject *path;
|
||||
PyObject *append = Py_True;
|
||||
if (!PyArg_ParseTuple(args, "sO|O",&sub,&path,&append))
|
||||
return NULL;
|
||||
void *ptr = 0;
|
||||
Base::Interpreter().convertSWIGPointerObj("pivy.coin", "_p_SoPath", path, &ptr, 0);
|
||||
SoPath *pPath = reinterpret_cast<SoPath*>(ptr);
|
||||
if(!pPath)
|
||||
throw Base::TypeError("type must be of coin.SoPath");
|
||||
SoDetail *det = 0;
|
||||
if(!getViewProviderPtr()->getDetailPath(
|
||||
sub,static_cast<SoFullPath*>(pPath),PyObject_IsTrue(append),det))
|
||||
{
|
||||
if(det) delete det;
|
||||
Py_Return;
|
||||
}
|
||||
if(!det)
|
||||
return Py::new_reference_to(Py::True());
|
||||
return Base::Interpreter().createSWIGPointerObj("pivy.coin", "_p_SoDetail", (void*)det, 0);
|
||||
}
|
||||
|
||||
PyObject *ViewProviderPy::signalChangeIcon(PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
@@ -385,6 +514,22 @@ PyObject *ViewProviderPy::signalChangeIcon(PyObject *args)
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject *ViewProviderPy::getBoundingBox(PyObject *args) {
|
||||
PyObject *transform=Py_True;
|
||||
PyObject *pyView = 0;
|
||||
const char *subname = 0;
|
||||
if (!PyArg_ParseTuple(args, "|sOO!", &subname,&transform,View3DInventorPy::type_object(),&pyView))
|
||||
return NULL;
|
||||
PY_TRY {
|
||||
View3DInventor *view = 0;
|
||||
if(pyView)
|
||||
view = static_cast<View3DInventorPy*>(pyView)->getView3DIventorPtr();
|
||||
auto bbox = getViewProviderPtr()->getBoundingBox(subname,PyObject_IsTrue(transform),view);
|
||||
Py::Object ret(new Base::BoundBoxPy(new Base::BoundBox3d(bbox)));
|
||||
return Py::new_reference_to(ret);
|
||||
} PY_CATCH;
|
||||
}
|
||||
|
||||
PyObject *ViewProviderPy::doubleClicked(PyObject *args) {
|
||||
if(!PyArg_ParseTuple(args, ""))
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user