yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
layout_coordinator.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <filesystem>
5
6#include "absl/strings/str_format.h"
13#include "imgui/imgui.h"
14#include "imgui/imgui_internal.h"
15#include "util/log.h"
16#include "util/platform_paths.h"
17
18namespace yaze {
19namespace editor {
20
29
30// ==========================================================================
31// Layout Offset Calculations
32// ==========================================================================
33
36 float viewport_width, float activity_bar_width, float left_side_panel_width,
37 float right_sidebar_width, float right_sidebar_budget_width,
38 float min_canvas_width) {
39 const float activity = std::max(0.0f, activity_bar_width);
40 const float left_panel = std::max(0.0f, left_side_panel_width);
41 const float right_panel = std::max(0.0f, right_sidebar_width);
42 const float right_budget = right_sidebar_budget_width >= 0.0f
43 ? right_sidebar_budget_width
44 : right_panel;
45 const float desired_left = activity + left_panel;
46
47 if (viewport_width > 0.0f && viewport_width - desired_left - right_budget <
48 std::max(0.0f, min_canvas_width)) {
49 return {
50 .left_offset = activity,
51 .right_offset = 0.0f,
52 .side_panels_overlay = left_panel > 0.0f || right_panel > 0.0f,
53 };
54 }
55
56 return {
57 .left_offset = desired_left,
58 .right_offset = right_panel,
59 .side_panels_overlay = false,
60 };
61}
62
65 float viewport_width = 0.0f;
66 if (ImGui::GetCurrentContext()) {
67 const ImGuiViewport* viewport = ImGui::GetMainViewport();
68 viewport_width = viewport ? viewport->WorkSize.x : 0.0f;
69 }
70
71 float activity_width = 0.0f;
72 float left_panel_width = 0.0f;
73 const bool show_left_chrome =
77 if (show_left_chrome) {
80 left_panel_width =
82 }
83 }
84
85 const float right_sidebar_width =
87 const float right_sidebar_budget_width =
89 : 0.0f;
90 return ResolveWorkspaceChromeBudget(viewport_width, activity_width,
91 left_panel_width, right_sidebar_width,
92 right_sidebar_budget_width);
93}
94
98
102
107
108// ==========================================================================
109// Layout Operations
110// ==========================================================================
111
113 if (!layout_manager_) {
114 return;
115 }
116
117 if (ImGui::GetCurrentContext()) {
118 static const char kEmptyIni[] = "\n";
119 ImGui::LoadIniSettingsFromMemory(kEmptyIni, sizeof(kEmptyIni) - 1);
120 }
121
122 if (auto ini_path = util::PlatformPaths::GetImGuiIniPath(); ini_path.ok()) {
123 std::error_code ec;
124 std::filesystem::remove(*ini_path, ec);
125 if (ec) {
126 LOG_WARN("LayoutCoordinator", "Failed to remove ImGui ini: %s",
127 ec.message().c_str());
128 }
129 }
130
133
134 // Force immediate rebuild for active context
135 ImGuiContext* imgui_ctx = ImGui::GetCurrentContext();
136 if (imgui_ctx && imgui_ctx->WithinFrameScope) {
137 // Determine which layout to rebuild based on emulator visibility
142 LOG_INFO("LayoutCoordinator", "Emulator layout reset complete");
143 }
144 // Note: Current editor check would need to be passed in or stored
145 } else {
146 // Not in frame scope - rebuild will happen on next tick via RequestRebuild()
147 LOG_INFO("LayoutCoordinator", "Layout reset queued for next frame");
148 }
149}
150
151void LayoutCoordinator::ApplyLayoutPreset(const std::string& preset_name,
152 size_t session_id) {
153 if (!window_manager_) {
154 return;
155 }
156
157 PanelLayoutPreset preset;
158
159 if (!LayoutPresets::TryGetNamedPreset(preset_name, &preset)) {
160 LOG_WARN("LayoutCoordinator", "Unknown layout preset: %s",
161 preset_name.c_str());
162 if (toast_manager_) {
163 toast_manager_->Show(absl::StrFormat("Unknown preset: %s", preset_name),
165 }
166 return;
167 }
168
169 // An open Dungeon Workbench is the dungeon editor's workflow mode, not an
170 // optional tool window; a named preset must not switch the user out of it.
171 const bool keep_dungeon_workbench = window_manager_->IsWindowOpen(
173
174 // Hide all panels first
176
177 // Show only the panels defined in the preset
178 for (const auto& panel_id : preset.default_visible_panels) {
179 window_manager_->OpenWindow(session_id, panel_id);
180 }
181 if (keep_dungeon_workbench) {
182 window_manager_->OpenWindow(session_id,
184 }
185
186 // Request a dock rebuild so the preset positions are applied
187 if (layout_manager_) {
189 }
190
191 LOG_INFO("LayoutCoordinator", "Applied layout preset: %s",
192 preset_name.c_str());
193 if (toast_manager_) {
194 toast_manager_->Show(absl::StrFormat("Layout: %s", preset_name),
196 }
197}
198
200 return "Before default: " + EditorRegistry::GetEditorCategory(type);
201}
202
207
209 if (!HasPreviousEditorLayout(type))
210 return false;
211 const std::string backup = DefaultLayoutBackupName(type);
215 if (toast_manager_) {
216 toast_manager_->Show("Previous layout restored", ToastType::kSuccess);
217 }
218 return true;
219}
220
222 size_t session_id) {
223 if (!window_manager_) {
224 if (toast_manager_) {
225 toast_manager_->Show("No active editor to reset", ToastType::kWarning);
226 }
227 return;
228 }
229
230 // Keep the first pre-reset workspace until it is explicitly restored.
231 // Repeated default-layout tests must not overwrite the user's recovery copy.
232 if (layout_manager_) {
233 const std::string backup = DefaultLayoutBackupName(editor_type);
234 if (!layout_manager_->HasLayout(backup)) {
236 }
237 }
238
239 // Reset panels to defaults
240 window_manager_->ResetToDefaults(session_id, editor_type);
241
242 // Rebuild dock layout for this editor on next frame
243 if (layout_manager_) {
246 }
247
248 LOG_INFO("LayoutCoordinator", "Reset editor layout to defaults for type %d",
249 static_cast<int>(editor_type));
250 if (toast_manager_) {
251 toast_manager_->Show("Default layout applied; previous layout saved",
253 }
254}
255
256// ==========================================================================
257// Layout Rebuild Handling
258// ==========================================================================
259
261 bool is_emulator_visible) {
262 if (!layout_manager_) {
263 return;
264 }
265
266 // The editor host shows this editor's dockspace. With no editor open the
267 // last one stays so its panels keep their dock nodes.
268 EditorType rebuild_type = EditorType::kUnknown;
269 if (is_emulator_visible) {
270 rebuild_type = EditorType::kEmulator;
271 } else if (current_editor_type != EditorType::kUnknown) {
272 rebuild_type = current_editor_type;
273 }
274 if (rebuild_type != EditorType::kUnknown) {
276 }
277
280 return;
281 }
282
283 // Only rebuild if we're in a valid ImGui frame with dockspace
284 ImGuiContext* imgui_ctx = ImGui::GetCurrentContext();
285 if (!imgui_ctx || !imgui_ctx->WithinFrameScope) {
286 return;
287 }
288
289 // Execute rebuild if we have a valid editor type
290 if (rebuild_type != EditorType::kUnknown) {
292 rebuild_type, LayoutManager::EditorDockspaceId(rebuild_type));
293 LOG_INFO("LayoutCoordinator", "Layout rebuilt for editor type %d",
294 static_cast<int>(rebuild_type));
295 }
296
298}
299
301 if (!layout_manager_) {
302 return;
303 }
304
306 return;
307 }
308
309 // Defer layout initialization to ensure we are in the correct scope
310 QueueDeferredAction([this, type]() {
312 layout_manager_->InitializeEditorLayout(
313 type, LayoutManager::EditorDockspaceId(type));
314 }
315 });
316}
317
318void LayoutCoordinator::QueueDeferredAction(std::function<void()> action) {
319 deferred_actions_.push_back(std::move(action));
320 pending_deferred_actions_.fetch_add(1, std::memory_order_relaxed);
321}
322
324 if (deferred_actions_.empty()) {
325 return;
326 }
327
328 std::vector<std::function<void()>> actions_to_execute;
329 actions_to_execute.swap(deferred_actions_);
330 const int processed_count = static_cast<int>(actions_to_execute.size());
331
332 for (auto& action : actions_to_execute) {
333 action();
334 }
335
336 if (processed_count > 0) {
337 const int remaining = pending_deferred_actions_.fetch_sub(
338 processed_count, std::memory_order_relaxed) -
339 processed_count;
340 if (remaining < 0) {
341 pending_deferred_actions_.store(0, std::memory_order_relaxed);
342 }
343 }
344}
345
346} // namespace editor
347} // namespace yaze
static std::string GetEditorCategory(EditorType type)
bool RestorePreviousEditorLayout(EditorType type)
std::vector< std::function< void()> > deferred_actions_
void QueueDeferredAction(std::function< void()> action)
Queue an action to be executed on the next frame.
static std::string DefaultLayoutBackupName(EditorType type)
void ProcessDeferredActions()
Process all queued deferred actions.
WorkspaceChromeBudget GetWorkspaceChromeBudget() const
float GetBottomLayoutOffset() const
Get the bottom margin needed for status bar.
static WorkspaceChromeBudget ResolveWorkspaceChromeBudget(float viewport_width, float activity_bar_width, float left_side_panel_width, float right_sidebar_width, float right_sidebar_budget_width=-1.0f, float min_canvas_width=640.0f)
bool HasPreviousEditorLayout(EditorType type) const
void ResetWorkspaceLayout()
Reset the workspace layout to defaults.
void ProcessLayoutRebuild(EditorType current_editor_type, bool is_emulator_visible)
Process pending layout rebuild requests.
RightDrawerManager * right_drawer_manager_
WorkspaceWindowManager * window_manager_
std::atomic< int > pending_deferred_actions_
void InitializeEditorLayout(EditorType type)
Initialize layout for an editor type on first activation.
float GetRightLayoutOffset() const
Get the right margin needed for drawers.
void ResetCurrentEditorLayout(EditorType editor_type, size_t session_id)
Reset current editor layout to its default configuration.
void ApplyLayoutPreset(const std::string &preset_name, size_t session_id)
Apply a named layout preset.
void Initialize(const Dependencies &deps)
Initialize with all dependencies.
float GetLeftLayoutOffset() const
Get the left margin needed for sidebar (Activity Bar + Side Panel)
void LoadLayout(const std::string &name)
Load a saved layout by name.
void RebuildLayout(EditorType type, ImGuiID dockspace_id)
Force rebuild of layout for a specific editor type.
static ImGuiID EditorDockspaceId(EditorType type)
Dockspace that holds one editor's panels.
void ClearInitializationFlags()
Clear all initialization flags (for testing)
bool DeleteLayout(const std::string &name)
Delete a saved layout by name.
bool IsLayoutInitialized(EditorType type) const
Check if a layout has been initialized for an editor.
void ResetToDefaultLayout(EditorType type)
Reset the layout for an editor to its default.
void ClearRebuildRequest()
Clear rebuild request flag.
void SaveCurrentLayout(const std::string &name, bool persist=true)
Save the current layout with a custom name.
void RequestRebuild()
Request a layout rebuild on next frame.
void SetActiveEditorType(EditorType type)
bool IsRebuildRequested() const
Check if rebuild was requested.
bool HasLayout(const std::string &name) const
Check if a layout exists.
static bool TryGetNamedPreset(const std::string &name, PanelLayoutPreset *preset_out)
bool IsEnabled() const
Definition status_bar.h:72
float GetHeight() const
Get the height of the status bar.
Definition status_bar.cc:81
void Show(const std::string &message, ToastType type=ToastType::kInfo, float ttl_seconds=3.0f, std::string action_label={}, std::function< void()> on_action=nullptr)
bool IsWindowOpen(size_t session_id, const std::string &base_window_id) const
float GetActiveSidePanelWidth(float viewport_width) const
bool OpenWindow(size_t session_id, const std::string &base_window_id)
static absl::StatusOr< std::filesystem::path > GetImGuiIniPath()
Get the ImGui ini path for YAZE.
#define LOG_WARN(category, format,...)
Definition log.h:138
#define LOG_INFO(category, format,...)
Definition log.h:136
All dependencies required by LayoutCoordinator.
static constexpr const char * kDungeonWorkbench
Defines default panel visibility for an editor type.
std::vector< std::string > default_visible_panels