yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
settings_editor.cc
Go to the documentation of this file.
2
3#include "absl/status/status.h"
11#include "imgui/imgui.h"
12#include "util/log.h"
13
14#include <set>
15#include <filesystem>
16
17namespace yaze {
18namespace editor {
19
20using ImGui::BeginTabBar;
21using ImGui::BeginTabItem;
22using ImGui::BeginTable;
23using ImGui::EndTabBar;
24using ImGui::EndTabItem;
25using ImGui::EndTable;
26using ImGui::TableHeadersRow;
27using ImGui::TableNextColumn;
28using ImGui::TableSetupColumn;
29
31 // Register cards with EditorCardRegistry (dependency injection)
32 if (!dependencies_.card_registry) return;
33 auto* card_registry = dependencies_.card_registry;
34
35 card_registry->RegisterCard({
36 .card_id = MakeCardId("settings.general"),
37 .display_name = "General Settings",
38 .icon = ICON_MD_SETTINGS,
39 .category = "System",
40 .priority = 10
41 });
42
43 card_registry->RegisterCard({
44 .card_id = MakeCardId("settings.appearance"),
45 .display_name = "Appearance",
46 .icon = ICON_MD_PALETTE,
47 .category = "System",
48 .priority = 20
49 });
50
51 card_registry->RegisterCard({
52 .card_id = MakeCardId("settings.editor_behavior"),
53 .display_name = "Editor Behavior",
54 .icon = ICON_MD_TUNE,
55 .category = "System",
56 .priority = 30
57 });
58
59 card_registry->RegisterCard({
60 .card_id = MakeCardId("settings.performance"),
61 .display_name = "Performance",
62 .icon = ICON_MD_SPEED,
63 .category = "System",
64 .priority = 40
65 });
66
67 card_registry->RegisterCard({
68 .card_id = MakeCardId("settings.ai_agent"),
69 .display_name = "AI Agent",
70 .icon = ICON_MD_SMART_TOY,
71 .category = "System",
72 .priority = 50
73 });
74
75 card_registry->RegisterCard({
76 .card_id = MakeCardId("settings.shortcuts"),
77 .display_name = "Keyboard Shortcuts",
78 .icon = ICON_MD_KEYBOARD,
79 .category = "System",
80 .priority = 60
81 });
82
83 // Show general settings by default
84 card_registry->ShowCard(MakeCardId("settings.general"));
85}
86
87absl::Status SettingsEditor::Load() {
88 gfx::ScopedTimer timer("SettingsEditor::Load");
89 return absl::OkStatus();
90}
91
92absl::Status SettingsEditor::Update() {
93 if (!dependencies_.card_registry) return absl::OkStatus();
94 auto* card_registry = dependencies_.card_registry;
95
96 // General Settings Card - Check visibility flag and pass to Begin() for proper X button
97 bool* general_visible = card_registry->GetVisibilityFlag(MakeCardId("settings.general"));
98 if (general_visible && *general_visible) {
99 static gui::EditorCard general_card("General Settings", ICON_MD_SETTINGS);
100 general_card.SetDefaultSize(600, 500);
101 if (general_card.Begin(general_visible)) {
103 }
104 general_card.End();
105 }
106
107 // Appearance Card (Themes + Font Manager combined) - Check visibility and pass flag
108 bool* appearance_visible = card_registry->GetVisibilityFlag(MakeCardId("settings.appearance"));
109 if (appearance_visible && *appearance_visible) {
110 static gui::EditorCard appearance_card("Appearance", ICON_MD_PALETTE);
111 appearance_card.SetDefaultSize(600, 600);
112 if (appearance_card.Begin(appearance_visible)) {
114 ImGui::Separator();
116 }
117 appearance_card.End();
118 }
119
120 // Editor Behavior Card - Check visibility and pass flag
121 bool* behavior_visible = card_registry->GetVisibilityFlag(MakeCardId("settings.editor_behavior"));
122 if (behavior_visible && *behavior_visible) {
123 static gui::EditorCard behavior_card("Editor Behavior", ICON_MD_TUNE);
124 behavior_card.SetDefaultSize(600, 500);
125 if (behavior_card.Begin(behavior_visible)) {
127 }
128 behavior_card.End();
129 }
130
131 // Performance Card - Check visibility and pass flag
132 bool* perf_visible = card_registry->GetVisibilityFlag(MakeCardId("settings.performance"));
133 if (perf_visible && *perf_visible) {
134 static gui::EditorCard perf_card("Performance", ICON_MD_SPEED);
135 perf_card.SetDefaultSize(600, 450);
136 if (perf_card.Begin(perf_visible)) {
138 }
139 perf_card.End();
140 }
141
142 // AI Agent Settings Card - Check visibility and pass flag
143 bool* ai_visible = card_registry->GetVisibilityFlag(MakeCardId("settings.ai_agent"));
144 if (ai_visible && *ai_visible) {
145 static gui::EditorCard ai_card("AI Agent", ICON_MD_SMART_TOY);
146 ai_card.SetDefaultSize(600, 550);
147 if (ai_card.Begin(ai_visible)) {
149 }
150 ai_card.End();
151 }
152
153 // Keyboard Shortcuts Card - Check visibility and pass flag
154 bool* shortcuts_visible = card_registry->GetVisibilityFlag(MakeCardId("settings.shortcuts"));
155 if (shortcuts_visible && *shortcuts_visible) {
156 static gui::EditorCard shortcuts_card("Keyboard Shortcuts", ICON_MD_KEYBOARD);
157 shortcuts_card.SetDefaultSize(700, 600);
158 if (shortcuts_card.Begin(shortcuts_visible)) {
160 }
161 shortcuts_card.End();
162 }
163
164 return absl::OkStatus();
165}
166
168 static gui::FlagsMenu flags;
169
170 if (BeginTable("##SettingsTable", 4,
171 ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable |
172 ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable)) {
173 TableSetupColumn("System Flags", ImGuiTableColumnFlags_WidthStretch);
174 TableSetupColumn("Overworld Flags", ImGuiTableColumnFlags_WidthStretch);
175 TableSetupColumn("Dungeon Flags", ImGuiTableColumnFlags_WidthStretch);
176 TableSetupColumn("Resource Flags", ImGuiTableColumnFlags_WidthStretch,
177 0.0f);
178
179 TableHeadersRow();
180
181 TableNextColumn();
182 flags.DrawSystemFlags();
183
184 TableNextColumn();
185 flags.DrawOverworldFlags();
186
187 TableNextColumn();
188 flags.DrawDungeonFlags();
189
190 TableNextColumn();
191 flags.DrawResourceFlags();
192
193 EndTable();
194 }
195}
196
198 ImGui::Text("Keyboard shortcut customization coming soon...");
199 ImGui::Separator();
200
201 // TODO: Implement keyboard shortcut editor with:
202 // - Visual shortcut conflict detection
203 // - Import/export shortcut profiles
204 // - Search and filter shortcuts
205 // - Live editing and rebinding
206}
207
209 using namespace ImGui;
210
211 auto& theme_manager = gui::ThemeManager::Get();
212
213 Text("%s Theme Management", ICON_MD_PALETTE);
214 Separator();
215
216 // Current theme selection
217 Text("Current Theme:");
218 SameLine();
219 auto current = theme_manager.GetCurrentThemeName();
220 TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f), "%s", current.c_str());
221
222 Spacing();
223
224 // Available themes grid
225 Text("Available Themes:");
226 for (const auto& theme_name : theme_manager.GetAvailableThemes()) {
227 PushID(theme_name.c_str());
228 bool is_current = (theme_name == current);
229
230 if (is_current) {
231 PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.6f, 0.8f, 1.0f));
232 }
233
234 if (Button(theme_name.c_str(), ImVec2(180, 0))) {
235 theme_manager.LoadTheme(theme_name);
236 }
237
238 if (is_current) {
239 PopStyleColor();
240 SameLine();
241 Text(ICON_MD_CHECK);
242 }
243
244 PopID();
245 }
246
247 Separator();
248 Spacing();
249
250 // Theme operations
251 if (CollapsingHeader(ICON_MD_EDIT " Theme Operations")) {
252 TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f),
253 "Theme import/export coming soon");
254 }
255}
256
258 using namespace ImGui;
259
260 if (!user_settings_) {
261 Text("No user settings available");
262 return;
263 }
264
265 Text("%s Editor Behavior Settings", ICON_MD_TUNE);
266 Separator();
267
268 // Autosave settings
269 if (CollapsingHeader(ICON_MD_SAVE " Auto-Save", ImGuiTreeNodeFlags_DefaultOpen)) {
270 if (Checkbox("Enable Auto-Save", &user_settings_->prefs().autosave_enabled)) {
272 }
273
275 int interval = static_cast<int>(user_settings_->prefs().autosave_interval);
276 if (SliderInt("Interval (seconds)", &interval, 60, 600)) {
277 user_settings_->prefs().autosave_interval = static_cast<float>(interval);
279 }
280
281 if (Checkbox("Create Backup Before Save", &user_settings_->prefs().backup_before_save)) {
283 }
284 }
285 }
286
287 // Recent files
288 if (CollapsingHeader(ICON_MD_HISTORY " Recent Files")) {
289 if (SliderInt("Recent Files Limit", &user_settings_->prefs().recent_files_limit, 5, 50)) {
291 }
292 }
293
294 // Editor defaults
295 if (CollapsingHeader(ICON_MD_EDIT " Default Editor")) {
296 Text("Editor to open on ROM load:");
297 const char* editors[] = { "None", "Overworld", "Dungeon", "Graphics" };
298 if (Combo("##DefaultEditor", &user_settings_->prefs().default_editor, editors, IM_ARRAYSIZE(editors))) {
300 }
301 }
302}
303
305 using namespace ImGui;
306
307 if (!user_settings_) {
308 Text("No user settings available");
309 return;
310 }
311
312 Text("%s Performance Settings", ICON_MD_SPEED);
313 Separator();
314
315 // Graphics settings
316 if (CollapsingHeader(ICON_MD_IMAGE " Graphics", ImGuiTreeNodeFlags_DefaultOpen)) {
317 if (Checkbox("V-Sync", &user_settings_->prefs().vsync)) {
319 }
320
321 if (SliderInt("Target FPS", &user_settings_->prefs().target_fps, 30, 144)) {
323 }
324 }
325
326 // Memory settings
327 if (CollapsingHeader(ICON_MD_MEMORY " Memory")) {
328 if (SliderInt("Cache Size (MB)", &user_settings_->prefs().cache_size_mb, 128, 2048)) {
330 }
331
332 if (SliderInt("Undo History", &user_settings_->prefs().undo_history_size, 10, 200)) {
334 }
335 }
336
337 Separator();
338 Text("Current FPS: %.1f", ImGui::GetIO().Framerate);
339 Text("Frame Time: %.3f ms", 1000.0f / ImGui::GetIO().Framerate);
340}
341
343 using namespace ImGui;
344
345 if (!user_settings_) {
346 Text("No user settings available");
347 return;
348 }
349
350 Text("%s AI Agent Configuration", ICON_MD_SMART_TOY);
351 Separator();
352
353 // Provider selection
354 if (CollapsingHeader(ICON_MD_CLOUD " AI Provider", ImGuiTreeNodeFlags_DefaultOpen)) {
355 const char* providers[] = { "Ollama (Local)", "Gemini (Cloud)", "Mock (Testing)" };
356 if (Combo("Provider", &user_settings_->prefs().ai_provider, providers, IM_ARRAYSIZE(providers))) {
358 }
359
360 Spacing();
361
362 if (user_settings_->prefs().ai_provider == 0) { // Ollama
363 char url_buffer[256];
364 strncpy(url_buffer, user_settings_->prefs().ollama_url.c_str(), sizeof(url_buffer) - 1);
365 url_buffer[sizeof(url_buffer) - 1] = '\0';
366 if (InputText("URL", url_buffer, IM_ARRAYSIZE(url_buffer))) {
367 user_settings_->prefs().ollama_url = url_buffer;
369 }
370 } else if (user_settings_->prefs().ai_provider == 1) { // Gemini
371 char key_buffer[128];
372 strncpy(key_buffer, user_settings_->prefs().gemini_api_key.c_str(), sizeof(key_buffer) - 1);
373 key_buffer[sizeof(key_buffer) - 1] = '\0';
374 if (InputText("API Key", key_buffer, IM_ARRAYSIZE(key_buffer), ImGuiInputTextFlags_Password)) {
375 user_settings_->prefs().gemini_api_key = key_buffer;
377 }
378 }
379 }
380
381 // Model parameters
382 if (CollapsingHeader(ICON_MD_TUNE " Model Parameters")) {
383 if (SliderFloat("Temperature", &user_settings_->prefs().ai_temperature, 0.0f, 2.0f)) {
385 }
386 TextDisabled("Higher = more creative");
387
388 if (SliderInt("Max Tokens", &user_settings_->prefs().ai_max_tokens, 256, 8192)) {
390 }
391 }
392
393 // Agent behavior
394 if (CollapsingHeader(ICON_MD_PSYCHOLOGY " Behavior")) {
395 if (Checkbox("Proactive Suggestions", &user_settings_->prefs().ai_proactive)) {
397 }
398
399 if (Checkbox("Auto-Learn Preferences", &user_settings_->prefs().ai_auto_learn)) {
401 }
402
403 if (Checkbox("Enable Vision/Multimodal", &user_settings_->prefs().ai_multimodal)) {
405 }
406 }
407
408 // z3ed CLI logging settings
409 if (CollapsingHeader(ICON_MD_TERMINAL " CLI Logging", ImGuiTreeNodeFlags_DefaultOpen)) {
410 Text("Configure z3ed command-line logging behavior");
411 Spacing();
412
413 // Log level selection
414 const char* log_levels[] = { "Debug (Verbose)", "Info (Normal)", "Warning (Quiet)", "Error (Critical)", "Fatal Only" };
415 if (Combo("Log Level", &user_settings_->prefs().log_level, log_levels, IM_ARRAYSIZE(log_levels))) {
416 // Apply log level immediately using existing LogManager
417 util::LogLevel level;
418 switch (user_settings_->prefs().log_level) {
419 case 0: level = util::LogLevel::YAZE_DEBUG; break;
420 case 1: level = util::LogLevel::INFO; break;
421 case 2: level = util::LogLevel::WARNING; break;
422 case 3: level = util::LogLevel::ERROR; break;
423 case 4: level = util::LogLevel::FATAL; break;
424 default: level = util::LogLevel::INFO; break;
425 }
426
427 // Get current categories
428 std::set<std::string> categories;
429 if (user_settings_->prefs().log_ai_requests) categories.insert("AI");
430 if (user_settings_->prefs().log_rom_operations) categories.insert("ROM");
431 if (user_settings_->prefs().log_gui_automation) categories.insert("GUI");
432 if (user_settings_->prefs().log_proposals) categories.insert("Proposals");
433
434 // Reconfigure with new level
437 Text("✓ Log level applied");
438 }
439 TextDisabled("Controls verbosity of YAZE and z3ed output");
440
441 Spacing();
442
443 // Logging targets
444 if (Checkbox("Log to File", &user_settings_->prefs().log_to_file)) {
446 // Set default path if empty
447 if (user_settings_->prefs().log_file_path.empty()) {
448 const char* home = std::getenv("HOME");
449 if (home) {
450 user_settings_->prefs().log_file_path = std::string(home) + "/.yaze/logs/yaze.log";
451 }
452 }
453
454 // Enable file logging
455 std::set<std::string> categories;
458 } else {
459 // Disable file logging
460 std::set<std::string> categories;
462 util::LogManager::instance().configure(level, "", categories);
463 }
465 }
466
468 Indent();
469 char path_buffer[512];
470 strncpy(path_buffer, user_settings_->prefs().log_file_path.c_str(), sizeof(path_buffer) - 1);
471 path_buffer[sizeof(path_buffer) - 1] = '\0';
472 if (InputText("Log File", path_buffer, IM_ARRAYSIZE(path_buffer))) {
473 // Update log file path
474 user_settings_->prefs().log_file_path = path_buffer;
475 std::set<std::string> categories;
479 }
480
481 TextDisabled("Log file path (supports ~ for home directory)");
482 Unindent();
483 }
484
485 Spacing();
486
487 // Log filtering
488 Text(ICON_MD_FILTER_ALT " Category Filtering");
489 Separator();
490 TextDisabled("Enable/disable specific log categories");
491 Spacing();
492
493 bool categories_changed = false;
494
495 categories_changed |= Checkbox("AI API Requests", &user_settings_->prefs().log_ai_requests);
496 categories_changed |= Checkbox("ROM Operations", &user_settings_->prefs().log_rom_operations);
497 categories_changed |= Checkbox("GUI Automation", &user_settings_->prefs().log_gui_automation);
498 categories_changed |= Checkbox("Proposal Generation", &user_settings_->prefs().log_proposals);
499
500 if (categories_changed) {
501 // Rebuild category set
502 std::set<std::string> categories;
503 if (user_settings_->prefs().log_ai_requests) categories.insert("AI");
504 if (user_settings_->prefs().log_rom_operations) categories.insert("ROM");
505 if (user_settings_->prefs().log_gui_automation) categories.insert("GUI");
506 if (user_settings_->prefs().log_proposals) categories.insert("Proposals");
507
508 // Reconfigure LogManager
512 categories);
514 }
515
516 Spacing();
517
518 // Quick actions
519 if (Button(ICON_MD_DELETE " Clear Logs")) {
521 std::filesystem::path path(user_settings_->prefs().log_file_path);
522 if (std::filesystem::exists(path)) {
523 std::filesystem::remove(path);
524 LOG_DEBUG("Settings", "Log file cleared: %s", user_settings_->prefs().log_file_path.c_str());
525 }
526 }
527 }
528 SameLine();
529 if (Button(ICON_MD_FOLDER_OPEN " Open Log Directory")) {
531 std::filesystem::path path(user_settings_->prefs().log_file_path);
532 std::filesystem::path dir = path.parent_path();
533
534 // Platform-specific command to open directory
535#ifdef _WIN32
536 std::string cmd = "explorer " + dir.string();
537#elif __APPLE__
538 std::string cmd = "open " + dir.string();
539#else
540 std::string cmd = "xdg-open " + dir.string();
541#endif
542 system(cmd.c_str());
543 }
544 }
545
546 Spacing();
547 Separator();
548
549 // Log test buttons
550 Text(ICON_MD_BUG_REPORT " Test Logging");
551 if (Button("Test Debug")) {
552 LOG_DEBUG("Settings", "This is a debug message");
553 }
554 SameLine();
555 if (Button("Test Info")) {
556 LOG_INFO("Settings", "This is an info message");
557 }
558 SameLine();
559 if (Button("Test Warning")) {
560 LOG_WARN("Settings", "This is a warning message");
561 }
562 SameLine();
563 if (Button("Test Error")) {
564 LOG_ERROR("Settings", "This is an error message");
565 }
566 }
567}
568
569} // namespace editor
570} // namespace yaze
bool * GetVisibilityFlag(size_t session_id, const std::string &base_card_id)
Get visibility flag pointer for a card.
void RegisterCard(size_t session_id, const CardInfo &base_info)
Register a card for a specific session.
EditorDependencies dependencies_
Definition editor.h:165
std::string MakeCardId(const std::string &base_id) const
Definition editor.h:176
absl::Status Update() override
absl::Status Load() override
RAII timer for automatic timing management.
Draggable, dockable card for editor sub-windows.
bool Begin(bool *p_open=nullptr)
void SetDefaultSize(float width, float height)
static ThemeManager & Get()
static LogManager & instance()
Definition log.cc:29
void configure(LogLevel level, const std::string &file_path, const std::set< std::string > &categories)
Configures the logging system.
Definition log.cc:43
#define ICON_MD_FOLDER_OPEN
Definition icons.h:811
#define ICON_MD_SETTINGS
Definition icons.h:1697
#define ICON_MD_MEMORY
Definition icons.h:1193
#define ICON_MD_CHECK
Definition icons.h:395
#define ICON_MD_TUNE
Definition icons.h:2020
#define ICON_MD_BUG_REPORT
Definition icons.h:325
#define ICON_MD_EDIT
Definition icons.h:643
#define ICON_MD_SPEED
Definition icons.h:1815
#define ICON_MD_KEYBOARD
Definition icons.h:1026
#define ICON_MD_PSYCHOLOGY
Definition icons.h:1521
#define ICON_MD_IMAGE
Definition icons.h:980
#define ICON_MD_TERMINAL
Definition icons.h:1949
#define ICON_MD_SAVE
Definition icons.h:1642
#define ICON_MD_DELETE
Definition icons.h:528
#define ICON_MD_PALETTE
Definition icons.h:1368
#define ICON_MD_CLOUD
Definition icons.h:421
#define ICON_MD_FILTER_ALT
Definition icons.h:759
#define ICON_MD_SMART_TOY
Definition icons.h:1779
#define ICON_MD_HISTORY
Definition icons.h:944
#define LOG_DEBUG(category, format,...)
Definition log.h:104
#define LOG_ERROR(category, format,...)
Definition log.h:110
#define LOG_WARN(category, format,...)
Definition log.h:108
#define LOG_INFO(category, format,...)
Definition log.h:106
Definition input.cc:20
void DrawFontManager()
Definition style.cc:1286
LogLevel
Defines the severity levels for log messages. This allows for filtering messages based on their impor...
Definition log.h:27
Main namespace for the application.
Definition controller.cc:20
EditorCardRegistry * card_registry
Definition editor.h:80