Skip to content

Commit f227bef

Browse files
committed
refactor: extract registry results UI
1 parent 749cc65 commit f227bef

3 files changed

Lines changed: 92 additions & 75 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#pragma once
2+
3+
#include "MeshCraft/ModelRegistry.hpp"
4+
5+
#include <cstdint>
6+
#include <functional>
7+
#include <vector>
8+
9+
namespace MeshCraft::Application::UI {
10+
11+
struct RegistryResultsContext {
12+
std::vector<ModelRegistry::Entry>& results;
13+
std::function<void(const ModelRegistry::Entry&)> insert;
14+
std::function<void(int64_t)> remove;
15+
};
16+
17+
class Registry final {
18+
public:
19+
static void drawResults(RegistryResultsContext& context);
20+
};
21+
22+
} // namespace MeshCraft::Application::UI

plan.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,9 @@ _All items in this workstream are DONE — archived to [`docs/history/plan_20260
574574
component is now `Application::UI::Validation`: it receives only a
575575
`ValidationContext` (visibility, source label, immutable validation result),
576576
while the application retains ownership and mutation of that state. The
577+
Registry results table is likewise now `Application::UI::Registry`; it sees
578+
only entries plus Insert/Remove callbacks, while document mutation, undo,
579+
status reporting, and database lifetime remain in the application. The
577580
historical audit references retain their former paths as time-accurate
578581
evidence.
579582
Static undo-audit and snapshot-lint path checks pass after their tracked

src/MeshCraft/Application/UI/Registry.cpp

Lines changed: 67 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "MeshCraft/Application/MeshCraftApplication.hpp"
2+
#include "MeshCraft/Application/UI/Registry.hpp"
23
#include "MeshCraft/ModelRegistry.hpp"
34

45
#include <MeshCraft/Mc3/Mc3Document.hpp>
@@ -56,84 +57,36 @@ void MeshCraftApplication::drawRegistryPanel() {
5657

5758
ImGui::Spacing();
5859

59-
// Results table
60-
const float tableH = ImGui::GetContentRegionAvail().y - 36.0f;
61-
if (ImGui::BeginTable("##regtable", 4,
62-
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
63-
ImGuiTableFlags_ScrollY | ImGuiTableFlags_SizingStretchProp,
64-
ImVec2(0, tableH)))
65-
{
66-
ImGui::TableSetupScrollFreeze(0, 1);
67-
ImGui::TableSetupColumn("Group", ImGuiTableColumnFlags_WidthStretch, 0.22f);
68-
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0.38f);
69-
ImGui::TableSetupColumn("Variant", ImGuiTableColumnFlags_WidthStretch, 0.22f);
70-
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 66.0f);
71-
ImGui::TableHeadersRow();
72-
73-
for (auto& entry : regCachedResults_) {
74-
ImGui::TableNextRow();
75-
ImGui::TableSetColumnIndex(0); ImGui::TextUnformatted(entry.group.c_str());
76-
ImGui::TableSetColumnIndex(1); ImGui::TextUnformatted(entry.name.c_str());
77-
ImGui::TableSetColumnIndex(2); ImGui::TextUnformatted(entry.variant.c_str());
78-
ImGui::TableSetColumnIndex(3);
79-
ImGui::PushID(static_cast<int>(entry.id));
80-
if (ImGui::SmallButton("Insert")) {
60+
UI::RegistryResultsContext resultsContext{
61+
.results = regCachedResults_,
62+
.insert = [this](const ModelRegistry::Entry& entry) {
63+
try {
64+
pushUndo();
65+
std::string defId;
8166
try {
82-
// insertIntoScene() writes doc.textures/materials/definitions
83-
// directly (F7): pushUndo() must snapshot the document BEFORE
84-
// that call, not just before the objects.push_back() below,
85-
// or Ctrl+Z after an Insert leaves the imported definition and
86-
// its textures/materials permanently orphaned in the scene.
87-
// insertIntoScene() only ever throws before touching doc (temp
88-
// file I/O and the empty-definitions check both precede any
89-
// doc mutation), so on failure the just-pushed snapshot is
90-
// popped back off unapplied instead of leaving a no-op undo
91-
// step, mirroring this codebase's established no-op-undo rule.
92-
pushUndo();
93-
std::string defId;
94-
try {
95-
defId = registry_.insertIntoScene(document_, entry);
96-
} catch (...) {
97-
undoManager_.popUndoWithoutApplying();
98-
throw;
99-
}
100-
// Place an instance of the definition at the origin
101-
auto obj = std::make_shared<Mc3::Mc3Object>();
102-
obj->type = Mc3::ObjectType::Instance;
103-
obj->definition = defId;
104-
obj->name = entry.name +
105-
(entry.variant.empty() ? "" : "_" + entry.variant);
106-
std::string base = "reg_" + defId;
107-
obj->id = base;
108-
int n = 1;
109-
while (flatFindById(obj->id))
110-
obj->id = base + "_" + std::to_string(n++);
111-
112-
document_.objects.push_back(obj);
113-
modified_ = true;
114-
setStatusMsg("Inserted '" + entry.name + "' from registry");
115-
} catch (const std::exception& ex) {
116-
setStatusMsg(std::string("Insert failed: ") + ex.what(), true);
67+
defId = registry_.insertIntoScene(document_, entry);
68+
} catch (...) {
69+
undoManager_.popUndoWithoutApplying();
70+
throw;
11771
}
72+
auto obj = std::make_shared<Mc3::Mc3Object>();
73+
obj->type = Mc3::ObjectType::Instance;
74+
obj->definition = defId;
75+
obj->name = entry.name + (entry.variant.empty() ? "" : "_" + entry.variant);
76+
std::string base = "reg_" + defId;
77+
obj->id = base;
78+
int n = 1;
79+
while (flatFindById(obj->id)) obj->id = base + "_" + std::to_string(n++);
80+
document_.objects.push_back(obj);
81+
modified_ = true;
82+
setStatusMsg("Inserted '" + entry.name + "' from registry");
83+
} catch (const std::exception& ex) {
84+
setStatusMsg(std::string("Insert failed: ") + ex.what(), true);
11885
}
119-
// Delete button (right-click context or explicit — keep visible for power users)
120-
ImGui::SameLine(0, 4);
121-
if (ImGui::SmallButton("X")) {
122-
registry_.remove(entry.id);
123-
regResultsDirty_ = true;
124-
}
125-
if (ImGui::IsItemHovered())
126-
ImGui::SetTooltip("Remove from registry");
127-
ImGui::PopID();
128-
}
129-
130-
if (regCachedResults_.empty()) {
131-
ImGui::TableNextRow();
132-
ImGui::TableSetColumnIndex(0);
133-
ImGui::TextDisabled("(empty)");
134-
}
135-
ImGui::EndTable();
136-
}
86+
},
87+
.remove = [this](int64_t id) { registry_.remove(id); regResultsDirty_ = true; },
88+
};
89+
UI::Registry::drawResults(resultsContext);
13790

13891
ImGui::Separator();
13992
if (ImGui::Button("Save Definition to Registry..."))
@@ -239,3 +192,42 @@ void MeshCraftApplication::drawRegistryPanel() {
239192
}
240193

241194
} // namespace MeshCraft::Application
195+
196+
namespace MeshCraft::Application::UI {
197+
198+
void Registry::drawResults(RegistryResultsContext& context) {
199+
const float tableH = ImGui::GetContentRegionAvail().y - 36.0f;
200+
if (!ImGui::BeginTable("##regtable", 4,
201+
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
202+
ImGuiTableFlags_ScrollY | ImGuiTableFlags_SizingStretchProp,
203+
ImVec2(0, tableH))) return;
204+
205+
ImGui::TableSetupScrollFreeze(0, 1);
206+
ImGui::TableSetupColumn("Group", ImGuiTableColumnFlags_WidthStretch, 0.22f);
207+
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0.38f);
208+
ImGui::TableSetupColumn("Variant", ImGuiTableColumnFlags_WidthStretch, 0.22f);
209+
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 66.0f);
210+
ImGui::TableHeadersRow();
211+
212+
for (auto& entry : context.results) {
213+
ImGui::TableNextRow();
214+
ImGui::TableSetColumnIndex(0); ImGui::TextUnformatted(entry.group.c_str());
215+
ImGui::TableSetColumnIndex(1); ImGui::TextUnformatted(entry.name.c_str());
216+
ImGui::TableSetColumnIndex(2); ImGui::TextUnformatted(entry.variant.c_str());
217+
ImGui::TableSetColumnIndex(3);
218+
ImGui::PushID(static_cast<int>(entry.id));
219+
if (ImGui::SmallButton("Insert")) context.insert(entry);
220+
ImGui::SameLine(0, 4);
221+
if (ImGui::SmallButton("X")) context.remove(entry.id);
222+
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Remove from registry");
223+
ImGui::PopID();
224+
}
225+
if (context.results.empty()) {
226+
ImGui::TableNextRow();
227+
ImGui::TableSetColumnIndex(0);
228+
ImGui::TextDisabled("(empty)");
229+
}
230+
ImGui::EndTable();
231+
}
232+
233+
} // namespace MeshCraft::Application::UI

0 commit comments

Comments
 (0)