yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dungeon_status_bar.cc
Go to the documentation of this file.
2#include "util/i18n/tr.h"
3
4#include <algorithm>
5#include <cstdio>
6
15#include "imgui/imgui.h"
16
17namespace yaze::editor {
18
19namespace {
20
21float CalcStatusIconButtonWidth(const char* icon, float button_height) {
22 if (!icon || !*icon) {
23 return button_height;
24 }
25
26 const ImGuiStyle& style = ImGui::GetStyle();
27 const float glyph_width = ImGui::CalcTextSize(icon).x;
28 const float extra = std::max(2.0f, style.FramePadding.x);
29 return std::max(
30 button_height,
31 std::ceil(glyph_width + (style.FramePadding.x * 2.0f) + extra));
32}
33
34} // namespace
35
37 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
38
39 // Reserve a fixed-height bar at the bottom, respecting UIConfig minimum
40 const float font_bar =
41 ImGui::GetFontSize() + ImGui::GetStyle().FramePadding.y * 2.0f;
42 const float bar_height = std::max(font_bar, gui::UIConfig::kStatusBarHeight);
43
44 gui::StyleColorGuard bar_colors({
45 {ImGuiCol_ChildBg, gui::ConvertColorToImVec4(theme.frame_bg)},
46 });
47
48 ImGui::BeginChild(
49 "##DungeonStatusBar", ImVec2(-1, bar_height), false,
50 ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
51
52 const float spacing = ImGui::GetStyle().ItemSpacing.x;
53
54 // Tool mode indicator
55 ImGui::AlignTextToFramePadding();
56 ImGui::TextDisabled(ICON_MD_BUILD);
57 ImGui::SameLine(0, 4);
58 ImGui::Text("%s", state.tool_mode);
59 if (state.workflow_mode != nullptr && state.workflow_mode[0] != '\0') {
60 ImGui::SameLine(0, spacing);
61 ImGui::TextDisabled("|");
62 ImGui::SameLine(0, spacing);
63 const ImVec4 workflow_color =
64 state.workflow_primary ? gui::ConvertColorToImVec4(theme.success)
65 : gui::ConvertColorToImVec4(theme.warning);
66 ImGui::TextColored(workflow_color, "%s %s", ICON_MD_WORKSPACES,
67 state.workflow_mode);
68 }
69 ImGui::SameLine(0, spacing * 2);
70
71 // Separator
72 ImGui::TextDisabled("|");
73 ImGui::SameLine(0, spacing * 2);
74
75 // Undo/Redo buttons with depth indicator
76 {
77 const float button_height =
78 std::max(gui::UIConfig::kIconButtonSmall + 4.0f, bar_height - 4.0f);
79 const ImVec2 undo_size(
80 CalcStatusIconButtonWidth(ICON_MD_UNDO, button_height), button_height);
81 const ImVec2 redo_size(
82 CalcStatusIconButtonWidth(ICON_MD_REDO, button_height), button_height);
83
84 if (!state.can_undo)
85 ImGui::BeginDisabled();
86
87 // Build tooltip string for undo
88 char undo_tip[128];
89 snprintf(undo_tip, sizeof(undo_tip), "Undo%s%s",
90 state.undo_desc ? ": " : "",
91 state.undo_desc ? state.undo_desc : "");
92 if (gui::ThemedIconButton(ICON_MD_UNDO, undo_tip, undo_size)) {
93 if (state.on_undo)
94 state.on_undo();
95 }
96 if (!state.can_undo)
97 ImGui::EndDisabled();
98 ImGui::SameLine(0, 4);
99
100 if (!state.can_redo)
101 ImGui::BeginDisabled();
102
103 // Build tooltip string for redo
104 char redo_tip[128];
105 snprintf(redo_tip, sizeof(redo_tip), "Redo%s%s",
106 state.redo_desc ? ": " : "",
107 state.redo_desc ? state.redo_desc : "");
108 if (gui::ThemedIconButton(ICON_MD_REDO, redo_tip, redo_size)) {
109 if (state.on_redo)
110 state.on_redo();
111 }
112 if (!state.can_redo)
113 ImGui::EndDisabled();
114
115 if (state.undo_depth > 0) {
116 ImGui::SameLine(0, 4);
117 ImGui::TextDisabled("(%d)", state.undo_depth);
118 }
119 }
120 ImGui::SameLine(0, spacing * 2);
121
122 // Separator
123 ImGui::TextDisabled("|");
124 ImGui::SameLine(0, spacing * 2);
125
126 // Selection summary
127 if (state.selection_count > 0) {
128 ImGui::TextDisabled(ICON_MD_SELECT_ALL);
129 ImGui::SameLine(0, 4);
130 ImGui::Text("%s", state.selection_summary.c_str());
131 } else {
132 ImGui::TextDisabled("%s", state.selection_summary.c_str());
133 }
134 ImGui::SameLine(0, spacing * 2);
135
136 // Separator
137 ImGui::TextDisabled("|");
138 ImGui::SameLine(0, spacing * 2);
139
140 // Zoom level
141 ImGui::TextDisabled(ICON_MD_ZOOM_IN);
142 ImGui::SameLine(0, 4);
143 ImGui::Text("%d%%", state.zoom_percent);
144 ImGui::SameLine(0, spacing * 2);
145
146 // Separator
147 ImGui::TextDisabled("|");
148 ImGui::SameLine(0, spacing * 2);
149
150 // Cursor tile coordinates
151 if (state.cursor_tile_x >= 0 && state.cursor_tile_y >= 0) {
152 ImGui::TextDisabled(ICON_MD_MY_LOCATION);
153 ImGui::SameLine(0, 4);
154 ImGui::Text("(%d, %d)", state.cursor_tile_x, state.cursor_tile_y);
155 } else {
156 ImGui::TextDisabled(ICON_MD_MY_LOCATION " --");
157 }
158
159 // Right-aligned section: dirty indicator + room ID
160 {
161 char right_text[64];
162 if (state.room_id >= 0) {
163 if (state.room_dirty) {
164 snprintf(right_text, sizeof(right_text), ICON_MD_CIRCLE " Room 0x%03X",
165 state.room_id);
166 } else {
167 snprintf(right_text, sizeof(right_text), "Room 0x%03X", state.room_id);
168 }
169 } else {
170 snprintf(right_text, sizeof(right_text), "No room");
171 }
172
173 const float text_width = ImGui::CalcTextSize(right_text).x;
174 const float right_x = ImGui::GetWindowWidth() - text_width -
175 ImGui::GetStyle().WindowPadding.x;
176
177 ImGui::SameLine(std::max(ImGui::GetCursorPosX(), right_x));
178
179 if (state.room_dirty) {
180 ImGui::TextColored(gui::ConvertColorToImVec4(theme.warning), "%s",
181 right_text);
182 if (ImGui::IsItemHovered()) {
183 ImGui::SetTooltip(
184 tr("Room has pending editor changes. Apply Room writes them to the "
185 "loaded ROM buffer."));
186 }
187 } else {
188 ImGui::TextDisabled("%s", right_text);
189 }
190 }
191
192 ImGui::EndChild();
193}
194
196 const DungeonCanvasViewer& viewer, const char* tool_mode, bool room_dirty) {
198 state.tool_mode = tool_mode;
199 state.room_dirty = room_dirty;
200 state.room_id = viewer.current_room_id();
201
202 // Zoom from canvas
203 float scale = viewer.canvas().GetGlobalScale();
204 state.zoom_percent = static_cast<int>(scale * 100.0f + 0.5f);
205
206 // Selection from object interaction
207 const auto& interaction =
208 const_cast<DungeonCanvasViewer&>(viewer).object_interaction();
209 const auto snapshot = BuildDungeonSelectionSnapshot(
210 interaction, viewer.rooms(), viewer.current_room_id());
211 state.selection_count = static_cast<int>(snapshot.count);
212 state.selection_layer = snapshot.selection_layer;
214
215 // Cursor coordinates from ImGui hover state on canvas
216 // Note: the actual tile coordinates are derived from the canvas hover
217 // position. Since we don't have direct access to the canvas mouse pos
218 // from outside the draw call, we leave these at -1 (the canvas viewer
219 // itself could populate this if we add a public accessor later).
220 state.cursor_tile_x = -1;
221 state.cursor_tile_y = -1;
222
223 return state;
224}
225
226} // namespace yaze::editor
static void Draw(const DungeonStatusBarState &state)
static DungeonStatusBarState BuildState(const DungeonCanvasViewer &viewer, const char *tool_mode, bool room_dirty)
float GetGlobalScale() const
Definition canvas.h:376
RAII guard for ImGui style colors.
Definition style_guard.h:27
const Theme & GetCurrentTheme() const
static ThemeManager & Get()
#define ICON_MD_MY_LOCATION
Definition icons.h:1270
#define ICON_MD_CIRCLE
Definition icons.h:411
#define ICON_MD_REDO
Definition icons.h:1570
#define ICON_MD_BUILD
Definition icons.h:328
#define ICON_MD_ZOOM_IN
Definition icons.h:2194
#define ICON_MD_SELECT_ALL
Definition icons.h:1680
#define ICON_MD_WORKSPACES
Definition icons.h:2186
#define ICON_MD_UNDO
Definition icons.h:2039
float CalcStatusIconButtonWidth(const char *icon, float button_height)
Editors are the view controllers for the application.
DungeonSelectionSnapshot BuildDungeonSelectionSnapshot(const DungeonObjectInteraction &interaction, const DungeonRoomStore *rooms, int room_id)
std::string GetDungeonSelectionSummaryText(const DungeonSelectionSnapshot &snapshot)
bool ThemedIconButton(const char *icon, const char *tooltip, const ImVec2 &size, bool is_active, bool is_disabled, const char *panel_id, const char *anim_id)
Draw a standard icon button with theme-aware colors.
ImVec4 ConvertColorToImVec4(const Color &color)
Definition color.h:134
static constexpr float kStatusBarHeight
Definition ui_config.h:21
static constexpr float kIconButtonSmall
Definition ui_config.h:61