From 251174ddc3bd1edd3832a71be92c043d0a081002 Mon Sep 17 00:00:00 2001 From: indigo Date: Wed, 17 Jun 2026 07:28:04 +0800 Subject: [PATCH] Property panel: display and edit primvars:displayColor[] as color swatches DrawVtValueWidget now handles Color-role array attributes (VtArray and VtArray) that previously fell through to the generic [array N] fallback. - Single element: inline ColorEdit3/4 - Multiple elements: collapsible row with up to 5 swatch previews + [N] count; expanded view shows per-index ColorEdit3/4 (capped at 16 entries) - Editing any element writes the full modified VtArray back via attr.Set() Covers primvars:displayColor, primvars:displayOpacity[], and any other color3f[]/color4f[] primvar. Co-Authored-By: Claude Sonnet 4.6 --- src/ui/PropertyPanel.cpp | 96 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/src/ui/PropertyPanel.cpp b/src/ui/PropertyPanel.cpp index b348cdc..cfd771b 100644 --- a/src/ui/PropertyPanel.cpp +++ b/src/ui/PropertyPanel.cpp @@ -577,8 +577,9 @@ static pxr::VtValue DrawVtValueWidget(pxr::UsdAttribute& attr, { using namespace pxr; - // Color role → ColorEdit3/4 + // Color role → ColorEdit3/4 (scalar and array) if (attr.GetRoleName() == TfToken("Color")) { + // ---- scalar ---- if (val.IsHolding()) { GfVec3f c = val.UncheckedGet(); if (ImGui::ColorEdit3("##col", c.data())) @@ -591,6 +592,99 @@ static pxr::VtValue DrawVtValueWidget(pxr::UsdAttribute& attr, return VtValue(c); return VtValue(); } + + // ---- color3f[] (e.g. primvars:displayColor) ---- + if (val.IsHolding>()) { + VtArray arr = val.UncheckedGet>(); + bool changed = false; + if (arr.size() == 1) { + GfVec3f c = arr[0]; + if (ImGui::ColorEdit3("##dc", c.data())) + { arr[0] = c; changed = true; } + } else if (!arr.empty()) { + // Collapsible: arrow + swatch preview on header line + bool open = ImGui::TreeNodeEx("##dcarr", + ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_SpanAvailWidth); + ImGui::SameLine(0, 6); + float sz = ImGui::GetTextLineHeight(); + size_t shown = std::min(arr.size(), (size_t)5); + for (size_t i = 0; i < shown; ++i) { + if (i > 0) ImGui::SameLine(0, 2); + char sid[16]; snprintf(sid, sizeof(sid), "##sv%d", (int)i); + ImGui::ColorButton(sid, + ImVec4(arr[i][0], arr[i][1], arr[i][2], 1.f), + ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, + ImVec2(sz, sz)); + } + ImGui::SameLine(0, 4); + ImGui::TextDisabled("[%zu]", arr.size()); + if (open) { + static constexpr size_t kEditLimit = 16; + size_t lim = std::min(arr.size(), kEditLimit); + for (size_t i = 0; i < lim; ++i) { + ImGui::PushID((int)i); + ImGui::Text("[%d]", (int)i); + ImGui::SameLine(); + GfVec3f c = arr[i]; + ImGui::SetNextItemWidth(-FLT_MIN); + if (ImGui::ColorEdit3("##ce", c.data())) + { arr[i] = c; changed = true; } + ImGui::PopID(); + } + if (arr.size() > kEditLimit) + ImGui::TextDisabled(" ... %zu more", arr.size() - kEditLimit); + ImGui::TreePop(); + } + } + if (changed) return VtValue(arr); + return VtValue(); + } + + // ---- color4f[] ---- + if (val.IsHolding>()) { + VtArray arr = val.UncheckedGet>(); + bool changed = false; + if (arr.size() == 1) { + GfVec4f c = arr[0]; + if (ImGui::ColorEdit4("##dc4", c.data())) + { arr[0] = c; changed = true; } + } else if (!arr.empty()) { + bool open = ImGui::TreeNodeEx("##dcarr4", + ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_SpanAvailWidth); + ImGui::SameLine(0, 6); + float sz = ImGui::GetTextLineHeight(); + size_t shown = std::min(arr.size(), (size_t)5); + for (size_t i = 0; i < shown; ++i) { + if (i > 0) ImGui::SameLine(0, 2); + char sid[16]; snprintf(sid, sizeof(sid), "##sv4%d", (int)i); + ImGui::ColorButton(sid, + ImVec4(arr[i][0], arr[i][1], arr[i][2], arr[i][3]), + ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, + ImVec2(sz, sz)); + } + ImGui::SameLine(0, 4); + ImGui::TextDisabled("[%zu]", arr.size()); + if (open) { + static constexpr size_t kEditLimit = 16; + size_t lim = std::min(arr.size(), kEditLimit); + for (size_t i = 0; i < lim; ++i) { + ImGui::PushID((int)i); + ImGui::Text("[%d]", (int)i); + ImGui::SameLine(); + GfVec4f c = arr[i]; + ImGui::SetNextItemWidth(-FLT_MIN); + if (ImGui::ColorEdit4("##ce4", c.data())) + { arr[i] = c; changed = true; } + ImGui::PopID(); + } + if (arr.size() > kEditLimit) + ImGui::TextDisabled(" ... %zu more", arr.size() - kEditLimit); + ImGui::TreePop(); + } + } + if (changed) return VtValue(arr); + return VtValue(); + } } // ---- Scalar types ----