Skip to content

Commit 2ef979a

Browse files
committed
Compute optimal scene hierarchy width
1 parent 5dc2fb4 commit 2ef979a

11 files changed

Lines changed: 132 additions & 14 deletions

File tree

application/F3DOptionsTools.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ static inline const std::map<std::string_view, std::string_view> LibOptionsNames
122122
{ "fps", "ui.fps" },
123123
{ "filename", "ui.filename" },
124124
{ "metadata", "ui.metadata" },
125-
{ "scene-hierarchy", "ui.scene_hierarchy" },
125+
{ "scene-hierarchy", "ui.scene_hierarchy.enable" },
126126
{ "notifications", "ui.notifications.enable" },
127127
{ "hdri-filename", "ui.hdri_filename" },
128128
{ "blur-background", "render.background.blur.enable" },

doc/libf3d/03-OPTIONS.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,13 +576,17 @@ Set the opacity of the backdrop behind the UI elements. Value is between 0.0 (fu
576576

577577
CLI: `--backdrop-opacity`.
578578

579-
### `ui.scene_hierarchy` (_bool_, default: `false`)
579+
### `ui.scene_hierarchy.enable` (_bool_, default: `false`)
580580

581581
Display the _scene hierarchy_ as a tree representing the internal structure of the model, with checkboxes allowing to hide or show individual parts.
582582
By default the tree is only expanded enough to show nodes that have meaningful names, but all nodes can be fully expanded manually.
583583

584584
CLI: `--scene-hierarchy`.
585585

586+
### `ui.scene_hierarchy.max_width` (_int_, default: `600`)
587+
588+
Maximum initial width of the _scene hierarchy_ widget.
589+
586590
### `ui.notifications.enable` (_bool_, default: `false`)
587591

588592
Show notifications at the bottom left of the viewport.

library/options.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,14 @@
296296
"default_value": "false"
297297
},
298298
"scene_hierarchy": {
299-
"type": "bool",
300-
"default_value": "false"
299+
"enable": {
300+
"type": "bool",
301+
"default_value": "false"
302+
},
303+
"max_width": {
304+
"type": "int",
305+
"default_value": "600"
306+
}
301307
},
302308
"notifications": {
303309
"enable": {

library/src/interactor_impl.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1714,7 +1714,7 @@ interactor& interactor_impl::initBindings()
17141714
this->addBinding({mod_t::NONE, "N"}, "toggle ui.filename","Scene", std::bind(docTgl, "Filename", std::cref(opts.ui.filename)), f3d::interactor::BindingType::TOGGLE);
17151715
this->addBinding({mod_t::NONE, "M"}, "toggle ui.metadata","Scene", std::bind(docTgl, "Metadata", std::cref(opts.ui.metadata)), f3d::interactor::BindingType::TOGGLE);
17161716
this->addBinding({mod_t::SHIFT, "N"}, "toggle ui.hdri_filename","Scene", std::bind(docTgl, "HDRI filename", std::cref(opts.ui.hdri_filename)), f3d::interactor::BindingType::TOGGLE);
1717-
this->addBinding({mod_t::SHIFT, "H"}, "toggle ui.scene_hierarchy","Scene", std::bind(docTgl, "Scene hierarchy", std::cref(opts.ui.scene_hierarchy)), f3d::interactor::BindingType::TOGGLE);
1717+
this->addBinding({mod_t::SHIFT, "H"}, "toggle ui.scene_hierarchy.enable","Scene", std::bind(docTgl, "Scene hierarchy", std::cref(opts.ui.scene_hierarchy.enable)), f3d::interactor::BindingType::TOGGLE);
17181718
this->addBinding({mod_t::NONE, "Z"}, "toggle ui.fps","Scene", std::bind(docTgl, "FPS Counter", std::cref(opts.ui.fps)), f3d::interactor::BindingType::TOGGLE);
17191719
#endif
17201720
#if F3D_MODULE_RAYTRACING

library/src/window_impl.cxx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,8 @@ void window_impl::UpdateDynamicOptions()
459459
renderer->SetFilenameInfo(opt.ui.filename_info);
460460
renderer->ShowMetaData(opt.ui.metadata);
461461
renderer->ShowHDRIFilename(opt.ui.hdri_filename);
462-
renderer->ShowSceneHierarchy(opt.ui.scene_hierarchy);
462+
renderer->ShowSceneHierarchy(opt.ui.scene_hierarchy.enable);
463+
renderer->SetSceneHierarchyMaxWidth(opt.ui.scene_hierarchy.max_width);
463464
renderer->ShowCheatSheet(opt.ui.cheatsheet);
464465
renderer->ShowConsole(opt.ui.console);
465466
renderer->ShowMinimalConsole(opt.ui.minimal_console);

vtkext/private/module/vtkF3DImguiActor.cxx

Lines changed: 86 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,61 @@ class vtkF3DRenderDataAssemblyVisitor : public vtkDataAssemblyVisitor
239239
};
240240
vtkStandardNewMacro(vtkF3DRenderDataAssemblyVisitor);
241241

242+
/**
243+
* Visitor used to traverse a full tree (one per importer).
244+
* It will take care of estimate the maximum width of the tree nodes in order to set the width of
245+
* the scene hierarchy UI widget.
246+
*/
247+
class vtkF3DMaxWidthAssemblyVisitor : public vtkDataAssemblyVisitor
248+
{
249+
public:
250+
static vtkF3DMaxWidthAssemblyVisitor* New();
251+
vtkTypeMacro(vtkF3DMaxWidthAssemblyVisitor, vtkDataAssemblyVisitor);
252+
253+
float GetMaxWidth() const
254+
{
255+
return this->MaxWidth;
256+
}
257+
258+
protected:
259+
bool GetTraverseSubtree(int nodeid) override
260+
{
261+
return this->GetAssembly()->GetAttributeOrDefault(nodeid, "f3d_collapsed", 0) == 0;
262+
}
263+
264+
void Visit(int nodeid) override
265+
{
266+
const char* defaultLabel =
267+
this->GetAssembly()->GetNumberOfChildren(nodeid) > 0 ? "<group>" : "<object>";
268+
269+
float width =
270+
ImGui::CalcTextSize(this->GetAssembly()->GetAttributeOrDefault(nodeid, "label", defaultLabel))
271+
.x;
272+
273+
// arrow or bullet
274+
width += ImGui::GetFontSize();
275+
276+
// spacing between arrow/bullet and checkbox
277+
width += ImGui::GetStyle().ItemSpacing.x;
278+
279+
// checkbox
280+
width += ImGui::GetFontSize() + ImGui::GetStyle().ItemInnerSpacing.x;
281+
282+
// indentation for parent nodes
283+
while (nodeid != vtkDataAssembly::GetRootNode())
284+
{
285+
width += ImGui::GetStyle().IndentSpacing;
286+
nodeid = this->GetAssembly()->GetParent(nodeid);
287+
}
288+
289+
this->MaxWidth = std::max(this->MaxWidth, width);
290+
}
291+
292+
private:
293+
float MaxWidth = 0.f;
294+
};
295+
vtkStandardNewMacro(vtkF3DMaxWidthAssemblyVisitor);
296+
242297
}
243298

244299
struct vtkF3DImguiActor::Internals
@@ -586,8 +641,14 @@ void vtkF3DImguiActor::RenderSceneHierarchy(vtkOpenGLRenderWindow* renWin)
586641
const ImGuiViewport* viewport = ImGui::GetMainViewport();
587642
assert(viewport);
588643

644+
vtkF3DRenderer* ren = vtkF3DRenderer::SafeDownCast(renWin->GetRenderers()->GetFirstRenderer());
645+
assert(ren != nullptr);
646+
647+
vtkF3DMetaImporter* importer = ren->GetMetaImporter();
648+
assert(importer != nullptr);
649+
589650
constexpr float margin = F3DStyle::GetDefaultMargin();
590-
constexpr float defaultWidth = 200.f;
651+
float defaultWidth = this->CalculateHierarchyWidth(importer);
591652
float winHeight = viewport->WorkSize.y - 2.0f * margin;
592653

593654
float posX = margin;
@@ -608,12 +669,6 @@ void vtkF3DImguiActor::RenderSceneHierarchy(vtkOpenGLRenderWindow* renWin)
608669

609670
ImGui::Begin("Scene Hierarchy", nullptr, flags);
610671

611-
vtkF3DRenderer* ren = vtkF3DRenderer::SafeDownCast(renWin->GetRenderers()->GetFirstRenderer());
612-
assert(ren != nullptr);
613-
614-
vtkF3DMetaImporter* importer = ren->GetMetaImporter();
615-
assert(importer != nullptr);
616-
617672
for (int i = 0; i < importer->GetImporterInfoCount(); i++)
618673
{
619674
vtkF3DMetaImporter::ImporterInfo info = importer->GetImporterInfo(i);
@@ -629,6 +684,30 @@ void vtkF3DImguiActor::RenderSceneHierarchy(vtkOpenGLRenderWindow* renWin)
629684
ImGui::End();
630685
}
631686

687+
//----------------------------------------------------------------------------
688+
float vtkF3DImguiActor::CalculateHierarchyWidth(vtkF3DMetaImporter* importer)
689+
{
690+
float maxWidth = 0.0f;
691+
const float indentPerLevel = ImGui::GetStyle().IndentSpacing;
692+
const float treeArrowWidth = ImGui::GetFontSize();
693+
const float checkboxWidth = ImGui::GetFrameHeight() + ImGui::GetStyle().ItemInnerSpacing.x;
694+
695+
for (int i = 0; i < importer->GetImporterInfoCount(); i++)
696+
{
697+
vtkF3DMetaImporter::ImporterInfo info = importer->GetImporterInfo(i);
698+
699+
vtkNew<::vtkF3DMaxWidthAssemblyVisitor> visitor;
700+
info.DataAssembly->Visit(vtkDataAssembly::GetRootNode(), visitor);
701+
702+
maxWidth = std::max(maxWidth, visitor->GetMaxWidth());
703+
}
704+
705+
float totalWidth =
706+
maxWidth + 2.0f * ImGui::GetStyle().WindowPadding.x + ImGui::GetStyle().ScrollbarSize;
707+
708+
return std::min(totalWidth, static_cast<float>(this->SceneHierarchyMaxWidth));
709+
}
710+
632711
//----------------------------------------------------------------------------
633712
void vtkF3DImguiActor::RenderDropZone()
634713
{

vtkext/private/module/vtkF3DImguiActor.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <memory>
1414

15+
class vtkF3DMetaImporter;
1516
class vtkOpenGLRenderWindow;
1617
class vtkWindow;
1718

@@ -120,6 +121,11 @@ class vtkF3DImguiActor : public vtkF3DUIActor
120121
* Compute the width of a badge
121122
*/
122123
float CalcBadgeWidth(const std::string& text);
124+
125+
/**
126+
* Calculate the default width of the scene hierarchy UI widget
127+
*/
128+
float CalculateHierarchyWidth(vtkF3DMetaImporter* importer);
123129
};
124130

125131
#endif

vtkext/private/module/vtkF3DRenderer.cxx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1885,6 +1885,12 @@ void vtkF3DRenderer::ConfigureMetaData()
18851885
this->MetaDataConfigured = true;
18861886
}
18871887

1888+
//----------------------------------------------------------------------------
1889+
void vtkF3DRenderer::SetSceneHierarchyMaxWidth(const int maxWidth)
1890+
{
1891+
this->UIActor->SetSceneHierarchyMaxWidth(maxWidth);
1892+
}
1893+
18881894
//----------------------------------------------------------------------------
18891895
void vtkF3DRenderer::ShowSceneHierarchy(bool show)
18901896
{

vtkext/private/module/vtkF3DRenderer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ class vtkF3DRenderer : public vtkOpenGLRenderer
132132
void SetGridColor(const std::vector<double>& color);
133133
void SetAxesColor(const std::vector<double>& colorXAxis, const std::vector<double>& colorYAxis,
134134
const std::vector<double>& colorZAxis);
135+
void SetSceneHierarchyMaxWidth(const int width);
135136
///@}
136137

137138
/**

vtkext/private/module/vtkF3DUIActor.cxx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,16 @@ void vtkF3DUIActor::SetBackdropOpacity(const double backdropOpacity)
190190
}
191191
}
192192

193+
//----------------------------------------------------------------------------
194+
void vtkF3DUIActor::SetSceneHierarchyMaxWidth(const int width)
195+
{
196+
if (this->SceneHierarchyMaxWidth != width)
197+
{
198+
this->SceneHierarchyMaxWidth = width;
199+
this->Initialized = false;
200+
}
201+
}
202+
193203
//----------------------------------------------------------------------------
194204
int vtkF3DUIActor::RenderOverlay(vtkViewport* vp)
195205
{

0 commit comments

Comments
 (0)