yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
editor_activator.cc
Go to the documentation of this file.
1#include "editor_activator.h"
2
16#include "app/gui/core/icons.h"
17#include "imgui/imgui.h"
18#include "imgui/imgui_internal.h"
19#include "util/log.h"
20#include "zelda3/common.h"
21
22namespace yaze {
23namespace editor {
24
26 deps_ = deps;
27 initialized_ = true;
28
29 // Subscribe to navigation events via EventBus
30 if (deps_.event_bus) {
32 [this](const JumpToRoomRequestEvent& event) {
33 JumpToDungeonRoom(event.room_id);
34 });
35
37 [this](const JumpToMapRequestEvent& event) {
38 JumpToOverworldMap(event.map_id);
39 });
40
42 [this](const JumpToMessageRequestEvent& event) {
43 JumpToMessage(event.message_id);
44 });
45
47 [this](const JumpToAssemblySymbolRequestEvent& event) {
48 JumpToAssemblySymbol(event.symbol);
49 });
50
51 LOG_INFO("EditorActivator", "Subscribed to navigation events");
52 }
53}
54
55void EditorActivator::SwitchToEditor(EditorType editor_type, bool force_visible,
56 bool from_dialog) {
57 if (!initialized_) {
58 LOG_WARN("EditorActivator", "Not initialized, cannot switch editor");
59 return;
60 }
61
62 // Avoid touching ImGui docking state when outside a frame
63 ImGuiContext* imgui_ctx = ImGui::GetCurrentContext();
64 const bool frame_active = imgui_ctx != nullptr && imgui_ctx->WithinFrameScope;
65 if (!frame_active && deps_.queue_deferred_action) {
66 const bool validate_session =
67 static_cast<bool>(deps_.get_current_session_id);
68 const size_t expected_session_id =
69 validate_session ? deps_.get_current_session_id() : 0;
70 deps_.queue_deferred_action([this, editor_type, force_visible, from_dialog,
71 validate_session, expected_session_id]() {
72 if (validate_session &&
74 deps_.get_current_session_id() != expected_session_id)) {
75 return;
76 }
77 SwitchToEditor(editor_type, force_visible, from_dialog);
78 });
79 return;
80 }
81
82 // If NOT coming from dialog, close editor selection UI
83 if (!from_dialog && deps_.ui_coordinator) {
85 }
86
87 auto* editor_set =
89 if (!editor_set) {
90 return;
91 }
92
94 switch (editor_type) {
104 case EditorType::kSprite: {
105 const auto status = deps_.ensure_editor_assets_loaded(editor_type);
106 if (!status.ok()) {
107 if (deps_.toast_manager) {
109 "Failed to prepare editor: " + std::string(status.message()),
111 }
112 return;
113 }
114 break;
115 }
116 default:
117 break;
118 }
119 }
120
121 // Toggle the editor in the active editors list
122 for (auto* editor : editor_set->active_editors_) {
123 if (editor->type() == editor_type) {
124 if (force_visible) {
125 editor->set_active(true);
126 } else {
127 editor->toggle_active();
128 }
129
130 if (EditorRegistry::IsPanelBasedEditor(editor_type)) {
131 if (*editor->active()) {
132 // Smooth transition: fade out old, then fade in new
133 // Panel refresh handled by OnEditorSwitch below
134 ActivatePanelBasedEditor(editor_type, editor);
135 } else {
136 DeactivatePanelBasedEditor(editor_type, editor, editor_set);
137 }
138 }
139 return;
140 }
141 }
142
143 // Handle non-editor-class cases (Assembly, Emulator, Hex, Settings, Agent)
144 HandleNonEditorClassSwitch(editor_type, force_visible);
145}
146
148 Editor* editor) {
150 return;
151
152 std::string old_category = deps_.window_manager->GetActiveCategory();
153 std::string new_category = EditorRegistry::GetEditorCategory(type);
154
155 // Only trigger OnEditorSwitch if category actually changes
156 if (old_category != new_category) {
157 // Kill any in-flight panel transitions from the previous editor so the
158 // new editor's windows start their fade from a clean state. Without this,
159 // stale alpha values leave old bitmap surfaces ghosted during the switch.
161 deps_.window_manager->OnEditorSwitch(old_category, new_category);
162 }
163
164 // Activate the layout context on every editor activation. LayoutManager
165 // builds the default tree only once, but repeated calls refresh the live
166 // editor/session context used by lazy first-open panel docking.
167 if (deps_.layout_manager) {
169 }
170}
171
173 Editor* editor,
174 EditorSet* editor_set) {
175 if (!deps_.window_manager || !editor_set)
176 return;
177
178 // Switch to another active panel-based editor
179 for (auto* other : editor_set->active_editors_) {
180 if (*other->active() && EditorRegistry::IsPanelBasedEditor(other->type()) &&
181 other != editor) {
182 std::string old_category = deps_.window_manager->GetActiveCategory();
183 std::string new_category =
185 if (old_category != new_category) {
187 deps_.window_manager->OnEditorSwitch(old_category, new_category);
188 }
189
190 // The fallback editor was already active, so it does not pass through
191 // ActivatePanelBasedEditor again. Refresh its live docking context here
192 // before any of its hidden-by-default panels are opened.
193 const EditorType fallback_type = other->type();
194 if (deps_.layout_manager) {
195 QueueEditorLayoutInitialization(fallback_type);
196 }
197 break;
198 }
199 }
200}
201
203 if (!deps_.layout_manager) {
204 return;
205 }
208 return;
209 }
210
211 const bool validate_session = static_cast<bool>(deps_.get_current_session_id);
212 const size_t expected_session_id =
213 validate_session ? deps_.get_current_session_id() : 0;
215 [this, type, validate_session, expected_session_id]() {
216 if (validate_session &&
218 deps_.get_current_session_id() != expected_session_id)) {
219 return;
220 }
222 });
223}
224
226 bool force_visible) {
227 switch (type) {
229 if (deps_.ui_coordinator) {
230 bool is_visible = !deps_.ui_coordinator->IsAsmEditorVisible();
231 if (force_visible) {
232 is_visible = true;
233 }
234
236
237 if (is_visible && deps_.window_manager) {
240 }
241 }
242 break;
243
245 if (deps_.ui_coordinator) {
246 bool is_visible = !deps_.ui_coordinator->IsEmulatorVisible();
247 if (force_visible)
248 is_visible = true;
249
251
252 if (is_visible && deps_.window_manager) {
254
257 ImGuiContext* ctx = ImGui::GetCurrentContext();
258 if (deps_.layout_manager && ctx && ctx->WithinFrameScope) {
259 ImGuiID dockspace_id = ImGui::GetID("MainDockSpace");
263 EditorType::kEmulator, dockspace_id);
264 LOG_INFO("EditorActivator", "Initialized emulator layout");
265 }
266 }
267 });
268 }
269 }
270 }
271 break;
272
273 case EditorType::kHex:
276 "Hex Editor");
277 }
278 break;
279
284 !force_visible) {
286 } else {
289 }
290 }
291 break;
292
293 default:
294 // Other editor types not handled here
295 break;
296 }
297}
298
301 return;
302
303 ImGuiContext* ctx = ImGui::GetCurrentContext();
304 if (!ctx || !ctx->WithinFrameScope) {
307 }
308 return;
309 }
310
311 const bool was_initialized = deps_.layout_manager->IsLayoutInitialized(type);
312 ImGuiID dockspace_id = ImGui::GetID("MainDockSpace");
313 deps_.layout_manager->InitializeEditorLayout(type, dockspace_id);
314 if (!was_initialized && deps_.layout_manager->IsLayoutInitialized(type)) {
315 LOG_INFO("EditorActivator", "Initialized layout for editor type %d",
316 static_cast<int>(type));
317 }
318}
319
321 auto* editor_set =
323 if (!editor_set)
324 return;
325
328 if (!status.ok()) {
329 if (deps_.toast_manager) {
330 deps_.toast_manager->Show("Failed to prepare Dungeon editor: " +
331 std::string(status.message()),
333 }
334 return;
335 }
336 }
337
338 // Switch to dungeon editor
340
341 // Open the room in the dungeon editor
342 editor_set->GetDungeonEditor()->add_room(room_id);
343}
344
346 if (map_id < 0 || map_id >= zelda3::kNumOverworldMaps) {
347 LOG_WARN("EditorActivator", "Rejected invalid overworld map jump target %d",
348 map_id);
349 if (deps_.toast_manager) {
351 "Invalid overworld map ID: " + std::to_string(map_id),
353 }
354 return;
355 }
356
357 auto* editor_set =
359 if (!editor_set)
360 return;
361
363 const auto status =
365 if (!status.ok()) {
366 if (deps_.toast_manager) {
367 deps_.toast_manager->Show("Failed to prepare Overworld editor: " +
368 std::string(status.message()),
370 }
371 return;
372 }
373 }
374
375 // Switch to overworld editor
377
378 // Use the editor's navigation path so graphics, viewport and hover-follow
379 // state agree with the requested map, including startup --map requests.
380 editor_set->GetOverworldEditor()->JumpToMap(map_id);
381}
382
383void EditorActivator::JumpToMessage(int message_id) {
384 if (message_id < 0)
385 return;
386
387 auto* editor_set =
389 if (!editor_set)
390 return;
391
394 if (!status.ok()) {
395 if (deps_.toast_manager) {
396 deps_.toast_manager->Show("Failed to prepare Message editor: " +
397 std::string(status.message()),
399 }
400 return;
401 }
402 }
403
404 // Switch to message editor (force visible so this behaves like navigation).
405 SwitchToEditor(EditorType::kMessage, /*force_visible=*/true);
406
407 if (auto* message_editor = editor_set->GetMessageEditor()) {
408 if (!message_editor->OpenMessageById(message_id)) {
409 if (deps_.toast_manager) {
411 "Message ID not found: " + std::to_string(message_id),
413 }
414 }
415 }
416}
417
418void EditorActivator::JumpToAssemblySymbol(const std::string& symbol) {
419 if (symbol.empty())
420 return;
421
422 auto* editor_set =
424 if (!editor_set)
425 return;
426
428 const auto status =
430 if (!status.ok()) {
431 if (deps_.toast_manager) {
432 deps_.toast_manager->Show("Failed to prepare Assembly editor: " +
433 std::string(status.message()),
435 }
436 return;
437 }
438 }
439
440 // Switch to assembly editor (force visible so this behaves like navigation).
441 SwitchToEditor(EditorType::kAssembly, /*force_visible=*/true);
442
443 if (auto* asm_editor = editor_set->GetAssemblyEditor()) {
444 const auto status = asm_editor->JumpToReference(symbol);
445 if (!status.ok()) {
446 if (deps_.toast_manager) {
448 "Assembly jump failed: " + std::string(status.message()),
450 }
451 return;
452 }
453 }
454}
455
456} // namespace editor
457} // namespace yaze
HandlerId Subscribe(std::function< void(const T &)> handler)
Definition event_bus.h:22
void HandleNonEditorClassSwitch(EditorType type, bool force_visible)
void ActivatePanelBasedEditor(EditorType type, Editor *editor)
void JumpToAssemblySymbol(const std::string &symbol)
Jump to an assembly symbol definition in the Assembly editor.
void SwitchToEditor(EditorType type, bool force_visible=false, bool from_dialog=false)
Switch to an editor, optionally forcing visibility.
void Initialize(const Dependencies &deps)
void JumpToMessage(int message_id)
Jump to a specific message ID in the Message editor.
void InitializeEditorLayout(EditorType type)
Initialize the DockBuilder layout for an editor.
void JumpToDungeonRoom(int room_id)
Jump to a specific dungeon room.
void JumpToOverworldMap(int map_id)
Jump to a specific overworld map.
void QueueEditorLayoutInitialization(EditorType type)
void DeactivatePanelBasedEditor(EditorType type, Editor *editor, EditorSet *editor_set)
static bool IsPanelBasedEditor(EditorType type)
static std::string GetEditorCategory(EditorType type)
Contains a complete set of editors for a single ROM instance.
std::vector< Editor * > active_editors_
Interface for editor classes.
Definition editor.h:249
bool IsLayoutInitialized(EditorType type) const
Check if a layout has been initialized for an editor.
void InitializeEditorLayout(EditorType type, ImGuiID dockspace_id)
Initialize the default layout for a specific editor type.
void OpenDrawer(DrawerType type)
Open a specific drawer.
DrawerType GetActiveDrawer() const
Get the currently active drawer type.
void CloseDrawer()
Close the currently active drawer.
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)
void SetEmulatorVisible(bool visible)
void SetAsmEditorVisible(bool visible)
void SetEditorSelectionVisible(bool visible)
void SetActiveCategory(const std::string &category, bool notify=true)
void OnEditorSwitch(const std::string &from_category, const std::string &to_category)
Handle editor/category switching for panel visibility.
bool OpenWindow(size_t session_id, const std::string &base_window_id)
void ClearWorkspaceTransitionState()
Definition animator.cc:89
#define LOG_WARN(category, format,...)
Definition log.h:138
#define LOG_INFO(category, format,...)
Definition log.h:136
Animator & GetAnimator()
Definition animator.cc:318
constexpr int kNumOverworldMaps
Definition common.h:85
std::function< EditorSet *()> get_current_editor_set
std::function< void(std::function< void()>)> queue_deferred_action
std::function< absl::Status(EditorType)> ensure_editor_assets_loaded
Request to navigate to an assembly symbol definition.
Request to navigate to a specific overworld map.
Request to navigate to a specific message ID.
Request to navigate to a specific dungeon room.