Gui: Scene inspector improvements (#18781)

* Improve naming for root scene graph switch/separator nodes.

* Improve scene graph inspector.

This commit improves the scene graph inspector by improving the UI
layout and displaying information in a more human-readable way.

Instead of having a main generic string column for all node-specific
data, introduce specific columns for node name, memory address and data.

Better visualization was also added for `SoDrawStyle`, `SoPickStyle`
and `SoCoordinate3` node types.
This commit is contained in:
João Matos
2025-01-14 03:38:41 +00:00
committed by GitHub
parent 0213b4fc6c
commit 23a05bb250
8 changed files with 192 additions and 39 deletions

View File

@@ -23,6 +23,9 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <Inventor/nodes/SoSeparator.h>
# include <Inventor/nodes/SoDrawStyle.h>
# include <Inventor/nodes/SoPickStyle.h>
# include <Inventor/nodes/SoCoordinate3.h>
# include <QHeaderView>
# include <QTextStream>
#endif
@@ -45,12 +48,20 @@ SceneModel::SceneModel(QObject* parent)
{
}
enum class Column: std::int8_t {
INVENTOR_TREE = 0,
NAME = 1,
MEMORY_ADDRESS = 2,
DATA = 3,
COUNT = 4,
};
SceneModel::~SceneModel() = default;
int SceneModel::columnCount (const QModelIndex & parent) const
{
Q_UNUSED(parent);
return 2;
return static_cast<int>(Column::COUNT);
}
Qt::ItemFlags SceneModel::flags (const QModelIndex & index) const
@@ -63,10 +74,19 @@ QVariant SceneModel::headerData (int section, Qt::Orientation orientation, int r
if (orientation == Qt::Horizontal) {
if (role != Qt::DisplayRole)
return {};
if (section == 0)
switch ((Column)section) {
case Column::INVENTOR_TREE:
return tr("Inventor Tree");
else if (section == 1)
case Column::NAME:
return tr("Name");
case Column::MEMORY_ADDRESS:
return tr("Address");
case Column::DATA:
return tr("Data");
default:
assert(0 && "Not handled yet");
}
}
return {};
@@ -82,42 +102,135 @@ void SceneModel::setNode(SoNode* node)
this->clear();
this->setHeaderData(0, Qt::Horizontal, tr("Nodes"), Qt::DisplayRole);
this->insertColumns(0,2);
this->insertColumns(0, static_cast<int>(Column::COUNT));
this->insertRows(0,1);
setNode(this->index(0, 0), node);
}
static std::string_view formatSoSwitchValue(int32_t value)
{
switch (value)
{
case SO_SWITCH_NONE:
return {"None"};
case SO_SWITCH_INHERIT:
return {"Inherit"};
case SO_SWITCH_ALL:
return {"All"};
default:
return {"Child"};
}
}
static std::string_view formatSoSeparatorCacheEnabled(int32_t value)
{
switch (value)
{
case SoSeparator::OFF:
return {"Off"};
case SoSeparator::ON:
return {"On"};
case SoSeparator::AUTO:
return {"Auto"};
default:
throw Base::ValueError();
}
}
static std::string_view formatSoDrawStyleElement(int32_t value)
{
switch (value)
{
case SoDrawStyleElement::FILLED:
return {"Filled"};
case SoDrawStyleElement::LINES:
return {"Lines"};
case SoDrawStyleElement::POINTS:
return {"Points"};
case SoDrawStyleElement::INVISIBLE:
return {"Invisible"};
default:
throw Base::ValueError();
}
}
static std::string_view formatSoPickStyleElement(int32_t value)
{
switch (value)
{
case SoPickStyleElement::SHAPE:
return {"Shape"};
case SoPickStyleElement::BOUNDING_BOX:
return {"BoundingBox"};
case SoPickStyleElement::UNPICKABLE:
return {"Unpickable"};
case SoPickStyleElement::SHAPE_ON_TOP:
return {"ShapeOnTop"};
case SoPickStyleElement::BOUNDING_BOX_ON_TOP:
return {"BoundingBoxOnTop"};
case SoPickStyleElement::SHAPE_FRONTFACES:
return {"ShapeFrontFaces"};
default:
throw Base::ValueError();
}
}
void SceneModel::setNode(QModelIndex index, SoNode* node)
{
this->setData(index, QVariant(QString::fromLatin1(QByteArray(node->getTypeId().getName()))));
if (node->getTypeId().isDerivedFrom(SoGroup::getClassTypeId())) {
auto group = static_cast<SoGroup*>(node);
// insert SoGroup icon
this->insertColumns(0,2,index);
this->insertRows(0,group->getNumChildren(), index);
for (int i=0; i<group->getNumChildren();i++) {
SoNode* child = group->getChild(i);
setNode(this->index(i, 0, index), child);
this->setData(index.siblingAtColumn(static_cast<int>(Column::INVENTOR_TREE)),
QVariant(QString::fromLatin1(QByteArray(node->getTypeId().getName()))));
QHash<SoNode*, QString>::iterator it = nodeNames.find(child);
QString name;
QTextStream stream(&name);
stream << child << ", ";
if(child->isOfType(SoSwitch::getClassTypeId())) {
auto pcSwitch = static_cast<SoSwitch*>(child);
stream << pcSwitch->whichChild.getValue() << ", ";
} else if (child->isOfType(SoSeparator::getClassTypeId())) {
auto pcSeparator = static_cast<SoSeparator*>(child);
stream << pcSeparator->renderCaching.getValue() << ", ";
}
if (it != nodeNames.end())
stream << it.value();
else
stream << child->getName();
this->setData(this->index(i, 1, index), QVariant(name));
QHash<SoNode*, QString>::iterator it = nodeNames.find(node);
const QString name {
(it != nodeNames.end()) ? it.value()
: QString::fromLatin1(QByteArray(node->getName()))
};
this->setData(index.siblingAtColumn(static_cast<int>(Column::NAME)), QVariant(name));
this->setData(index.siblingAtColumn(static_cast<int>(Column::MEMORY_ADDRESS)),
QVariant(QString::fromStdString(fmt::format("{}", (void*)node))));
QString data;
QTextStream stream(&data);
if(static_cast<bool>(node->isOfType(SoSwitch::getClassTypeId()))) {
auto pcSwitch = static_cast<SoSwitch*>(node);
auto value = pcSwitch->whichChild.getValue();
stream << fmt::format("Which: {} ({})", formatSoSwitchValue(value), value).c_str();
} else if (static_cast<bool>(node->isOfType(SoSeparator::getClassTypeId()))) {
auto pcSeparator = static_cast<SoSeparator*>(node);
auto value = pcSeparator->renderCaching.getValue();
stream << fmt::format("RenderCaching: {} ({})", formatSoSeparatorCacheEnabled(value), value).c_str();
} else if (static_cast<bool>(node->isOfType(SoDrawStyle::getClassTypeId()))) {
auto pcDrawStyle = static_cast<SoDrawStyle*>(node);
auto value = pcDrawStyle->style.getValue();
stream << fmt::format("Style: {} ({})", formatSoDrawStyleElement(value), value).c_str();
} else if (static_cast<bool>(node->isOfType(SoPickStyle::getClassTypeId()))) {
auto pcPickStyle = static_cast<SoPickStyle*>(node);
auto value = pcPickStyle->style.getValue();
stream << fmt::format("Style: {} ({})", formatSoPickStyleElement(value), value).c_str();
} else if (static_cast<bool>(node->isOfType(SoCoordinate3::getClassTypeId()))) {
auto pcCoords = static_cast<SoCoordinate3*>(node);
auto values = pcCoords->point.getValues(0);
if (values) {
float x { 0 };
float y { 0 };
float z { 0 };
values->getValue(x, y, z);
stream << fmt::format("XYZ: {}, {}, {}", x, y, z).c_str();
}
}
this->setData(index.siblingAtColumn((int)Column::DATA), QVariant(data));
if (static_cast<bool>(node->getTypeId().isDerivedFrom(SoGroup::getClassTypeId()))) {
auto group = static_cast<SoGroup*>(node);
this->insertColumns(0, static_cast<int>(Column::COUNT), index);
this->insertRows(0, group->getNumChildren(), index);
for (int i=0; i < group->getNumChildren(); i++) {
SoNode* child = group->getChild(i);
setNode(this->index(i, 0, index), child);
}
}
// insert icon
}
void SceneModel::setNodeNames(const QHash<SoNode*, QString>& names)
@@ -169,7 +282,12 @@ void DlgInspector::setNode(SoNode* node)
model->setNode(node);
QHeaderView* header = ui->treeView->header();
header->setSectionResizeMode(0, QHeaderView::Stretch);
header->setSectionResizeMode(static_cast<int>(Column::INVENTOR_TREE), QHeaderView::Interactive);
header->resizeSection(static_cast<int>(Column::INVENTOR_TREE), 300);
header->setSectionResizeMode(static_cast<int>(Column::NAME), QHeaderView::Interactive);
header->resizeSection(static_cast<int>(Column::NAME), 200);
header->setSectionResizeMode(static_cast<int>(Column::MEMORY_ADDRESS), QHeaderView::Interactive);
header->setSectionResizeMode(static_cast<int>(Column::DATA), QHeaderView::Stretch);
header->setSectionsMovable(false);
}

View File

@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>296</width>
<width>805</width>
<height>583</height>
</rect>
</property>

View File

@@ -49,19 +49,22 @@ View3DInventorSelection::View3DInventorSelection(SoFCUnifiedSelection* root)
pcGroupOnTop = new SoSeparator;
pcGroupOnTop->ref();
pcGroupOnTop->setName("GroupOnTop");
root->addChild(pcGroupOnTop);
auto pcGroupOnTopPickStyle = new SoPickStyle;
pcGroupOnTopPickStyle->style = SoPickStyle::UNPICKABLE;
pcGroupOnTopPickStyle->setOverride(true);
pcGroupOnTopPickStyle->setName("GroupOnTopPickStyle");
pcGroupOnTop->addChild(pcGroupOnTopPickStyle);
coin_setenv("COIN_SEPARATE_DIFFUSE_TRANSPARENCY_OVERRIDE", "1", TRUE);
auto pcOnTopMaterial = new SoMaterial;
pcOnTopMaterial->transparency = 0.5;
pcOnTopMaterial->diffuseColor.setIgnored(true);
pcOnTopMaterial->setOverride(true);
pcGroupOnTop->addChild(pcOnTopMaterial);
auto pcGroupOnTopMaterial = new SoMaterial;
pcGroupOnTopMaterial->transparency = 0.5;
pcGroupOnTopMaterial->diffuseColor.setIgnored(true);
pcGroupOnTopMaterial->setOverride(true);
pcGroupOnTopMaterial->setName("GroupOnTopMaterial");
pcGroupOnTop->addChild(pcGroupOnTopMaterial);
{
auto selRoot = new SoFCSelectionRoot;

View File

@@ -443,6 +443,7 @@ void View3DInventorViewer::init()
backgroundroot = new SoSeparator;
backgroundroot->ref();
this->backgroundroot->addChild(cam);
this->backgroundroot->setName("backgroundroot");
// Background stuff
pcBackGround = new SoFCBackgroundGradient;
@@ -451,6 +452,7 @@ void View3DInventorViewer::init()
// Set up foreground, overlaid scenegraph.
this->foregroundroot = new SoSeparator;
this->foregroundroot->ref();
this->foregroundroot->setName("foregroundroot");
auto lm = new SoLightModel;
lm->model = SoLightModel::BASE_COLOR;
@@ -493,9 +495,14 @@ void View3DInventorViewer::init()
pEventCallback->addEventCallback(SoEvent::getClassTypeId(), handleEventCB, this);
dimensionRoot = new SoSwitch(SO_SWITCH_NONE);
dimensionRoot->setName("RootDimensions");
pcViewProviderRoot->addChild(dimensionRoot);
dimensionRoot->addChild(new SoSwitch()); //first one will be for the 3d dimensions.
dimensionRoot->addChild(new SoSwitch()); //second one for the delta dimensions.
auto dimensions3d = new SoSwitch();
dimensions3d->setName("_3dDimensions");
dimensionRoot->addChild(dimensions3d); //first one will be for the 3d dimensions.
auto dimensionsDelta = new SoSwitch();
dimensionsDelta->setName("DeltaDimensions");
dimensionRoot->addChild(dimensionsDelta); //second one for the delta dimensions.
// This is a callback node that logs all action that traverse the Inventor tree.
#if defined (FC_DEBUG) && defined(FC_LOGGING_CB)
@@ -521,6 +528,7 @@ void View3DInventorViewer::init()
// Create group for the physical object
objectGroup = new SoGroup();
objectGroup->ref();
objectGroup->setName("ObjectGroup");
pcViewProviderRoot->addChild(objectGroup);
// Set our own render action which show a bounding box if

View File

@@ -107,6 +107,7 @@ ViewProvider::ViewProvider()
pcRoot->ref();
pcModeSwitch = new SoSwitch();
pcModeSwitch->ref();
pcModeSwitch->setName("ModeSwitch");
pcTransform = new SoFCTransform();
pcTransform->ref();
pcRoot->addChild(pcTransform);

View File

@@ -101,12 +101,15 @@ ViewProviderGeometryObject::ViewProviderGeometryObject()
pcShapeMaterial = new SoMaterial;
setCoinAppearance(mat);
pcShapeMaterial->ref();
pcShapeMaterial->setName("ShapeMaterial");
pcBoundingBox = new Gui::SoFCBoundingBox;
pcBoundingBox->ref();
pcBoundingBox->setName("BoundingBox");
pcBoundColor = new SoBaseColor();
pcBoundColor->ref();
pcBoundColor->setName("BoundColor");
sPixmap = "Feature";
}
@@ -302,6 +305,7 @@ void ViewProviderGeometryObject::showBoundingBox(bool show)
blue = ((bbcol >> 8) & 0xff) / 255.0F;
pcBoundSwitch = new SoSwitch();
pcBoundSwitch->setName("BoundSwitch");
auto pBoundingSep = new SoSeparator();
auto lineStyle = new SoDrawStyle;
lineStyle->lineWidth = 2.0F;

View File

@@ -48,14 +48,18 @@ ViewProviderTextureExtension::ViewProviderTextureExtension()
pcSwitchAppearance = new SoSwitch;
pcSwitchAppearance->ref();
pcSwitchAppearance->setName("SwitchAppearance");
pcSwitchTexture = new SoSwitch;
pcSwitchTexture->ref();
pcSwitchTexture->setName("SwitchTexture");
pcShapeTexture2D = new SoTexture2;
pcShapeTexture2D->ref();
pcShapeTexture2D->setName("ShapeTexture2D");
pcTextureGroup3D = new SoGroup;
pcTextureGroup3D->ref();
pcTextureGroup3D->setName("TextureGroup3D");
}
void ViewProviderTextureExtension::setup(SoMaterial* pcShapeMaterial)
@@ -160,10 +164,13 @@ ViewProviderFaceTexture::ViewProviderFaceTexture()
// Support for textured faces
pcShapeTexture3D = new SoTexture3;
pcShapeTexture3D->ref();
pcShapeTexture3D->setName("ShapeTexture3D");
pcShapeCoordinates = new SoCoordinate3;
pcShapeCoordinates->ref();
pcShapeCoordinates->setName("ShapeCoordinates");
pcShapeFaceset = new SoIndexedFaceSet;
pcShapeFaceset->ref();
pcShapeFaceset->setName("ShapeFaceset");
}
ViewProviderFaceTexture::~ViewProviderFaceTexture()

View File

@@ -214,28 +214,35 @@ ViewProviderPartExt::ViewProviderPartExt()
pcFaceBind = new SoMaterialBinding();
pcFaceBind->ref();
pcFaceBind->setName("FaceBind");
pcLineBind = new SoMaterialBinding();
pcLineBind->ref();
pcLineBind->setName("LineBind");
pcLineMaterial = new SoMaterial;
pcLineMaterial->ref();
pcLineMaterial->setName("LineMaterial");
LineMaterial.touch();
pcPointBind = new SoMaterialBinding();
pcPointBind->ref();
pcPointBind->setName("PointBind");
pcPointMaterial = new SoMaterial;
pcPointMaterial->ref();
pcPointMaterial->setName("PointMaterial");
PointMaterial.touch();
pcLineStyle = new SoDrawStyle();
pcLineStyle->ref();
pcLineStyle->style = SoDrawStyle::LINES;
pcLineStyle->lineWidth = LineWidth.getValue();
pcLineStyle->setName("LineStyle");
pcPointStyle = new SoDrawStyle();
pcPointStyle->ref();
pcPointStyle->style = SoDrawStyle::POINTS;
pcPointStyle->pointSize = PointSize.getValue();
pcPointStyle->setName("PointStyle");
pShapeHints = new SoShapeHints;
pShapeHints->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE;
@@ -410,9 +417,13 @@ void ViewProviderPartExt::attach(App::DocumentObject *pcFeat)
// Workaround for #0000433, i.e. use SoSeparator instead of SoGroup
auto* pcNormalRoot = new SoSeparator();
pcNormalRoot->setName("NormalRoot");
auto* pcFlatRoot = new SoSeparator();
pcFlatRoot->setName("FlatRoot");
auto* pcWireframeRoot = new SoSeparator();
pcWireframeRoot->setName("WireframeRoot");
auto* pcPointsRoot = new SoSeparator();
pcPointsRoot->setName("PointsRoot");
auto* wireframe = new SoSeparator();
// Must turn off all intermediate render caching, and let pcRoot to handle
@@ -452,6 +463,7 @@ void ViewProviderPartExt::attach(App::DocumentObject *pcFeat)
pcFlatRoot->addChild(texture.getAppearance());
texture.setup(pcShapeMaterial);
SoDrawStyle* pcFaceStyle = new SoDrawStyle();
pcFaceStyle->setName("FaceStyle");
pcFaceStyle->style = SoDrawStyle::FILLED;
pcFlatRoot->addChild(pcFaceStyle);
pcFlatRoot->addChild(norm);