yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
editor_layout.cc
Go to the documentation of this file.
1#define IMGUI_DEFINE_MATH_OPERATORS
2
4
5#include "absl/strings/str_format.h"
6#include "app/gui/icons.h"
7#include "app/gui/input.h"
11#include "imgui/imgui.h"
12#include "imgui/imgui_internal.h"
13
14namespace yaze {
15namespace gui {
16
17// ============================================================================
18// Toolset Implementation
19// ============================================================================
20
22 // Ultra-compact toolbar with minimal padding
23 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4, 2));
24 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(3, 3));
25 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(6, 4));
26
27 // Don't use BeginGroup - it causes stretching. Just use direct layout.
28 in_toolbar_ = true;
29 button_count_ = 0;
31
32}
33
35 // End the current line
36 ImGui::NewLine();
37
38 ImGui::PopStyleVar(3);
39 ImGui::Separator();
40 in_toolbar_ = false;
42}
43
45 // Compact inline mode buttons without child window to avoid scroll issues
46 // Just use a simple colored background rect
47 ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.15f, 0.15f, 0.17f, 0.5f));
48
49 // Use a frameless child with exact button height to avoid scrolling
50 const float button_size = 28.0f; // Smaller buttons to match toolbar height
51 const float padding = 4.0f;
52 const int num_buttons = 2;
53 const float item_spacing = ImGui::GetStyle().ItemSpacing.x;
54
55 float total_width = (num_buttons * button_size) +
56 ((num_buttons - 1) * item_spacing) +
57 (padding * 2);
58
59 ImGui::BeginChild("##ModeGroup", ImVec2(total_width, button_size + padding),
60 ImGuiChildFlags_AlwaysUseWindowPadding,
61 ImGuiWindowFlags_NoScrollbar);
62
63 // Store for button sizing
64 mode_group_button_size_ = button_size;
65}
66
67bool Toolset::ModeButton(const char* icon, bool selected, const char* tooltip) {
68 if (selected) {
69 ImGui::PushStyleColor(ImGuiCol_Button, GetAccentColor());
70 }
71
72 // Use smaller buttons that fit the toolbar height
73 float size = mode_group_button_size_ > 0 ? mode_group_button_size_ : 28.0f;
74 bool clicked = ImGui::Button(icon, ImVec2(size, size));
75
76 if (selected) {
77 ImGui::PopStyleColor();
78 }
79
80 if (tooltip && ImGui::IsItemHovered()) {
81 ImGui::SetTooltip("%s", tooltip);
82 }
83
84 ImGui::SameLine();
86
87 return clicked;
88}
89
91 ImGui::EndChild();
92 ImGui::PopStyleColor();
93 ImGui::SameLine();
95}
96
98 // Use a proper separator that doesn't stretch
99 ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
100 ImGui::SameLine();
101}
102
103void Toolset::AddRomBadge(uint8_t version, std::function<void()> on_upgrade) {
104 RomVersionBadge(version == 0xFF ? "Vanilla" :
105 absl::StrFormat("v%d", version).c_str(),
106 version == 0xFF);
107
108 if (on_upgrade && (version == 0xFF || version < 3)) {
109 ImGui::SameLine(0, 2); // Tighter spacing
110 if (ImGui::SmallButton(ICON_MD_UPGRADE)) {
111 on_upgrade();
112 }
113 if (ImGui::IsItemHovered()) {
114 ImGui::SetTooltip("Upgrade to ZSCustomOverworld v3");
115 }
116 }
117
118 ImGui::SameLine();
119}
120
121bool Toolset::AddProperty(const char* icon, const char* label,
122 uint8_t* value,
123 std::function<void()> on_change) {
124 ImGui::Text("%s", icon);
125 ImGui::SameLine();
126 ImGui::SetNextItemWidth(55);
127
128 bool changed = InputHexByte(label, value);
129 if (changed && on_change) {
130 on_change();
131 }
132
133 ImGui::SameLine();
134 return changed;
135}
136
137bool Toolset::AddProperty(const char* icon, const char* label,
138 uint16_t* value,
139 std::function<void()> on_change) {
140 ImGui::Text("%s", icon);
141 ImGui::SameLine();
142 ImGui::SetNextItemWidth(70);
143
144 bool changed = InputHexWord(label, value);
145 if (changed && on_change) {
146 on_change();
147 }
148
149 ImGui::SameLine();
150 return changed;
151}
152
153bool Toolset::AddCombo(const char* icon, int* current,
154 const char* const items[], int count) {
155 ImGui::Text("%s", icon);
156 ImGui::SameLine(0, 2); // Reduce spacing between icon and combo
157 ImGui::SetNextItemWidth(100); // Slightly narrower for better fit
158
159 bool changed = ImGui::Combo("##combo", current, items, count);
160 ImGui::SameLine();
161
162 return changed;
163}
164
165bool Toolset::AddToggle(const char* icon, bool* state, const char* tooltip) {
166 bool result = ToggleIconButton(icon, icon, state, tooltip);
167 ImGui::SameLine();
168 return result;
169}
170
171bool Toolset::AddAction(const char* icon, const char* tooltip) {
172 bool clicked = ImGui::SmallButton(icon);
173
174 // Register for test automation
175 if (ImGui::GetItemID() != 0 && tooltip) {
176 std::string button_path = absl::StrFormat("ToolbarAction:%s", tooltip);
178 button_path, "button", ImGui::GetItemID(), tooltip);
179 }
180
181 if (tooltip && ImGui::IsItemHovered()) {
182 ImGui::SetTooltip("%s", tooltip);
183 }
184
185 ImGui::SameLine();
186 return clicked;
187}
188
189bool Toolset::BeginCollapsibleSection(const char* label, bool* p_open) {
190 ImGui::NewLine(); // Start on new line
191 bool is_open = ImGui::CollapsingHeader(label, ImGuiTreeNodeFlags_None);
192 if (p_open) *p_open = is_open;
193 in_section_ = is_open;
194 return is_open;
195}
196
200
201void Toolset::AddV3StatusBadge(uint8_t version, std::function<void()> on_settings) {
202 if (version >= 3 && version != 0xFF) {
203 StatusBadge("v3 Active", ButtonType::Success);
204 ImGui::SameLine();
205 if (ImGui::SmallButton(ICON_MD_TUNE " Settings") && on_settings) {
206 on_settings();
207 }
208 } else {
209 StatusBadge("v3 Available", ButtonType::Default);
210 ImGui::SameLine();
211 if (ImGui::SmallButton(ICON_MD_UPGRADE " Upgrade")) {
212 ImGui::OpenPopup("UpgradeROMVersion");
213 }
214 }
215 ImGui::SameLine();
216}
217
218bool Toolset::AddUsageStatsButton(const char* tooltip) {
219 bool clicked = ImGui::SmallButton(ICON_MD_ANALYTICS " Usage");
220 if (tooltip && ImGui::IsItemHovered()) {
221 ImGui::SetTooltip("%s", tooltip);
222 }
223 ImGui::SameLine();
224 return clicked;
225}
226
227// ============================================================================
228// EditorCard Implementation
229// ============================================================================
230
231EditorCard::EditorCard(const char* title, const char* icon)
232 : title_(title), icon_(icon ? icon : ""), default_size_(400, 300) {
233 window_name_ = icon_.empty() ? title_ : icon_ + " " + title_;
234}
235
236EditorCard::EditorCard(const char* title, const char* icon, bool* p_open)
237 : title_(title), icon_(icon ? icon : ""), default_size_(400, 300) {
238 p_open_ = p_open;
239 window_name_ = icon_.empty() ? title_ : icon_ + " " + title_;
240}
241
242void EditorCard::SetDefaultSize(float width, float height) {
243 default_size_ = ImVec2(width, height);
244}
245
247 position_ = pos;
248}
249
250bool EditorCard::Begin(bool* p_open) {
251 // Handle icon-collapsed state
254 return false;
255 }
256
257 ImGuiWindowFlags flags = ImGuiWindowFlags_None;
258
259 // Apply headless mode
260 if (headless_) {
261 flags |= ImGuiWindowFlags_NoTitleBar;
262 flags |= ImGuiWindowFlags_NoCollapse;
263 }
264
265 // Control docking
266 if (!docking_allowed_) {
267 flags |= ImGuiWindowFlags_NoDocking;
268 }
269
270 // Set initial position based on position enum
271 if (first_draw_) {
272 float display_width = ImGui::GetIO().DisplaySize.x;
273 float display_height = ImGui::GetIO().DisplaySize.y;
274
275 switch (position_) {
276 case Position::Right:
277 ImGui::SetNextWindowPos(ImVec2(display_width - default_size_.x - 10, 30),
278 ImGuiCond_FirstUseEver);
279 break;
280 case Position::Left:
281 ImGui::SetNextWindowPos(ImVec2(10, 30), ImGuiCond_FirstUseEver);
282 break;
283 case Position::Bottom:
284 ImGui::SetNextWindowPos(
285 ImVec2(10, display_height - default_size_.y - 10),
286 ImGuiCond_FirstUseEver);
287 break;
289 case Position::Free:
290 ImGui::SetNextWindowPos(
291 ImVec2(display_width * 0.5f - default_size_.x * 0.5f,
292 display_height * 0.3f),
293 ImGuiCond_FirstUseEver);
294 break;
295 }
296
297 ImGui::SetNextWindowSize(default_size_, ImGuiCond_FirstUseEver);
298 first_draw_ = false;
299 }
300
301 // Create window title with icon
302 std::string window_title = icon_.empty() ? title_ : icon_ + " " + title_;
303
304 // Modern card styling
305 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 8.0f);
306 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10));
307 ImGui::PushStyleColor(ImGuiCol_TitleBg, GetThemeColor(ImGuiCol_TitleBg));
308 ImGui::PushStyleColor(ImGuiCol_TitleBgActive, GetAccentColor());
309
310 // Use p_open parameter if provided, otherwise use stored p_open_
311 bool* actual_p_open = p_open ? p_open : p_open_;
312
313 // If closable is false, don't pass p_open (removes X button)
314 bool visible = ImGui::Begin(window_title.c_str(),
315 closable_ ? actual_p_open : nullptr,
316 flags);
317
318 // Register card window for test automation
319 if (ImGui::GetCurrentWindow() && ImGui::GetCurrentWindow()->ID != 0) {
320 std::string card_path = absl::StrFormat("EditorCard:%s", title_.c_str());
322 card_path, "window", ImGui::GetCurrentWindow()->ID,
323 absl::StrFormat("Editor card: %s", title_.c_str()));
324 }
325
326 return visible;
327}
328
330 // Check if window was focused this frame
331 focused_ = ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows);
332
333 ImGui::End();
334 ImGui::PopStyleColor(2);
335 ImGui::PopStyleVar(2);
336}
337
339 // Set window focus using ImGui's focus system
340 ImGui::SetWindowFocus(window_name_.c_str());
341 focused_ = true;
342}
343
345 // Draw a small floating button with the icon
346 ImGui::SetNextWindowPos(saved_icon_pos_, ImGuiCond_Always);
347 ImGui::SetNextWindowSize(ImVec2(50, 50));
348
349 ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar |
350 ImGuiWindowFlags_NoResize |
351 ImGuiWindowFlags_NoScrollbar |
352 ImGuiWindowFlags_NoCollapse;
353
354 std::string icon_window_name = window_name_ + "##IconCollapsed";
355
356 if (ImGui::Begin(icon_window_name.c_str(), nullptr, flags)) {
357 // Draw icon button
358 if (ImGui::Button(icon_.c_str(), ImVec2(40, 40))) {
359 collapsed_to_icon_ = false; // Expand back to full window
360 }
361
362 if (ImGui::IsItemHovered()) {
363 ImGui::SetTooltip("Expand %s", title_.c_str());
364 }
365
366 // Allow dragging the icon
367 if (ImGui::IsWindowHovered() && ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
368 ImVec2 mouse_delta = ImGui::GetIO().MouseDelta;
369 saved_icon_pos_.x += mouse_delta.x;
370 saved_icon_pos_.y += mouse_delta.y;
371 }
372 }
373 ImGui::End();
374}
375
376// ============================================================================
377// EditorLayout Implementation
378// ============================================================================
379
381 toolbar_.Begin();
382 in_layout_ = true;
383}
384
386 toolbar_.End();
387 in_layout_ = false;
388}
389
391 // Main canvas takes remaining space
392 ImGui::BeginChild("##MainCanvas", ImVec2(0, 0), false);
393}
394
396 ImGui::EndChild();
397}
398
400 cards_.push_back(card);
401}
402
403} // namespace gui
404} // namespace yaze
405
Draggable, dockable card for editor sub-windows.
bool Begin(bool *p_open=nullptr)
void SetDefaultSize(float width, float height)
void SetPosition(Position pos)
EditorCard(const char *title, const char *icon=nullptr)
std::vector< EditorCard * > cards_
void RegisterCard(EditorCard *card)
bool ModeButton(const char *icon, bool selected, const char *tooltip)
bool AddUsageStatsButton(const char *tooltip)
bool BeginCollapsibleSection(const char *label, bool *p_open)
bool AddProperty(const char *icon, const char *label, uint8_t *value, std::function< void()> on_change=nullptr)
bool AddAction(const char *icon, const char *tooltip)
bool AddCombo(const char *icon, int *current, const char *const items[], int count)
void AddRomBadge(uint8_t version, std::function< void()> on_upgrade=nullptr)
void AddV3StatusBadge(uint8_t version, std::function< void()> on_settings)
bool AddToggle(const char *icon, bool *state, const char *tooltip)
void RegisterWidget(const std::string &full_path, const std::string &type, ImGuiID imgui_id, const std::string &description="", const WidgetMetadata &metadata=WidgetMetadata())
static WidgetIdRegistry & Instance()
#define ICON_MD_UPGRADE
Definition icons.h:2045
#define ICON_MD_TUNE
Definition icons.h:2020
#define ICON_MD_ANALYTICS
Definition icons.h:152
bool ToggleIconButton(const char *icon_on, const char *icon_off, bool *state, const char *tooltip)
bool InputHexWord(const char *label, uint16_t *data, float input_width, bool no_step)
Definition input.cc:175
void RomVersionBadge(const char *version, bool is_vanilla)
ImVec4 GetThemeColor(ImGuiCol idx)
Definition ui_helpers.cc:16
bool InputHexByte(const char *label, uint8_t *data, float input_width, bool no_step)
Definition input.cc:189
void StatusBadge(const char *text, ButtonType type)
ImVec4 GetAccentColor()
Definition ui_helpers.cc:40
Main namespace for the application.