Skip to content

Commit 9d39aad

Browse files
committed
refactor: extract gizmo drag overlay
1 parent 630eac2 commit 9d39aad

5 files changed

Lines changed: 118 additions & 57 deletions

File tree

NEXT.md

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ replacing the former flat `src/MeshCraft/MeshCraftApplication_*.cpp` layout.
2020
`MeshCraft::Application::MeshCraftApplication`; the old public include remains
2121
a compatibility forwarder. Actual UI components currently cover Validation,
2222
Registry results, Toolbar tools/display/snap-surface/proportional/grid controls,
23-
Properties delegation, Camera Preset Overlay, and the View-menu panel/overlay/direction/focus/
23+
Properties delegation, Camera Preset Overlay, Gizmo Drag Overlay, and the View-menu panel/overlay/direction/focus/
2424
Camera-Bookmarks/Walk-Mode/Bloom-SSAO presentation, plus the Add/CSG and Help menu
2525
presentation and the Edit-history, clipboard, object-action, and
2626
selection-action groups, the Select-by-Type/Tag/Material, Align-Selection,
@@ -105,7 +105,7 @@ before when explicitly requested (`SYS-W14-##` rows).
105105
## 2. Current status
106106

107107
- **Last full build: clean after the current Phase 13 File-open-recent,
108-
View-Bloom/SSAO, SSAO-regression, and Camera Preset Overlay slices.** Testing is enabled in the current Ninja Release tree, and
108+
View-Bloom/SSAO, SSAO-regression, Camera Preset Overlay, and Gizmo Drag Overlay slices.** Testing is enabled in the current Ninja Release tree, and
109109
`CCACHE_DISABLE=1 cmake --build b-release -j4` linked all targets successfully
110110
on EASYGL. Alternate-backend runtime qualification remains blocked.
111111
- **Tests:** the fresh Release tree registers 182 tests. All passed again after
@@ -174,7 +174,7 @@ before when explicitly requested (`SYS-W14-##` rows).
174174
application into `MeshCraft::Application`, organized implementation files
175175
by application/UI ownership, and is extracting UI presentation through
176176
narrow contexts. Validation, Registry results, Toolbar controls, Properties
177-
delegation, Camera Preset Overlay, and the View-menu directions/focus/overlays/panels/
177+
delegation, Camera Preset Overlay, Gizmo Drag Overlay, and the View-menu directions/focus/overlays/panels/
178178
Camera-Bookmarks/Walk-Mode/Bloom-SSAO presentation, plus the Add/CSG and Help menu
179179
presentation and the Edit-history, clipboard, object-action, and
180180
selection-action groups, the Select-by-Type/Tag/Material, Align-Selection,
@@ -224,6 +224,14 @@ before when explicitly requested (`SYS-W14-##` rows).
224224
camera-preset regression still verifies the shared Front/Top/Right/Persp
225225
table; the extracted header compiles independently and the Xvfb `smoke_test`
226226
passed after the move.
227+
- **Recently implemented (2026-07-25):** the follow-up overlay audit moved the
228+
cursor-following gizmo drag-delta display into
229+
`Application::UI::GizmoDragOverlay`. Its context receives only axis index,
230+
current/start transform values, unit, and rotation/snap snapshots. The
231+
application retains gizmo and selection lifetime, transform inspection, and
232+
every mutation path. It preserves the X/Y/Z colors, signed delta, units, and
233+
Ctrl-or-grid rotation snap indicator; the header compiles independently and
234+
the focused `mc3_commands` plus Xvfb `smoke_test` regressions passed.
227235
- **Recently implemented (2026-07-20 through 2026-07-25):** all 7
228236
raw-OpenGL(ES)-vs-CNA migrations, `AUD-082` through `AUD-088` — full
229237
detail with file:line evidence and
@@ -825,7 +833,7 @@ git stash pop && cmake --build b-release -j4 --target <affected-target>
825833
No actionable follow-up audit task remains: `AUD-089` through `AUD-092` are
826834
complete, while Android (`AUD-042`) is environment/owner deferred.
827835
`SYS-W3-01` has 12 completed subsystem phases and an active Phase 13 for
828-
application/UI ownership. The authorized Camera Bookmarks, Camera Preset Overlay, Walk Mode, View
836+
application/UI ownership. The authorized Camera Bookmarks, Camera Preset Overlay, Gizmo Drag Overlay, Walk Mode, View
829837
Bloom/SSAO, Help, Add/CSG, Edit-history, Edit-clipboard, and Edit-object-actions
830838
menu slices are implemented and verified, together with Edit-selection-actions,
831839
Edit-select-by-type/tag/material, Edit-copy-properties, Edit-grouping,
@@ -1073,7 +1081,12 @@ one item does not authorize the next.
10731081
`Application::UI::CameraPresetOverlay`; camera mutation, document-camera
10741082
lookup, selection, and rendering remain application-owned.
10751083

1076-
2. **Fresh post-overlay boundary audit.** Identify the next coherent
1084+
2. **First post-overlay follow-up — complete.** The cursor-following gizmo
1085+
drag-delta display is now `Application::UI::GizmoDragOverlay`. The
1086+
application computes a read-only transform/snap snapshot; axis colors,
1087+
signed delta, units, and snap presentation are component-owned.
1088+
1089+
3. **Fresh post-overlay boundary audit.** Identify the next coherent
10771090
presentation-only cluster before changing `MeshCraftApplication`; avoid a
10781091
broad `Overlays.cpp` extraction or a context that exposes document/renderer
10791092
internals.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#pragma once
2+
3+
#include <string_view>
4+
5+
namespace MeshCraft::Application::UI {
6+
7+
struct GizmoDragOverlayContext {
8+
int axisIndex;
9+
float currentValue;
10+
float startValue;
11+
std::string_view unit{""};
12+
bool isRotation;
13+
bool snapEnabled;
14+
float snapRotation;
15+
};
16+
17+
class GizmoDragOverlay final {
18+
public:
19+
static void draw(const GizmoDragOverlayContext& context);
20+
};
21+
22+
} // namespace MeshCraft::Application::UI

plan.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ still internally consistent.
164164
research pass.
165165
6. **SYS-W3-01 (P2/W3), Phase 13 is active:** application/UI ownership is
166166
being reduced one narrow presentation slice at a time. The authorized
167-
Camera Bookmarks, Camera Preset Overlay, Walk Mode, View Bloom/SSAO, Help, Add/CSG, Edit-history,
167+
Camera Bookmarks, Camera Preset Overlay, Gizmo Drag Overlay, Walk Mode, View Bloom/SSAO, Help, Add/CSG, Edit-history,
168168
Edit-clipboard,
169169
Edit-object-actions, Edit-selection-actions, Edit-select-by-type,
170170
Edit-select-by-tag/material, Edit-copy-properties, Edit-grouping,
@@ -187,7 +187,10 @@ still internally consistent.
187187
resulting camera-preset/projection/look-through control candidate is now
188188
component-owned as `Application::UI::CameraPresetOverlay`; the application
189189
still owns `EditorCamera`, document-camera lookup, selection, and rendering.
190-
The next Phase 13 action is a fresh narrow boundary audit.
190+
The following narrow audit also moved the gizmo drag-delta presentation into
191+
`Application::UI::GizmoDragOverlay`; the application supplies only axis,
192+
transform snapshots, and snap state. The next Phase 13 action is a fresh
193+
narrow boundary audit.
191194

192195
---
193196

@@ -619,6 +622,10 @@ _All items in this workstream are DONE — archived to [`docs/history/plan_20260
619622
presentation. Its context carries only projection/look-through snapshots,
620623
an optional selected-camera name, and callbacks; the application retains
621624
camera reset/orbit mutation, document access, and all render-state decisions.
625+
`Application::UI::GizmoDragOverlay` likewise owns the cursor-following
626+
drag-delta presentation, including axis color, signed delta, units, and the
627+
rotation snap indicator. `Overlays.cpp` retains gizmo/selection inspection
628+
and supplies a read-only snapshot; the component cannot mutate scene state.
622629
The bookmark state remains the already-extracted
623630
`Editor::CameraBookmarks`; a `CameraBookmarksContext` exposes only the
624631
read-only slots plus Save/Restore callbacks, leaving camera mutation and
@@ -794,7 +801,8 @@ _All items in this workstream are DONE — archived to [`docs/history/plan_20260
794801
Edit-hide-selection, Edit-show-all-hidden, File-merge-scene,
795802
File-export-selection, File-export-GLB, File-export-OBJ, File-save,
796803
File-save-as, File-import-OBJ, File-new, File-open, File-open-recent, and
797-
File-exit slices, the Bloom/SSAO controls, and the CameraPresetOverlay,
804+
File-exit slices, the Bloom/SSAO controls, CameraPresetOverlay, and
805+
GizmoDragOverlay,
798806
each incremental Release link and the same 147/147 + 35/35 partitions pass
799807
again.
800808
For the current MenuBar slices, the public UI header also compiles as a
@@ -804,7 +812,9 @@ _All items in this workstream are DONE — archived to [`docs/history/plan_20260
804812
normal and `MESHCRAFT_TEST_FORCE_SSAO=1` renders, rather than merely proving
805813
that the SSAO path exits cleanly. The CameraPresetOverlay also preserves the
806814
tested shared preset table while reducing `Overlays.cpp` to state snapshots
807-
and callbacks. The next Phase 13 action is a fresh narrow-boundary audit.
815+
and callbacks. GizmoDragOverlay follows the same boundary for a pure
816+
read-only drag snapshot. The next Phase 13 action is a fresh narrow-boundary
817+
audit.
808818
**SYS-W3-01 roadmap status after this session's investigation round:**
809819
Phases 1–12 done (Keybindings, Preferences, MacroRecorder, UndoManager,
810820
animation-override computation, WalkController, AudioPreview,
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include "MeshCraft/Application/UI/GizmoDragOverlay.hpp"
2+
3+
#include <imgui.h>
4+
5+
namespace MeshCraft::Application::UI {
6+
7+
void GizmoDragOverlay::draw(const GizmoDragOverlayContext& context)
8+
{
9+
ImVec2 mousePosition = ImGui::GetIO().MousePos;
10+
ImGui::SetNextWindowPos(ImVec2(mousePosition.x + 18.0f, mousePosition.y - 10.0f),
11+
ImGuiCond_Always);
12+
ImGui::SetNextWindowBgAlpha(0.75f);
13+
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(6, 4));
14+
ImGui::Begin("##gizmoDelta", nullptr,
15+
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs |
16+
ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoMove |
17+
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings |
18+
ImGuiWindowFlags_NoBringToFrontOnFocus);
19+
20+
static constexpr const char* kAxis[] = {"X", "Y", "Z"};
21+
static const ImVec4 kAxisColor[] = {
22+
{1.0f, 0.25f, 0.25f, 1.0f},
23+
{0.25f, 1.0f, 0.25f, 1.0f},
24+
{0.25f, 0.55f, 1.0f, 1.0f},
25+
};
26+
const float delta = context.currentValue - context.startValue;
27+
28+
ImGui::TextColored(kAxisColor[context.axisIndex], "%s", kAxis[context.axisIndex]);
29+
ImGui::SameLine(0, 4);
30+
if (delta >= 0.0f)
31+
ImGui::TextColored(ImVec4(0.8f, 1.0f, 0.8f, 1.0f), "+%.4g%s", delta, context.unit.data());
32+
else
33+
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.8f, 1.0f), "%.4g%s", delta, context.unit.data());
34+
ImGui::SameLine(0, 6);
35+
ImGui::TextDisabled("(%.4g)", context.currentValue);
36+
if (context.isRotation && (ImGui::GetIO().KeyCtrl || context.snapEnabled)) {
37+
ImGui::SameLine(0, 6);
38+
ImGui::TextColored(ImVec4(1.0f, 0.85f, 0.3f, 1.0f),
39+
"[snap %.4g\xc2\xb0]", context.snapRotation);
40+
}
41+
42+
ImGui::End();
43+
ImGui::PopStyleVar();
44+
}
45+
46+
} // namespace MeshCraft::Application::UI

src/MeshCraft/Application/UI/Overlays.cpp

Lines changed: 18 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "MeshCraft/Application/MeshCraftApplication.hpp"
22
#include "MeshCraft/Application/UI/CameraPresetOverlay.hpp"
3+
#include "MeshCraft/Application/UI/GizmoDragOverlay.hpp"
34
#include "MeshCraft/MeshCraftPrivate.hpp"
45
#include "MeshCraft/EditorAlgorithms.hpp"
56
#include "MeshCraft/Scene/SceneHierarchyPanel.hpp"
@@ -93,67 +94,36 @@ void MeshCraftApplication::drawStatsOverlay(int screenW, [[maybe_unused]] int sc
9394
(void)tlH2;
9495
}
9596

96-
// Gizmo drag delta overlay — shown near the mouse cursor while dragging
97+
// Gizmo drag delta overlay — shown near the mouse cursor while dragging.
9798
if (gizmo_.isDragging() && selection_.hasSelection()) {
9899
const auto& sel0 = *selection_.selection().front();
99-
int axIdx = gizmoDragAxisIdx_;
100+
const int axisIndex = gizmoDragAxisIdx_;
100101
float curVal = 0.0f;
101-
const char* unit = "";
102-
const char* axName = "XYZ"[axIdx] == 'X' ? "X" : ("XYZ"[axIdx] == 'Y' ? "Y" : "Z");
103-
static const char* kAxis[3] = {"X","Y","Z"};
102+
std::string_view unit{""};
104103

105104
switch (activeTool_) {
106105
case ActiveTool::Move:
107-
curVal = sel0.transform.position[axIdx];
108-
unit = " u";
106+
curVal = sel0.transform.position[axisIndex];
107+
unit = " u";
109108
break;
110109
case ActiveTool::Rotate:
111-
curVal = sel0.transform.rotation[axIdx];
112-
unit = "°";
110+
curVal = sel0.transform.rotation[axisIndex];
111+
unit = "°";
113112
break;
114113
case ActiveTool::Scale:
115-
curVal = sel0.transform.scale[axIdx];
116-
unit = "";
114+
curVal = sel0.transform.scale[axisIndex];
117115
break;
118116
default: break;
119117
}
120-
float delta = curVal - gizmoDragStartVal_;
121-
122-
ImVec2 mp = ImGui::GetIO().MousePos;
123-
ImGui::SetNextWindowPos(ImVec2(mp.x + 18.0f, mp.y - 10.0f), ImGuiCond_Always);
124-
ImGui::SetNextWindowBgAlpha(0.75f);
125-
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(6, 4));
126-
ImGui::Begin("##gizmoDelta", nullptr,
127-
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs |
128-
ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoMove |
129-
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings |
130-
ImGuiWindowFlags_NoBringToFrontOnFocus);
131-
132-
// Axis label colored
133-
static const ImVec4 kAxisCol[3] = {
134-
{1.0f, 0.25f, 0.25f, 1.0f},
135-
{0.25f, 1.0f, 0.25f, 1.0f},
136-
{0.25f, 0.55f, 1.0f, 1.0f}
137-
};
138-
ImGui::TextColored(kAxisCol[axIdx], "%s", kAxis[axIdx]);
139-
ImGui::SameLine(0, 4);
140-
if (delta >= 0.0f)
141-
ImGui::TextColored(ImVec4(0.8f, 1.0f, 0.8f, 1.0f), "+%.4g%s", delta, unit);
142-
else
143-
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.8f, 1.0f), "%.4g%s", delta, unit);
144-
ImGui::SameLine(0, 6);
145-
ImGui::TextDisabled("(%.4g)", curVal);
146-
// Show snap indicator for rotate when Ctrl or snap grid is active
147-
if (activeTool_ == ActiveTool::Rotate) {
148-
bool ctrlDown = ImGui::GetIO().KeyCtrl;
149-
if (ctrlDown || snapEnabled_) {
150-
ImGui::SameLine(0, 6);
151-
ImGui::TextColored(ImVec4(1.0f, 0.85f, 0.3f, 1.0f), "[snap %.4g\xc2\xb0]", snapRotate_);
152-
}
153-
}
154-
ImGui::End();
155-
ImGui::PopStyleVar();
156-
(void)axName;
118+
UI::GizmoDragOverlay::draw({
119+
.axisIndex = axisIndex,
120+
.currentValue = curVal,
121+
.startValue = gizmoDragStartVal_,
122+
.unit = unit,
123+
.isRotation = activeTool_ == ActiveTool::Rotate,
124+
.snapEnabled = snapEnabled_,
125+
.snapRotation = snapRotate_,
126+
});
157127
}
158128

159129
// Measurement tool overlay

0 commit comments

Comments
 (0)