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:
@@ -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