Add multi-select, specifier column, and visibility shortcuts to hierarchy panel
Ctrl+click toggles prim selection; Shift+click range-selects using a per-frame visible-order list. Multi-selection is broadcast to the viewport via a new SetOnPrimsSelected callback so Hydra highlights all selected prims. Adds a 5th table column showing each prim's SdfSpecifier (def/over/class) with colour coding. 'over' prims are shown in orange to make overrides immediately visible. Visibility icon updated: invisible prims show EyeSlash in orange instead of grey. Ctrl+H / Shift+H keyboard shortcuts hide / show all selected prims. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -115,6 +115,11 @@ bool Application::Initialize(const std::string& windowTitle, int width, int heig
|
|||||||
m_curveEditorPanel->SetSelectedPrimPath(path);
|
m_curveEditorPanel->SetSelectedPrimPath(path);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_sceneHierarchyPanel->SetOnPrimsSelected(
|
||||||
|
[this](const std::vector<std::string>& paths) {
|
||||||
|
m_viewportPanel->SetSelectedPrimPaths(paths);
|
||||||
|
});
|
||||||
|
|
||||||
m_sceneHierarchyPanel->SetOnStageMetadataChanged(
|
m_sceneHierarchyPanel->SetOnStageMetadataChanged(
|
||||||
[this]() {
|
[this]() {
|
||||||
RefreshManagers();
|
RefreshManagers();
|
||||||
|
|||||||
+120
-11
@@ -86,9 +86,58 @@ void SceneHierarchyPanel::SetSelectedPathFromClick(const std::string& path) {
|
|||||||
m_primarySelectedPath = path;
|
m_primarySelectedPath = path;
|
||||||
m_primarySdfPath = path.empty() ? SdfPath() : SdfPath(path);
|
m_primarySdfPath = path.empty() ? SdfPath() : SdfPath(path);
|
||||||
if (!path.empty()) m_selectedPaths.insert(path);
|
if (!path.empty()) m_selectedPaths.insert(path);
|
||||||
// No scroll — user clicked the item directly, it's already visible.
|
if (!path.empty()) m_rangeAnchorPath = SdfPath(path);
|
||||||
m_scrollToSelected = false;
|
m_scrollToSelected = false;
|
||||||
if (m_onPrimSelected) m_onPrimSelected(path);
|
if (m_onPrimSelected) m_onPrimSelected(path);
|
||||||
|
if (m_onPrimsSelected) {
|
||||||
|
std::vector<std::string> v;
|
||||||
|
if (!path.empty()) v.push_back(path);
|
||||||
|
m_onPrimsSelected(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneHierarchyPanel::ToggleSelectionFromClick(const std::string& path) {
|
||||||
|
if (m_selectedPaths.count(path)) {
|
||||||
|
m_selectedPaths.erase(path);
|
||||||
|
if (m_primarySelectedPath == path) {
|
||||||
|
m_primarySelectedPath = m_selectedPaths.empty() ? "" : *m_selectedPaths.begin();
|
||||||
|
m_primarySdfPath = m_primarySelectedPath.empty()
|
||||||
|
? SdfPath() : SdfPath(m_primarySelectedPath);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_selectedPaths.insert(path);
|
||||||
|
m_primarySelectedPath = path;
|
||||||
|
m_primarySdfPath = SdfPath(path);
|
||||||
|
m_rangeAnchorPath = SdfPath(path);
|
||||||
|
}
|
||||||
|
m_scrollToSelected = false;
|
||||||
|
if (m_onPrimSelected) m_onPrimSelected(m_primarySelectedPath);
|
||||||
|
if (m_onPrimsSelected) {
|
||||||
|
std::vector<std::string> v(m_selectedPaths.begin(), m_selectedPaths.end());
|
||||||
|
m_onPrimsSelected(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneHierarchyPanel::RangeSelectToPath(const SdfPath& path) {
|
||||||
|
auto it1 = std::find(m_visiblePrimOrder.begin(), m_visiblePrimOrder.end(), m_rangeAnchorPath);
|
||||||
|
auto it2 = std::find(m_visiblePrimOrder.begin(), m_visiblePrimOrder.end(), path);
|
||||||
|
if (it1 != m_visiblePrimOrder.end() && it2 != m_visiblePrimOrder.end()) {
|
||||||
|
int idx1 = static_cast<int>(it1 - m_visiblePrimOrder.begin());
|
||||||
|
int idx2 = static_cast<int>(it2 - m_visiblePrimOrder.begin());
|
||||||
|
if (idx1 > idx2) std::swap(idx1, idx2);
|
||||||
|
for (int i = idx1; i <= idx2; ++i)
|
||||||
|
m_selectedPaths.insert(m_visiblePrimOrder[i].GetString());
|
||||||
|
} else {
|
||||||
|
m_selectedPaths.insert(path.GetString());
|
||||||
|
}
|
||||||
|
m_primarySelectedPath = path.GetString();
|
||||||
|
m_primarySdfPath = path;
|
||||||
|
m_scrollToSelected = false;
|
||||||
|
if (m_onPrimSelected) m_onPrimSelected(m_primarySelectedPath);
|
||||||
|
if (m_onPrimsSelected) {
|
||||||
|
std::vector<std::string> v(m_selectedPaths.begin(), m_selectedPaths.end());
|
||||||
|
m_onPrimsSelected(v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* SceneHierarchyPanel::GetPrimTypeIcon(const UsdPrim& prim) const {
|
const char* SceneHierarchyPanel::GetPrimTypeIcon(const UsdPrim& prim) const {
|
||||||
@@ -185,6 +234,26 @@ void SceneHierarchyPanel::HandleKeyboardShortcuts() {
|
|||||||
SetSelectedPathFromClick(groupPath.GetString());
|
SetSelectedPathFromClick(groupPath.GetString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ctrl+H — hide selected prims (visibility = invisible).
|
||||||
|
if (ImGui::GetIO().KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_H, false) &&
|
||||||
|
!m_selectedPaths.empty() && m_stage) {
|
||||||
|
for (const auto& pathStr : m_selectedPaths) {
|
||||||
|
UsdPrim prim = m_stage->GetPrimAtPath(SdfPath(pathStr));
|
||||||
|
if (prim.IsValid() && prim.IsA<UsdGeomImageable>())
|
||||||
|
UsdGeomImageable(prim).GetVisibilityAttr().Set(UsdGeomTokens->invisible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift+H — show selected prims (visibility = inherited).
|
||||||
|
if (ImGui::GetIO().KeyShift && ImGui::IsKeyPressed(ImGuiKey_H, false) &&
|
||||||
|
!m_selectedPaths.empty() && m_stage) {
|
||||||
|
for (const auto& pathStr : m_selectedPaths) {
|
||||||
|
UsdPrim prim = m_stage->GetPrimAtPath(SdfPath(pathStr));
|
||||||
|
if (prim.IsValid() && prim.IsA<UsdGeomImageable>())
|
||||||
|
UsdGeomImageable(prim).GetVisibilityAttr().Set(UsdGeomTokens->inherited);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Delete — open the remove-prim confirmation modal.
|
// Delete — open the remove-prim confirmation modal.
|
||||||
if (ImGui::IsKeyPressed(ImGuiKey_Delete, false) && !m_primarySdfPath.IsEmpty()) {
|
if (ImGui::IsKeyPressed(ImGuiKey_Delete, false) && !m_primarySdfPath.IsEmpty()) {
|
||||||
auto rootLayer = m_stage->GetRootLayer();
|
auto rootLayer = m_stage->GetRootLayer();
|
||||||
@@ -266,6 +335,9 @@ void SceneHierarchyPanel::Render() {
|
|||||||
} else {
|
} else {
|
||||||
UsdPrim root = m_stage->GetPseudoRoot();
|
UsdPrim root = m_stage->GetPseudoRoot();
|
||||||
|
|
||||||
|
// Rebuilt each frame as RenderPrimNode visits prims — used for range select.
|
||||||
|
m_visiblePrimOrder.clear();
|
||||||
|
|
||||||
// Rebuild local-layer set once per frame (used by RenderPrimNode to
|
// Rebuild local-layer set once per frame (used by RenderPrimNode to
|
||||||
// detect attribute overrides). GetLayerStack() returns only the stage's
|
// detect attribute overrides). GetLayerStack() returns only the stage's
|
||||||
// own layers — root layer, sublayers, session layer — NOT reference layers.
|
// own layers — root layer, sublayers, session layer — NOT reference layers.
|
||||||
@@ -288,12 +360,14 @@ void SceneHierarchyPanel::Render() {
|
|||||||
ImGuiTableFlags_RowBg |
|
ImGuiTableFlags_RowBg |
|
||||||
ImGuiTableFlags_SizingFixedFit;
|
ImGuiTableFlags_SizingFixedFit;
|
||||||
|
|
||||||
if (ImGui::BeginTable("##primtree", 4, tblFlags)) {
|
const float kSpecW = ImGui::CalcTextSize("over").x + 2.f;
|
||||||
// Col 0 stretches; cols 1-3 are small fixed-width icon columns.
|
if (ImGui::BeginTable("##primtree", 5, tblFlags)) {
|
||||||
|
// Col 0 stretches; cols 1-4 are small fixed-width columns.
|
||||||
ImGui::TableSetupColumn("##prim", ImGuiTableColumnFlags_WidthStretch);
|
ImGui::TableSetupColumn("##prim", ImGuiTableColumnFlags_WidthStretch);
|
||||||
ImGui::TableSetupColumn("##type", ImGuiTableColumnFlags_WidthFixed, kIconW);
|
ImGui::TableSetupColumn("##type", ImGuiTableColumnFlags_WidthFixed, kIconW);
|
||||||
ImGui::TableSetupColumn("##vis", ImGuiTableColumnFlags_WidthFixed, kIconW);
|
ImGui::TableSetupColumn("##vis", ImGuiTableColumnFlags_WidthFixed, kIconW);
|
||||||
ImGui::TableSetupColumn("##ref", ImGuiTableColumnFlags_WidthFixed, kIconW);
|
ImGui::TableSetupColumn("##ref", ImGuiTableColumnFlags_WidthFixed, kIconW);
|
||||||
|
ImGui::TableSetupColumn("##spec", ImGuiTableColumnFlags_WidthFixed, kSpecW);
|
||||||
|
|
||||||
for (const auto& child : root.GetChildren())
|
for (const auto& child : root.GetChildren())
|
||||||
RenderPrimNode(child);
|
RenderPrimNode(child);
|
||||||
@@ -524,6 +598,7 @@ void SceneHierarchyPanel::RenderPrimNode(const UsdPrim& prim) {
|
|||||||
bool isInvisible = false;
|
bool isInvisible = false;
|
||||||
bool hasRefs = prim.HasAuthoredReferences();
|
bool hasRefs = prim.HasAuthoredReferences();
|
||||||
bool hasChildren = !prim.GetChildren().empty();
|
bool hasChildren = !prim.GetChildren().empty();
|
||||||
|
SdfSpecifier spec = prim.GetSpecifier();
|
||||||
|
|
||||||
if (isImageable) {
|
if (isImageable) {
|
||||||
UsdGeomImageable img(prim);
|
UsdGeomImageable img(prim);
|
||||||
@@ -565,6 +640,7 @@ void SceneHierarchyPanel::RenderPrimNode(const UsdPrim& prim) {
|
|||||||
// ────────────────────────────────────────────────────────────────────────
|
// ────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
|
m_visiblePrimOrder.push_back(primPath); // for Shift+LMB range select
|
||||||
ImGui::TableNextColumn(); // Col 0 — prim name + tree arrow
|
ImGui::TableNextColumn(); // Col 0 — prim name + tree arrow
|
||||||
|
|
||||||
ImGui::PushID(primStr.c_str());
|
ImGui::PushID(primStr.c_str());
|
||||||
@@ -642,6 +718,7 @@ void SceneHierarchyPanel::RenderPrimNode(const UsdPrim& prim) {
|
|||||||
ImGui::TableNextColumn(); // Col 1
|
ImGui::TableNextColumn(); // Col 1
|
||||||
ImGui::TableNextColumn(); // Col 2
|
ImGui::TableNextColumn(); // Col 2
|
||||||
ImGui::TableNextColumn(); // Col 3
|
ImGui::TableNextColumn(); // Col 3
|
||||||
|
ImGui::TableNextColumn(); // Col 4
|
||||||
if (open && hasChildren)
|
if (open && hasChildren)
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
@@ -655,9 +732,16 @@ void SceneHierarchyPanel::RenderPrimNode(const UsdPrim& prim) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!isRenaming) {
|
if (!isRenaming) {
|
||||||
// Selection on click (not on toggle arrow).
|
// Selection on LMB click (not on toggle arrow).
|
||||||
if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
|
// Shift+LMB: range-select from anchor. Ctrl+LMB: toggle. Plain: replace.
|
||||||
SetSelectedPathFromClick(primStr);
|
if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) {
|
||||||
|
if (ImGui::GetIO().KeyShift)
|
||||||
|
RangeSelectToPath(primPath);
|
||||||
|
else if (ImGui::GetIO().KeyCtrl)
|
||||||
|
ToggleSelectionFromClick(primStr);
|
||||||
|
else
|
||||||
|
SetSelectedPathFromClick(primStr);
|
||||||
|
}
|
||||||
|
|
||||||
// Double-click to start inline rename.
|
// Double-click to start inline rename.
|
||||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
|
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
|
||||||
@@ -705,7 +789,7 @@ void SceneHierarchyPanel::RenderPrimNode(const UsdPrim& prim) {
|
|||||||
ImGui::EndDragDropTarget();
|
ImGui::EndDragDropTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context menu (must follow the last widget = the tree node).
|
// Context menu on RMB.
|
||||||
RenderContextMenu(prim);
|
RenderContextMenu(prim);
|
||||||
|
|
||||||
// A context menu op (Unparent, Group, etc.) may have moved this prim,
|
// A context menu op (Unparent, Group, etc.) may have moved this prim,
|
||||||
@@ -714,6 +798,7 @@ void SceneHierarchyPanel::RenderPrimNode(const UsdPrim& prim) {
|
|||||||
ImGui::TableNextColumn(); // Col 1
|
ImGui::TableNextColumn(); // Col 1
|
||||||
ImGui::TableNextColumn(); // Col 2
|
ImGui::TableNextColumn(); // Col 2
|
||||||
ImGui::TableNextColumn(); // Col 3
|
ImGui::TableNextColumn(); // Col 3
|
||||||
|
ImGui::TableNextColumn(); // Col 4
|
||||||
if (open && hasChildren)
|
if (open && hasChildren)
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
@@ -740,8 +825,9 @@ void SceneHierarchyPanel::RenderPrimNode(const UsdPrim& prim) {
|
|||||||
const float iconSz = ImGui::GetTextLineHeight();
|
const float iconSz = ImGui::GetTextLineHeight();
|
||||||
const ImVec2 iconVec(iconSz, iconSz);
|
const ImVec2 iconVec(iconSz, iconSz);
|
||||||
Icon visIcon = isInvisible ? Icon::EyeSlash : Icon::Eye;
|
Icon visIcon = isInvisible ? Icon::EyeSlash : Icon::Eye;
|
||||||
ImVec4 visTint = isInvisible ? ImVec4(0.45f, 0.45f, 0.45f, 0.6f)
|
// Invisible: EyeSlash in orange; Visible: Eye at full alpha (dimmer tint).
|
||||||
: ImVec4(0.9f, 0.9f, 0.9f, 1.0f);
|
ImVec4 visTint = isInvisible ? ImVec4(1.00f, 0.60f, 0.15f, 1.0f)
|
||||||
|
: ImVec4(0.60f, 0.60f, 0.60f, 1.0f);
|
||||||
ImTextureID id = m_iconManager ? m_iconManager->Get(visIcon) : ImTextureID_Invalid;
|
ImTextureID id = m_iconManager ? m_iconManager->Get(visIcon) : ImTextureID_Invalid;
|
||||||
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0,0,0,0));
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0,0,0,0));
|
||||||
@@ -750,7 +836,8 @@ void SceneHierarchyPanel::RenderPrimNode(const UsdPrim& prim) {
|
|||||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0));
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0));
|
||||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 1.f);
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 1.f);
|
||||||
|
|
||||||
if (ImGui::ImageButton("##vis", ImTextureRef(id), iconVec,
|
std::string visId = "##vis_" + primStr;
|
||||||
|
if (ImGui::ImageButton(visId.c_str(), ImTextureRef(id), iconVec,
|
||||||
ImVec2(0,0), ImVec2(1,1), ImVec4(0,0,0,0), visTint)) {
|
ImVec2(0,0), ImVec2(1,1), ImVec4(0,0,0,0), visTint)) {
|
||||||
try {
|
try {
|
||||||
UsdGeomImageable img(prim);
|
UsdGeomImageable img(prim);
|
||||||
@@ -789,6 +876,28 @@ void SceneHierarchyPanel::RenderPrimNode(const UsdPrim& prim) {
|
|||||||
ImGui::SetTooltip("Has references");
|
ImGui::SetTooltip("Has references");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Col 4: Specifier (def / over / class) ──────────────────────────────
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
{
|
||||||
|
const char* label = nullptr;
|
||||||
|
ImVec4 color;
|
||||||
|
switch (spec) {
|
||||||
|
case SdfSpecifierOver:
|
||||||
|
label = "over";
|
||||||
|
color = ImVec4(1.00f, 0.60f, 0.10f, isActive ? 1.0f : 0.45f);
|
||||||
|
break;
|
||||||
|
case SdfSpecifierClass:
|
||||||
|
label = "class";
|
||||||
|
color = ImVec4(0.40f, 0.70f, 1.00f, isActive ? 1.0f : 0.45f);
|
||||||
|
break;
|
||||||
|
default: // SdfSpecifierDef
|
||||||
|
label = "def";
|
||||||
|
color = ImVec4(0.45f, 0.45f, 0.45f, isActive ? 0.55f : 0.30f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ImGui::TextColored(color, "%s", label);
|
||||||
|
}
|
||||||
|
|
||||||
// ── Recurse into children ───────────────────────────────────────────────
|
// ── Recurse into children ───────────────────────────────────────────────
|
||||||
// TreePop must be called in the SAME column as TreeNodeEx (col 0).
|
// TreePop must be called in the SAME column as TreeNodeEx (col 0).
|
||||||
// Since we called TableNextColumn three more times above, we must move
|
// Since we called TableNextColumn three more times above, we must move
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../core/PropertyManager.h"
|
#include "../core/PropertyManager.h"
|
||||||
#include "../core/CommandHistory.h"
|
#include "../core/CommandHistory.h"
|
||||||
@@ -62,6 +62,9 @@ public:
|
|||||||
using PrimSelectCallback = std::function<void(const std::string& path)>;
|
using PrimSelectCallback = std::function<void(const std::string& path)>;
|
||||||
void SetOnPrimSelected(PrimSelectCallback callback) { m_onPrimSelected = callback; }
|
void SetOnPrimSelected(PrimSelectCallback callback) { m_onPrimSelected = callback; }
|
||||||
|
|
||||||
|
using MultiPrimSelectCallback = std::function<void(const std::vector<std::string>&)>;
|
||||||
|
void SetOnPrimsSelected(MultiPrimSelectCallback cb) { m_onPrimsSelected = cb; }
|
||||||
|
|
||||||
/// Called when stage-level metadata (e.g. up axis) is changed via the hierarchy panel.
|
/// Called when stage-level metadata (e.g. up axis) is changed via the hierarchy panel.
|
||||||
using StageMetadataChangedCallback = std::function<void()>;
|
using StageMetadataChangedCallback = std::function<void()>;
|
||||||
void SetOnStageMetadataChanged(StageMetadataChangedCallback callback) { m_onStageMetadataChanged = callback; }
|
void SetOnStageMetadataChanged(StageMetadataChangedCallback callback) { m_onStageMetadataChanged = callback; }
|
||||||
@@ -96,7 +99,12 @@ private:
|
|||||||
/// NOT layers that came in through references or payloads.
|
/// NOT layers that came in through references or payloads.
|
||||||
std::unordered_set<std::string> m_localLayers;
|
std::unordered_set<std::string> m_localLayers;
|
||||||
|
|
||||||
|
/// Visible prim order rebuilt each frame — used for Shift+RMB range select.
|
||||||
|
std::vector<pxr::SdfPath> m_visiblePrimOrder;
|
||||||
|
pxr::SdfPath m_rangeAnchorPath;
|
||||||
|
|
||||||
PrimSelectCallback m_onPrimSelected;
|
PrimSelectCallback m_onPrimSelected;
|
||||||
|
MultiPrimSelectCallback m_onPrimsSelected;
|
||||||
StageMetadataChangedCallback m_onStageMetadataChanged;
|
StageMetadataChangedCallback m_onStageMetadataChanged;
|
||||||
|
|
||||||
/// Remove-prim confirmation state.
|
/// Remove-prim confirmation state.
|
||||||
@@ -121,6 +129,8 @@ private:
|
|||||||
bool m_renameJustStarted = false;
|
bool m_renameJustStarted = false;
|
||||||
|
|
||||||
void HandleKeyboardShortcuts();
|
void HandleKeyboardShortcuts();
|
||||||
|
void ToggleSelectionFromClick(const std::string& path);
|
||||||
|
void RangeSelectToPath(const pxr::SdfPath& path);
|
||||||
SdfPath FindUniqueChildPath(const SdfPath& parent, const std::string& baseName);
|
SdfPath FindUniqueChildPath(const SdfPath& parent, const std::string& baseName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -138,6 +138,17 @@ void ViewportPanel::SetSelectedPrimPath(const std::string& path)
|
|||||||
BroadcastSelection();
|
BroadcastSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ViewportPanel::SetSelectedPrimPaths(const std::vector<std::string>& paths)
|
||||||
|
{
|
||||||
|
m_selectedSdfPaths.clear();
|
||||||
|
m_selectedPrimPath.clear();
|
||||||
|
for (const auto& p : paths)
|
||||||
|
m_selectedSdfPaths.push_back(pxr::SdfPath(p));
|
||||||
|
if (!paths.empty())
|
||||||
|
m_selectedPrimPath = paths.front();
|
||||||
|
BroadcastSelection();
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Forwarding accessors
|
// Forwarding accessors
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -384,7 +395,7 @@ void ViewportPanel::RenderGlobalLeftToolbar(ImVec2 contentPos, ImVec2 /*contentS
|
|||||||
const float kIconPad = 5.0f;
|
const float kIconPad = 5.0f;
|
||||||
const float kRounding = 4.0f;
|
const float kRounding = 4.0f;
|
||||||
const float kSpacing = 3.0f;
|
const float kSpacing = 3.0f;
|
||||||
const float kPadX = 9.0f; // left padding inside the strip
|
const float kPadX = 4.0f; // left padding inside the strip
|
||||||
const float kPadY = 10.0f; // top padding
|
const float kPadY = 10.0f; // top padding
|
||||||
const float kSepH = 1.0f; // separator line height
|
const float kSepH = 1.0f; // separator line height
|
||||||
const float kSepGap = 6.0f; // space around separator
|
const float kSepGap = 6.0f; // space around separator
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ public:
|
|||||||
// ── Selection (called by SceneHierarchyPanel) ────────────────────────────
|
// ── Selection (called by SceneHierarchyPanel) ────────────────────────────
|
||||||
/// Set a single selected prim (clears any multi-selection).
|
/// Set a single selected prim (clears any multi-selection).
|
||||||
void SetSelectedPrimPath(const std::string& path);
|
void SetSelectedPrimPath(const std::string& path);
|
||||||
|
/// Set multiple selected prims (from hierarchy Ctrl+click multi-select).
|
||||||
|
void SetSelectedPrimPaths(const std::vector<std::string>& paths);
|
||||||
|
|
||||||
// ── Main render (called from Application::RenderUI) ──────────────────────
|
// ── Main render (called from Application::RenderUI) ──────────────────────
|
||||||
void Render(bool* p_open = nullptr);
|
void Render(bool* p_open = nullptr);
|
||||||
@@ -99,7 +101,7 @@ private:
|
|||||||
bool IsMouseOverDivider(ImVec2 origin, ImVec2 total) const;
|
bool IsMouseOverDivider(ImVec2 origin, ImVec2 total) const;
|
||||||
|
|
||||||
/// Width (px) of the reserved left toolbar strip.
|
/// Width (px) of the reserved left toolbar strip.
|
||||||
static constexpr float kToolbarW = 52.0f;
|
static constexpr float kToolbarW = 40.0f;
|
||||||
|
|
||||||
// ── Selection management ─────────────────────────────────────────────────
|
// ── Selection management ─────────────────────────────────────────────────
|
||||||
/// Push the current shared selection into every tile and the manipulator.
|
/// Push the current shared selection into every tile and the manipulator.
|
||||||
|
|||||||
Reference in New Issue
Block a user