yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
editor_manager_frame.cc
Go to the documentation of this file.
2
3#include <chrono>
4#include <string>
5#include <unordered_set>
6#include <utility>
7
8#include "absl/strings/str_format.h"
14#include "app/gui/core/icons.h"
15#include "app/platform/timing.h"
18
19#if defined(YAZE_BUILD_AGENT_UI)
21#endif
22
23namespace yaze {
24namespace editor {
25namespace {
26
27void UpdateBuildWorkflowStatus(StatusBar* status_bar,
28 ProjectManagementPanel* project_panel,
29 const ProjectWorkflowStatus& status) {
31 if (status_bar != nullptr) {
32 status_bar->SetBuildStatus(status);
33 }
34 if (project_panel != nullptr) {
35 project_panel->SetBuildStatus(status);
36 }
37}
38
39void AppendWorkflowHistoryEntry(const std::string& kind,
40 const ProjectWorkflowStatus& status,
41 const std::string& output_log) {
43 {.kind = kind,
44 .status = status,
45 .output_log = output_log,
46 .timestamp = std::chrono::system_clock::now()});
47}
48
49} // namespace
50
67absl::Status EditorManager::Update() {
71
72 return status_;
73}
74
76 // Space/focus transitions can leave mid-animation surfaces ghosted.
77 // Reset transient animation state to a stable endpoint.
80 right_drawer_manager_->OnHostVisibilityChanged(visible);
81 }
82}
83
85 // Update timing manager for accurate delta time across the application
87
88 // Execute keyboard shortcuts (registered via ShortcutConfigurator)
90}
91
93 status_ = absl::OkStatus();
95 if (ui_coordinator_) {
96 ui_coordinator_->RefreshWorkflowActions();
97 }
98 // Check for layout rebuild requests and execute if needed (delegated to LayoutCoordinator)
99 bool is_emulator_visible =
100 ui_coordinator_ && ui_coordinator_->IsEmulatorVisible();
101 EditorType current_type =
103 layout_coordinator_.ProcessLayoutRebuild(current_type, is_emulator_visible);
104
105 // Periodic user settings auto-save
106 if (settings_dirty_) {
107 const float elapsed = TimingManager::Get().GetElapsedTime();
108 if (elapsed - settings_dirty_timestamp_ >= 1.0f) {
109 auto save_status = user_settings_.Save();
110 if (!save_status.ok()) {
111 LOG_WARN("EditorManager", "Failed to save user settings: %s",
112 save_status.ToString().c_str());
113 }
114 settings_dirty_ = false;
115 }
116 }
117
118 // Update agent editor dashboard
120
121 // Ensure TestManager always has the current ROM
122 static Rom* last_test_rom = nullptr;
123 auto* current_rom = GetCurrentRom();
124 if (last_test_rom != current_rom) {
125 LOG_DEBUG(
126 "EditorManager",
127 "EditorManager::Update - ROM changed, updating TestManager: %p -> %p",
128 (void*)last_test_rom, (void*)current_rom);
130 last_test_rom = current_rom;
131 }
132
133 // Autosave uses the same guarded serialization, validation, backup, and
134 // atomic commit pipeline as an explicit save. Writing Rom::SaveToFile here
135 // would skip editor model serialization and could persist a partially
136 // failed buffer while clearing its dirty bit.
137 const bool current_session_has_unsaved_work =
139 const auto* current_session =
140 session_coordinator_ ? session_coordinator_->GetActiveRomSession()
141 : nullptr;
142 const bool backup_restore_requires_explicit_save =
143 current_session != nullptr && current_session->backup_restore_pending;
145 current_session_has_unsaved_work &&
146 !backup_restore_requires_explicit_save) {
147 autosave_timer_ += ImGui::GetIO().DeltaTime;
149 autosave_timer_ = 0.0f;
150 auto st = AutosaveActiveSession();
151 if (st.ok()) {
152 toast_manager_.Show("Autosave completed", editor::ToastType::kSuccess);
153 } else if (absl::IsCancelled(st)) {
154 toast_manager_.Show("Autosave paused: confirmation required",
156 } else {
158 absl::StrFormat("Autosave failed: %s", st.message()),
160 }
161 }
162 } else {
163 autosave_timer_ = 0.0f;
164 }
165
166 // Update ROM context for agent UI
167 if (current_rom && current_rom->is_loaded()) {
168 agent_ui_.SetRomContext(current_rom);
170 if (auto* editor_set = GetCurrentEditorSet()) {
171 agent_ui_.SetAsarWrapperContext(editor_set->GetAsarWrapper());
172 // Backend-agnostic symbol feed. Works for ASAR and z3dk alike; tools
173 // prefer this pointer over reaching through the wrapper.
175 &editor_set->GetAssemblySymbols());
176 }
177 }
178
179 // Delegate session updates to SessionCoordinator
181 session_coordinator_->UpdateSessions();
182 }
183}
184
187 return;
188 }
189
190 const auto snapshot = active_project_build_->GetSnapshot();
191 UpdateBuildWorkflowStatus(
194 snapshot.running
195 ? "Build running"
196 : (snapshot.status.ok() ? "Build succeeded" : "Build failed"),
197 snapshot.output_tail.empty()
198 ? (snapshot.running
199 ? std::string(
200 "Running the configured project build command")
201 : std::string(snapshot.status.message()))
202 : snapshot.output_tail,
203 snapshot.running
205 : (snapshot.status.ok() ? ProjectWorkflowState::kSuccess
207 snapshot.output_tail, snapshot.running));
209 project_management_panel_->SetBuildLogOutput(snapshot.output);
210 }
212
213 if (snapshot.running || active_project_build_reported_) {
214 return;
215 }
216
218 if (!snapshot.status.ok()) {
219 AppendWorkflowHistoryEntry(
220 "Build",
221 MakeBuildStatus("Build failed", std::string(snapshot.status.message()),
222 ProjectWorkflowState::kFailure, snapshot.output_tail,
223 false),
224 snapshot.output);
226 absl::StrFormat("Build failed: %s", snapshot.status.message()),
227 snapshot.status.code() == absl::StatusCode::kCancelled
230 return;
231 }
232
233 AppendWorkflowHistoryEntry(
234 "Build",
236 "Build succeeded",
237 snapshot.output_tail.empty() ? std::string("Project build completed")
238 : snapshot.output_tail,
239 ProjectWorkflowState::kSuccess, snapshot.output_tail, false),
240 snapshot.output);
241 toast_manager_.Show(snapshot.output_tail.empty()
242 ? "Project build completed"
243 : absl::StrFormat("Project build completed: %s",
244 snapshot.output_tail),
246}
247
249
250 // Draw editor selection dialog (managed by UICoordinator)
251 if (ui_coordinator_ && ui_coordinator_->IsEditorSelectionVisible()) {
252 dashboard_panel_->Show();
253 dashboard_panel_->Draw();
254 if (!dashboard_panel_->IsVisible()) {
255 ui_coordinator_->SetEditorSelectionVisible(false);
256 }
257 }
258
259 // Draw ROM load options dialog (ZSCustomOverworld, feature flags, project)
262 }
263
264 // Draw window browser (managed by UICoordinator)
265 if (ui_coordinator_ && ui_coordinator_->IsWindowBrowserVisible()) {
266 bool show = true;
267 if (activity_bar_) {
268 activity_bar_->DrawWindowBrowser(GetCurrentSessionId(), &show);
269 }
270 if (!show) {
271 ui_coordinator_->SetWindowBrowserVisible(false);
272 }
273 }
274
275 // Draw background grid effects
276 if (ui_coordinator_) {
277 ui_coordinator_->DrawBackground();
278 }
279
280 // Draw UICoordinator UI components (Welcome Screen, Command Palette, etc.)
281 if (ui_coordinator_) {
282 ui_coordinator_->DrawAllUI();
283 }
284
285 // Handle Welcome screen early-exit for rendering
286 if (ui_coordinator_ && ui_coordinator_->ShouldShowWelcome()) {
288 // Close drawers left over from an editor only when the Welcome screen
289 // replaces the editor surface. Closing them every frame made every
290 // drawer opened from the Welcome screen (File > Settings, Ctrl/Cmd+,,
291 // the drawers button) close again before it was drawn. The Welcome
292 // screen already lays itself out around the drawer width
293 // (GetRightLayoutOffset).
294 if (!welcome_was_shown_) {
295 right_drawer_manager_->CloseDrawer();
296 }
298 right_drawer_manager_->Draw();
299 }
300 welcome_was_shown_ = true;
301 return;
302 }
303 welcome_was_shown_ = false;
304
307 RunEmulator();
308
309 // Draw sidebar
310 if (ui_coordinator_ && ui_coordinator_->IsPanelSidebarVisible()) {
311 auto all_categories = EditorRegistry::GetAllEditorCategories();
312 std::unordered_set<std::string> active_editor_categories;
313
314 if (auto* current_editor_set = GetCurrentEditorSet()) {
316 for (size_t session_idx = 0;
317 session_idx < session_coordinator_->GetTotalSessionCount();
318 ++session_idx) {
319 auto* session = static_cast<RomSession*>(
320 session_coordinator_->GetSession(session_idx));
321 if (!session || !session->rom.is_loaded()) {
322 continue;
323 }
324
325 for (auto* editor : session->editors.active_editors_) {
326 if (*editor->active() && IsPanelBasedEditor(editor->type())) {
327 std::string category =
328 EditorRegistry::GetEditorCategory(editor->type());
329 active_editor_categories.insert(category);
330 }
331 }
332 }
333
334 if (ui_coordinator_->IsEmulatorVisible()) {
335 active_editor_categories.insert("Emulator");
336 }
337 }
338 }
339
340 const bool prefer_dashboard_only =
343 std::string sidebar_category = window_manager_.GetActiveCategory();
344 if (!prefer_dashboard_only && sidebar_category.empty() &&
345 !all_categories.empty()) {
346 sidebar_category = GetPreferredStartupCategory("", all_categories);
347 if (!sidebar_category.empty()) {
348 window_manager_.SetActiveCategory(sidebar_category, /*notify=*/false);
349 SyncEditorContextForCategory(sidebar_category);
351 sidebar_category);
352 if (it != user_settings_.prefs().panel_visibility_state.end()) {
354 window_manager_.GetActiveSessionId(), it->second);
355 }
356 }
357 }
358
359 auto has_rom_callback = [this]() -> bool {
360 auto* rom = GetCurrentRom();
361 return rom && rom->is_loaded();
362 };
363
364 if (activity_bar_ && ui_coordinator_->ShouldShowActivityBar()) {
365 auto is_rom_dirty_callback = [this]() -> bool {
366 auto* rom = GetCurrentRom();
367 return rom && rom->is_loaded() && rom->dirty();
368 };
369 auto pending_dungeon_rooms_callback = [this]() -> int {
370 if (auto* editor_set = GetCurrentEditorSet()) {
371 if (auto* dungeon_editor = editor_set->GetEditorAs<DungeonEditorV2>(
373 return dungeon_editor->PendingRoomCount();
374 }
375 }
376 return 0;
377 };
378 activity_bar_->Render(GetCurrentSessionId(), sidebar_category,
379 all_categories, active_editor_categories,
380 has_rom_callback, is_rom_dirty_callback,
381 pending_dungeon_rooms_callback);
382 }
383 }
384
385 // Draw right panel
388 right_drawer_manager_->Draw();
389 }
390
391 // Update and draw status bar
394 const size_t session_index = GetCurrentSessionIndex();
395 const size_t session_count = session_coordinator_->GetActiveSessionCount();
397 session_index, session_count,
398 session_count > 1 ? session_coordinator_->GetActiveSessionDisplayName()
399 : std::string{});
400 }
401
402 bool has_agent_info = false;
403#if defined(YAZE_BUILD_AGENT_UI)
404 if (auto* agent_editor = agent_ui_.GetAgentEditor()) {
405 auto* chat = agent_editor->GetAgentChat();
406 const auto* ctx = agent_ui_.GetContext();
407 if (ctx) {
408 const auto& config = ctx->agent_config();
409 bool active = chat && *chat->active();
410 status_bar_.SetAgentInfo(config.ai_provider, config.ai_model, active);
411 has_agent_info = true;
412 }
413 }
414#endif
415 if (!has_agent_info) {
417 }
420 }
421
422 // Editor-aware context: let the active editor push its own mode/custom
423 // segments for this frame without wiping event-driven cursor/selection/zoom
424 // state that older editors still publish through the event bus.
426 if (current_editor_) {
428
429 StatusBarSegmentOptions editor_opts;
430 editor_opts.tooltip = "Click to switch editor (Ctrl+E)";
431 editor_opts.on_click = [this]() {
432 if (ui_coordinator_) {
433 ui_coordinator_->ShowEditorSelection();
434 }
435 };
438 std::move(editor_opts));
439 } else {
441 }
442
443 const size_t session_index = GetCurrentSessionIndex();
444 if (SessionHasPendingUnsavedWork(session_index)) {
445 StatusBarSegmentOptions dirty_opts;
446 dirty_opts.tooltip = absl::StrFormat(
447 "%s. Click to save ROM when ROM-buffer work is pending, otherwise open "
448 "the Project drawer.",
449 DescribePendingUnsavedWork(session_index));
450 dirty_opts.on_click = [this, session_index]() {
451 if (SessionHasPendingRomWork(session_index)) {
452 auto status = SaveRom();
453 if (!status.ok()) {
454 toast_manager_.Show(std::string(status.message()), ToastType::kError);
455 }
456 } else if (right_drawer_manager_) {
457 right_drawer_manager_->OpenDrawer(
459 }
460 };
462 std::move(dirty_opts));
463 } else {
465 }
466
467 if (right_drawer_manager_ && right_drawer_manager_->IsDrawerExpanded()) {
468 const auto active = right_drawer_manager_->GetActiveDrawer();
470 StatusBarSegmentOptions drawer_opts;
471 drawer_opts.tooltip =
472 "Right sidebar open — Esc closes, View > Right Sidebar toggles";
474 std::move(drawer_opts));
475 }
476 }
477
479
480 // Check if ROM is loaded before drawing panels
481 auto* current_editor_set = GetCurrentEditorSet();
482 if (!current_editor_set || !GetCurrentRom()) {
483 if (window_manager_.GetActiveCategory() == "Agent") {
485 }
486 return;
487 }
488
489 // Central workspace window drawing
491
492 // The Performance Dashboard is rendered by DrawSecondaryWindows below, which
493 // also drives Update() and syncs the visibility flag back. Rendering here as
494 // well gave a second Begin/End on the same window name every frame, stacking
495 // duplicate metrics, memory blocks and frame plots with colliding plot IDs.
496
497 // Draw SessionCoordinator UI components
499 session_coordinator_->DrawSessionSwitcher();
500 session_coordinator_->DrawSessionManager();
501 session_coordinator_->DrawSessionRenameDialog();
502 }
503}
504
506 if (ImGui::BeginMenuBar()) {
507 const bool sidebar_visible = window_manager_.IsSidebarVisible();
508 const char* icon = sidebar_visible ? ICON_MD_MENU_OPEN : ICON_MD_MENU;
509 const char* tooltip = sidebar_visible ? "Hide Activity Bar (Ctrl+B)"
510 : "Show Activity Bar (Ctrl+B)";
511 if (ui_coordinator_ && ui_coordinator_->DrawMenuBarIconButton(
512 icon, tooltip, sidebar_visible)) {
514 }
515
516 // Delegate menu building to MenuOrchestrator
517 if (menu_orchestrator_) {
518 menu_orchestrator_->BuildMainMenu();
519 }
520
521 // Delegate menu bar extras to UICoordinator
522 if (ui_coordinator_) {
523 ui_coordinator_->DrawMenuBarExtras();
524 }
525
526 ImGui::EndMenuBar();
527 }
528}
529
531
532 // ImGui debug windows
533 if (ui_coordinator_) {
534 if (ui_coordinator_->IsImGuiDemoVisible()) {
535 bool visible = true;
536 ImGui::ShowDemoWindow(&visible);
537 if (!visible)
538 ui_coordinator_->SetImGuiDemoVisible(false);
539 }
540
541 if (ui_coordinator_->IsImGuiMetricsVisible()) {
542 bool visible = true;
543 ImGui::ShowMetricsWindow(&visible);
544 if (!visible)
545 ui_coordinator_->SetImGuiMetricsVisible(false);
546 }
547 }
548
549 // Legacy window-based editors
550 if (auto* editor_set = GetCurrentEditorSet()) {
551 bool* hex_visibility =
552 window_manager_.GetWindowVisibilityFlag("memory.hex_editor");
553 if (hex_visibility) {
554 if (auto* editor = editor_set->GetEditor(EditorType::kHex)) {
555 // Keep the legacy panel visibility flag in sync with the window close
556 // button (ImGui::Begin will toggle Editor::active_).
557 editor->set_active(*hex_visibility);
558 editor->Update();
559 *hex_visibility = *editor->active();
560 }
561 }
562
563 if (ui_coordinator_ && ui_coordinator_->IsAsmEditorVisible()) {
564 if (auto* editor = editor_set->GetEditor(EditorType::kAssembly)) {
565 editor->set_active(true);
566 editor->Update();
567 if (!*editor->active()) {
568 ui_coordinator_->SetAsmEditorVisible(false);
569 }
570 }
571 }
572 }
573
574 // Project and performance tools
577
578 if (ui_coordinator_ && ui_coordinator_->IsPerformanceDashboardVisible()) {
582 if (!gfx::PerformanceDashboard::Get().IsVisible()) {
583 ui_coordinator_->SetPerformanceDashboardVisible(false);
584 }
585 }
586
587#ifdef YAZE_ENABLE_TESTING
588 if (show_test_dashboard_) {
590 test::TestManager::Get().DrawTestDashboard(&show_test_dashboard_);
591 }
592#endif
593}
594
596 // Update proposal drawer context
598
599 // Agent UI popups
601
602 // Resource label management
603 if (ui_coordinator_ && ui_coordinator_->IsResourceLabelManagerVisible() &&
604 GetCurrentRom()) {
605 bool visible = true;
611 }
612 if (!visible)
613 ui_coordinator_->SetResourceLabelManagerVisible(false);
614 }
615
616 // Layout presets
617 if (ui_coordinator_) {
618 ui_coordinator_->DrawLayoutPresets();
619 }
620}
621
623 auto* current_rom = GetCurrentRom();
624 if (!current_rom)
625 return;
626
627 // Visible emulator: lazy-init + render + tick via Run(rom).
628 // Hidden emulator: pause by default so switching editors does not keep game
629 // audio/frame state advancing. Opt-in background keep-alive is a user pref.
630 // MusicPlayer drives its own RunAudioFrame path when needed.
631 if (ui_coordinator_ && ui_coordinator_->IsEmulatorVisible()) {
632 emulator_.Run(current_rom);
633 return;
634 }
635
637 return;
638 }
641 return;
642 }
643
646 } else {
648 }
649}
650
651} // namespace editor
652} // namespace yaze
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:49
project::ResourceLabelManager * resource_label()
Definition rom.h:225
bool dirty() const
Definition rom.h:188
bool is_loaded() const
Definition rom.h:187
static TimingManager & Get()
Definition timing.h:20
float Update()
Update the timing manager (call once per frame)
Definition timing.h:29
float GetElapsedTime() const
Get total elapsed time since first update.
Definition timing.h:70
AgentConfigState & agent_config()
void SetProjectContext(project::YazeProject *project)
void SetAssemblySymbolTableContext(const std::map< std::string, core::AsarSymbol > *table)
void SetAsarWrapperContext(core::AsarWrapper *asar_wrapper)
DungeonEditorV2 - Simplified dungeon editor using component delegation.
std::unique_ptr< SessionCoordinator > session_coordinator_
project::YazeProject current_project_
std::unique_ptr< RightDrawerManager > right_drawer_manager_
std::string GetPreferredStartupCategory(const std::string &saved_category, const std::vector< std::string > &available_categories) const
bool SessionHasPendingRomWork(size_t session_index) const
Rom * GetCurrentRom() const override
std::unique_ptr< DashboardPanel > dashboard_panel_
std::string CompactPendingUnsavedWorkLabel(size_t session_index) const
void SyncEditorContextForCategory(const std::string &category)
LayoutCoordinator layout_coordinator_
auto GetCurrentEditorSet() const -> EditorSet *
std::string DescribePendingUnsavedWork(size_t session_index) const
std::unique_ptr< MenuOrchestrator > menu_orchestrator_
ProjectFileEditor project_file_editor_
void HandleHostVisibilityChanged(bool visible)
WorkspaceWindowManager window_manager_
RomLoadOptionsDialog rom_load_options_dialog_
std::vector< std::string > startup_panel_hints_
StartupVisibility dashboard_mode_override_
static bool IsPanelBasedEditor(EditorType type)
absl::Status Update()
Main update loop for the editor application.
size_t GetCurrentSessionId() const
Stable workspace identity; unlike the UI index, it does not compact.
std::unique_ptr< ActivityBar > activity_bar_
ShortcutManager shortcut_manager_
bool SessionHasPendingUnsavedWork(size_t session_index) const
std::unique_ptr< BackgroundCommandTask > active_project_build_
std::unique_ptr< ProjectManagementPanel > project_management_panel_
ProjectWorkflowStatus MakeBuildStatus(const std::string &summary, const std::string &detail, ProjectWorkflowState state, const std::string &output_tail="", bool can_cancel=false) const
std::unique_ptr< UICoordinator > ui_coordinator_
static std::vector< std::string > GetAllEditorCategories()
Get all editor categories in display order for sidebar.
static std::string GetEditorCategory(EditorType type)
virtual void ContributeStatus(StatusBar *)
Definition editor.h:330
EditorType type() const
Definition editor.h:343
void ProcessLayoutRebuild(EditorType current_editor_type, bool is_emulator_visible)
Process pending layout rebuild requests.
Panel for managing project settings, ROM versions, and snapshots.
void SetBuildStatus(const ProjectWorkflowStatus &status)
void Draw(bool *p_open)
Draw the dialog (wrapper around Show)
A session-aware status bar displayed at the bottom of the application.
Definition status_bar.h:57
void SetBuildStatus(const ProjectWorkflowStatus &status)
Definition status_bar.h:209
void SetSessionInfo(size_t session_id, size_t total_sessions, const std::string &display_name={})
Set session information.
void SetRom(Rom *rom)
Set the current ROM for dirty status and filename display.
Definition status_bar.h:77
void SetActiveEditor(const std::string &name)
Set the active editor category/name for the context strip.
void SetDirtyScope(const std::string &short_label)
Compact dirty-scope chip (ROM / Project / Rooms / …).
void SetCustomSegment(const std::string &key, const std::string &value)
Set a custom segment with key-value pair.
void ClearEditorContributions()
Clear frame-scoped editor contributions.
void Draw()
Draw the status bar.
void SetAgentInfo(const std::string &provider, const std::string &model, bool active)
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 RestoreVisibilityState(size_t session_id, const std::unordered_map< std::string, bool > &state, bool publish_events=false)
Restore panel visibility state from persistence.
void SetActiveCategory(const std::string &category, bool notify=true)
bool * GetWindowVisibilityFlag(size_t session_id, const std::string &base_window_id)
bool is_audio_focus_mode() const
Definition emulator.h:111
bool is_snes_initialized() const
Definition emulator.h:129
void Run(Rom *rom)
Definition emulator.cc:469
auto running() const -> bool
Definition emulator.h:61
static PerformanceDashboard & Get()
void SetVisible(bool visible)
Show/hide the dashboard.
void Update()
Update dashboard with current performance data.
void Render()
Render the performance dashboard UI.
void ClearWorkspaceTransitionState()
Definition animator.cc:89
void SetCurrentRom(Rom *rom)
void DrawTestDashboard(bool *show_dashboard=nullptr)
static TestManager & Get()
#define ICON_MD_MENU
Definition icons.h:1196
#define ICON_MD_MENU_OPEN
Definition icons.h:1198
#define LOG_DEBUG(category, format,...)
Definition log.h:133
#define LOG_WARN(category, format,...)
Definition log.h:138
void AppendWorkflowHistory(const ProjectWorkflowHistoryEntry &entry)
void SetBuildWorkflowStatus(const ProjectWorkflowStatus &status)
void SetBuildWorkflowLog(const std::string &output)
const char * GetDrawerTypeName(RightDrawerManager::DrawerType type)
bool ShouldTickEmulatorWhenHidden(bool keep_running_in_background)
void ExecuteShortcuts(const ShortcutManager &shortcut_manager)
Fire at most one shortcut for this frame's key press.
Animator & GetAnimator()
Definition animator.cc:318
Represents a single session, containing a ROM and its associated editors.
Optional behavior for an interactive status bar segment.
Definition status_bar.h:27
std::function< void()> on_click
Definition status_bar.h:28
std::unordered_map< std::string, std::unordered_map< std::string, bool > > panel_visibility_state
bool project_opened() const
Definition project.h:505
std::string labels_filename
Definition project.h:314