yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
app_delegate.mm
Go to the documentation of this file.
1// AppDelegate.mm
2
3// Must define before any ImGui includes (needed by imgui_test_engine via editor_manager.h)
4#ifndef IMGUI_DEFINE_MATH_OPERATORS
5#define IMGUI_DEFINE_MATH_OPERATORS
6#endif
7
9#import "app/controller.h"
10#import "app/application.h"
12#import "util/file_util.h"
13#import "app/editor/editor.h"
14#import "rom/rom.h"
15#include <vector>
16
17#if defined(__APPLE__) && defined(__MACH__)
18/* Apple OSX and iOS (Darwin). */
19#include <TargetConditionals.h>
20
21#import <CoreText/CoreText.h>
22
23#if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1
24/* iOS in Xcode simulator */
25
26#elif TARGET_OS_MAC == 1
27/* macOS */
28#import <Cocoa/Cocoa.h>
29
30@interface AppDelegate : NSObject <NSApplicationDelegate>
31- (void)setupMenus;
32@end
33
34@implementation AppDelegate
35
36- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
37 [self setupMenus];
38
39 // Disable automatic UI state persistence to prevent crashes
40 // macOS NSPersistentUIManager can crash if state gets corrupted
41 [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSQuitAlwaysKeepsWindows"];
42}
43
44- (void)setupMenus {
45 NSMenu *mainMenu = [NSApp mainMenu];
46
47 NSMenuItem *fileMenuItem = [mainMenu itemWithTitle:@"File"];
48 if (!fileMenuItem) {
49 NSMenu *fileMenu = [[NSMenu alloc] initWithTitle:@"File"];
50 fileMenuItem = [[NSMenuItem alloc] initWithTitle:@"File" action:nil keyEquivalent:@""];
51 [fileMenuItem setSubmenu:fileMenu];
52
53 NSMenuItem *openItem = [[NSMenuItem alloc] initWithTitle:@"Open"
54 action:@selector(openFileAction:)
55 keyEquivalent:@"o"];
56 [fileMenu addItem:openItem];
57
58 // Open Recent (System handled usually, but we can add our own if needed)
59 NSMenu *openRecentMenu = [[NSMenu alloc] initWithTitle:@"Open Recent"];
60 NSMenuItem *openRecentMenuItem = [[NSMenuItem alloc] initWithTitle:@"Open Recent"
61 action:nil
62 keyEquivalent:@""];
63 [openRecentMenuItem setSubmenu:openRecentMenu];
64 [fileMenu addItem:openRecentMenuItem];
65
66 [fileMenu addItem:[NSMenuItem separatorItem]];
67
68 // Save
69 NSMenuItem *saveItem = [[NSMenuItem alloc] initWithTitle:@"Save"
70 action:@selector(saveAction:)
71 keyEquivalent:@"s"];
72 [fileMenu addItem:saveItem];
73
74 // Save As
75 NSMenuItem *saveAsItem = [[NSMenuItem alloc] initWithTitle:@"Save As..."
76 action:@selector(saveAsAction:)
77 keyEquivalent:@"S"];
78 [fileMenu addItem:saveAsItem];
79
80 [fileMenu addItem:[NSMenuItem separatorItem]];
81
82 [mainMenu insertItem:fileMenuItem atIndex:1];
83 }
84
85 // Edit Menu
86 NSMenuItem *editMenuItem = [mainMenu itemWithTitle:@"Edit"];
87 if (!editMenuItem) {
88 NSMenu *editMenu = [[NSMenu alloc] initWithTitle:@"Edit"];
89 editMenuItem = [[NSMenuItem alloc] initWithTitle:@"Edit" action:nil keyEquivalent:@""];
90 [editMenuItem setSubmenu:editMenu];
91
92 NSMenuItem *undoItem = [[NSMenuItem alloc] initWithTitle:@"Undo"
93 action:@selector(undoAction:)
94 keyEquivalent:@"z"];
95 [editMenu addItem:undoItem];
96
97 NSMenuItem *redoItem = [[NSMenuItem alloc] initWithTitle:@"Redo"
98 action:@selector(redoAction:)
99 keyEquivalent:@"Z"];
100 [editMenu addItem:redoItem];
101
102 [editMenu addItem:[NSMenuItem separatorItem]];
103
104 // System-handled copy/paste usually works if we don't override,
105 // but we might want to wire them to our internal clipboard if needed.
106 // For now, let SDL handle keyboard events for copy/paste in ImGui.
107
108 [mainMenu insertItem:editMenuItem atIndex:2];
109 }
110
111 // View Menu
112 NSMenuItem *viewMenuItem = [mainMenu itemWithTitle:@"View"];
113 if (!viewMenuItem) {
114 NSMenu *viewMenu = [[NSMenu alloc] initWithTitle:@"View"];
115 viewMenuItem = [[NSMenuItem alloc] initWithTitle:@"View" action:nil keyEquivalent:@""];
116 [viewMenuItem setSubmenu:viewMenu];
117
118 NSMenuItem *toggleFullscreenItem = [[NSMenuItem alloc] initWithTitle:@"Toggle Fullscreen"
119 action:@selector(toggleFullscreenAction:)
120 keyEquivalent:@"f"];
121 [viewMenu addItem:toggleFullscreenItem];
122
123 [mainMenu insertItem:viewMenuItem atIndex:3];
124 }
125}
126
127// ============================================================================
128// Menu Actions
129// ============================================================================
130
131- (void)openFileAction:(id)sender {
132 // Use our internal file dialog via Application -> Controller -> EditorManager
133 // Or trigger the native dialog here and pass the path back.
134 // Since we have ImGui dialogs, we might prefer those, but native is nice on macOS.
135 // For now, let's just trigger the LoadRom logic which opens the dialog.
136 auto& app = yaze::Application::Instance();
137 if (app.IsReady() && app.GetController()) {
138 if (auto* manager = app.GetController()->editor_manager()) {
139 (void)manager->LoadRom();
140 }
141 }
142}
143
144- (void)saveAction:(id)sender {
145 auto& app = yaze::Application::Instance();
146 if (app.IsReady() && app.GetController()) {
147 if (auto* manager = app.GetController()->editor_manager()) {
148 (void)manager->SaveRom();
149 }
150 }
151}
152
153- (void)saveAsAction:(id)sender {
154 auto& app = yaze::Application::Instance();
155 if (app.IsReady() && app.GetController()) {
156 if (auto* manager = app.GetController()->editor_manager()) {
157 if (auto* popup_manager = manager->popup_manager()) {
158 popup_manager->Show(yaze::editor::PopupID::kSaveAs);
159 }
160 }
161 }
162}
163
164- (void)undoAction:(id)sender {
165 // Route to active editor
166 auto& app = yaze::Application::Instance();
167 if (app.IsReady() && app.GetController()) {
168 if (auto* manager = app.GetController()->editor_manager()) {
169 // manager->card_registry().TriggerUndo(); // If we exposed TriggerUndo
170 // Or directly:
171 if (auto* current = manager->GetCurrentEditor()) {
172 (void)current->Undo();
173 }
174 }
175 }
176}
177
178- (void)redoAction:(id)sender {
179 auto& app = yaze::Application::Instance();
180 if (app.IsReady() && app.GetController()) {
181 if (auto* manager = app.GetController()->editor_manager()) {
182 if (auto* current = manager->GetCurrentEditor()) {
183 (void)current->Redo();
184 }
185 }
186 }
187}
188
189- (void)toggleFullscreenAction:(id)sender {
190 // Toggle fullscreen on the window
191 // SDL usually handles this, but we can trigger it via SDL_SetWindowFullscreen
192 // Accessing window via Application -> Controller -> Window
193 // Use SDL backend logic
194 // For now, rely on the View menu item shortcut that ImGui might catch,
195 // or implement proper toggling in Controller.
196}
197
198@end
199
200extern "C" void yaze_initialize_cocoa() {
201 @autoreleasepool {
202 AppDelegate *delegate = [[AppDelegate alloc] init];
203 [NSApplication sharedApplication];
204 [NSApp setDelegate:delegate];
205 [NSApp finishLaunching];
206 }
207}
208
209extern "C" int yaze_run_cocoa_app_delegate(const yaze::AppConfig& config) {
210 yaze_initialize_cocoa();
211
212 // Initialize the Application singleton with the provided config
213 // This will create the Controller and the SDL Window
215
216 // Main loop
217 // We continue to run our own loop rather than [NSApp run]
218 // because we're driving SDL/ImGui manually.
219 // SDL's event polling works fine with Cocoa in this setup.
220
221 auto& app = yaze::Application::Instance();
222
223 while (app.IsReady() && app.GetController()->IsActive()) {
224 @autoreleasepool {
225 app.Tick();
226 }
227 }
228
229 app.Shutdown();
230 return EXIT_SUCCESS;
231}
232
233#endif
234
235#endif
static Application & Instance()
void Initialize(const AppConfig &config)
constexpr const char * kSaveAs
Configuration options for the application startup.
Definition application.h:26