Ember
Loading...
Searching...
No Matches
PreferencesDialog.cpp
Go to the documentation of this file.
2#include "App/MainFrame.h"
6#include "Utils/Logger.h"
7#include <cmath>
8#include <functional>
9#include <wx/sizer.h>
10#include <wx/statbox.h>
11#include <wx/statline.h>
12#include <wx/stattext.h>
13
15 EVT_TREE_SEL_CHANGED(ID_SECTION_TREE, PreferencesDialog::OnSectionSelected)
16 EVT_BUTTON(wxID_OK, PreferencesDialog::OnOK) EVT_BUTTON(wxID_CANCEL, PreferencesDialog::OnCancel)
17 EVT_BUTTON(ID_APPLY, PreferencesDialog::OnApply)
18 EVT_BUTTON(ID_RESTORE_DEFAULTS, PreferencesDialog::OnRestoreDefaults)
19 EVT_BUTTON(ID_CONFIGURE_PARSER, PreferencesDialog::OnConfigureParser)
20 EVT_SLIDER(ID_DEFAULT_ZOOM, PreferencesDialog::OnZoomSliderChanged) // Update zoom label
21 EVT_SLIDER(ID_ZOOM_STEP_SIZE, PreferencesDialog::OnZoomSliderChanged) // Update zoom step label
22 EVT_SLIDER(ID_SELECTED_NODE_BG_TINT, PreferencesDialog::OnZoomSliderChanged) // Update tint label
23 EVT_SLIDER(ID_HOVERED_NODE_BG_TINT, PreferencesDialog::OnZoomSliderChanged) // Update tint label
24 EVT_SLIDER(ID_MOUSE_WHEEL_SENSITIVITY,
25 PreferencesDialog::OnMouseWheelSensitivityChanged) // Update sensitivity label
26 EVT_SLIDER(ID_PAN_SENSITIVITY, PreferencesDialog::OnPanSensitivityChanged) // Update pan sensitivity label
27 EVT_SLIDER(ID_PAN_SMOOTHNESS, PreferencesDialog::OnPanSmoothnessChanged) // Update pan smoothness label
28 EVT_SLIDER(ID_PAN_STEP_SIZE, PreferencesDialog::OnPanStepSizeChanged) // Update pan step size label
29 EVT_CHECKBOX(ID_MAX_WINDOW_UNLIMITED,
30 PreferencesDialog::OnMaxWindowUnlimitedChanged) // Enable/disable max size controls
31 EVT_CHECKBOX(ID_MAX_SCENES_UNLIMITED,
32 PreferencesDialog::OnMaxScenesUnlimitedChanged) // Enable/disable max scenes control
33 EVT_CHECKBOX(ID_BOTTOM_PANEL_HEIGHT_ENABLED, PreferencesDialog::OnBottomPanelHeightEnabledChanged)
34 EVT_CHECKBOX(ID_BOTTOM_PANEL_MIN_HEIGHT_ENABLED, PreferencesDialog::OnBottomPanelMinHeightEnabledChanged)
35 EVT_CHECKBOX(ID_LEFT_PANEL_WIDTH_ENABLED, PreferencesDialog::OnLeftPanelWidthEnabledChanged)
36 EVT_CHECKBOX(ID_LEFT_PANEL_MIN_WIDTH_ENABLED, PreferencesDialog::OnLeftPanelMinWidthEnabledChanged)
37 EVT_CHECKBOX(ID_RIGHT_PANEL_WIDTH_ENABLED, PreferencesDialog::OnRightPanelWidthEnabledChanged)
38 EVT_CHECKBOX(ID_RIGHT_PANEL_MIN_WIDTH_ENABLED,
39 PreferencesDialog::OnRightPanelMinWidthEnabledChanged) wxEND_EVENT_TABLE()
40
41 // Custom tree item data to store panel pointer
42 class SectionTreeItemData : public wxTreeItemData {
43 public:
44 SectionTreeItemData(wxPanel *panel) : m_panel(panel) {}
45 wxPanel *GetPanel() const { return m_panel; }
46
47 private:
48 wxPanel *m_panel;
49};
50
52 : EmberUI::ScalableDialog(parent, wxID_ANY, "EmberForge Preferences", wxSize(1600, 1000)), m_splitter(nullptr),
53 m_sectionTree(nullptr), m_settingsPanel(nullptr), m_windowPanel(nullptr), m_mainPanelPanel(nullptr),
54 m_behaviorTreeViewPanel(nullptr), m_bottomPanelPanel(nullptr), m_fileExplorerPanel(nullptr),
55 m_sidePanelPanel(nullptr), m_parserPanel(nullptr), m_panUpHotkeyTextCtrl(nullptr),
56 m_panUpHotkeyCaptureButton(nullptr), m_panDownHotkeyTextCtrl(nullptr), m_panDownHotkeyCaptureButton(nullptr),
57 m_panLeftHotkeyTextCtrl(nullptr), m_panLeftHotkeyCaptureButton(nullptr), m_panRightHotkeyTextCtrl(nullptr),
58 m_panRightHotkeyCaptureButton(nullptr),
59 // Initialize debug text controls to nullptr (order must match declaration)
60 m_showCoordinateInfo(nullptr), m_coordinateInfoFontSize(nullptr), m_coordinateInfoColorPicker(nullptr),
61 m_coordinateInfoAnchor(nullptr), m_coordinateInfoX(nullptr), m_coordinateInfoY(nullptr),
62 m_showSelectedNodeInfo(nullptr), m_selectedNodeInfoFontSize(nullptr), m_selectedNodeDebugInfoColorPicker(nullptr),
63 m_selectedNodeInfoAnchor(nullptr), m_selectedNodeInfoX(nullptr), m_selectedNodeInfoY(nullptr),
64 m_showTreeInfo(nullptr), m_treeInfoFontSize(nullptr), m_treeInfoColorPicker(nullptr), m_treeInfoAnchor(nullptr),
65 m_treeInfoX(nullptr), m_treeInfoY(nullptr), m_showControlsHelp(nullptr), m_controlsHelpFontSize(nullptr),
66 m_controlsHelpColorPicker(nullptr), m_controlsHelpAnchor(nullptr), m_controlsHelpX(nullptr),
67 m_controlsHelpY(nullptr), m_capturingTextCtrl(nullptr) {
68 SetMinSize(wxSize(1400, 900));
69 CreateLayout();
70 LoadCurrentSettings();
71
72 // Bind dialog-level mouse events for capturing mouse buttons anywhere in the dialog
73 Bind(wxEVT_LEFT_DOWN, &PreferencesDialog::OnDialogMouseDown, this);
74 Bind(wxEVT_MIDDLE_DOWN, &PreferencesDialog::OnDialogMouseDown, this);
75 Bind(wxEVT_RIGHT_DOWN, &PreferencesDialog::OnDialogMouseDown, this);
76
77 // Select first item in tree by default
78 wxTreeItemId rootId = m_sectionTree->GetRootItem();
79 if (rootId.IsOk()) {
80 wxTreeItemIdValue cookie;
81 wxTreeItemId firstItem = m_sectionTree->GetFirstChild(rootId, cookie);
82 if (firstItem.IsOk()) {
83 m_sectionTree->SelectItem(firstItem);
84 }
85 }
86
87 // Bind mousewheel event to all spin controls to prevent accidental value changes while scrolling
88 auto preventScrollWhenUnfocused = [](wxMouseEvent &event) {
89 wxSpinCtrl *spin = dynamic_cast<wxSpinCtrl *>(event.GetEventObject());
90 if (spin && spin->HasFocus()) {
91 event.Skip(); // Allow scroll wheel when focused
92 }
93 // Otherwise consume the event (don't skip) to prevent value changes
94 };
95
96 // Bind to all spin controls
97 if (m_minWindowWidth)
98 m_minWindowWidth->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
99 if (m_minWindowHeight)
100 m_minWindowHeight->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
101 if (m_maxWindowWidth)
102 m_maxWindowWidth->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
103 if (m_maxWindowHeight)
104 m_maxWindowHeight->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
105 if (m_gridSize)
106 m_gridSize->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
107 if (m_coordinateInfoFontSize)
108 m_coordinateInfoFontSize->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
109 if (m_coordinateInfoX)
110 m_coordinateInfoX->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
111 if (m_coordinateInfoY)
112 m_coordinateInfoY->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
113 if (m_selectedNodeInfoFontSize)
114 m_selectedNodeInfoFontSize->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
115 if (m_selectedNodeInfoX)
116 m_selectedNodeInfoX->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
117 if (m_selectedNodeInfoY)
118 m_selectedNodeInfoY->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
119 if (m_treeInfoFontSize)
120 m_treeInfoFontSize->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
121 if (m_treeInfoX)
122 m_treeInfoX->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
123 if (m_treeInfoY)
124 m_treeInfoY->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
125 if (m_controlsHelpFontSize)
126 m_controlsHelpFontSize->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
127 if (m_controlsHelpX)
128 m_controlsHelpX->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
129 if (m_controlsHelpY)
130 m_controlsHelpY->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
131 if (m_maxScenes)
132 m_maxScenes->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
133 if (m_bottomPanelHeight)
134 m_bottomPanelHeight->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
135 if (m_bottomPanelMinHeight)
136 m_bottomPanelMinHeight->Bind(wxEVT_MOUSEWHEEL, preventScrollWhenUnfocused);
137
138 // Make the settings panel and section panels steal focus when clicked
139 // This ensures spin controls lose focus when clicking on empty space
140 auto stealFocusOnClick = [this](wxMouseEvent &event) {
141 // Transfer focus to the section tree to remove focus from spin controls
142 if (m_sectionTree) {
143 m_sectionTree->SetFocus();
144 }
145 event.Skip();
146 };
147
148 // Bind click handlers to the settings panel and all section panels
149 if (m_settingsPanel) {
150 m_settingsPanel->Bind(wxEVT_LEFT_DOWN, stealFocusOnClick);
151 }
152 if (m_windowPanel)
153 m_windowPanel->Bind(wxEVT_LEFT_DOWN, stealFocusOnClick);
154 if (m_mainPanelPanel)
155 m_mainPanelPanel->Bind(wxEVT_LEFT_DOWN, stealFocusOnClick);
156 if (m_behaviorTreeViewPanel)
157 m_behaviorTreeViewPanel->Bind(wxEVT_LEFT_DOWN, stealFocusOnClick);
158 if (m_bottomPanelPanel)
159 m_bottomPanelPanel->Bind(wxEVT_LEFT_DOWN, stealFocusOnClick);
160 if (m_fileExplorerPanel)
161 m_fileExplorerPanel->Bind(wxEVT_LEFT_DOWN, stealFocusOnClick);
162 if (m_logTabPanel)
163 m_logTabPanel->Bind(wxEVT_LEFT_DOWN, stealFocusOnClick);
164 if (m_sidePanelPanel)
165 m_sidePanelPanel->Bind(wxEVT_LEFT_DOWN, stealFocusOnClick);
166 if (m_leftPanelPanel)
167 m_leftPanelPanel->Bind(wxEVT_LEFT_DOWN, stealFocusOnClick);
168 if (m_rightPanelPanel)
169 m_rightPanelPanel->Bind(wxEVT_LEFT_DOWN, stealFocusOnClick);
170 if (m_tabsSubPanel)
171 m_tabsSubPanel->Bind(wxEVT_LEFT_DOWN, stealFocusOnClick);
172 if (m_parserPanel)
173 m_parserPanel->Bind(wxEVT_LEFT_DOWN, stealFocusOnClick);
174 if (m_performancePanel)
175 m_performancePanel->Bind(wxEVT_LEFT_DOWN, stealFocusOnClick);
176
177 LOG_INFO("UI", "Preferences dialog created");
178}
179
181 wxBoxSizer *mainSizer = new wxBoxSizer(wxVERTICAL);
182
183 // Create splitter window
184 m_splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_3D | wxSP_LIVE_UPDATE);
185 m_splitter->SetMinimumPaneSize(120);
186 m_splitter->SetSashGravity(0.15); // 15% for section list, 85% for settings
187
188 // Create left panel for section tree
189 wxPanel *leftPanel = new wxPanel(m_splitter, wxID_ANY);
190 leftPanel->SetBackgroundColour(wxColour(45, 45, 45));
191 wxBoxSizer *leftSizer = new wxBoxSizer(wxVERTICAL);
192
193 // Section tree
194 m_sectionTree = new wxTreeCtrl(leftPanel, ID_SECTION_TREE, wxDefaultPosition, wxDefaultSize,
195 wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT | wxTR_NO_LINES);
196 m_sectionTree->SetBackgroundColour(wxColour(45, 45, 45));
197 m_sectionTree->SetForegroundColour(wxColour(200, 200, 200));
198
199 leftSizer->Add(m_sectionTree, 1, wxEXPAND | wxALL, 5);
200 leftPanel->SetSizer(leftSizer);
201
202 // Create right panel for settings
203 wxPanel *rightPanel = new wxPanel(m_splitter, wxID_ANY);
204 rightPanel->SetBackgroundColour(wxColour(50, 50, 50));
205 wxBoxSizer *rightSizer = new wxBoxSizer(wxVERTICAL);
206
207 // Settings scrolled window
208 m_settingsPanel = new wxScrolledWindow(rightPanel, wxID_ANY);
209 m_settingsPanel->SetBackgroundColour(wxColour(50, 50, 50));
210 m_settingsPanel->SetScrollRate(0, 10);
211
212 m_settingsSizer = new wxBoxSizer(wxVERTICAL);
213
214 // Create all section panels
216
218 rightSizer->Add(m_settingsPanel, 1, wxEXPAND | wxALL, 10);
219
220 rightPanel->SetSizer(rightSizer);
221
222 // Split the window
223 m_splitter->SplitVertically(leftPanel, rightPanel, 150);
224 mainSizer->Add(m_splitter, 1, wxEXPAND | wxALL, 0);
225
226 // Button sizer at bottom
227 wxBoxSizer *buttonSizer = new wxBoxSizer(wxHORIZONTAL);
228
229 m_restoreDefaultsButton = new wxButton(this, ID_RESTORE_DEFAULTS, "Restore Defaults");
230 m_restoreDefaultsButton->SetToolTip("Reset all settings to their default values");
231
232 buttonSizer->Add(m_restoreDefaultsButton, 0, wxALL, 5);
233 buttonSizer->AddStretchSpacer();
234
235 m_applyButton = new wxButton(this, ID_APPLY, "Apply");
236 m_applyButton->SetToolTip("Apply changes without closing the dialog");
237
238 m_cancelButton = new wxButton(this, wxID_CANCEL, "Cancel");
239 m_okButton = new wxButton(this, wxID_OK, "OK");
240 m_okButton->SetDefault();
241
242 buttonSizer->Add(m_applyButton, 0, wxALL, 5);
243 buttonSizer->Add(m_cancelButton, 0, wxALL, 5);
244 buttonSizer->Add(m_okButton, 0, wxALL, 5);
245
246 mainSizer->Add(buttonSizer, 0, wxEXPAND | wxALL, 10);
247
248 SetSizer(mainSizer);
249 Layout();
250}
251
253 // Create all section panels (hidden initially)
266
267 // Add to sizer (all will be shown/hidden dynamically)
268 m_settingsSizer->Add(m_windowPanel, 1, wxEXPAND | wxALL, 5);
269 m_settingsSizer->Add(m_mainPanelPanel, 1, wxEXPAND | wxALL, 5);
270 m_settingsSizer->Add(m_behaviorTreeViewPanel, 1, wxEXPAND | wxALL, 5);
271 m_settingsSizer->Add(m_bottomPanelPanel, 1, wxEXPAND | wxALL, 5);
272 m_settingsSizer->Add(m_fileExplorerPanel, 1, wxEXPAND | wxALL, 5);
273 m_settingsSizer->Add(m_logTabPanel, 1, wxEXPAND | wxALL, 5);
274 m_settingsSizer->Add(m_sidePanelPanel, 1, wxEXPAND | wxALL, 5);
275 m_settingsSizer->Add(m_leftPanelPanel, 1, wxEXPAND | wxALL, 5);
276 m_settingsSizer->Add(m_rightPanelPanel, 1, wxEXPAND | wxALL, 5);
277 m_settingsSizer->Add(m_tabsSubPanel, 1, wxEXPAND | wxALL, 5);
278 m_settingsSizer->Add(m_parserPanel, 1, wxEXPAND | wxALL, 5);
279 m_settingsSizer->Add(m_performancePanel, 1, wxEXPAND | wxALL, 5);
280
281 // Hide all panels initially
282 m_windowPanel->Hide();
283 m_mainPanelPanel->Hide();
285 m_bottomPanelPanel->Hide();
286 m_fileExplorerPanel->Hide();
287 m_logTabPanel->Hide();
288 m_sidePanelPanel->Hide();
289 m_leftPanelPanel->Hide();
290 m_rightPanelPanel->Hide();
291 m_tabsSubPanel->Hide();
292 m_parserPanel->Hide();
293 m_performancePanel->Hide();
294
295 // Build tree structure after panels are created
296 wxTreeItemId root = m_sectionTree->AddRoot("Preferences");
297
298 // Window section
299 wxTreeItemId windowItem = m_sectionTree->AppendItem(root, "Window");
300 m_sectionTree->SetItemData(windowItem, new SectionTreeItemData(m_windowPanel));
301
302 // Main Panel section with child
303 wxTreeItemId mainPanelItem = m_sectionTree->AppendItem(root, "Main Panel");
304 m_sectionTree->SetItemData(mainPanelItem, new SectionTreeItemData(m_mainPanelPanel));
305
306 wxTreeItemId behaviorTreeViewItem = m_sectionTree->AppendItem(mainPanelItem, "Behavior Tree View");
307 m_sectionTree->SetItemData(behaviorTreeViewItem, new SectionTreeItemData(m_behaviorTreeViewPanel));
308
309 // Expand Main Panel by default to show child
310 m_sectionTree->Expand(mainPanelItem);
311
312 // Side Panel section (parent for all panels that inherit from SidePanel)
313 wxTreeItemId sidePanelItem = m_sectionTree->AppendItem(root, "Side Panel");
314 m_sectionTree->SetItemData(sidePanelItem, new SectionTreeItemData(m_sidePanelPanel));
315
316 // Left Panel under Side Panel
317 wxTreeItemId leftPanelItem = m_sectionTree->AppendItem(sidePanelItem, "Left Panel");
318 m_sectionTree->SetItemData(leftPanelItem, new SectionTreeItemData(m_leftPanelPanel));
319
320 // Right Panel under Side Panel
321 wxTreeItemId rightPanelItem = m_sectionTree->AppendItem(sidePanelItem, "Right Panel");
322 m_sectionTree->SetItemData(rightPanelItem, new SectionTreeItemData(m_rightPanelPanel));
323
324 // Bottom Panel under Side Panel
325 wxTreeItemId bottomPanelItem = m_sectionTree->AppendItem(sidePanelItem, "Bottom Panel");
326 m_sectionTree->SetItemData(bottomPanelItem, new SectionTreeItemData(m_bottomPanelPanel));
327
328 // Expand Side Panel by default
329 m_sectionTree->Expand(sidePanelItem);
330
331 // Tabs section (top-level)
332 wxTreeItemId tabsItem = m_sectionTree->AppendItem(root, "Tabs");
333 m_sectionTree->SetItemData(tabsItem, new SectionTreeItemData(m_tabsSubPanel));
334
335 // File Explorer Tab under Tabs
336 wxTreeItemId fileExplorerItem = m_sectionTree->AppendItem(tabsItem, "File Explorer Tab");
337 m_sectionTree->SetItemData(fileExplorerItem, new SectionTreeItemData(m_fileExplorerPanel));
338
339 // Log Tab under Tabs
340 wxTreeItemId logTabItem = m_sectionTree->AppendItem(tabsItem, "Log Tab");
341 m_sectionTree->SetItemData(logTabItem, new SectionTreeItemData(m_logTabPanel));
342
343 // Expand Tabs by default
344 m_sectionTree->Expand(tabsItem);
345
346 // Parser section
347 wxTreeItemId parserItem = m_sectionTree->AppendItem(root, "Parser");
348 m_sectionTree->SetItemData(parserItem, new SectionTreeItemData(m_parserPanel));
349
350 // Performance section
351 wxTreeItemId performanceItem = m_sectionTree->AppendItem(root, "Performance");
352 m_sectionTree->SetItemData(performanceItem, new SectionTreeItemData(m_performancePanel));
353}
354
355wxPanel *PreferencesDialog::CreateWindowSettings(wxWindow *parent) {
356 wxPanel *panel = new wxPanel(parent, wxID_ANY);
357 panel->SetBackgroundColour(wxColour(50, 50, 50));
358 wxBoxSizer *panelSizer = new wxBoxSizer(wxVERTICAL);
359
360 // Appearance group
361 wxStaticBoxSizer *appearanceGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Appearance");
362
363 // Theme choice
364 wxBoxSizer *themeSizer = new wxBoxSizer(wxHORIZONTAL);
365 wxStaticText *themeLabel = new wxStaticText(panel, wxID_ANY, "Theme:");
366 themeLabel->SetForegroundColour(wxColour(200, 200, 200));
367 themeSizer->Add(themeLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
368
369 wxArrayString themes;
370 themes.Add("Dark");
371 themes.Add("Light (Not Implemented)");
372 m_themeChoice = new wxChoice(panel, ID_THEME_CHOICE, wxDefaultPosition, wxDefaultSize, themes);
373 themeSizer->Add(m_themeChoice, 1, wxEXPAND);
374 appearanceGroup->Add(themeSizer, 0, wxEXPAND | wxALL, 5);
375
376 // Accent color
377 wxBoxSizer *accentSizer = new wxBoxSizer(wxHORIZONTAL);
378 wxStaticText *accentLabel = new wxStaticText(panel, wxID_ANY, "Accent Color:");
379 accentLabel->SetForegroundColour(wxColour(200, 200, 200));
380 accentSizer->Add(accentLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
381
382 m_accentColorPicker = new wxColourPickerCtrl(panel, ID_ACCENT_COLOR);
383 accentSizer->Add(m_accentColorPicker, 0, wxALIGN_CENTER_VERTICAL);
384 appearanceGroup->Add(accentSizer, 0, wxEXPAND | wxALL, 5);
385
386 panelSizer->Add(appearanceGroup, 0, wxEXPAND | wxALL, 5);
387
388 // Startup group
389 wxStaticBoxSizer *startupGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Startup");
390
391 wxBoxSizer *startupModeSizer = new wxBoxSizer(wxHORIZONTAL);
392 wxStaticText *startupModeLabel = new wxStaticText(panel, wxID_ANY, "Window mode on startup:");
393 startupModeLabel->SetForegroundColour(wxColour(200, 200, 200));
394 startupModeSizer->Add(startupModeLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
395
396 wxArrayString startupModes;
397 startupModes.Add("Normal");
398 startupModes.Add("Maximized");
399 m_startupModeChoice = new wxChoice(panel, ID_STARTUP_MODE, wxDefaultPosition, wxDefaultSize, startupModes);
400 startupModeSizer->Add(m_startupModeChoice, 1, wxEXPAND);
401 startupGroup->Add(startupModeSizer, 0, wxEXPAND | wxALL, 5);
402
403 panelSizer->Add(startupGroup, 0, wxEXPAND | wxALL, 5);
404
405 // File Menu Hotkeys group
406 wxStaticBoxSizer *fileHotkeysGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "File Menu Hotkeys");
407
408 // Helper lambda to create hotkey row
409 auto createHotkeyRow = [&](const wxString &labelText, wxTextCtrl *&textCtrl, wxButton *&captureBtn) {
410 wxBoxSizer *sizer = new wxBoxSizer(wxHORIZONTAL);
411 wxStaticText *label = new wxStaticText(panel, wxID_ANY, labelText, wxDefaultPosition, wxSize(120, -1));
412 label->SetForegroundColour(wxColour(200, 200, 200));
413 sizer->Add(label, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
414
415 textCtrl = new wxTextCtrl(panel, wxID_ANY, "", wxDefaultPosition, wxSize(150, -1), wxTE_READONLY);
416 textCtrl->SetBackgroundColour(wxColour(60, 60, 60));
417 textCtrl->SetForegroundColour(wxColour(200, 200, 200));
418 textCtrl->Bind(wxEVT_KEY_DOWN, &PreferencesDialog::OnHotkeyTextKeyDown, this);
419 textCtrl->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent &e) { /* Prevent direct clicks */ });
420 sizer->Add(textCtrl, 1, wxEXPAND);
421
422 captureBtn = new wxButton(panel, wxID_ANY, "Capture", wxDefaultPosition, wxSize(80, -1));
423 captureBtn->Bind(wxEVT_BUTTON, &PreferencesDialog::OnHotkeyCaptureClicked, this);
424 sizer->Add(captureBtn, 0, wxLEFT, 5);
425
426 return sizer;
427 };
428
429 fileHotkeysGroup->Add(createHotkeyRow("New Project:", m_newProjectHotkeyTextCtrl, m_newProjectHotkeyCaptureButton),
430 0, wxEXPAND | wxALL, 3);
431 fileHotkeysGroup->Add(
432 createHotkeyRow("Open Project:", m_openProjectHotkeyTextCtrl, m_openProjectHotkeyCaptureButton), 0,
433 wxEXPAND | wxALL, 3);
434 fileHotkeysGroup->Add(createHotkeyRow("Open File:", m_openFileHotkeyTextCtrl, m_openFileHotkeyCaptureButton), 0,
435 wxEXPAND | wxALL, 3);
436 fileHotkeysGroup->Add(createHotkeyRow("Save:", m_saveHotkeyTextCtrl, m_saveHotkeyCaptureButton), 0,
437 wxEXPAND | wxALL, 3);
438 fileHotkeysGroup->Add(createHotkeyRow("Save As:", m_saveAsHotkeyTextCtrl, m_saveAsHotkeyCaptureButton), 0,
439 wxEXPAND | wxALL, 3);
440
441 panelSizer->Add(fileHotkeysGroup, 0, wxEXPAND | wxALL, 5);
442
443 // View Menu Hotkeys group
444 wxStaticBoxSizer *viewHotkeysGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "View Menu Hotkeys");
445 viewHotkeysGroup->Add(createHotkeyRow("Maximize:", m_maximizeHotkeyTextCtrl, m_maximizeHotkeyCaptureButton), 0,
446 wxEXPAND | wxALL, 3);
447 viewHotkeysGroup->Add(createHotkeyRow("Reset UI:", m_resetUIHotkeyTextCtrl, m_resetUIHotkeyCaptureButton), 0,
448 wxEXPAND | wxALL, 3);
449
450 panelSizer->Add(viewHotkeysGroup, 0, wxEXPAND | wxALL, 5);
451
452 // Settings Menu Hotkeys group
453 wxStaticBoxSizer *settingsHotkeysGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Settings Menu Hotkeys");
454 settingsHotkeysGroup->Add(
455 createHotkeyRow("Preferences:", m_preferencesHotkeyTextCtrl, m_preferencesHotkeyCaptureButton), 0,
456 wxEXPAND | wxALL, 3);
457 settingsHotkeysGroup->Add(
458 createHotkeyRow("Parser Config:", m_parserConfigHotkeyTextCtrl, m_parserConfigHotkeyCaptureButton), 0,
459 wxEXPAND | wxALL, 3);
460
461 panelSizer->Add(settingsHotkeysGroup, 0, wxEXPAND | wxALL, 5);
462
463 // Window Appearance group
464 wxStaticBoxSizer *windowAppearanceGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Window Appearance");
465
466 // Show status bar
467 m_showStatusBar = new wxCheckBox(panel, ID_SHOW_STATUS_BAR, "Show status bar at bottom");
468 m_showStatusBar->SetForegroundColour(wxColour(200, 200, 200));
469 m_showStatusBar->SetToolTip("Display the status bar at the bottom of the window");
470 windowAppearanceGroup->Add(m_showStatusBar, 0, wxALL, 5);
471
472 // Show panel captions
473 m_showPanelCaptions = new wxCheckBox(panel, ID_SHOW_PANEL_CAPTIONS, "Show panel caption headers");
474 m_showPanelCaptions->SetForegroundColour(wxColour(200, 200, 200));
475 m_showPanelCaptions->SetToolTip("Display caption headers above panels (Left Panel, Right Panel, etc.)");
476 windowAppearanceGroup->Add(m_showPanelCaptions, 0, wxALL, 5);
477
478 // Always on top
479 m_alwaysOnTop = new wxCheckBox(panel, ID_ALWAYS_ON_TOP, "Always on top");
480 m_alwaysOnTop->SetForegroundColour(wxColour(200, 200, 200));
481 m_alwaysOnTop->SetToolTip("Keep window above all other windows");
482 windowAppearanceGroup->Add(m_alwaysOnTop, 0, wxALL, 5);
483
484 panelSizer->Add(windowAppearanceGroup, 0, wxEXPAND | wxALL, 5);
485
486 // Window Constraints group
487 wxStaticBoxSizer *constraintsGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Window Constraints");
488
489 // Minimum size
490 wxStaticText *minSizeLabel = new wxStaticText(panel, wxID_ANY, "Minimum Window Size (% of screen):");
491 minSizeLabel->SetForegroundColour(wxColour(200, 200, 200));
492 constraintsGroup->Add(minSizeLabel, 0, wxALL, 5);
493
494 wxBoxSizer *minSizeSizer = new wxBoxSizer(wxHORIZONTAL);
495 wxStaticText *minWidthLabel = new wxStaticText(panel, wxID_ANY, "Width %:");
496 minWidthLabel->SetForegroundColour(wxColour(200, 200, 200));
497 minSizeSizer->Add(minWidthLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
498
499 m_minWindowWidth = new wxSpinCtrl(panel, ID_MIN_WINDOW_WIDTH, "42", wxDefaultPosition, wxSize(120, -1),
500 wxSP_ARROW_KEYS, 10, 100, 42);
501 minSizeSizer->Add(m_minWindowWidth, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
502
503 wxStaticText *minHeightLabel = new wxStaticText(panel, wxID_ANY, "Height %:");
504 minHeightLabel->SetForegroundColour(wxColour(200, 200, 200));
505 minSizeSizer->Add(minHeightLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
506
507 m_minWindowHeight = new wxSpinCtrl(panel, ID_MIN_WINDOW_HEIGHT, "56", wxDefaultPosition, wxSize(120, -1),
508 wxSP_ARROW_KEYS, 10, 100, 56);
509 minSizeSizer->Add(m_minWindowHeight, 0);
510
511 constraintsGroup->Add(minSizeSizer, 0, wxEXPAND | wxALL, 5);
512
513 // Maximum size
514 wxStaticText *maxSizeLabel = new wxStaticText(panel, wxID_ANY, "Maximum Window Size (% of screen):");
515 maxSizeLabel->SetForegroundColour(wxColour(200, 200, 200));
516 constraintsGroup->Add(maxSizeLabel, 0, wxALL, 5);
517
518 m_maxWindowUnlimited = new wxCheckBox(panel, ID_MAX_WINDOW_UNLIMITED, "Unlimited (no maximum size)");
519 m_maxWindowUnlimited->SetForegroundColour(wxColour(200, 200, 200));
520 constraintsGroup->Add(m_maxWindowUnlimited, 0, wxALL, 5);
521
522 wxBoxSizer *maxSizeSizer = new wxBoxSizer(wxHORIZONTAL);
523 wxStaticText *maxWidthLabel = new wxStaticText(panel, wxID_ANY, "Width %:");
524 maxWidthLabel->SetForegroundColour(wxColour(200, 200, 200));
525 maxSizeSizer->Add(maxWidthLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
526
527 m_maxWindowWidth = new wxSpinCtrl(panel, ID_MAX_WINDOW_WIDTH, "-1", wxDefaultPosition, wxSize(120, -1),
528 wxSP_ARROW_KEYS, -1, 100, -1);
529 maxSizeSizer->Add(m_maxWindowWidth, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
530
531 wxStaticText *maxHeightLabel = new wxStaticText(panel, wxID_ANY, "Height %:");
532 maxHeightLabel->SetForegroundColour(wxColour(200, 200, 200));
533 maxSizeSizer->Add(maxHeightLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
534
535 m_maxWindowHeight = new wxSpinCtrl(panel, ID_MAX_WINDOW_HEIGHT, "-1", wxDefaultPosition, wxSize(120, -1),
536 wxSP_ARROW_KEYS, -1, 100, -1);
537 maxSizeSizer->Add(m_maxWindowHeight, 0);
538
539 constraintsGroup->Add(maxSizeSizer, 0, wxEXPAND | wxALL, 5);
540
541 // Aspect ratio
542 m_enforceAspectRatio = new wxCheckBox(panel, ID_ENFORCE_ASPECT_RATIO, "Enforce aspect ratio");
543 m_enforceAspectRatio->SetForegroundColour(wxColour(200, 200, 200));
544 m_enforceAspectRatio->SetToolTip("Maintain window width/height ratio when resizing");
545 constraintsGroup->Add(m_enforceAspectRatio, 0, wxALL, 5);
546
547 wxBoxSizer *aspectRatioSizer = new wxBoxSizer(wxHORIZONTAL);
548 wxStaticText *aspectLabel = new wxStaticText(panel, wxID_ANY, "Aspect Ratio:");
549 aspectLabel->SetForegroundColour(wxColour(200, 200, 200));
550 aspectRatioSizer->Add(aspectLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
551
552 m_aspectRatioWidth = new wxTextCtrl(panel, ID_ASPECT_RATIO_WIDTH, "16", wxDefaultPosition, wxSize(50, -1));
553 aspectRatioSizer->Add(m_aspectRatioWidth, 0, wxRIGHT, 5);
554
555 wxStaticText *aspectColon = new wxStaticText(panel, wxID_ANY, ":");
556 aspectColon->SetForegroundColour(wxColour(200, 200, 200));
557 aspectRatioSizer->Add(aspectColon, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
558
559 m_aspectRatioHeight = new wxTextCtrl(panel, ID_ASPECT_RATIO_HEIGHT, "9", wxDefaultPosition, wxSize(50, -1));
560 aspectRatioSizer->Add(m_aspectRatioHeight, 0);
561
562 wxStaticText *aspectNote = new wxStaticText(panel, wxID_ANY, "(e.g., 16:9, 4:3, 21:9)");
563 aspectNote->SetForegroundColour(wxColour(150, 150, 150));
564 aspectRatioSizer->Add(aspectNote, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 10);
565
566 constraintsGroup->Add(aspectRatioSizer, 0, wxEXPAND | wxALL, 5);
567
568 panelSizer->Add(constraintsGroup, 0, wxEXPAND | wxALL, 5);
569 panelSizer->AddStretchSpacer();
570
571 panel->SetSizer(panelSizer);
572 return panel;
573}
574
576 wxPanel *panel = new wxPanel(parent, wxID_ANY);
577 panel->SetBackgroundColour(wxColour(50, 50, 50));
578 wxBoxSizer *panelSizer = new wxBoxSizer(wxVERTICAL);
579
580 // Canvas group
581 wxStaticBoxSizer *canvasGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Canvas");
582
583 wxBoxSizer *bgColorSizer = new wxBoxSizer(wxHORIZONTAL);
584 wxStaticText *bgColorLabel = new wxStaticText(panel, wxID_ANY, "Background Color:");
585 bgColorLabel->SetForegroundColour(wxColour(200, 200, 200));
586 bgColorSizer->Add(bgColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
587
588 m_canvasBackgroundPicker = new wxColourPickerCtrl(panel, ID_CANVAS_BACKGROUND);
589 bgColorSizer->Add(m_canvasBackgroundPicker, 0, wxALIGN_CENTER_VERTICAL);
590 canvasGroup->Add(bgColorSizer, 0, wxEXPAND | wxALL, 5);
591
592 panelSizer->Add(canvasGroup, 0, wxEXPAND | wxALL, 5);
593
594 // Scene Management group
595 wxStaticBoxSizer *sceneManagementGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Scene Management");
596
597 wxBoxSizer *maxScenesSizer = new wxBoxSizer(wxHORIZONTAL);
598 wxStaticText *maxScenesLabel = new wxStaticText(panel, wxID_ANY, "Maximum Scenes:");
599 maxScenesLabel->SetForegroundColour(wxColour(200, 200, 200));
600 maxScenesSizer->Add(maxScenesLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
601
603 new wxSpinCtrl(panel, ID_MAX_SCENES, "10", wxDefaultPosition, wxSize(120, -1), wxSP_ARROW_KEYS, 1, 50, 10);
604 maxScenesSizer->Add(m_maxScenes, 0, wxALIGN_CENTER_VERTICAL);
605
606 m_maxScenesUnlimited = new wxCheckBox(panel, ID_MAX_SCENES_UNLIMITED, "Unlimited");
607 m_maxScenesUnlimited->SetForegroundColour(wxColour(200, 200, 200));
608 maxScenesSizer->Add(m_maxScenesUnlimited, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 40);
609
610 sceneManagementGroup->Add(maxScenesSizer, 0, wxEXPAND | wxALL, 5);
611
612 wxStaticText *sceneNote =
613 new wxStaticText(panel, wxID_ANY, "Limit the number of behavior tree scenes that can be open simultaneously");
614 sceneNote->SetForegroundColour(wxColour(150, 150, 150));
615 sceneNote->Wrap(450);
616 sceneManagementGroup->Add(sceneNote, 0, wxALL, 5);
617
618 // Close confirmation
619 wxBoxSizer *closeConfirmSizer = new wxBoxSizer(wxHORIZONTAL);
620 wxStaticText *closeConfirmLabel = new wxStaticText(panel, wxID_ANY, "Close Confirmation:");
621 closeConfirmLabel->SetForegroundColour(wxColour(200, 200, 200));
622 closeConfirmSizer->Add(closeConfirmLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
623
624 wxArrayString closeConfirmOptions;
625 closeConfirmOptions.Add("Always Ask");
626 closeConfirmOptions.Add("Never Ask");
627 closeConfirmOptions.Add("Ask If Unsaved");
629 new wxChoice(panel, ID_CLOSE_CONFIRMATION, wxDefaultPosition, wxDefaultSize, closeConfirmOptions);
630 closeConfirmSizer->Add(m_closeConfirmation, 1, wxEXPAND);
631
632 sceneManagementGroup->Add(closeConfirmSizer, 0, wxEXPAND | wxALL, 5);
633
634 panelSizer->Add(sceneManagementGroup, 0, wxEXPAND | wxALL, 5);
635
636 // Tab Switching Hotkeys group
637 wxStaticBoxSizer *tabSwitchingGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Tab Switching");
638
639 // Next scene hotkey
640 wxBoxSizer *nextSceneHotkeySizer = new wxBoxSizer(wxHORIZONTAL);
641 wxStaticText *nextSceneLabel = new wxStaticText(panel, wxID_ANY, "Next Scene:");
642 nextSceneLabel->SetForegroundColour(wxColour(200, 200, 200));
643 nextSceneHotkeySizer->Add(nextSceneLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
644
645 m_nextSceneHotkeyTextCtrl = new wxTextCtrl(panel, wxID_ANY, "", wxDefaultPosition, wxSize(150, -1), wxTE_READONLY);
646 m_nextSceneHotkeyTextCtrl->SetBackgroundColour(wxColour(60, 60, 60));
647 m_nextSceneHotkeyTextCtrl->SetForegroundColour(wxColour(200, 200, 200));
649 m_nextSceneHotkeyTextCtrl->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent &e) { /* Prevent direct clicks */ });
650 nextSceneHotkeySizer->Add(m_nextSceneHotkeyTextCtrl, 1, wxEXPAND);
651
652 m_nextSceneHotkeyCaptureButton = new wxButton(panel, wxID_ANY, "Capture", wxDefaultPosition, wxSize(80, -1));
654 nextSceneHotkeySizer->Add(m_nextSceneHotkeyCaptureButton, 0, wxLEFT, 5);
655
656 tabSwitchingGroup->Add(nextSceneHotkeySizer, 0, wxEXPAND | wxALL, 5);
657
658 // Previous scene hotkey
659 wxBoxSizer *previousSceneHotkeySizer = new wxBoxSizer(wxHORIZONTAL);
660 wxStaticText *previousSceneLabel = new wxStaticText(panel, wxID_ANY, "Previous Scene:");
661 previousSceneLabel->SetForegroundColour(wxColour(200, 200, 200));
662 previousSceneHotkeySizer->Add(previousSceneLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
663
665 new wxTextCtrl(panel, wxID_ANY, "", wxDefaultPosition, wxSize(150, -1), wxTE_READONLY);
666 m_previousSceneHotkeyTextCtrl->SetBackgroundColour(wxColour(60, 60, 60));
667 m_previousSceneHotkeyTextCtrl->SetForegroundColour(wxColour(200, 200, 200));
669 m_previousSceneHotkeyTextCtrl->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent &e) { /* Prevent direct clicks */ });
670 previousSceneHotkeySizer->Add(m_previousSceneHotkeyTextCtrl, 1, wxEXPAND);
671
672 m_previousSceneHotkeyCaptureButton = new wxButton(panel, wxID_ANY, "Capture", wxDefaultPosition, wxSize(80, -1));
674 previousSceneHotkeySizer->Add(m_previousSceneHotkeyCaptureButton, 0, wxLEFT, 5);
675
676 tabSwitchingGroup->Add(previousSceneHotkeySizer, 0, wxEXPAND | wxALL, 5);
677
678 panelSizer->Add(tabSwitchingGroup, 0, wxEXPAND | wxALL, 5);
679 panelSizer->AddStretchSpacer();
680
681 panel->SetSizer(panelSizer);
682 return panel;
683}
684
686 wxPanel *panel = new wxPanel(parent, wxID_ANY);
687 panel->SetBackgroundColour(wxColour(50, 50, 50));
688 wxBoxSizer *panelSizer = new wxBoxSizer(wxVERTICAL);
689
690 // Zoom group
691 wxStaticBoxSizer *zoomGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Zoom & View");
692
693 // Default zoom slider
694 wxBoxSizer *zoomSizer = new wxBoxSizer(wxHORIZONTAL);
695 wxStaticText *zoomLabelText = new wxStaticText(panel, wxID_ANY, "Default Zoom:");
696 zoomLabelText->SetForegroundColour(wxColour(200, 200, 200));
697 zoomSizer->Add(zoomLabelText, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
698
700 new wxSlider(panel, ID_DEFAULT_ZOOM, 100, 10, 200, wxDefaultPosition, wxSize(200, -1), wxSL_HORIZONTAL);
701 m_defaultZoomSlider->Bind(wxEVT_MOUSEWHEEL, &PreferencesDialog::OnSliderMouseWheel, this);
702 zoomSizer->Add(m_defaultZoomSlider, 1, wxEXPAND | wxRIGHT, 10);
703
704 m_zoomLabel = new wxStaticText(panel, wxID_ANY, "100%");
705 m_zoomLabel->SetForegroundColour(wxColour(200, 200, 200));
706 m_zoomLabel->SetMinSize(wxSize(50, -1));
707 zoomSizer->Add(m_zoomLabel, 0, wxALIGN_CENTER_VERTICAL);
708
709 zoomGroup->Add(zoomSizer, 0, wxEXPAND | wxALL, 5);
710
711 // Zoom step size
712 wxBoxSizer *zoomStepSizer = new wxBoxSizer(wxHORIZONTAL);
713 wxStaticText *zoomStepLabel = new wxStaticText(panel, wxID_ANY, "Zoom step size:");
714 zoomStepLabel->SetForegroundColour(wxColour(200, 200, 200));
715 zoomStepSizer->Add(zoomStepLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
716
718 new wxSlider(panel, ID_ZOOM_STEP_SIZE, 10, 1, 50, wxDefaultPosition, wxSize(200, -1), wxSL_HORIZONTAL);
719 m_zoomStepSize->Bind(wxEVT_MOUSEWHEEL, &PreferencesDialog::OnSliderMouseWheel, this);
720 zoomStepSizer->Add(m_zoomStepSize, 1, wxEXPAND | wxRIGHT, 10);
721
722 m_zoomStepSizeLabel = new wxStaticText(panel, wxID_ANY, "10%");
723 m_zoomStepSizeLabel->SetForegroundColour(wxColour(200, 200, 200));
724 m_zoomStepSizeLabel->SetMinSize(wxSize(50, -1));
725 zoomStepSizer->Add(m_zoomStepSizeLabel, 0, wxALIGN_CENTER_VERTICAL);
726
727 zoomGroup->Add(zoomStepSizer, 0, wxEXPAND | wxALL, 5);
728
729 // Mouse wheel sensitivity
730 wxBoxSizer *wheelSensitivitySizer = new wxBoxSizer(wxHORIZONTAL);
731 wxStaticText *wheelSensitivityText = new wxStaticText(panel, wxID_ANY, "Mouse wheel sensitivity:");
732 wheelSensitivityText->SetForegroundColour(wxColour(200, 200, 200));
733 wheelSensitivitySizer->Add(wheelSensitivityText, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
734
735 m_mouseWheelSensitivity = new wxSlider(panel, ID_MOUSE_WHEEL_SENSITIVITY, 100, 10, 500, wxDefaultPosition,
736 wxSize(200, -1), wxSL_HORIZONTAL);
738 wheelSensitivitySizer->Add(m_mouseWheelSensitivity, 1, wxEXPAND | wxRIGHT, 10);
739
740 m_mouseWheelSensitivityLabel = new wxStaticText(panel, wxID_ANY, "1.0x");
741 m_mouseWheelSensitivityLabel->SetForegroundColour(wxColour(200, 200, 200));
742 m_mouseWheelSensitivityLabel->SetMinSize(wxSize(50, -1));
743 wheelSensitivitySizer->Add(m_mouseWheelSensitivityLabel, 0, wxALIGN_CENTER_VERTICAL);
744 zoomGroup->Add(wheelSensitivitySizer, 0, wxEXPAND | wxALL, 5);
745
746 // Zoom follows cursor
747 m_zoomFollowsCursor = new wxCheckBox(panel, ID_ZOOM_FOLLOWS_CURSOR, "Zoom towards cursor position");
748 m_zoomFollowsCursor->SetForegroundColour(wxColour(200, 200, 200));
749 zoomGroup->Add(m_zoomFollowsCursor, 0, wxALL, 5);
750
751 // Reset view hotkey (full reset: zoom + pan)
752 wxBoxSizer *resetViewHotkeySizer = new wxBoxSizer(wxHORIZONTAL);
753 wxStaticText *resetViewHotkeyLabel = new wxStaticText(panel, wxID_ANY, "Reset view hotkey:");
754 resetViewHotkeyLabel->SetForegroundColour(wxColour(200, 200, 200));
755 resetViewHotkeySizer->Add(resetViewHotkeyLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
756
757 m_resetViewHotkeyTextCtrl = new wxTextCtrl(panel, ID_RESET_VIEW_HOTKEY_TEXT, "R", wxDefaultPosition,
758 wxSize(150, -1), wxTE_READONLY | wxTE_CENTRE);
759 m_resetViewHotkeyTextCtrl->SetBackgroundColour(wxColour(60, 60, 60));
760 m_resetViewHotkeyTextCtrl->SetForegroundColour(wxColour(200, 200, 200));
762 m_resetViewHotkeyTextCtrl->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent &e) { /* Prevent direct clicks */ });
763 resetViewHotkeySizer->Add(m_resetViewHotkeyTextCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
764
765 m_resetViewHotkeyCaptureButton = new wxButton(panel, ID_RESET_VIEW_HOTKEY_CAPTURE, "Capture");
767 resetViewHotkeySizer->Add(m_resetViewHotkeyCaptureButton, 0, wxALIGN_CENTER_VERTICAL);
768 zoomGroup->Add(resetViewHotkeySizer, 0, wxEXPAND | wxALL, 5);
769
770 panelSizer->Add(zoomGroup, 0, wxEXPAND | wxALL, 5);
771
772 // Pan group
773 wxStaticBoxSizer *panGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Panning");
774
775 // Pan sensitivity slider
776 wxBoxSizer *panSensitivitySizer = new wxBoxSizer(wxHORIZONTAL);
777 wxStaticText *panSensitivityText = new wxStaticText(panel, wxID_ANY, "Pan sensitivity:");
778 panSensitivityText->SetForegroundColour(wxColour(200, 200, 200));
779 panSensitivitySizer->Add(panSensitivityText, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
780
782 new wxSlider(panel, ID_PAN_SENSITIVITY, 151, 10, 200, wxDefaultPosition, wxSize(200, -1), wxSL_HORIZONTAL);
783 m_panSensitivity->Bind(wxEVT_MOUSEWHEEL, &PreferencesDialog::OnSliderMouseWheel, this);
784 panSensitivitySizer->Add(m_panSensitivity, 1, wxEXPAND | wxRIGHT, 10);
785
786 m_panSensitivityLabel = new wxStaticText(panel, wxID_ANY, "1.51x");
787 m_panSensitivityLabel->SetForegroundColour(wxColour(200, 200, 200));
788 m_panSensitivityLabel->SetMinSize(wxSize(50, -1));
789 panSensitivitySizer->Add(m_panSensitivityLabel, 0, wxALIGN_CENTER_VERTICAL);
790 panGroup->Add(panSensitivitySizer, 0, wxEXPAND | wxALL, 5);
791
792 // Pan smoothness slider
793 wxBoxSizer *panSmoothnessSizer = new wxBoxSizer(wxHORIZONTAL);
794 wxStaticText *panSmoothnessText = new wxStaticText(panel, wxID_ANY, "Pan smoothness:");
795 panSmoothnessText->SetForegroundColour(wxColour(200, 200, 200));
796 panSmoothnessSizer->Add(panSmoothnessText, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
797
799 new wxSlider(panel, ID_PAN_SMOOTHNESS, 30, 0, 100, wxDefaultPosition, wxSize(200, -1), wxSL_HORIZONTAL);
800 m_panSmoothness->Bind(wxEVT_MOUSEWHEEL, &PreferencesDialog::OnSliderMouseWheel, this);
802 panSmoothnessSizer->Add(m_panSmoothness, 1, wxEXPAND | wxRIGHT, 10);
803
804 m_panSmoothnessLabel = new wxStaticText(panel, wxID_ANY, "30%");
805 m_panSmoothnessLabel->SetForegroundColour(wxColour(200, 200, 200));
806 m_panSmoothnessLabel->SetMinSize(wxSize(50, -1));
807 panSmoothnessSizer->Add(m_panSmoothnessLabel, 0, wxALIGN_CENTER_VERTICAL);
808 panGroup->Add(panSmoothnessSizer, 0, wxEXPAND | wxALL, 5);
809
810 // Pan step size slider
811 wxBoxSizer *panStepSizeSizer = new wxBoxSizer(wxHORIZONTAL);
812 wxStaticText *panStepSizeText = new wxStaticText(panel, wxID_ANY, "Pan step size:");
813 panStepSizeText->SetForegroundColour(wxColour(200, 200, 200));
814 panStepSizeSizer->Add(panStepSizeText, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
815
817 new wxSlider(panel, ID_PAN_STEP_SIZE, 40, 10, 500, wxDefaultPosition, wxSize(200, -1), wxSL_HORIZONTAL);
818 m_panStepSize->Bind(wxEVT_MOUSEWHEEL, &PreferencesDialog::OnSliderMouseWheel, this);
819 m_panStepSize->Bind(wxEVT_SLIDER, &PreferencesDialog::OnPanStepSizeChanged, this);
820 panStepSizeSizer->Add(m_panStepSize, 1, wxEXPAND | wxRIGHT, 10);
821
822 m_panStepSizeLabel = new wxStaticText(panel, wxID_ANY, "40px");
823 m_panStepSizeLabel->SetForegroundColour(wxColour(200, 200, 200));
824 m_panStepSizeLabel->SetMinSize(wxSize(50, -1));
825 panStepSizeSizer->Add(m_panStepSizeLabel, 0, wxALIGN_CENTER_VERTICAL);
826 panGroup->Add(panStepSizeSizer, 0, wxEXPAND | wxALL, 5);
827
828 // Enable smooth panning checkbox
829 m_enableSmoothPanning = new wxCheckBox(panel, ID_ENABLE_SMOOTH_PANNING, "Enable smooth panning (arrow keys)");
830 m_enableSmoothPanning->SetForegroundColour(wxColour(200, 200, 200));
831 panGroup->Add(m_enableSmoothPanning, 0, wxALL, 5);
832
833 // Pan key (hold to pan)
834 wxBoxSizer *panKeyHotkeySizer = new wxBoxSizer(wxHORIZONTAL);
835 wxStaticText *panKeyHotkeyLabel = new wxStaticText(panel, wxID_ANY, "Pan key (hold + drag):");
836 panKeyHotkeyLabel->SetForegroundColour(wxColour(200, 200, 200));
837 panKeyHotkeySizer->Add(panKeyHotkeyLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
838
839 m_panKeyTextCtrl = new wxTextCtrl(panel, ID_PAN_KEY_TEXT, "Middle Mouse Button", wxDefaultPosition, wxSize(150, -1),
840 wxTE_READONLY | wxTE_CENTRE);
841 m_panKeyTextCtrl->SetBackgroundColour(wxColour(60, 60, 60));
842 m_panKeyTextCtrl->SetForegroundColour(wxColour(200, 200, 200));
843 m_panKeyTextCtrl->Bind(wxEVT_KEY_DOWN, &PreferencesDialog::OnHotkeyTextKeyDown, this);
844 m_panKeyTextCtrl->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent &e) { /* Prevent direct clicks */ });
845 // Mouse events are now handled at dialog level via OnDialogMouseDown
846 panKeyHotkeySizer->Add(m_panKeyTextCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
847
848 m_panKeyCaptureButton = new wxButton(panel, ID_PAN_KEY_CAPTURE, "Capture");
850 panKeyHotkeySizer->Add(m_panKeyCaptureButton, 0, wxALIGN_CENTER_VERTICAL);
851 panGroup->Add(panKeyHotkeySizer, 0, wxEXPAND | wxALL, 5);
852
853 // Pan up hotkey
854 wxBoxSizer *panUpHotkeySizer = new wxBoxSizer(wxHORIZONTAL);
855 wxStaticText *panUpLabel = new wxStaticText(panel, wxID_ANY, "Pan up:");
856 panUpLabel->SetForegroundColour(wxColour(200, 200, 200));
857 panUpHotkeySizer->Add(panUpLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
858
859 m_panUpHotkeyTextCtrl = new wxTextCtrl(panel, ID_PAN_UP_HOTKEY_TEXT, "Up", wxDefaultPosition, wxSize(150, -1),
860 wxTE_READONLY | wxTE_CENTRE);
861 m_panUpHotkeyTextCtrl->SetBackgroundColour(wxColour(60, 60, 60));
862 m_panUpHotkeyTextCtrl->SetForegroundColour(wxColour(200, 200, 200));
864 m_panUpHotkeyTextCtrl->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent &e) { /* Prevent direct clicks */ });
865 panUpHotkeySizer->Add(m_panUpHotkeyTextCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
866
867 m_panUpHotkeyCaptureButton = new wxButton(panel, ID_PAN_UP_HOTKEY_CAPTURE, "Capture");
869 panUpHotkeySizer->Add(m_panUpHotkeyCaptureButton, 0, wxALIGN_CENTER_VERTICAL);
870 panGroup->Add(panUpHotkeySizer, 0, wxEXPAND | wxALL, 5);
871
872 // Pan down hotkey
873 wxBoxSizer *panDownHotkeySizer = new wxBoxSizer(wxHORIZONTAL);
874 wxStaticText *panDownLabel = new wxStaticText(panel, wxID_ANY, "Pan down:");
875 panDownLabel->SetForegroundColour(wxColour(200, 200, 200));
876 panDownHotkeySizer->Add(panDownLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
877
878 m_panDownHotkeyTextCtrl = new wxTextCtrl(panel, ID_PAN_DOWN_HOTKEY_TEXT, "Down", wxDefaultPosition, wxSize(150, -1),
879 wxTE_READONLY | wxTE_CENTRE);
880 m_panDownHotkeyTextCtrl->SetBackgroundColour(wxColour(60, 60, 60));
881 m_panDownHotkeyTextCtrl->SetForegroundColour(wxColour(200, 200, 200));
883 m_panDownHotkeyTextCtrl->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent &e) { /* Prevent direct clicks */ });
884 panDownHotkeySizer->Add(m_panDownHotkeyTextCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
885
886 m_panDownHotkeyCaptureButton = new wxButton(panel, ID_PAN_DOWN_HOTKEY_CAPTURE, "Capture");
888 panDownHotkeySizer->Add(m_panDownHotkeyCaptureButton, 0, wxALIGN_CENTER_VERTICAL);
889 panGroup->Add(panDownHotkeySizer, 0, wxEXPAND | wxALL, 5);
890
891 // Pan left hotkey
892 wxBoxSizer *panLeftHotkeySizer = new wxBoxSizer(wxHORIZONTAL);
893 wxStaticText *panLeftLabel = new wxStaticText(panel, wxID_ANY, "Pan left:");
894 panLeftLabel->SetForegroundColour(wxColour(200, 200, 200));
895 panLeftHotkeySizer->Add(panLeftLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
896
897 m_panLeftHotkeyTextCtrl = new wxTextCtrl(panel, ID_PAN_LEFT_HOTKEY_TEXT, "Left", wxDefaultPosition, wxSize(150, -1),
898 wxTE_READONLY | wxTE_CENTRE);
899 m_panLeftHotkeyTextCtrl->SetBackgroundColour(wxColour(60, 60, 60));
900 m_panLeftHotkeyTextCtrl->SetForegroundColour(wxColour(200, 200, 200));
902 m_panLeftHotkeyTextCtrl->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent &e) { /* Prevent direct clicks */ });
903 panLeftHotkeySizer->Add(m_panLeftHotkeyTextCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
904
905 m_panLeftHotkeyCaptureButton = new wxButton(panel, ID_PAN_LEFT_HOTKEY_CAPTURE, "Capture");
907 panLeftHotkeySizer->Add(m_panLeftHotkeyCaptureButton, 0, wxALIGN_CENTER_VERTICAL);
908 panGroup->Add(panLeftHotkeySizer, 0, wxEXPAND | wxALL, 5);
909
910 // Pan right hotkey
911 wxBoxSizer *panRightHotkeySizer = new wxBoxSizer(wxHORIZONTAL);
912 wxStaticText *panRightLabel = new wxStaticText(panel, wxID_ANY, "Pan right:");
913 panRightLabel->SetForegroundColour(wxColour(200, 200, 200));
914 panRightHotkeySizer->Add(panRightLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
915
916 m_panRightHotkeyTextCtrl = new wxTextCtrl(panel, ID_PAN_RIGHT_HOTKEY_TEXT, "Right", wxDefaultPosition,
917 wxSize(150, -1), wxTE_READONLY | wxTE_CENTRE);
918 m_panRightHotkeyTextCtrl->SetBackgroundColour(wxColour(60, 60, 60));
919 m_panRightHotkeyTextCtrl->SetForegroundColour(wxColour(200, 200, 200));
921 m_panRightHotkeyTextCtrl->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent &e) { /* Prevent direct clicks */ });
922 panRightHotkeySizer->Add(m_panRightHotkeyTextCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
923
924 m_panRightHotkeyCaptureButton = new wxButton(panel, ID_PAN_RIGHT_HOTKEY_CAPTURE, "Capture");
926 panRightHotkeySizer->Add(m_panRightHotkeyCaptureButton, 0, wxALIGN_CENTER_VERTICAL);
927 panGroup->Add(panRightHotkeySizer, 0, wxEXPAND | wxALL, 5);
928
929 panelSizer->Add(panGroup, 0, wxEXPAND | wxALL, 5);
930
931 // Action hotkeys group
932 wxStaticBoxSizer *navGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Action Hotkeys");
933
934 // Expand/Collapse hotkey (previously "Center on selected")
935 wxBoxSizer *centerHotkeySizer = new wxBoxSizer(wxHORIZONTAL);
936 wxStaticText *centerHotkeyLabel = new wxStaticText(panel, wxID_ANY, "Expand/Collapse:");
937 centerHotkeyLabel->SetForegroundColour(wxColour(200, 200, 200));
938 centerHotkeySizer->Add(centerHotkeyLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
939
940 m_centerOnNodeHotkeyTextCtrl = new wxTextCtrl(panel, ID_CENTER_ON_NODE_HOTKEY_TEXT, "C", wxDefaultPosition,
941 wxSize(150, -1), wxTE_READONLY | wxTE_CENTRE);
942 m_centerOnNodeHotkeyTextCtrl->SetBackgroundColour(wxColour(60, 60, 60));
943 m_centerOnNodeHotkeyTextCtrl->SetForegroundColour(wxColour(200, 200, 200));
945 m_centerOnNodeHotkeyTextCtrl->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent &e) { /* Prevent direct clicks */ });
946 centerHotkeySizer->Add(m_centerOnNodeHotkeyTextCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
947
950 centerHotkeySizer->Add(m_centerOnNodeHotkeyCaptureButton, 0, wxALIGN_CENTER_VERTICAL);
951 navGroup->Add(centerHotkeySizer, 0, wxEXPAND | wxALL, 5);
952
953 // Delete node hotkey
954 wxBoxSizer *deleteHotkeySizer = new wxBoxSizer(wxHORIZONTAL);
955 wxStaticText *deleteHotkeyLabel = new wxStaticText(panel, wxID_ANY, "Delete node:");
956 deleteHotkeyLabel->SetForegroundColour(wxColour(200, 200, 200));
957 deleteHotkeySizer->Add(deleteHotkeyLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
958
959 m_deleteNodeHotkeyTextCtrl = new wxTextCtrl(panel, ID_DELETE_NODE_HOTKEY_TEXT, "Delete", wxDefaultPosition,
960 wxSize(150, -1), wxTE_READONLY | wxTE_CENTRE);
961 m_deleteNodeHotkeyTextCtrl->SetBackgroundColour(wxColour(60, 60, 60));
962 m_deleteNodeHotkeyTextCtrl->SetForegroundColour(wxColour(200, 200, 200));
964 m_deleteNodeHotkeyTextCtrl->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent &e) { /* Prevent direct clicks */ });
965 deleteHotkeySizer->Add(m_deleteNodeHotkeyTextCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
966
967 m_deleteNodeHotkeyCaptureButton = new wxButton(panel, ID_DELETE_NODE_HOTKEY_CAPTURE, "Capture");
969 deleteHotkeySizer->Add(m_deleteNodeHotkeyCaptureButton, 0, wxALIGN_CENTER_VERTICAL);
970 navGroup->Add(deleteHotkeySizer, 0, wxEXPAND | wxALL, 5);
971
972 panelSizer->Add(navGroup, 0, wxEXPAND | wxALL, 5);
973
974 // Grid group
975 wxStaticBoxSizer *gridGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Grid");
976
977 m_showGrid = new wxCheckBox(panel, ID_SHOW_GRID, "Show grid");
978 m_showGrid->SetForegroundColour(wxColour(200, 200, 200));
979 gridGroup->Add(m_showGrid, 0, wxALL, 5);
980
981 wxBoxSizer *gridSizeSizer = new wxBoxSizer(wxHORIZONTAL);
982 wxStaticText *gridSizeLabel = new wxStaticText(panel, wxID_ANY, "Grid size (pixels):");
983 gridSizeLabel->SetForegroundColour(wxColour(200, 200, 200));
984 gridSizeSizer->Add(gridSizeLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
985
986 m_gridSize =
987 new wxSpinCtrl(panel, ID_GRID_SIZE, "20", wxDefaultPosition, wxSize(120, -1), wxSP_ARROW_KEYS, 10, 100, 20);
988 gridSizeSizer->Add(m_gridSize, 0, wxALIGN_CENTER_VERTICAL);
989 gridGroup->Add(gridSizeSizer, 0, wxEXPAND | wxALL, 5);
990
991 // Grid background color
992 wxBoxSizer *gridBgColorSizer = new wxBoxSizer(wxHORIZONTAL);
993 wxStaticText *gridBgColorLabel = new wxStaticText(panel, wxID_ANY, "Grid background color:");
994 gridBgColorLabel->SetForegroundColour(wxColour(200, 200, 200));
995 gridBgColorSizer->Add(gridBgColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
996
997 m_gridBackgroundPicker = new wxColourPickerCtrl(panel, ID_GRID_BACKGROUND);
998 gridBgColorSizer->Add(m_gridBackgroundPicker, 0, wxALIGN_CENTER_VERTICAL);
999 gridGroup->Add(gridBgColorSizer, 0, wxEXPAND | wxALL, 5);
1000
1001 // Grid line color
1002 wxBoxSizer *gridLineColorSizer = new wxBoxSizer(wxHORIZONTAL);
1003 wxStaticText *gridLineColorLabel = new wxStaticText(panel, wxID_ANY, "Grid line color:");
1004 gridLineColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1005 gridLineColorSizer->Add(gridLineColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1006
1007 m_gridLineColorPicker = new wxColourPickerCtrl(panel, ID_GRID_LINE_COLOR);
1008 gridLineColorSizer->Add(m_gridLineColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1009 gridGroup->Add(gridLineColorSizer, 0, wxEXPAND | wxALL, 5);
1010
1011 // Connection line color
1012 wxBoxSizer *connectionColorSizer = new wxBoxSizer(wxHORIZONTAL);
1013 wxStaticText *connectionColorLabel = new wxStaticText(panel, wxID_ANY, "Connection line color:");
1014 connectionColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1015 connectionColorSizer->Add(connectionColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1016
1017 m_connectionLineColorPicker = new wxColourPickerCtrl(panel, ID_CONNECTION_LINE_COLOR);
1018 connectionColorSizer->Add(m_connectionLineColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1019 gridGroup->Add(connectionColorSizer, 0, wxEXPAND | wxALL, 5);
1020
1021 // Highlight path to selected node
1022 m_highlightPathToSelected = new wxCheckBox(panel, ID_HIGHLIGHT_PATH_TO_SELECTED, "Highlight path to selected node");
1023 m_highlightPathToSelected->SetForegroundColour(wxColour(200, 200, 200));
1024 gridGroup->Add(m_highlightPathToSelected, 0, wxALL, 5);
1025
1026 // Path highlight color
1027 wxBoxSizer *pathHighlightColorSizer = new wxBoxSizer(wxHORIZONTAL);
1028 wxStaticText *pathHighlightColorLabel = new wxStaticText(panel, wxID_ANY, "Path highlight color:");
1029 pathHighlightColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1030 pathHighlightColorSizer->Add(pathHighlightColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1031
1032 m_pathHighlightColorPicker = new wxColourPickerCtrl(panel, ID_PATH_HIGHLIGHT_COLOR);
1033 pathHighlightColorSizer->Add(m_pathHighlightColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1034 gridGroup->Add(pathHighlightColorSizer, 0, wxEXPAND | wxALL, 5);
1035
1036 panelSizer->Add(gridGroup, 0, wxEXPAND | wxALL, 5);
1037
1038 // Node Appearance group
1039 wxStaticBoxSizer *nodeAppearanceGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Node Appearance");
1040
1041 // === IDLE NODE SUBSECTION ===
1042 wxStaticBoxSizer *idleNodeGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Idle Node");
1043
1044 // Background color
1045 wxBoxSizer *idleNodeBgColorSizer = new wxBoxSizer(wxHORIZONTAL);
1046 wxStaticText *idleNodeBgColorLabel = new wxStaticText(panel, wxID_ANY, "Background color:");
1047 idleNodeBgColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1048 idleNodeBgColorSizer->Add(idleNodeBgColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1049 m_idleNodeBgColorPicker = new wxColourPickerCtrl(panel, ID_IDLE_NODE_BG_COLOR);
1050 idleNodeBgColorSizer->Add(m_idleNodeBgColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1051 idleNodeGroup->Add(idleNodeBgColorSizer, 0, wxEXPAND | wxALL, 3);
1052
1053 // Border color
1054 wxBoxSizer *idleNodeBorderColorSizer = new wxBoxSizer(wxHORIZONTAL);
1055 wxStaticText *idleNodeBorderColorLabel = new wxStaticText(panel, wxID_ANY, "Border color:");
1056 idleNodeBorderColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1057 idleNodeBorderColorSizer->Add(idleNodeBorderColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1058 m_idleNodeBorderColorPicker = new wxColourPickerCtrl(panel, ID_IDLE_NODE_BORDER_COLOR);
1059 idleNodeBorderColorSizer->Add(m_idleNodeBorderColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1060 idleNodeGroup->Add(idleNodeBorderColorSizer, 0, wxEXPAND | wxALL, 3);
1061
1062 // Text color
1063 wxBoxSizer *idleNodeTextColorSizer = new wxBoxSizer(wxHORIZONTAL);
1064 wxStaticText *idleNodeTextColorLabel = new wxStaticText(panel, wxID_ANY, "Text color:");
1065 idleNodeTextColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1066 idleNodeTextColorSizer->Add(idleNodeTextColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1067 m_idleNodeTextColorPicker = new wxColourPickerCtrl(panel, ID_IDLE_NODE_TEXT_COLOR);
1068 idleNodeTextColorSizer->Add(m_idleNodeTextColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1069 idleNodeGroup->Add(idleNodeTextColorSizer, 0, wxEXPAND | wxALL, 3);
1070
1071 nodeAppearanceGroup->Add(idleNodeGroup, 0, wxEXPAND | wxALL, 3);
1072
1073 // === HOVERED NODE SUBSECTION ===
1074 wxStaticBoxSizer *hoveredNodeGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Hovered Node");
1075
1076 // Background tint
1077 wxBoxSizer *hoveredNodeBgTintSizer = new wxBoxSizer(wxHORIZONTAL);
1078 wxStaticText *hoveredNodeBgTintText = new wxStaticText(panel, wxID_ANY, "Background tint:");
1079 hoveredNodeBgTintText->SetForegroundColour(wxColour(200, 200, 200));
1080 hoveredNodeBgTintSizer->Add(hoveredNodeBgTintText, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1081 m_hoveredNodeBgTint = new wxSlider(panel, ID_HOVERED_NODE_BG_TINT, -13, -100, 100, wxDefaultPosition,
1082 wxSize(200, -1), wxSL_HORIZONTAL);
1083 m_hoveredNodeBgTint->Bind(wxEVT_MOUSEWHEEL, &PreferencesDialog::OnSliderMouseWheel, this);
1084 hoveredNodeBgTintSizer->Add(m_hoveredNodeBgTint, 1, wxEXPAND | wxRIGHT, 10);
1085 m_hoveredNodeBgTintLabel = new wxStaticText(panel, wxID_ANY, "-13%");
1086 m_hoveredNodeBgTintLabel->SetForegroundColour(wxColour(200, 200, 200));
1087 m_hoveredNodeBgTintLabel->SetMinSize(wxSize(50, -1));
1088 hoveredNodeBgTintSizer->Add(m_hoveredNodeBgTintLabel, 0, wxALIGN_CENTER_VERTICAL);
1089 hoveredNodeGroup->Add(hoveredNodeBgTintSizer, 0, wxEXPAND | wxALL, 3);
1090
1091 // Border color
1092 wxBoxSizer *hoveredNodeColorSizer = new wxBoxSizer(wxHORIZONTAL);
1093 wxStaticText *hoveredNodeColorLabel = new wxStaticText(panel, wxID_ANY, "Border color:");
1094 hoveredNodeColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1095 hoveredNodeColorSizer->Add(hoveredNodeColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1096 m_hoveredNodeColorPicker = new wxColourPickerCtrl(panel, ID_HOVERED_NODE_COLOR);
1097 hoveredNodeColorSizer->Add(m_hoveredNodeColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1098 hoveredNodeGroup->Add(hoveredNodeColorSizer, 0, wxEXPAND | wxALL, 3);
1099
1100 // Text color
1101 wxBoxSizer *hoveredNodeTextColorSizer = new wxBoxSizer(wxHORIZONTAL);
1102 wxStaticText *hoveredNodeTextColorLabel = new wxStaticText(panel, wxID_ANY, "Text color:");
1103 hoveredNodeTextColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1104 hoveredNodeTextColorSizer->Add(hoveredNodeTextColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1105 m_hoveredNodeTextColorPicker = new wxColourPickerCtrl(panel, ID_HOVERED_NODE_TEXT_COLOR);
1106 hoveredNodeTextColorSizer->Add(m_hoveredNodeTextColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1107 hoveredNodeGroup->Add(hoveredNodeTextColorSizer, 0, wxEXPAND | wxALL, 3);
1108
1109 // Info text color
1110 wxBoxSizer *hoveredNodeInfoColorSizer = new wxBoxSizer(wxHORIZONTAL);
1111 wxStaticText *hoveredNodeInfoColorLabel = new wxStaticText(panel, wxID_ANY, "Info text color:");
1112 hoveredNodeInfoColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1113 hoveredNodeInfoColorSizer->Add(hoveredNodeInfoColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1114 m_hoveredNodeInfoColorPicker = new wxColourPickerCtrl(panel, ID_HOVERED_NODE_INFO_COLOR);
1115 hoveredNodeInfoColorSizer->Add(m_hoveredNodeInfoColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1116 hoveredNodeGroup->Add(hoveredNodeInfoColorSizer, 0, wxEXPAND | wxALL, 3);
1117
1118 nodeAppearanceGroup->Add(hoveredNodeGroup, 0, wxEXPAND | wxALL, 3);
1119
1120 // === SELECTED NODE SUBSECTION ===
1121 wxStaticBoxSizer *selectedNodeGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Selected Node");
1122
1123 // Background tint
1124 wxBoxSizer *selectedNodeBgTintSizer = new wxBoxSizer(wxHORIZONTAL);
1125 wxStaticText *selectedNodeBgTintText = new wxStaticText(panel, wxID_ANY, "Background tint:");
1126 selectedNodeBgTintText->SetForegroundColour(wxColour(200, 200, 200));
1127 selectedNodeBgTintSizer->Add(selectedNodeBgTintText, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1128 m_selectedNodeBgTint = new wxSlider(panel, ID_SELECTED_NODE_BG_TINT, -33, -100, 100, wxDefaultPosition,
1129 wxSize(200, -1), wxSL_HORIZONTAL);
1130 m_selectedNodeBgTint->Bind(wxEVT_MOUSEWHEEL, &PreferencesDialog::OnSliderMouseWheel, this);
1131 selectedNodeBgTintSizer->Add(m_selectedNodeBgTint, 1, wxEXPAND | wxRIGHT, 10);
1132 m_selectedNodeBgTintLabel = new wxStaticText(panel, wxID_ANY, "-33%");
1133 m_selectedNodeBgTintLabel->SetForegroundColour(wxColour(200, 200, 200));
1134 m_selectedNodeBgTintLabel->SetMinSize(wxSize(50, -1));
1135 selectedNodeBgTintSizer->Add(m_selectedNodeBgTintLabel, 0, wxALIGN_CENTER_VERTICAL);
1136 selectedNodeGroup->Add(selectedNodeBgTintSizer, 0, wxEXPAND | wxALL, 3);
1137
1138 // Border color
1139 wxBoxSizer *selectedNodeColorSizer = new wxBoxSizer(wxHORIZONTAL);
1140 wxStaticText *selectedNodeColorLabel = new wxStaticText(panel, wxID_ANY, "Border color:");
1141 selectedNodeColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1142 selectedNodeColorSizer->Add(selectedNodeColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1143 m_selectedNodeColorPicker = new wxColourPickerCtrl(panel, ID_SELECTED_NODE_COLOR);
1144 selectedNodeColorSizer->Add(m_selectedNodeColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1145 selectedNodeGroup->Add(selectedNodeColorSizer, 0, wxEXPAND | wxALL, 3);
1146
1147 // Text color
1148 wxBoxSizer *selectedNodeTextColorSizer = new wxBoxSizer(wxHORIZONTAL);
1149 wxStaticText *selectedNodeTextColorLabel = new wxStaticText(panel, wxID_ANY, "Text color:");
1150 selectedNodeTextColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1151 selectedNodeTextColorSizer->Add(selectedNodeTextColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1152 m_selectedNodeTextColorPicker = new wxColourPickerCtrl(panel, ID_SELECTED_NODE_TEXT_COLOR);
1153 selectedNodeTextColorSizer->Add(m_selectedNodeTextColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1154 selectedNodeGroup->Add(selectedNodeTextColorSizer, 0, wxEXPAND | wxALL, 3);
1155
1156 // Info text color
1157 wxBoxSizer *selectedNodeInfoColorSizer = new wxBoxSizer(wxHORIZONTAL);
1158 wxStaticText *selectedNodeInfoColorLabel = new wxStaticText(panel, wxID_ANY, "Info text color:");
1159 selectedNodeInfoColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1160 selectedNodeInfoColorSizer->Add(selectedNodeInfoColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1161 m_selectedNodeInfoColorPicker = new wxColourPickerCtrl(panel, ID_SELECTED_NODE_INFO_COLOR);
1162 selectedNodeInfoColorSizer->Add(m_selectedNodeInfoColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1163 selectedNodeGroup->Add(selectedNodeInfoColorSizer, 0, wxEXPAND | wxALL, 3);
1164
1165 nodeAppearanceGroup->Add(selectedNodeGroup, 0, wxEXPAND | wxALL, 3);
1166
1167 panelSizer->Add(nodeAppearanceGroup, 0, wxEXPAND | wxALL, 5);
1168
1169 // ==================== DEBUG TEXT CUSTOMIZATION SECTIONS ====================
1170
1171 // === COORDINATE SYSTEM INFO (Zoom & Pan) ===
1172 wxStaticBoxSizer *coordInfoGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Coordinate System Info (Zoom & Pan)");
1173
1174 m_showCoordinateInfo = new wxCheckBox(panel, ID_SHOW_COORDINATE_INFO, "Show coordinate system info");
1176 m_showCoordinateInfo->SetForegroundColour(wxColour(200, 200, 200));
1177 coordInfoGroup->Add(m_showCoordinateInfo, 0, wxALL, 5);
1178 }
1179
1180 // Font size
1181 wxBoxSizer *coordFontSizeSizer = new wxBoxSizer(wxHORIZONTAL);
1182 wxStaticText *coordFontSizeLabel = new wxStaticText(panel, wxID_ANY, "Font size:");
1183 if (coordFontSizeLabel) {
1184 coordFontSizeLabel->SetForegroundColour(wxColour(200, 200, 200));
1185 coordFontSizeSizer->Add(coordFontSizeLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1186 }
1187 m_coordinateInfoFontSize = new wxSpinCtrl(panel, ID_COORDINATE_INFO_FONT_SIZE, "9", wxDefaultPosition,
1188 wxSize(120, -1), wxSP_ARROW_KEYS, 6, 20, 9);
1190 coordFontSizeSizer->Add(m_coordinateInfoFontSize, 0, wxALIGN_CENTER_VERTICAL);
1191 }
1192 if (coordFontSizeSizer->GetItemCount() > 0) {
1193 coordInfoGroup->Add(coordFontSizeSizer, 0, wxEXPAND | wxALL, 5);
1194 }
1195
1196 // Color
1197 wxBoxSizer *coordColorSizer = new wxBoxSizer(wxHORIZONTAL);
1198 wxStaticText *coordColorLabel = new wxStaticText(panel, wxID_ANY, "Text color:");
1199 coordColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1200 coordColorSizer->Add(coordColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1201 m_coordinateInfoColorPicker = new wxColourPickerCtrl(panel, ID_COORDINATE_INFO_COLOR);
1202 coordColorSizer->Add(m_coordinateInfoColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1203 coordInfoGroup->Add(coordColorSizer, 0, wxEXPAND | wxALL, 5);
1204
1205 // Anchor
1206 wxBoxSizer *coordAnchorSizer = new wxBoxSizer(wxHORIZONTAL);
1207 wxStaticText *coordAnchorLabel = new wxStaticText(panel, wxID_ANY, "Anchor:");
1208 coordAnchorLabel->SetForegroundColour(wxColour(200, 200, 200));
1209 coordAnchorSizer->Add(coordAnchorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1210 wxArrayString anchorChoices;
1211 anchorChoices.Add("Top-Left");
1212 anchorChoices.Add("Top-Right");
1213 anchorChoices.Add("Bottom-Left");
1214 anchorChoices.Add("Bottom-Right");
1215 m_coordinateInfoAnchor = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(150, -1), anchorChoices);
1216 m_coordinateInfoAnchor->SetSelection(0);
1217 coordAnchorSizer->Add(m_coordinateInfoAnchor, 0, wxALIGN_CENTER_VERTICAL);
1218 coordInfoGroup->Add(coordAnchorSizer, 0, wxEXPAND | wxALL, 5);
1219
1220 // Position X and Y
1221 wxBoxSizer *coordPosSizer = new wxBoxSizer(wxHORIZONTAL);
1222 wxStaticText *coordPosLabel = new wxStaticText(panel, wxID_ANY, "Offset:");
1223 coordPosLabel->SetForegroundColour(wxColour(200, 200, 200));
1224 coordPosSizer->Add(coordPosLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1225 wxStaticText *coordXLabel = new wxStaticText(panel, wxID_ANY, "X:");
1226 coordXLabel->SetForegroundColour(wxColour(200, 200, 200));
1227 coordPosSizer->Add(coordXLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
1228 m_coordinateInfoX = new wxSpinCtrl(panel, ID_COORDINATE_INFO_X, "10", wxDefaultPosition, wxSize(120, -1),
1229 wxSP_ARROW_KEYS, 0, 9999, 10);
1230 coordPosSizer->Add(m_coordinateInfoX, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1231 wxStaticText *coordYLabel = new wxStaticText(panel, wxID_ANY, "Y:");
1232 coordYLabel->SetForegroundColour(wxColour(200, 200, 200));
1233 coordPosSizer->Add(coordYLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
1234 m_coordinateInfoY = new wxSpinCtrl(panel, ID_COORDINATE_INFO_Y, "10", wxDefaultPosition, wxSize(120, -1),
1235 wxSP_ARROW_KEYS, 0, 9999, 10);
1236 coordPosSizer->Add(m_coordinateInfoY, 0, wxALIGN_CENTER_VERTICAL);
1237 coordInfoGroup->Add(coordPosSizer, 0, wxEXPAND | wxALL, 5);
1238
1239 panelSizer->Add(coordInfoGroup, 0, wxEXPAND | wxALL, 5);
1240
1241 // === SELECTED NODE INFO ===
1242 wxStaticBoxSizer *selectedInfoGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Selected Node Info");
1243
1244 m_showSelectedNodeInfo = new wxCheckBox(panel, ID_SHOW_SELECTED_NODE_INFO, "Show selected node info");
1245 m_showSelectedNodeInfo->SetForegroundColour(wxColour(200, 200, 200));
1246 selectedInfoGroup->Add(m_showSelectedNodeInfo, 0, wxALL, 5);
1247
1248 // Font size
1249 wxBoxSizer *selFontSizeSizer = new wxBoxSizer(wxHORIZONTAL);
1250 wxStaticText *selFontSizeLabel = new wxStaticText(panel, wxID_ANY, "Font size:");
1251 selFontSizeLabel->SetForegroundColour(wxColour(200, 200, 200));
1252 selFontSizeSizer->Add(selFontSizeLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1253 m_selectedNodeInfoFontSize = new wxSpinCtrl(panel, ID_SELECTED_NODE_INFO_FONT_SIZE, "9", wxDefaultPosition,
1254 wxSize(120, -1), wxSP_ARROW_KEYS, 6, 20, 9);
1255 selFontSizeSizer->Add(m_selectedNodeInfoFontSize, 0, wxALIGN_CENTER_VERTICAL);
1256 selectedInfoGroup->Add(selFontSizeSizer, 0, wxEXPAND | wxALL, 5);
1257
1258 // Color
1259 wxBoxSizer *selColorSizer = new wxBoxSizer(wxHORIZONTAL);
1260 wxStaticText *selColorLabel = new wxStaticText(panel, wxID_ANY, "Text color:");
1261 selColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1262 selColorSizer->Add(selColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1264 selColorSizer->Add(m_selectedNodeDebugInfoColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1265 selectedInfoGroup->Add(selColorSizer, 0, wxEXPAND | wxALL, 5);
1266
1267 // Anchor
1268 wxBoxSizer *selAnchorSizer = new wxBoxSizer(wxHORIZONTAL);
1269 wxStaticText *selAnchorLabel = new wxStaticText(panel, wxID_ANY, "Anchor:");
1270 selAnchorLabel->SetForegroundColour(wxColour(200, 200, 200));
1271 selAnchorSizer->Add(selAnchorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1272 m_selectedNodeInfoAnchor = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(150, -1), anchorChoices);
1273 m_selectedNodeInfoAnchor->SetSelection(0);
1274 selAnchorSizer->Add(m_selectedNodeInfoAnchor, 0, wxALIGN_CENTER_VERTICAL);
1275 selectedInfoGroup->Add(selAnchorSizer, 0, wxEXPAND | wxALL, 5);
1276
1277 // Position X and Y
1278 wxBoxSizer *selPosSizer = new wxBoxSizer(wxHORIZONTAL);
1279 wxStaticText *selPosLabel = new wxStaticText(panel, wxID_ANY, "Offset:");
1280 selPosLabel->SetForegroundColour(wxColour(200, 200, 200));
1281 selPosSizer->Add(selPosLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1282 wxStaticText *selXLabel = new wxStaticText(panel, wxID_ANY, "X:");
1283 selXLabel->SetForegroundColour(wxColour(200, 200, 200));
1284 selPosSizer->Add(selXLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
1285 m_selectedNodeInfoX = new wxSpinCtrl(panel, ID_SELECTED_NODE_INFO_X, "10", wxDefaultPosition, wxSize(120, -1),
1286 wxSP_ARROW_KEYS, 0, 9999, 10);
1287 selPosSizer->Add(m_selectedNodeInfoX, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1288 wxStaticText *selYLabel = new wxStaticText(panel, wxID_ANY, "Y:");
1289 selYLabel->SetForegroundColour(wxColour(200, 200, 200));
1290 selPosSizer->Add(selYLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
1291 m_selectedNodeInfoY = new wxSpinCtrl(panel, ID_SELECTED_NODE_INFO_Y, "30", wxDefaultPosition, wxSize(120, -1),
1292 wxSP_ARROW_KEYS, 0, 9999, 30);
1293 selPosSizer->Add(m_selectedNodeInfoY, 0, wxALIGN_CENTER_VERTICAL);
1294 selectedInfoGroup->Add(selPosSizer, 0, wxEXPAND | wxALL, 5);
1295
1296 panelSizer->Add(selectedInfoGroup, 0, wxEXPAND | wxALL, 5);
1297
1298 // === TREE STATISTICS INFO ===
1299 wxStaticBoxSizer *treeStatsGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Tree Statistics Info");
1300
1301 m_showTreeInfo = new wxCheckBox(panel, ID_SHOW_TREE_INFO, "Show tree statistics");
1302 m_showTreeInfo->SetForegroundColour(wxColour(200, 200, 200));
1303 treeStatsGroup->Add(m_showTreeInfo, 0, wxALL, 5);
1304
1305 // Font size
1306 wxBoxSizer *treeFontSizeSizer = new wxBoxSizer(wxHORIZONTAL);
1307 wxStaticText *treeFontSizeLabel = new wxStaticText(panel, wxID_ANY, "Font size:");
1308 treeFontSizeLabel->SetForegroundColour(wxColour(200, 200, 200));
1309 treeFontSizeSizer->Add(treeFontSizeLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1310 m_treeInfoFontSize = new wxSpinCtrl(panel, ID_TREE_INFO_FONT_SIZE, "9", wxDefaultPosition, wxSize(120, -1),
1311 wxSP_ARROW_KEYS, 6, 20, 9);
1312 treeFontSizeSizer->Add(m_treeInfoFontSize, 0, wxALIGN_CENTER_VERTICAL);
1313 treeStatsGroup->Add(treeFontSizeSizer, 0, wxEXPAND | wxALL, 5);
1314
1315 // Color
1316 wxBoxSizer *treeColorSizer = new wxBoxSizer(wxHORIZONTAL);
1317 wxStaticText *treeColorLabel = new wxStaticText(panel, wxID_ANY, "Text color:");
1318 treeColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1319 treeColorSizer->Add(treeColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1320 m_treeInfoColorPicker = new wxColourPickerCtrl(panel, ID_TREE_INFO_COLOR);
1321 treeColorSizer->Add(m_treeInfoColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1322 treeStatsGroup->Add(treeColorSizer, 0, wxEXPAND | wxALL, 5);
1323
1324 // Anchor
1325 wxBoxSizer *treeAnchorSizer = new wxBoxSizer(wxHORIZONTAL);
1326 wxStaticText *treeAnchorLabel = new wxStaticText(panel, wxID_ANY, "Anchor:");
1327 treeAnchorLabel->SetForegroundColour(wxColour(200, 200, 200));
1328 treeAnchorSizer->Add(treeAnchorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1329 m_treeInfoAnchor = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(150, -1), anchorChoices);
1330 m_treeInfoAnchor->SetSelection(0);
1331 treeAnchorSizer->Add(m_treeInfoAnchor, 0, wxALIGN_CENTER_VERTICAL);
1332 treeStatsGroup->Add(treeAnchorSizer, 0, wxEXPAND | wxALL, 5);
1333
1334 // Position X and Y
1335 wxBoxSizer *treePosSizer = new wxBoxSizer(wxHORIZONTAL);
1336 wxStaticText *treePosLabel = new wxStaticText(panel, wxID_ANY, "Offset:");
1337 treePosLabel->SetForegroundColour(wxColour(200, 200, 200));
1338 treePosSizer->Add(treePosLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1339 wxStaticText *treeXLabel = new wxStaticText(panel, wxID_ANY, "X:");
1340 treeXLabel->SetForegroundColour(wxColour(200, 200, 200));
1341 treePosSizer->Add(treeXLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
1342 m_treeInfoX =
1343 new wxSpinCtrl(panel, ID_TREE_INFO_X, "10", wxDefaultPosition, wxSize(120, -1), wxSP_ARROW_KEYS, 0, 9999, 10);
1344 treePosSizer->Add(m_treeInfoX, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1345 wxStaticText *treeYLabel = new wxStaticText(panel, wxID_ANY, "Y:");
1346 treeYLabel->SetForegroundColour(wxColour(200, 200, 200));
1347 treePosSizer->Add(treeYLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
1348 m_treeInfoY =
1349 new wxSpinCtrl(panel, ID_TREE_INFO_Y, "50", wxDefaultPosition, wxSize(120, -1), wxSP_ARROW_KEYS, 0, 9999, 50);
1350 treePosSizer->Add(m_treeInfoY, 0, wxALIGN_CENTER_VERTICAL);
1351 treeStatsGroup->Add(treePosSizer, 0, wxEXPAND | wxALL, 5);
1352
1353 panelSizer->Add(treeStatsGroup, 0, wxEXPAND | wxALL, 5);
1354
1355 // === FPS DISPLAY ===
1356 wxStaticBoxSizer *fpsGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "FPS Display");
1357
1358 m_showFPS = new wxCheckBox(panel, wxID_ANY, "Show FPS counter");
1359 m_showFPS->SetForegroundColour(wxColour(200, 200, 200));
1360 fpsGroup->Add(m_showFPS, 0, wxALL, 5);
1361
1362 // Font size
1363 wxBoxSizer *fpsFontSizeSizer = new wxBoxSizer(wxHORIZONTAL);
1364 wxStaticText *fpsFontSizeLabel = new wxStaticText(panel, wxID_ANY, "Font size:");
1365 fpsFontSizeLabel->SetForegroundColour(wxColour(200, 200, 200));
1366 fpsFontSizeSizer->Add(fpsFontSizeLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1367 m_fpsFontSize = new wxSpinCtrl(panel, wxID_ANY, "9", wxDefaultPosition, wxSize(120, -1), wxSP_ARROW_KEYS, 6, 20, 9);
1368 fpsFontSizeSizer->Add(m_fpsFontSize, 0, wxALIGN_CENTER_VERTICAL);
1369 fpsGroup->Add(fpsFontSizeSizer, 0, wxEXPAND | wxALL, 5);
1370
1371 // Color
1372 wxBoxSizer *fpsColorSizer = new wxBoxSizer(wxHORIZONTAL);
1373 wxStaticText *fpsColorLabel = new wxStaticText(panel, wxID_ANY, "Text color:");
1374 fpsColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1375 fpsColorSizer->Add(fpsColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1376 m_fpsColorPicker = new wxColourPickerCtrl(panel, wxID_ANY);
1377 fpsColorSizer->Add(m_fpsColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1378 fpsGroup->Add(fpsColorSizer, 0, wxEXPAND | wxALL, 5);
1379
1380 // Anchor
1381 wxBoxSizer *fpsAnchorSizer = new wxBoxSizer(wxHORIZONTAL);
1382 wxStaticText *fpsAnchorLabel = new wxStaticText(panel, wxID_ANY, "Anchor:");
1383 fpsAnchorLabel->SetForegroundColour(wxColour(200, 200, 200));
1384 fpsAnchorSizer->Add(fpsAnchorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1385 m_fpsAnchor = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(150, -1), anchorChoices);
1386 m_fpsAnchor->SetSelection(0); // Default to Top-Left
1387 fpsAnchorSizer->Add(m_fpsAnchor, 0, wxALIGN_CENTER_VERTICAL);
1388 fpsGroup->Add(fpsAnchorSizer, 0, wxEXPAND | wxALL, 5);
1389
1390 // Position X and Y
1391 wxBoxSizer *fpsPosSizer = new wxBoxSizer(wxHORIZONTAL);
1392 wxStaticText *fpsPosLabel = new wxStaticText(panel, wxID_ANY, "Offset:");
1393 fpsPosLabel->SetForegroundColour(wxColour(200, 200, 200));
1394 fpsPosSizer->Add(fpsPosLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1395 wxStaticText *fpsXLabel = new wxStaticText(panel, wxID_ANY, "X:");
1396 fpsXLabel->SetForegroundColour(wxColour(200, 200, 200));
1397 fpsPosSizer->Add(fpsXLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
1398 m_fpsX = new wxSpinCtrl(panel, wxID_ANY, "10", wxDefaultPosition, wxSize(120, -1), wxSP_ARROW_KEYS, 0, 9999, 10);
1399 fpsPosSizer->Add(m_fpsX, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1400 wxStaticText *fpsYLabel = new wxStaticText(panel, wxID_ANY, "Y:");
1401 fpsYLabel->SetForegroundColour(wxColour(200, 200, 200));
1402 fpsPosSizer->Add(fpsYLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
1403 m_fpsY = new wxSpinCtrl(panel, wxID_ANY, "70", wxDefaultPosition, wxSize(120, -1), wxSP_ARROW_KEYS, 0, 9999, 70);
1404 fpsPosSizer->Add(m_fpsY, 0, wxALIGN_CENTER_VERTICAL);
1405 fpsGroup->Add(fpsPosSizer, 0, wxEXPAND | wxALL, 5);
1406
1407 panelSizer->Add(fpsGroup, 0, wxEXPAND | wxALL, 5);
1408
1409 // === CONTROLS HELP TEXT ===
1410 wxStaticBoxSizer *controlsHelpGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Controls Help Text");
1411
1412 m_showControlsHelp = new wxCheckBox(panel, ID_SHOW_CONTROLS_HELP, "Show controls/hotkeys help");
1413 m_showControlsHelp->SetForegroundColour(wxColour(200, 200, 200));
1414 controlsHelpGroup->Add(m_showControlsHelp, 0, wxALL, 5);
1415
1416 // Font size
1417 wxBoxSizer *ctrlFontSizeSizer = new wxBoxSizer(wxHORIZONTAL);
1418 wxStaticText *ctrlFontSizeLabel = new wxStaticText(panel, wxID_ANY, "Font size:");
1419 ctrlFontSizeLabel->SetForegroundColour(wxColour(200, 200, 200));
1420 ctrlFontSizeSizer->Add(ctrlFontSizeLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1421 m_controlsHelpFontSize = new wxSpinCtrl(panel, ID_CONTROLS_HELP_FONT_SIZE, "11", wxDefaultPosition, wxSize(120, -1),
1422 wxSP_ARROW_KEYS, 6, 20, 11);
1423 ctrlFontSizeSizer->Add(m_controlsHelpFontSize, 0, wxALIGN_CENTER_VERTICAL);
1424 controlsHelpGroup->Add(ctrlFontSizeSizer, 0, wxEXPAND | wxALL, 5);
1425
1426 // Color
1427 wxBoxSizer *ctrlColorSizer = new wxBoxSizer(wxHORIZONTAL);
1428 wxStaticText *ctrlColorLabel = new wxStaticText(panel, wxID_ANY, "Text color:");
1429 ctrlColorLabel->SetForegroundColour(wxColour(200, 200, 200));
1430 ctrlColorSizer->Add(ctrlColorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1431 m_controlsHelpColorPicker = new wxColourPickerCtrl(panel, ID_CONTROLS_HELP_COLOR);
1432 ctrlColorSizer->Add(m_controlsHelpColorPicker, 0, wxALIGN_CENTER_VERTICAL);
1433 controlsHelpGroup->Add(ctrlColorSizer, 0, wxEXPAND | wxALL, 5);
1434
1435 // Anchor
1436 wxBoxSizer *ctrlAnchorSizer = new wxBoxSizer(wxHORIZONTAL);
1437 wxStaticText *ctrlAnchorLabel = new wxStaticText(panel, wxID_ANY, "Anchor:");
1438 ctrlAnchorLabel->SetForegroundColour(wxColour(200, 200, 200));
1439 ctrlAnchorSizer->Add(ctrlAnchorLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1440 m_controlsHelpAnchor = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(150, -1), anchorChoices);
1441 m_controlsHelpAnchor->SetSelection(2); // Default to Bottom-Left
1442 ctrlAnchorSizer->Add(m_controlsHelpAnchor, 0, wxALIGN_CENTER_VERTICAL);
1443 controlsHelpGroup->Add(ctrlAnchorSizer, 0, wxEXPAND | wxALL, 5);
1444
1445 // Position X and Y
1446 wxBoxSizer *ctrlPosSizer = new wxBoxSizer(wxHORIZONTAL);
1447 wxStaticText *ctrlPosLabel = new wxStaticText(panel, wxID_ANY, "Offset:");
1448 ctrlPosLabel->SetForegroundColour(wxColour(200, 200, 200));
1449 ctrlPosSizer->Add(ctrlPosLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1450 wxStaticText *ctrlXLabel = new wxStaticText(panel, wxID_ANY, "X:");
1451 ctrlXLabel->SetForegroundColour(wxColour(200, 200, 200));
1452 ctrlPosSizer->Add(ctrlXLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
1453 m_controlsHelpX = new wxSpinCtrl(panel, ID_CONTROLS_HELP_X, "10", wxDefaultPosition, wxSize(120, -1),
1454 wxSP_ARROW_KEYS, 0, 9999, 10);
1455 ctrlPosSizer->Add(m_controlsHelpX, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1456 wxStaticText *ctrlYLabel = new wxStaticText(panel, wxID_ANY, "Y:");
1457 ctrlYLabel->SetForegroundColour(wxColour(200, 200, 200));
1458 ctrlPosSizer->Add(ctrlYLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
1459 m_controlsHelpY = new wxSpinCtrl(panel, ID_CONTROLS_HELP_Y, "25", wxDefaultPosition, wxSize(120, -1),
1460 wxSP_ARROW_KEYS, 0, 9999, 25);
1461 ctrlPosSizer->Add(m_controlsHelpY, 0, wxALIGN_CENTER_VERTICAL);
1462 controlsHelpGroup->Add(ctrlPosSizer, 0, wxEXPAND | wxALL, 5);
1463
1464 panelSizer->Add(controlsHelpGroup, 0, wxEXPAND | wxALL, 5);
1465
1466 panelSizer->AddStretchSpacer();
1467
1468 panel->SetSizer(panelSizer);
1469 return panel;
1470}
1471
1473 wxPanel *panel = new wxPanel(parent, wxID_ANY);
1474 panel->SetBackgroundColour(wxColour(50, 50, 50));
1475 wxBoxSizer *panelSizer = new wxBoxSizer(wxVERTICAL);
1476
1477 // Panel Layout group
1478 wxStaticBoxSizer *layoutGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Panel Layout");
1479
1480 // Default panel height
1481 wxBoxSizer *heightSizer = new wxBoxSizer(wxHORIZONTAL);
1482
1484 new wxCheckBox(panel, ID_BOTTOM_PANEL_HEIGHT_ENABLED, "Default panel height (% of window):");
1485 m_bottomPanelHeightEnabled->SetForegroundColour(wxColour(200, 200, 200));
1486 m_bottomPanelHeightEnabled->SetValue(true);
1488 heightSizer->Add(m_bottomPanelHeightEnabled, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1489
1491 new wxSpinCtrl(panel, wxID_ANY, "25", wxDefaultPosition, wxSize(120, -1), wxSP_ARROW_KEYS, 5, 80, 25);
1492 heightSizer->Add(m_bottomPanelHeight, 0, wxALIGN_CENTER_VERTICAL);
1493 layoutGroup->Add(heightSizer, 0, wxEXPAND | wxALL, 5);
1494
1495 // Minimum panel height
1496 wxBoxSizer *minHeightSizer = new wxBoxSizer(wxHORIZONTAL);
1497
1499 new wxCheckBox(panel, ID_BOTTOM_PANEL_MIN_HEIGHT_ENABLED, "Minimum panel height (% of window):");
1500 m_bottomPanelMinHeightEnabled->SetForegroundColour(wxColour(200, 200, 200));
1501 m_bottomPanelMinHeightEnabled->SetValue(true);
1503 minHeightSizer->Add(m_bottomPanelMinHeightEnabled, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1504
1506 new wxSpinCtrl(panel, wxID_ANY, "15", wxDefaultPosition, wxSize(120, -1), wxSP_ARROW_KEYS, 5, 50, 15);
1507 minHeightSizer->Add(m_bottomPanelMinHeight, 0, wxALIGN_CENTER_VERTICAL);
1508 layoutGroup->Add(minHeightSizer, 0, wxEXPAND | wxALL, 5);
1509
1510 // Show panel on startup
1511 wxBoxSizer *startupSizer = new wxBoxSizer(wxHORIZONTAL);
1512 wxStaticText *startupLabel = new wxStaticText(panel, wxID_ANY, "On startup:");
1513 startupLabel->SetForegroundColour(wxColour(200, 200, 200));
1514 startupSizer->Add(startupLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1515
1516 wxArrayString startupOptions;
1517 startupOptions.Add("Show panel");
1518 startupOptions.Add("Hide panel");
1519 startupOptions.Add("Remember last state");
1520 m_bottomPanelStartup = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, startupOptions);
1521 m_bottomPanelStartup->SetSelection(0);
1522 startupSizer->Add(m_bottomPanelStartup, 1, wxEXPAND);
1523 layoutGroup->Add(startupSizer, 0, wxEXPAND | wxALL, 5);
1524
1525 panelSizer->Add(layoutGroup, 0, wxEXPAND | wxALL, 5);
1526
1527 // Tab Bar group
1528 wxStaticBoxSizer *tabBarGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Tab Bar");
1529
1530 m_showTabCloseButtons = new wxCheckBox(panel, wxID_ANY, "Show close buttons on tabs");
1531 m_showTabCloseButtons->SetForegroundColour(wxColour(200, 200, 200));
1532 m_showTabCloseButtons->SetValue(true);
1533 tabBarGroup->Add(m_showTabCloseButtons, 0, wxALL, 5);
1534
1535 panelSizer->Add(tabBarGroup, 0, wxEXPAND | wxALL, 5);
1536
1537 // Behavior group
1538 wxStaticBoxSizer *behaviorGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Behavior");
1539
1540 m_rememberLastTab = new wxCheckBox(panel, wxID_ANY, "Remember last active tab between sessions");
1541 m_rememberLastTab->SetForegroundColour(wxColour(200, 200, 200));
1542 m_rememberLastTab->SetValue(true);
1543 behaviorGroup->Add(m_rememberLastTab, 0, wxALL, 5);
1544
1545 m_allowPanelCollapse = new wxCheckBox(panel, wxID_ANY, "Allow panel collapse (drag splitter to hide)");
1546 m_allowPanelCollapse->SetForegroundColour(wxColour(200, 200, 200));
1547 m_allowPanelCollapse->SetValue(true);
1548 behaviorGroup->Add(m_allowPanelCollapse, 0, wxALL, 5);
1549
1550 panelSizer->Add(behaviorGroup, 0, wxEXPAND | wxALL, 5);
1551 panelSizer->AddStretchSpacer();
1552
1553 panel->SetSizer(panelSizer);
1554 return panel;
1555}
1556
1558 wxPanel *panel = new wxPanel(parent, wxID_ANY);
1559 panel->SetBackgroundColour(wxColour(50, 50, 50));
1560 wxBoxSizer *panelSizer = new wxBoxSizer(wxVERTICAL);
1561
1562 // General Settings group
1563 wxStaticBoxSizer *generalGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "General");
1564
1565 m_showBreadcrumb = new wxCheckBox(panel, wxID_ANY, "Show breadcrumb navigation");
1566 m_showBreadcrumb->SetForegroundColour(wxColour(200, 200, 200));
1567 generalGroup->Add(m_showBreadcrumb, 0, wxALL, 5);
1568
1569 m_showHistory = new wxCheckBox(panel, wxID_ANY, "Show navigation history button");
1570 m_showHistory->SetForegroundColour(wxColour(200, 200, 200));
1571 generalGroup->Add(m_showHistory, 0, wxALL, 5);
1572
1573 // Start Path Mode
1574 wxBoxSizer *startPathSizer = new wxBoxSizer(wxHORIZONTAL);
1575 wxStaticText *startPathLabel = new wxStaticText(panel, wxID_ANY, "Default start path:");
1576 startPathLabel->SetForegroundColour(wxColour(200, 200, 200));
1577 startPathSizer->Add(startPathLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1578
1579 wxArrayString startPathOptions;
1580 startPathOptions.Add("Executable Directory");
1581 startPathOptions.Add("Custom Path");
1582 m_startPathMode = new wxChoice(panel, ID_START_PATH_MODE, wxDefaultPosition, wxDefaultSize, startPathOptions);
1583 startPathSizer->Add(m_startPathMode, 1, wxEXPAND);
1584 generalGroup->Add(startPathSizer, 0, wxEXPAND | wxALL, 5);
1585
1586 // Custom Path
1587 wxBoxSizer *customPathSizer = new wxBoxSizer(wxHORIZONTAL);
1588 wxStaticText *customPathLabel = new wxStaticText(panel, wxID_ANY, "Custom path:");
1589 customPathLabel->SetForegroundColour(wxColour(200, 200, 200));
1590 customPathSizer->Add(customPathLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1591
1592 m_customStartPath = new wxTextCtrl(panel, ID_CUSTOM_START_PATH);
1593 m_customStartPath->SetBackgroundColour(wxColour(60, 60, 60));
1594 m_customStartPath->SetForegroundColour(wxColour(200, 200, 200));
1595 customPathSizer->Add(m_customStartPath, 1, wxEXPAND | wxRIGHT, 5);
1596
1597 m_browseStartPath = new wxButton(panel, ID_BROWSE_START_PATH, "Browse...", wxDefaultPosition, wxSize(80, -1));
1598 customPathSizer->Add(m_browseStartPath, 0);
1599 generalGroup->Add(customPathSizer, 0, wxEXPAND | wxALL, 5);
1600
1601 // Bind events
1603 m_browseStartPath->Bind(wxEVT_BUTTON, &PreferencesDialog::OnBrowseStartPath, this);
1604
1605 panelSizer->Add(generalGroup, 0, wxEXPAND | wxALL, 5);
1606
1607 // Tree View Settings group
1608 wxStaticBoxSizer *treeViewGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Tree View");
1609
1610 m_treeShowHiddenFiles = new wxCheckBox(panel, ID_TREE_SHOW_HIDDEN_FILES, "Show hidden files");
1611 m_treeShowHiddenFiles->SetForegroundColour(wxColour(200, 200, 200));
1612 treeViewGroup->Add(m_treeShowHiddenFiles, 0, wxALL, 5);
1613
1614 m_treeShowFileExtensions = new wxCheckBox(panel, ID_TREE_SHOW_EXTENSIONS, "Show file extensions");
1615 m_treeShowFileExtensions->SetForegroundColour(wxColour(200, 200, 200));
1616 treeViewGroup->Add(m_treeShowFileExtensions, 0, wxALL, 5);
1617
1618 // Tree Sort by
1619 wxBoxSizer *treeSortBySizer = new wxBoxSizer(wxHORIZONTAL);
1620 wxStaticText *treeSortByLabel = new wxStaticText(panel, wxID_ANY, "Sort files by:");
1621 treeSortByLabel->SetForegroundColour(wxColour(200, 200, 200));
1622 treeSortBySizer->Add(treeSortByLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1623
1624 wxArrayString sortOptions;
1625 sortOptions.Add("Name");
1626 sortOptions.Add("Date");
1627 sortOptions.Add("Size");
1628 sortOptions.Add("Type");
1629 m_treeSortFilesBy = new wxChoice(panel, ID_TREE_SORT_FILES_BY, wxDefaultPosition, wxDefaultSize, sortOptions);
1630 treeSortBySizer->Add(m_treeSortFilesBy, 1, wxEXPAND);
1631 treeViewGroup->Add(treeSortBySizer, 0, wxEXPAND | wxALL, 5);
1632
1633 // Tree Item Size
1634 wxBoxSizer *treeItemSizeSizer = new wxBoxSizer(wxHORIZONTAL);
1635 wxStaticText *treeItemSizeLabel = new wxStaticText(panel, wxID_ANY, "Item size:");
1636 treeItemSizeLabel->SetForegroundColour(wxColour(200, 200, 200));
1637 treeItemSizeSizer->Add(treeItemSizeLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1638
1639 wxArrayString treeItemSizeOptions;
1640 treeItemSizeOptions.Add("Small (Compact)");
1641 treeItemSizeOptions.Add("Medium (Standard)");
1642 treeItemSizeOptions.Add("Large (Spacious)");
1643 m_treeItemSize = new wxChoice(panel, ID_TREE_ITEM_SIZE, wxDefaultPosition, wxDefaultSize, treeItemSizeOptions);
1644 treeItemSizeSizer->Add(m_treeItemSize, 1, wxEXPAND);
1645 treeViewGroup->Add(treeItemSizeSizer, 0, wxEXPAND | wxALL, 5);
1646
1647 panelSizer->Add(treeViewGroup, 0, wxEXPAND | wxALL, 5);
1648
1649 // Grid View Settings group
1650 wxStaticBoxSizer *gridViewGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Grid View");
1651
1652 m_gridShowHiddenFiles = new wxCheckBox(panel, ID_GRID_SHOW_HIDDEN_FILES, "Show hidden files");
1653 m_gridShowHiddenFiles->SetForegroundColour(wxColour(200, 200, 200));
1654 gridViewGroup->Add(m_gridShowHiddenFiles, 0, wxALL, 5);
1655
1656 m_gridShowFileExtensions = new wxCheckBox(panel, ID_GRID_SHOW_EXTENSIONS, "Show file extensions");
1657 m_gridShowFileExtensions->SetForegroundColour(wxColour(200, 200, 200));
1658 gridViewGroup->Add(m_gridShowFileExtensions, 0, wxALL, 5);
1659
1660 // Grid Sort by
1661 wxBoxSizer *gridSortBySizer = new wxBoxSizer(wxHORIZONTAL);
1662 wxStaticText *gridSortByLabel = new wxStaticText(panel, wxID_ANY, "Sort files by:");
1663 gridSortByLabel->SetForegroundColour(wxColour(200, 200, 200));
1664 gridSortBySizer->Add(gridSortByLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1665
1666 m_gridSortFilesBy = new wxChoice(panel, ID_GRID_SORT_FILES_BY, wxDefaultPosition, wxDefaultSize, sortOptions);
1667 gridSortBySizer->Add(m_gridSortFilesBy, 1, wxEXPAND);
1668 gridViewGroup->Add(gridSortBySizer, 0, wxEXPAND | wxALL, 5);
1669
1670 // Icon Size
1671 wxBoxSizer *iconSizeSizer = new wxBoxSizer(wxHORIZONTAL);
1672 wxStaticText *iconSizeLabel = new wxStaticText(panel, wxID_ANY, "Icon size:");
1673 iconSizeLabel->SetForegroundColour(wxColour(200, 200, 200));
1674 iconSizeSizer->Add(iconSizeLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1675
1676 wxArrayString iconSizeOptions;
1677 iconSizeOptions.Add("Small (48x48)");
1678 iconSizeOptions.Add("Medium (80x80)");
1679 iconSizeOptions.Add("Large (128x128)");
1680 m_gridIconSize = new wxChoice(panel, ID_GRID_ICON_SIZE, wxDefaultPosition, wxDefaultSize, iconSizeOptions);
1681 iconSizeSizer->Add(m_gridIconSize, 1, wxEXPAND);
1682 gridViewGroup->Add(iconSizeSizer, 0, wxEXPAND | wxALL, 5);
1683
1684 panelSizer->Add(gridViewGroup, 0, wxEXPAND | wxALL, 5);
1685 panelSizer->AddStretchSpacer();
1686
1687 panel->SetSizer(panelSizer);
1688 return panel;
1689}
1690
1692 // Global side panel settings (currently empty - reserved for future global settings)
1693 wxPanel *panel = new wxPanel(parent, wxID_ANY);
1694 panel->SetBackgroundColour(wxColour(50, 50, 50));
1695 wxBoxSizer *panelSizer = new wxBoxSizer(wxVERTICAL);
1696
1697 wxStaticText *infoText = new wxStaticText(panel, wxID_ANY,
1698 "Global settings for all side panels.\n\n"
1699 "Configure individual panels:\n"
1700 " • Left Panel - Settings for the left side panel\n"
1701 " • Right Panel - Settings for the right side panel\n"
1702 " • Bottom Panel - Settings for the bottom panel");
1703 infoText->SetForegroundColour(wxColour(180, 180, 180));
1704 panelSizer->Add(infoText, 0, wxALL, 10);
1705
1706 panelSizer->AddStretchSpacer();
1707
1708 panel->SetSizer(panelSizer);
1709 return panel;
1710}
1711
1713 // Placeholder panel for "Tabs" submenu (navigation node)
1714 wxPanel *panel = new wxPanel(parent, wxID_ANY);
1715 panel->SetBackgroundColour(wxColour(50, 50, 50));
1716 wxBoxSizer *panelSizer = new wxBoxSizer(wxVERTICAL);
1717
1718 wxStaticText *infoText = new wxStaticText(panel, wxID_ANY,
1719 "Tab-specific settings.\n\n"
1720 "Configure individual tabs:\n"
1721 " • File Explorer Tab - Settings for file browsing\n"
1722 " • Log Tab - Settings for log display\n"
1723 " • Scene Hierarchy Tab - Settings for scene hierarchy display");
1724 infoText->SetForegroundColour(wxColour(180, 180, 180));
1725 panelSizer->Add(infoText, 0, wxALL, 10);
1726
1727 panelSizer->AddStretchSpacer();
1728
1729 panel->SetSizer(panelSizer);
1730 return panel;
1731}
1732
1734 wxPanel *panel = new wxPanel(parent, wxID_ANY);
1735 panel->SetBackgroundColour(wxColour(50, 50, 50));
1736 wxBoxSizer *panelSizer = new wxBoxSizer(wxVERTICAL);
1737
1738 // Panel Layout group
1739 wxStaticBoxSizer *layoutGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Panel Layout");
1740
1741 // Default panel width
1742 wxBoxSizer *widthSizer = new wxBoxSizer(wxHORIZONTAL);
1743
1744 m_leftPanelWidthEnabled = new wxCheckBox(panel, ID_LEFT_PANEL_WIDTH_ENABLED, "Default panel width (% of window):");
1745 m_leftPanelWidthEnabled->SetForegroundColour(wxColour(200, 200, 200));
1746 m_leftPanelWidthEnabled->SetValue(true);
1748 widthSizer->Add(m_leftPanelWidthEnabled, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1749
1751 new wxSpinCtrl(panel, wxID_ANY, "20", wxDefaultPosition, wxSize(120, -1), wxSP_ARROW_KEYS, 5, 80, 20);
1752 widthSizer->Add(m_leftPanelWidth, 0, wxALIGN_CENTER_VERTICAL);
1753 layoutGroup->Add(widthSizer, 0, wxEXPAND | wxALL, 5);
1754
1755 // Minimum panel width
1756 wxBoxSizer *minWidthSizer = new wxBoxSizer(wxHORIZONTAL);
1757
1759 new wxCheckBox(panel, ID_LEFT_PANEL_MIN_WIDTH_ENABLED, "Minimum panel width (% of window):");
1760 m_leftPanelMinWidthEnabled->SetForegroundColour(wxColour(200, 200, 200));
1761 m_leftPanelMinWidthEnabled->SetValue(true);
1763 minWidthSizer->Add(m_leftPanelMinWidthEnabled, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1764
1766 new wxSpinCtrl(panel, wxID_ANY, "10", wxDefaultPosition, wxSize(120, -1), wxSP_ARROW_KEYS, 5, 50, 10);
1767 minWidthSizer->Add(m_leftPanelMinWidth, 0, wxALIGN_CENTER_VERTICAL);
1768 layoutGroup->Add(minWidthSizer, 0, wxEXPAND | wxALL, 5);
1769
1770 // Show panel on startup
1771 wxBoxSizer *startupSizer = new wxBoxSizer(wxHORIZONTAL);
1772 wxStaticText *startupLabel = new wxStaticText(panel, wxID_ANY, "On startup:");
1773 startupLabel->SetForegroundColour(wxColour(200, 200, 200));
1774 startupSizer->Add(startupLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1775
1776 wxArrayString startupOptions;
1777 startupOptions.Add("Show panel");
1778 startupOptions.Add("Hide panel");
1779 startupOptions.Add("Remember last state");
1780 m_leftPanelStartup = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, startupOptions);
1781 m_leftPanelStartup->SetSelection(0);
1782 startupSizer->Add(m_leftPanelStartup, 1, wxEXPAND);
1783 layoutGroup->Add(startupSizer, 0, wxEXPAND | wxALL, 5);
1784
1785 panelSizer->Add(layoutGroup, 0, wxEXPAND | wxALL, 5);
1786
1787 // Tab Bar group
1788 wxStaticBoxSizer *tabBarGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Tab Bar");
1789
1790 m_leftPanelShowTabCloseButtons = new wxCheckBox(panel, wxID_ANY, "Show close buttons on tabs");
1791 m_leftPanelShowTabCloseButtons->SetForegroundColour(wxColour(200, 200, 200));
1792 m_leftPanelShowTabCloseButtons->SetValue(true);
1793 tabBarGroup->Add(m_leftPanelShowTabCloseButtons, 0, wxALL, 5);
1794
1795 panelSizer->Add(tabBarGroup, 0, wxEXPAND | wxALL, 5);
1796
1797 // Behavior group
1798 wxStaticBoxSizer *behaviorGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Behavior");
1799
1800 m_leftPanelRememberLastTab = new wxCheckBox(panel, wxID_ANY, "Remember last active tab between sessions");
1801 m_leftPanelRememberLastTab->SetForegroundColour(wxColour(200, 200, 200));
1802 m_leftPanelRememberLastTab->SetValue(true);
1803 behaviorGroup->Add(m_leftPanelRememberLastTab, 0, wxALL, 5);
1804
1805 m_leftPanelAllowCollapse = new wxCheckBox(panel, wxID_ANY, "Allow panel collapse (drag splitter to hide)");
1806 m_leftPanelAllowCollapse->SetForegroundColour(wxColour(200, 200, 200));
1807 m_leftPanelAllowCollapse->SetValue(true);
1808 behaviorGroup->Add(m_leftPanelAllowCollapse, 0, wxALL, 5);
1809
1810 panelSizer->Add(behaviorGroup, 0, wxEXPAND | wxALL, 5);
1811 panelSizer->AddStretchSpacer();
1812
1813 panel->SetSizer(panelSizer);
1814 return panel;
1815}
1816
1818 wxPanel *panel = new wxPanel(parent, wxID_ANY);
1819 panel->SetBackgroundColour(wxColour(50, 50, 50));
1820 wxBoxSizer *panelSizer = new wxBoxSizer(wxVERTICAL);
1821
1822 // Panel Layout group
1823 wxStaticBoxSizer *layoutGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Panel Layout");
1824
1825 // Default panel width
1826 wxBoxSizer *widthSizer = new wxBoxSizer(wxHORIZONTAL);
1827
1829 new wxCheckBox(panel, ID_RIGHT_PANEL_WIDTH_ENABLED, "Default panel width (% of window):");
1830 m_rightPanelWidthEnabled->SetForegroundColour(wxColour(200, 200, 200));
1831 m_rightPanelWidthEnabled->SetValue(true);
1833 widthSizer->Add(m_rightPanelWidthEnabled, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1834
1836 new wxSpinCtrl(panel, wxID_ANY, "20", wxDefaultPosition, wxSize(120, -1), wxSP_ARROW_KEYS, 5, 80, 20);
1837 widthSizer->Add(m_rightPanelWidth, 0, wxALIGN_CENTER_VERTICAL);
1838 layoutGroup->Add(widthSizer, 0, wxEXPAND | wxALL, 5);
1839
1840 // Minimum panel width
1841 wxBoxSizer *minWidthSizer = new wxBoxSizer(wxHORIZONTAL);
1842
1844 new wxCheckBox(panel, ID_RIGHT_PANEL_MIN_WIDTH_ENABLED, "Minimum panel width (% of window):");
1845 m_rightPanelMinWidthEnabled->SetForegroundColour(wxColour(200, 200, 200));
1846 m_rightPanelMinWidthEnabled->SetValue(true);
1848 minWidthSizer->Add(m_rightPanelMinWidthEnabled, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1849
1851 new wxSpinCtrl(panel, wxID_ANY, "10", wxDefaultPosition, wxSize(120, -1), wxSP_ARROW_KEYS, 5, 50, 10);
1852 minWidthSizer->Add(m_rightPanelMinWidth, 0, wxALIGN_CENTER_VERTICAL);
1853 layoutGroup->Add(minWidthSizer, 0, wxEXPAND | wxALL, 5);
1854
1855 // Show panel on startup
1856 wxBoxSizer *startupSizer = new wxBoxSizer(wxHORIZONTAL);
1857 wxStaticText *startupLabel = new wxStaticText(panel, wxID_ANY, "On startup:");
1858 startupLabel->SetForegroundColour(wxColour(200, 200, 200));
1859 startupSizer->Add(startupLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1860
1861 wxArrayString startupOptions;
1862 startupOptions.Add("Show panel");
1863 startupOptions.Add("Hide panel");
1864 startupOptions.Add("Remember last state");
1865 m_rightPanelStartup = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, startupOptions);
1866 m_rightPanelStartup->SetSelection(0);
1867 startupSizer->Add(m_rightPanelStartup, 1, wxEXPAND);
1868 layoutGroup->Add(startupSizer, 0, wxEXPAND | wxALL, 5);
1869
1870 panelSizer->Add(layoutGroup, 0, wxEXPAND | wxALL, 5);
1871
1872 // Tab Bar group
1873 wxStaticBoxSizer *tabBarGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Tab Bar");
1874
1875 m_rightPanelShowTabCloseButtons = new wxCheckBox(panel, wxID_ANY, "Show close buttons on tabs");
1876 m_rightPanelShowTabCloseButtons->SetForegroundColour(wxColour(200, 200, 200));
1877 m_rightPanelShowTabCloseButtons->SetValue(true);
1878 tabBarGroup->Add(m_rightPanelShowTabCloseButtons, 0, wxALL, 5);
1879
1880 panelSizer->Add(tabBarGroup, 0, wxEXPAND | wxALL, 5);
1881
1882 // Behavior group
1883 wxStaticBoxSizer *behaviorGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Behavior");
1884
1885 m_rightPanelRememberLastTab = new wxCheckBox(panel, wxID_ANY, "Remember last active tab between sessions");
1886 m_rightPanelRememberLastTab->SetForegroundColour(wxColour(200, 200, 200));
1887 m_rightPanelRememberLastTab->SetValue(true);
1888 behaviorGroup->Add(m_rightPanelRememberLastTab, 0, wxALL, 5);
1889
1890 m_rightPanelAllowCollapse = new wxCheckBox(panel, wxID_ANY, "Allow panel collapse (drag splitter to hide)");
1891 m_rightPanelAllowCollapse->SetForegroundColour(wxColour(200, 200, 200));
1892 m_rightPanelAllowCollapse->SetValue(true);
1893 behaviorGroup->Add(m_rightPanelAllowCollapse, 0, wxALL, 5);
1894
1895 panelSizer->Add(behaviorGroup, 0, wxEXPAND | wxALL, 5);
1896 panelSizer->AddStretchSpacer();
1897
1898 panel->SetSizer(panelSizer);
1899 return panel;
1900}
1901
1903 wxPanel *panel = new wxPanel(parent, wxID_ANY);
1904 panel->SetBackgroundColour(wxColour(50, 50, 50));
1905 wxBoxSizer *panelSizer = new wxBoxSizer(wxVERTICAL);
1906
1907 // Display Settings group
1908 wxStaticBoxSizer *displayGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Display Settings");
1909
1910 // Default Level Filter
1911 wxBoxSizer *levelSizer = new wxBoxSizer(wxHORIZONTAL);
1912 wxStaticText *levelLabel = new wxStaticText(panel, wxID_ANY, "Default level filter:");
1913 levelLabel->SetForegroundColour(wxColour(200, 200, 200));
1914 levelSizer->Add(levelLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1915
1916 wxArrayString levelOptions;
1917 levelOptions.Add("All");
1918 levelOptions.Add("Trace");
1919 levelOptions.Add("Info");
1920 levelOptions.Add("Warning");
1921 levelOptions.Add("Error");
1922 levelOptions.Add("Critical");
1923 m_logDefaultLevelFilter = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, levelOptions);
1924 levelSizer->Add(m_logDefaultLevelFilter, 1, wxEXPAND);
1925 displayGroup->Add(levelSizer, 0, wxEXPAND | wxALL, 5);
1926
1927 // Font Size
1928 wxBoxSizer *fontSizer = new wxBoxSizer(wxHORIZONTAL);
1929 wxStaticText *fontLabel = new wxStaticText(panel, wxID_ANY, "Font size:");
1930 fontLabel->SetForegroundColour(wxColour(200, 200, 200));
1931 fontSizer->Add(fontLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1932
1933 wxArrayString fontOptions;
1934 fontOptions.Add("Small");
1935 fontOptions.Add("Medium");
1936 fontOptions.Add("Large");
1937 m_logFontSize = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, fontOptions);
1938 fontSizer->Add(m_logFontSize, 1, wxEXPAND);
1939 displayGroup->Add(fontSizer, 0, wxEXPAND | wxALL, 5);
1940
1941 panelSizer->Add(displayGroup, 0, wxEXPAND | wxALL, 5);
1942
1943 // Behavior Settings group
1944 wxStaticBoxSizer *behaviorGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Behavior Settings");
1945
1946 // Auto-scroll enabled
1947 m_logAutoScrollEnabled = new wxCheckBox(panel, wxID_ANY, "Auto-scroll to newest logs");
1948 m_logAutoScrollEnabled->SetForegroundColour(wxColour(200, 200, 200));
1949 behaviorGroup->Add(m_logAutoScrollEnabled, 0, wxALL, 5);
1950
1951 // Max log entries
1952 wxBoxSizer *maxEntriesSizer = new wxBoxSizer(wxHORIZONTAL);
1953 wxStaticText *maxEntriesLabel = new wxStaticText(panel, wxID_ANY, "Max log entries:");
1954 maxEntriesLabel->SetForegroundColour(wxColour(200, 200, 200));
1955 maxEntriesSizer->Add(maxEntriesLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1956
1958 new wxSpinCtrl(panel, wxID_ANY, "2000", wxDefaultPosition, wxSize(150, -1), wxSP_ARROW_KEYS, 100, 50000, 2000);
1959 maxEntriesSizer->Add(m_logMaxEntries, 0, wxALIGN_CENTER_VERTICAL);
1960
1961 wxStaticText *maxEntriesHint = new wxStaticText(panel, wxID_ANY, "(100 - 50000)");
1962 maxEntriesHint->SetForegroundColour(wxColour(150, 150, 150));
1963 maxEntriesSizer->Add(maxEntriesHint, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 10);
1964
1965 behaviorGroup->Add(maxEntriesSizer, 0, wxEXPAND | wxALL, 5);
1966
1967 panelSizer->Add(behaviorGroup, 0, wxEXPAND | wxALL, 5);
1968
1969 // Color Settings group
1970 wxStaticBoxSizer *colorSettingsGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Color Settings");
1971
1972 // Enable GUI colors
1973 m_logEnableGuiColors = new wxCheckBox(panel, wxID_ANY, "Enable colored text in LogTab");
1974 m_logEnableGuiColors->SetForegroundColour(wxColour(200, 200, 200));
1975 m_logEnableGuiColors->SetToolTip("Show log entries with colored text based on log level");
1976 colorSettingsGroup->Add(m_logEnableGuiColors, 0, wxALL, 5);
1977
1978 // Enable console colors
1979 m_logEnableConsoleColors = new wxCheckBox(panel, wxID_ANY, "Enable ANSI colors in console output");
1980 m_logEnableConsoleColors->SetForegroundColour(wxColour(200, 200, 200));
1981 m_logEnableConsoleColors->SetToolTip("Enable colored output in terminal/console (via spdlog)");
1982 colorSettingsGroup->Add(m_logEnableConsoleColors, 0, wxALL, 5);
1983
1984 panelSizer->Add(colorSettingsGroup, 0, wxEXPAND | wxALL, 5);
1985
1986 // Level Colors group
1987 wxStaticBoxSizer *colorsGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Level Colors");
1988
1989 // Helper lambda to create a color picker row
1990 auto createColorRow = [&](const wxString &label, wxColourPickerCtrl *&picker, const wxColour &defaultColor) {
1991 wxBoxSizer *rowSizer = new wxBoxSizer(wxHORIZONTAL);
1992 wxStaticText *labelText = new wxStaticText(panel, wxID_ANY, label);
1993 labelText->SetForegroundColour(wxColour(200, 200, 200));
1994 labelText->SetMinSize(wxSize(80, -1));
1995 rowSizer->Add(labelText, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
1996
1997 picker = new wxColourPickerCtrl(panel, wxID_ANY, defaultColor, wxDefaultPosition, wxSize(60, 25));
1998 rowSizer->Add(picker, 0, wxALIGN_CENTER_VERTICAL);
1999
2000 colorsGroup->Add(rowSizer, 0, wxEXPAND | wxALL, 5);
2001 };
2002
2003 createColorRow("Trace:", m_logTraceColor, wxColour(128, 128, 128));
2004 createColorRow("Info:", m_logInfoColor, wxColour(100, 200, 100));
2005 createColorRow("Warning:", m_logWarningColor, wxColour(230, 180, 50));
2006 createColorRow("Error:", m_logErrorColor, wxColour(230, 80, 80));
2007 createColorRow("Critical:", m_logCriticalColor, wxColour(255, 50, 50));
2008
2009 panelSizer->Add(colorsGroup, 0, wxEXPAND | wxALL, 5);
2010 panelSizer->AddStretchSpacer();
2011
2012 panel->SetSizer(panelSizer);
2013 return panel;
2014}
2015
2017 wxPanel *panel = new wxPanel(parent, wxID_ANY);
2018 panel->SetBackgroundColour(wxColour(50, 50, 50));
2019 wxBoxSizer *panelSizer = new wxBoxSizer(wxVERTICAL);
2020
2021 // File Loading group
2022 wxStaticBoxSizer *fileGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "File Loading");
2023
2024 m_autoLoadLastFile = new wxCheckBox(panel, ID_AUTO_LOAD_LAST_FILE, "Auto-load last opened file on startup");
2025 m_autoLoadLastFile->SetForegroundColour(wxColour(200, 200, 200));
2026 fileGroup->Add(m_autoLoadLastFile, 0, wxALL, 5);
2027
2028 m_showParseWarnings = new wxCheckBox(panel, ID_SHOW_PARSE_WARNINGS, "Show parsing warnings");
2029 m_showParseWarnings->SetForegroundColour(wxColour(200, 200, 200));
2030 fileGroup->Add(m_showParseWarnings, 0, wxALL, 5);
2031
2032 // File encoding
2033 wxBoxSizer *encodingSizer = new wxBoxSizer(wxHORIZONTAL);
2034 wxStaticText *encodingLabel = new wxStaticText(panel, wxID_ANY, "Default file encoding:");
2035 encodingLabel->SetForegroundColour(wxColour(200, 200, 200));
2036 encodingSizer->Add(encodingLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
2037
2038 wxArrayString encodings;
2039 encodings.Add("UTF-8");
2040 encodings.Add("ASCII");
2041 encodings.Add("ISO-8859-1");
2042 m_fileEncoding = new wxChoice(panel, ID_FILE_ENCODING, wxDefaultPosition, wxDefaultSize, encodings);
2043 encodingSizer->Add(m_fileEncoding, 1, wxEXPAND);
2044 fileGroup->Add(encodingSizer, 0, wxEXPAND | wxALL, 5);
2045
2046 panelSizer->Add(fileGroup, 0, wxEXPAND | wxALL, 5);
2047
2048 // Parser Configuration group
2049 wxStaticBoxSizer *parserGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Parser Configuration");
2050
2051 wxStaticText *parserNote = new wxStaticText(
2052 panel, wxID_ANY, "For advanced parser settings including XML profiles,\nuse the parser configuration dialog:");
2053 parserNote->SetForegroundColour(wxColour(180, 180, 180));
2054 parserGroup->Add(parserNote, 0, wxALL, 5);
2055
2056 m_configureParserButton = new wxButton(panel, ID_CONFIGURE_PARSER, "Configure Parser...");
2057 parserGroup->Add(m_configureParserButton, 0, wxALL | wxALIGN_CENTER, 5);
2058
2059 panelSizer->Add(parserGroup, 0, wxEXPAND | wxALL, 5);
2060 panelSizer->AddStretchSpacer();
2061
2062 panel->SetSizer(panelSizer);
2063 return panel;
2064}
2065
2067 wxPanel *panel = new wxPanel(parent, wxID_ANY);
2068 panel->SetBackgroundColour(wxColour(50, 50, 50));
2069 wxBoxSizer *panelSizer = new wxBoxSizer(wxVERTICAL);
2070
2071 // === Rendering Settings ===
2072 wxStaticBoxSizer *renderingGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Rendering (wxWidgets-Supported)");
2073
2074 m_enableVSync = new wxCheckBox(panel, ID_ENABLE_VSYNC, "Enable VSync");
2075 m_enableVSync->SetForegroundColour(wxColour(200, 200, 200));
2076 m_enableVSync->SetToolTip("Vertical sync for smoother rendering (OpenGL contexts only)");
2077 renderingGroup->Add(m_enableVSync, 0, wxALL, 5);
2078
2079 m_hardwareAcceleration = new wxCheckBox(panel, ID_HARDWARE_ACCELERATION, "Hardware Acceleration (GPU)");
2080 m_hardwareAcceleration->SetForegroundColour(wxColour(200, 200, 200));
2081 m_hardwareAcceleration->SetToolTip("Use GPU for rendering (OpenGL contexts only, requires restart)");
2082 renderingGroup->Add(m_hardwareAcceleration, 0, wxALL, 5);
2083
2084 m_enableDoubleBuffering = new wxCheckBox(panel, ID_ENABLE_DOUBLE_BUFFERING, "Double Buffering");
2085 m_enableDoubleBuffering->SetForegroundColour(wxColour(200, 200, 200));
2086 m_enableDoubleBuffering->SetToolTip("Reduce flicker using window styles (wxBUFFER_VIRTUAL_AREA)");
2087 renderingGroup->Add(m_enableDoubleBuffering, 0, wxALL, 5);
2088
2089 m_enableAntiAliasing = new wxCheckBox(panel, ID_ENABLE_ANTI_ALIASING, "Graphics Anti-Aliasing");
2090 m_enableAntiAliasing->SetForegroundColour(wxColour(200, 200, 200));
2091 m_enableAntiAliasing->SetToolTip("Smooth edges using wxGraphicsContext");
2092 renderingGroup->Add(m_enableAntiAliasing, 0, wxALL, 5);
2093
2094 m_enableTextAntiAliasing = new wxCheckBox(panel, ID_ENABLE_TEXT_AA, "Text Anti-Aliasing");
2095 m_enableTextAntiAliasing->SetForegroundColour(wxColour(200, 200, 200));
2096 m_enableTextAntiAliasing->SetToolTip("Smooth text using font flags");
2097 renderingGroup->Add(m_enableTextAntiAliasing, 0, wxALL, 5);
2098
2099 m_enablePartialRedraws = new wxCheckBox(panel, ID_ENABLE_PARTIAL_REDRAWS, "Partial Redraws");
2100 m_enablePartialRedraws->SetForegroundColour(wxColour(200, 200, 200));
2101 m_enablePartialRedraws->SetToolTip("Only redraw changed areas (wxNO_FULL_REPAINT_ON_RESIZE)");
2102 renderingGroup->Add(m_enablePartialRedraws, 0, wxALL, 5);
2103
2104 m_enableBackgroundErase = new wxCheckBox(panel, ID_ENABLE_BACKGROUND_ERASE, "Background Erase");
2105 m_enableBackgroundErase->SetForegroundColour(wxColour(200, 200, 200));
2106 m_enableBackgroundErase->SetToolTip("Erase background before redraw (disable for better performance)");
2107 renderingGroup->Add(m_enableBackgroundErase, 0, wxALL, 5);
2108
2109 // FPS limit
2110 wxBoxSizer *fpsSizer = new wxBoxSizer(wxHORIZONTAL);
2111 wxStaticText *fpsLabel = new wxStaticText(panel, wxID_ANY, "Frame Rate Limit:");
2112 fpsLabel->SetForegroundColour(wxColour(200, 200, 200));
2113 fpsSizer->Add(fpsLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
2114
2115 wxArrayString fpsOptions;
2116 fpsOptions.Add("30 FPS");
2117 fpsOptions.Add("60 FPS");
2118 fpsOptions.Add("120 FPS");
2119 fpsOptions.Add("Unlimited");
2120 m_fpsLimit = new wxChoice(panel, ID_FPS_LIMIT, wxDefaultPosition, wxSize(150, -1), fpsOptions);
2121 m_fpsLimit->SetToolTip("Limit frame rate using wxTimer");
2122 fpsSizer->Add(m_fpsLimit, 0);
2123 renderingGroup->Add(fpsSizer, 0, wxEXPAND | wxALL, 5);
2124
2125 panelSizer->Add(renderingGroup, 0, wxEXPAND | wxALL, 10);
2126
2127 // === Viewport Culling (for Large Trees) ===
2128 wxStaticBoxSizer *cullingGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Viewport Culling (for Large Trees)");
2129
2130 m_enableViewportCulling = new wxCheckBox(panel, wxID_ANY, "Enable Viewport Culling");
2131 m_enableViewportCulling->SetForegroundColour(wxColour(200, 200, 200));
2132 m_enableViewportCulling->SetToolTip(
2133 "Only render nodes visible in viewport - major performance boost for large trees");
2134 cullingGroup->Add(m_enableViewportCulling, 0, wxALL, 5);
2135
2136 // Culling margin slider
2137 wxBoxSizer *marginSizer = new wxBoxSizer(wxHORIZONTAL);
2138 wxStaticText *marginLabel = new wxStaticText(panel, wxID_ANY, "Culling Margin:");
2139 marginLabel->SetForegroundColour(wxColour(200, 200, 200));
2140 marginSizer->Add(marginLabel, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
2141
2142 m_viewportCullingMargin = new wxSpinCtrl(panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(100, -1),
2143 wxSP_ARROW_KEYS, 100, 1000, 500);
2144 m_viewportCullingMargin->SetToolTip(
2145 "Safety margin in pixels - higher values prevent edge flickering but render more off-screen nodes");
2146 marginSizer->Add(m_viewportCullingMargin, 0);
2147
2148 wxStaticText *marginUnit = new wxStaticText(panel, wxID_ANY, " pixels");
2149 marginUnit->SetForegroundColour(wxColour(180, 180, 180));
2150 marginSizer->Add(marginUnit, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 5);
2151
2152 cullingGroup->Add(marginSizer, 0, wxEXPAND | wxALL, 5);
2153
2154 // Culling info
2155 wxStaticText *cullingInfo =
2156 new wxStaticText(panel, wxID_ANY,
2157 "Viewport culling dramatically improves performance with large trees (600+ nodes)\n"
2158 "by only rendering nodes visible in the current view. The margin prevents\n"
2159 "flickering when nodes are at viewport edges.");
2160 cullingInfo->SetForegroundColour(wxColour(150, 150, 150));
2161 cullingGroup->Add(cullingInfo, 0, wxALL, 5);
2162
2163 panelSizer->Add(cullingGroup, 0, wxEXPAND | wxALL, 10);
2164
2165 // === UI Responsiveness ===
2166 wxStaticBoxSizer *uiGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "UI Responsiveness");
2167
2168 m_enableIdleProcessing = new wxCheckBox(panel, ID_ENABLE_IDLE_PROCESSING, "Enable Idle Event Processing");
2169 m_enableIdleProcessing->SetForegroundColour(wxColour(200, 200, 200));
2170 m_enableIdleProcessing->SetToolTip("Process background tasks using wxIdleEvent");
2171 uiGroup->Add(m_enableIdleProcessing, 0, wxALL, 5);
2172
2173 panelSizer->Add(uiGroup, 0, wxEXPAND | wxALL, 10);
2174
2175 // Performance note
2176 wxStaticBoxSizer *noteGroup = new wxStaticBoxSizer(wxVERTICAL, panel, "Note");
2177 wxStaticText *noteText =
2178 new wxStaticText(panel, wxID_ANY,
2179 "These settings use wxWidgets native APIs for performance tuning.\n"
2180 "Some settings (VSync, Hardware Acceleration) apply only to OpenGL contexts.\n"
2181 "Changes may require an application restart to take full effect.");
2182 noteText->SetForegroundColour(wxColour(180, 180, 180));
2183 noteGroup->Add(noteText, 0, wxALL, 5);
2184 panelSizer->Add(noteGroup, 0, wxEXPAND | wxALL, 10);
2185
2186 panelSizer->AddStretchSpacer();
2187
2188 panel->SetSizer(panelSizer);
2189 return panel;
2190}
2191
2192void PreferencesDialog::ShowPanel(wxPanel *panel) {
2193 if (!panel)
2194 return;
2195
2196 // Hide all panels
2197 m_windowPanel->Hide();
2198 m_mainPanelPanel->Hide();
2200 m_bottomPanelPanel->Hide();
2201 m_fileExplorerPanel->Hide();
2202 m_logTabPanel->Hide();
2203 m_sidePanelPanel->Hide();
2204 m_leftPanelPanel->Hide();
2205 m_rightPanelPanel->Hide();
2206 m_tabsSubPanel->Hide();
2207 m_parserPanel->Hide();
2208 m_performancePanel->Hide();
2209
2210 // Show selected panel
2211 panel->Show();
2212
2213 // Update layout
2214 m_settingsPanel->Layout();
2215 m_settingsPanel->FitInside();
2216 m_settingsPanel->Refresh();
2217}
2218
2219bool PreferencesDialog::SelectSection(const wxString &sectionName) {
2220 if (!m_sectionTree)
2221 return false;
2222
2223 // Helper lambda to recursively find and select a tree item by name
2224 std::function<bool(wxTreeItemId)> findAndSelect = [&](wxTreeItemId item) -> bool {
2225 if (!item.IsOk())
2226 return false;
2227
2228 if (m_sectionTree->GetItemText(item) == sectionName) {
2229 m_sectionTree->SelectItem(item);
2230 m_sectionTree->EnsureVisible(item);
2231
2232 // Also show the corresponding panel
2233 SectionTreeItemData *data = dynamic_cast<SectionTreeItemData *>(m_sectionTree->GetItemData(item));
2234 if (data && data->GetPanel()) {
2235 ShowPanel(data->GetPanel());
2236 }
2237 return true;
2238 }
2239
2240 // Check children
2241 wxTreeItemIdValue cookie;
2242 wxTreeItemId child = m_sectionTree->GetFirstChild(item, cookie);
2243 while (child.IsOk()) {
2244 if (findAndSelect(child))
2245 return true;
2246 child = m_sectionTree->GetNextChild(item, cookie);
2247 }
2248 return false;
2249 };
2250
2251 // Start from root
2252 wxTreeItemId rootId = m_sectionTree->GetRootItem();
2253 return findAndSelect(rootId);
2254}
2255
2257 using namespace EmberForge;
2258 auto &prefs = AppPreferencesManager::GetInstance().GetPreferences();
2259
2260 // Window settings
2261 m_themeChoice->SetSelection(static_cast<int>(prefs.GetWindowSettings().theme));
2262 wxColour accentColor(prefs.GetWindowSettings().accentColor.r, prefs.GetWindowSettings().accentColor.g,
2263 prefs.GetWindowSettings().accentColor.b);
2264 m_accentColorPicker->SetColour(accentColor);
2265 m_startupModeChoice->SetSelection(static_cast<int>(prefs.GetWindowSettings().startupMode));
2266
2267 // File menu hotkeys
2268 m_newProjectHotkeyTextCtrl->SetValue(wxString(prefs.GetWindowSettings().newProjectHotkey));
2269 m_openProjectHotkeyTextCtrl->SetValue(wxString(prefs.GetWindowSettings().openProjectHotkey));
2270 m_openFileHotkeyTextCtrl->SetValue(wxString(prefs.GetWindowSettings().openFileHotkey));
2271 m_saveHotkeyTextCtrl->SetValue(wxString(prefs.GetWindowSettings().saveHotkey));
2272 m_saveAsHotkeyTextCtrl->SetValue(wxString(prefs.GetWindowSettings().saveAsHotkey));
2273
2274 // View menu hotkeys
2275 m_maximizeHotkeyTextCtrl->SetValue(wxString(prefs.GetWindowSettings().maximizeHotkey));
2276 m_resetUIHotkeyTextCtrl->SetValue(wxString(prefs.GetWindowSettings().resetUIHotkey));
2277
2278 // Settings menu hotkeys
2279 m_preferencesHotkeyTextCtrl->SetValue(wxString(prefs.GetWindowSettings().preferencesHotkey));
2280 m_parserConfigHotkeyTextCtrl->SetValue(wxString(prefs.GetWindowSettings().parserConfigHotkey));
2281
2282 // Window appearance
2283 m_showStatusBar->SetValue(prefs.GetWindowSettings().showStatusBar);
2284 m_showPanelCaptions->SetValue(prefs.GetWindowSettings().showPanelCaptions);
2285 m_alwaysOnTop->SetValue(prefs.GetWindowSettings().alwaysOnTop);
2286
2287 // Window constraints
2288 m_minWindowWidth->SetValue(prefs.GetWindowSettings().minWindowWidthPct);
2289 m_minWindowHeight->SetValue(prefs.GetWindowSettings().minWindowHeightPct);
2290 bool maxUnlimited =
2291 (prefs.GetWindowSettings().maxWindowWidthPct == -1 || prefs.GetWindowSettings().maxWindowHeightPct == -1);
2292 m_maxWindowUnlimited->SetValue(maxUnlimited);
2293 m_maxWindowWidth->SetValue(prefs.GetWindowSettings().maxWindowWidthPct);
2294 m_maxWindowHeight->SetValue(prefs.GetWindowSettings().maxWindowHeightPct);
2295 m_maxWindowWidth->Enable(!maxUnlimited);
2296 m_maxWindowHeight->Enable(!maxUnlimited);
2297
2298 m_enforceAspectRatio->SetValue(prefs.GetWindowSettings().enforceAspectRatio);
2299 // Parse aspect ratio from float
2300 float ratio = prefs.GetWindowSettings().aspectRatio;
2301 // Common ratios: 16:9 = 1.777..., 4:3 = 1.333..., 21:9 = 2.333...
2302 int width = 16, height = 9;
2303 if (std::abs(ratio - 16.0f / 9.0f) < 0.01f) {
2304 width = 16;
2305 height = 9;
2306 } else if (std::abs(ratio - 4.0f / 3.0f) < 0.01f) {
2307 width = 4;
2308 height = 3;
2309 } else if (std::abs(ratio - 21.0f / 9.0f) < 0.01f) {
2310 width = 21;
2311 height = 9;
2312 }
2313 m_aspectRatioWidth->SetValue(wxString::Format("%d", width));
2314 m_aspectRatioHeight->SetValue(wxString::Format("%d", height));
2315
2316 // Main panel settings
2317 int zoomPercent = static_cast<int>(prefs.GetMainPanelSettings().defaultZoomLevel * 100);
2318 m_defaultZoomSlider->SetValue(zoomPercent);
2319 m_zoomLabel->SetLabel(wxString::Format("%d%%", zoomPercent));
2320 m_showGrid->SetValue(prefs.GetMainPanelSettings().showGrid);
2321 m_gridSize->SetValue(prefs.GetMainPanelSettings().gridSize);
2322 wxColour gridBg(prefs.GetMainPanelSettings().gridBackgroundColor.r,
2323 prefs.GetMainPanelSettings().gridBackgroundColor.g,
2324 prefs.GetMainPanelSettings().gridBackgroundColor.b);
2325 m_gridBackgroundPicker->SetColour(gridBg);
2326 wxColour gridLineColor(prefs.GetMainPanelSettings().gridLineColor.r, prefs.GetMainPanelSettings().gridLineColor.g,
2327 prefs.GetMainPanelSettings().gridLineColor.b);
2328 m_gridLineColorPicker->SetColour(gridLineColor);
2329 wxColour canvasBg(prefs.GetMainPanelSettings().canvasBackgroundColor.r,
2330 prefs.GetMainPanelSettings().canvasBackgroundColor.g,
2331 prefs.GetMainPanelSettings().canvasBackgroundColor.b);
2332 m_canvasBackgroundPicker->SetColour(canvasBg);
2333 wxColour connectionLineColor(prefs.GetMainPanelSettings().connectionLineColor.r,
2334 prefs.GetMainPanelSettings().connectionLineColor.g,
2335 prefs.GetMainPanelSettings().connectionLineColor.b);
2336 m_connectionLineColorPicker->SetColour(connectionLineColor);
2337 m_highlightPathToSelected->SetValue(prefs.GetMainPanelSettings().highlightPathToSelected);
2338 wxColour pathHighlightColor(prefs.GetMainPanelSettings().pathHighlightColor.r,
2339 prefs.GetMainPanelSettings().pathHighlightColor.g,
2340 prefs.GetMainPanelSettings().pathHighlightColor.b);
2341 m_pathHighlightColorPicker->SetColour(pathHighlightColor);
2342 wxColour idleNodeBg(prefs.GetMainPanelSettings().idleNodeBgColor.r, prefs.GetMainPanelSettings().idleNodeBgColor.g,
2343 prefs.GetMainPanelSettings().idleNodeBgColor.b);
2344 m_idleNodeBgColorPicker->SetColour(idleNodeBg);
2345 wxColour idleNodeBorder(prefs.GetMainPanelSettings().idleNodeBorderColor.r,
2346 prefs.GetMainPanelSettings().idleNodeBorderColor.g,
2347 prefs.GetMainPanelSettings().idleNodeBorderColor.b);
2348 m_idleNodeBorderColorPicker->SetColour(idleNodeBorder);
2349 wxColour idleNodeText(prefs.GetMainPanelSettings().idleNodeTextColor.r,
2350 prefs.GetMainPanelSettings().idleNodeTextColor.g,
2351 prefs.GetMainPanelSettings().idleNodeTextColor.b);
2352 m_idleNodeTextColorPicker->SetColour(idleNodeText);
2353 int selectedTint = static_cast<int>(prefs.GetMainPanelSettings().selectedNodeBgTint * 100);
2354 m_selectedNodeBgTint->SetValue(selectedTint);
2355 m_selectedNodeBgTintLabel->SetLabel(wxString::Format("%d%%", selectedTint));
2356 int hoveredTint = static_cast<int>(prefs.GetMainPanelSettings().hoveredNodeBgTint * 100);
2357 m_hoveredNodeBgTint->SetValue(hoveredTint);
2358 m_hoveredNodeBgTintLabel->SetLabel(wxString::Format("%d%%", hoveredTint));
2359 wxColour selectedNode(prefs.GetMainPanelSettings().selectedNodeColor.r,
2360 prefs.GetMainPanelSettings().selectedNodeColor.g,
2361 prefs.GetMainPanelSettings().selectedNodeColor.b);
2362 m_selectedNodeColorPicker->SetColour(selectedNode);
2363 wxColour hoveredNode(prefs.GetMainPanelSettings().hoveredNodeColor.r,
2364 prefs.GetMainPanelSettings().hoveredNodeColor.g,
2365 prefs.GetMainPanelSettings().hoveredNodeColor.b);
2366 m_hoveredNodeColorPicker->SetColour(hoveredNode);
2367 wxColour selectedNodeText(prefs.GetMainPanelSettings().selectedNodeTextColor.r,
2368 prefs.GetMainPanelSettings().selectedNodeTextColor.g,
2369 prefs.GetMainPanelSettings().selectedNodeTextColor.b);
2370 m_selectedNodeTextColorPicker->SetColour(selectedNodeText);
2371 wxColour hoveredNodeText(prefs.GetMainPanelSettings().hoveredNodeTextColor.r,
2372 prefs.GetMainPanelSettings().hoveredNodeTextColor.g,
2373 prefs.GetMainPanelSettings().hoveredNodeTextColor.b);
2374 m_hoveredNodeTextColorPicker->SetColour(hoveredNodeText);
2375 wxColour selectedNodeInfo(prefs.GetMainPanelSettings().selectedNodeInfoColor.r,
2376 prefs.GetMainPanelSettings().selectedNodeInfoColor.g,
2377 prefs.GetMainPanelSettings().selectedNodeInfoColor.b);
2378 m_selectedNodeInfoColorPicker->SetColour(selectedNodeInfo);
2379 wxColour hoveredNodeInfo(prefs.GetMainPanelSettings().hoveredNodeInfoColor.r,
2380 prefs.GetMainPanelSettings().hoveredNodeInfoColor.g,
2381 prefs.GetMainPanelSettings().hoveredNodeInfoColor.b);
2382 m_hoveredNodeInfoColorPicker->SetColour(hoveredNodeInfo);
2383
2384 // Scene management
2385 bool scenesUnlimited = (prefs.GetMainPanelSettings().maxScenes == -1);
2386 m_maxScenesUnlimited->SetValue(scenesUnlimited);
2387 m_maxScenes->SetValue(prefs.GetMainPanelSettings().maxScenes > 0 ? prefs.GetMainPanelSettings().maxScenes : 10);
2388 m_maxScenes->Enable(!scenesUnlimited);
2389
2390 m_closeConfirmation->SetSelection(static_cast<int>(prefs.GetMainPanelSettings().closeConfirmation));
2391
2392 m_nextSceneHotkeyTextCtrl->SetValue(wxString(prefs.GetMainPanelSettings().nextSceneHotkey));
2393 m_previousSceneHotkeyTextCtrl->SetValue(wxString(prefs.GetMainPanelSettings().previousSceneHotkey));
2394
2395 // Behavior tree view settings
2396 const auto &btViewSettings = prefs.GetBehaviorTreeViewSettings();
2397
2398 // Convert zoom step size from float (0.0-1.0) to percentage (1-50)
2399 int zoomStepPercent = static_cast<int>(btViewSettings.zoomStepSize * 100);
2400 m_zoomStepSize->SetValue(zoomStepPercent);
2401 m_zoomStepSizeLabel->SetLabel(wxString::Format("%d%%", zoomStepPercent));
2402
2403 int wheelSensitivity = static_cast<int>(btViewSettings.mouseWheelSensitivity * 100);
2404 m_mouseWheelSensitivity->SetValue(wheelSensitivity);
2405 m_mouseWheelSensitivityLabel->SetLabel(wxString::Format("%.1fx", btViewSettings.mouseWheelSensitivity));
2406
2407 m_zoomFollowsCursor->SetValue(btViewSettings.zoomFollowsCursor);
2408 m_resetViewHotkeyTextCtrl->SetValue(wxString(btViewSettings.resetViewHotkey));
2409
2410 int panSensitivity = static_cast<int>(btViewSettings.panSensitivity * 100);
2411 m_panSensitivity->SetValue(panSensitivity);
2412 m_panSensitivityLabel->SetLabel(wxString::Format("%.1fx", btViewSettings.panSensitivity));
2413
2414 m_panKeyTextCtrl->SetValue(wxString(btViewSettings.panKey));
2415 m_enableSmoothPanning->SetValue(btViewSettings.enableSmoothPanning);
2416 m_panSmoothness->SetValue(static_cast<int>(btViewSettings.panSmoothness));
2417 m_panSmoothnessLabel->SetLabel(wxString::Format("%d%%", static_cast<int>(btViewSettings.panSmoothness)));
2418 m_panStepSize->SetValue(static_cast<int>(btViewSettings.panStepSize));
2419 m_panStepSizeLabel->SetLabel(wxString::Format("%dpx", static_cast<int>(btViewSettings.panStepSize)));
2420 m_centerOnNodeHotkeyTextCtrl->SetValue(wxString(btViewSettings.centerOnNodeHotkey));
2421 m_deleteNodeHotkeyTextCtrl->SetValue(wxString(btViewSettings.deleteNodeHotkey));
2422 m_panUpHotkeyTextCtrl->SetValue(wxString(btViewSettings.panUpHotkey));
2423 m_panDownHotkeyTextCtrl->SetValue(wxString(btViewSettings.panDownHotkey));
2424 m_panLeftHotkeyTextCtrl->SetValue(wxString(btViewSettings.panLeftHotkey));
2425 m_panRightHotkeyTextCtrl->SetValue(wxString(btViewSettings.panRightHotkey));
2426
2427 // Debug text settings - Coordinate System Info
2429 m_showCoordinateInfo->SetValue(btViewSettings.showCoordinateInfo);
2431 m_coordinateInfoFontSize->SetValue(btViewSettings.coordinateInfoFontSize);
2433 m_coordinateInfoColorPicker->SetColour(wxColour(btViewSettings.coordinateInfoColor.r,
2434 btViewSettings.coordinateInfoColor.g,
2435 btViewSettings.coordinateInfoColor.b));
2437 m_coordinateInfoAnchor->SetSelection(static_cast<int>(btViewSettings.coordinateInfoAnchor));
2439 m_coordinateInfoX->SetValue(btViewSettings.coordinateInfoX);
2441 m_coordinateInfoY->SetValue(btViewSettings.coordinateInfoY);
2442
2443 // Debug text settings - Selected Node Info
2445 m_showSelectedNodeInfo->SetValue(btViewSettings.showSelectedNodeInfo);
2447 m_selectedNodeInfoFontSize->SetValue(btViewSettings.selectedNodeInfoFontSize);
2449 m_selectedNodeDebugInfoColorPicker->SetColour(wxColour(btViewSettings.selectedNodeInfoColor.r,
2450 btViewSettings.selectedNodeInfoColor.g,
2451 btViewSettings.selectedNodeInfoColor.b));
2453 m_selectedNodeInfoAnchor->SetSelection(static_cast<int>(btViewSettings.selectedNodeInfoAnchor));
2455 m_selectedNodeInfoX->SetValue(btViewSettings.selectedNodeInfoX);
2457 m_selectedNodeInfoY->SetValue(btViewSettings.selectedNodeInfoY);
2458
2459 // Debug text settings - Tree Statistics Info
2460 if (m_showTreeInfo)
2461 m_showTreeInfo->SetValue(btViewSettings.showTreeInfo);
2463 m_treeInfoFontSize->SetValue(btViewSettings.treeInfoFontSize);
2465 m_treeInfoColorPicker->SetColour(
2466 wxColour(btViewSettings.treeInfoColor.r, btViewSettings.treeInfoColor.g, btViewSettings.treeInfoColor.b));
2467 if (m_treeInfoAnchor)
2468 m_treeInfoAnchor->SetSelection(static_cast<int>(btViewSettings.treeInfoAnchor));
2469 if (m_treeInfoX)
2470 m_treeInfoX->SetValue(btViewSettings.treeInfoX);
2471 if (m_treeInfoY)
2472 m_treeInfoY->SetValue(btViewSettings.treeInfoY);
2473
2474 // Debug text settings - FPS Display
2475 if (m_showFPS)
2476 m_showFPS->SetValue(btViewSettings.showFPS);
2477 if (m_fpsFontSize)
2478 m_fpsFontSize->SetValue(btViewSettings.fpsFontSize);
2479 if (m_fpsColorPicker)
2480 m_fpsColorPicker->SetColour(
2481 wxColour(btViewSettings.fpsColor.r, btViewSettings.fpsColor.g, btViewSettings.fpsColor.b));
2482 if (m_fpsAnchor)
2483 m_fpsAnchor->SetSelection(static_cast<int>(btViewSettings.fpsAnchor));
2484 if (m_fpsX)
2485 m_fpsX->SetValue(btViewSettings.fpsX);
2486 if (m_fpsY)
2487 m_fpsY->SetValue(btViewSettings.fpsY);
2488
2489 // Debug text settings - Controls Help Text
2491 m_showControlsHelp->SetValue(btViewSettings.showControlsHelp);
2493 m_controlsHelpFontSize->SetValue(btViewSettings.controlsHelpFontSize);
2495 m_controlsHelpColorPicker->SetColour(wxColour(btViewSettings.controlsHelpColor.r,
2496 btViewSettings.controlsHelpColor.g,
2497 btViewSettings.controlsHelpColor.b));
2499 m_controlsHelpAnchor->SetSelection(static_cast<int>(btViewSettings.controlsHelpAnchor));
2500 if (m_controlsHelpX)
2501 m_controlsHelpX->SetValue(btViewSettings.controlsHelpX);
2502 if (m_controlsHelpY)
2503 m_controlsHelpY->SetValue(btViewSettings.controlsHelpY);
2504
2505 // Bottom panel container settings
2506 const auto &bottomSettings = prefs.GetBottomPanelSettings();
2507 m_bottomPanelHeight->SetValue(bottomSettings.defaultPanelHeightPct);
2508 m_bottomPanelHeightEnabled->SetValue(bottomSettings.defaultPanelHeightEnabled);
2509 m_bottomPanelHeight->Enable(bottomSettings.defaultPanelHeightEnabled);
2510 m_bottomPanelMinHeight->SetValue(bottomSettings.minimumPanelHeightPct);
2511 m_bottomPanelMinHeightEnabled->SetValue(bottomSettings.minimumPanelHeightEnabled);
2512 m_bottomPanelMinHeight->Enable(bottomSettings.minimumPanelHeightEnabled);
2513 m_bottomPanelStartup->SetSelection(static_cast<int>(bottomSettings.panelStartupState));
2514 m_showTabCloseButtons->SetValue(bottomSettings.showTabCloseButtons);
2515 m_rememberLastTab->SetValue(bottomSettings.rememberLastTab);
2516 m_allowPanelCollapse->SetValue(bottomSettings.allowPanelCollapse);
2517
2518 // File Explorer tab general settings
2519 m_showBreadcrumb->SetValue(bottomSettings.showBreadcrumb);
2520 m_showHistory->SetValue(bottomSettings.showHistory);
2521
2522 // Start Path Mode
2523 int startPathModeIndex = static_cast<int>(bottomSettings.startPathMode);
2524 m_startPathMode->SetSelection(startPathModeIndex);
2525 m_customStartPath->SetValue(wxString(bottomSettings.customStartPath));
2526 bool enableCustomPath = (startPathModeIndex == 1); // CustomPath (second option)
2527 m_customStartPath->Enable(enableCustomPath);
2528 m_browseStartPath->Enable(enableCustomPath);
2529
2530 // Tree View settings
2531 m_treeShowHiddenFiles->SetValue(bottomSettings.treeView.showHiddenFiles);
2532 m_treeShowFileExtensions->SetValue(bottomSettings.treeView.showFileExtensions);
2533 m_treeSortFilesBy->SetSelection(static_cast<int>(bottomSettings.treeView.sortFilesBy));
2534
2535 // Tree Item Size
2536 int treeItemSizeIndex = 1; // Default to Medium
2537 switch (bottomSettings.treeView.itemSize) {
2539 treeItemSizeIndex = 0;
2540 break;
2542 treeItemSizeIndex = 1;
2543 break;
2545 treeItemSizeIndex = 2;
2546 break;
2547 }
2548 m_treeItemSize->SetSelection(treeItemSizeIndex);
2549
2550 // Grid View settings
2551 m_gridShowHiddenFiles->SetValue(bottomSettings.gridView.showHiddenFiles);
2552 m_gridShowFileExtensions->SetValue(bottomSettings.gridView.showFileExtensions);
2553 m_gridSortFilesBy->SetSelection(static_cast<int>(bottomSettings.gridView.sortFilesBy));
2554
2555 // Icon Size
2556 int iconSizeIndex = 1; // Default to Medium
2557 switch (bottomSettings.gridView.iconSize) {
2559 iconSizeIndex = 0;
2560 break;
2562 iconSizeIndex = 1;
2563 break;
2565 iconSizeIndex = 2;
2566 break;
2567 }
2568 m_gridIconSize->SetSelection(iconSizeIndex);
2569
2570 // Log Tab settings
2571 m_logDefaultLevelFilter->SetSelection(bottomSettings.logTab.defaultLevelFilter);
2572 m_logAutoScrollEnabled->SetValue(bottomSettings.logTab.autoScrollEnabled);
2573 m_logMaxEntries->SetValue(bottomSettings.logTab.maxLogEntries);
2574 m_logEnableGuiColors->SetValue(bottomSettings.logTab.enableGuiColors);
2575 m_logEnableConsoleColors->SetValue(bottomSettings.logTab.enableConsoleColors);
2576
2577 int logFontSizeIndex = 1; // Default to Medium
2578 switch (bottomSettings.logTab.fontSize) {
2580 logFontSizeIndex = 0;
2581 break;
2583 logFontSizeIndex = 1;
2584 break;
2586 logFontSizeIndex = 2;
2587 break;
2588 }
2589 m_logFontSize->SetSelection(logFontSizeIndex);
2590
2591 // Log level colors
2592 m_logTraceColor->SetColour(wxColour(bottomSettings.logTab.traceColor.r, bottomSettings.logTab.traceColor.g,
2593 bottomSettings.logTab.traceColor.b));
2594 m_logInfoColor->SetColour(wxColour(bottomSettings.logTab.infoColor.r, bottomSettings.logTab.infoColor.g,
2595 bottomSettings.logTab.infoColor.b));
2596 m_logWarningColor->SetColour(wxColour(bottomSettings.logTab.warningColor.r, bottomSettings.logTab.warningColor.g,
2597 bottomSettings.logTab.warningColor.b));
2598 m_logErrorColor->SetColour(wxColour(bottomSettings.logTab.errorColor.r, bottomSettings.logTab.errorColor.g,
2599 bottomSettings.logTab.errorColor.b));
2600 m_logCriticalColor->SetColour(wxColour(bottomSettings.logTab.criticalColor.r, bottomSettings.logTab.criticalColor.g,
2601 bottomSettings.logTab.criticalColor.b));
2602
2603 // Left Panel Settings
2604 const auto &leftSettings = prefs.GetLeftPanelSettings();
2605 m_leftPanelWidthEnabled->SetValue(leftSettings.defaultPanelWidthEnabled);
2606 m_leftPanelWidth->SetValue(leftSettings.defaultPanelWidthPct);
2607 m_leftPanelWidth->Enable(leftSettings.defaultPanelWidthEnabled);
2608 m_leftPanelMinWidthEnabled->SetValue(leftSettings.minimumPanelWidthEnabled);
2609 m_leftPanelMinWidth->SetValue(leftSettings.minimumPanelWidthPct);
2610 m_leftPanelMinWidth->Enable(leftSettings.minimumPanelWidthEnabled);
2611
2612 int leftPanelStartupIndex = 0;
2613 switch (leftSettings.panelStartupState) {
2615 leftPanelStartupIndex = 0;
2616 break;
2618 leftPanelStartupIndex = 1;
2619 break;
2621 leftPanelStartupIndex = 2;
2622 break;
2623 }
2624 m_leftPanelStartup->SetSelection(leftPanelStartupIndex);
2625
2626 m_leftPanelShowTabCloseButtons->SetValue(leftSettings.showTabCloseButtons);
2627 m_leftPanelRememberLastTab->SetValue(leftSettings.rememberLastTab);
2628 m_leftPanelAllowCollapse->SetValue(leftSettings.allowPanelCollapse);
2629
2630 // Right Panel Settings
2631 const auto &rightSettings = prefs.GetRightPanelSettings();
2632 m_rightPanelWidthEnabled->SetValue(rightSettings.defaultPanelWidthEnabled);
2633 m_rightPanelWidth->SetValue(rightSettings.defaultPanelWidthPct);
2634 m_rightPanelWidth->Enable(rightSettings.defaultPanelWidthEnabled);
2635 m_rightPanelMinWidthEnabled->SetValue(rightSettings.minimumPanelWidthEnabled);
2636 m_rightPanelMinWidth->SetValue(rightSettings.minimumPanelWidthPct);
2637 m_rightPanelMinWidth->Enable(rightSettings.minimumPanelWidthEnabled);
2638
2639 int rightPanelStartupIndex = 0;
2640 switch (rightSettings.panelStartupState) {
2642 rightPanelStartupIndex = 0;
2643 break;
2645 rightPanelStartupIndex = 1;
2646 break;
2648 rightPanelStartupIndex = 2;
2649 break;
2650 }
2651 m_rightPanelStartup->SetSelection(rightPanelStartupIndex);
2652
2653 m_rightPanelShowTabCloseButtons->SetValue(rightSettings.showTabCloseButtons);
2654 m_rightPanelRememberLastTab->SetValue(rightSettings.rememberLastTab);
2655 m_rightPanelAllowCollapse->SetValue(rightSettings.allowPanelCollapse);
2656
2657 // Parser settings
2658 m_autoLoadLastFile->SetValue(prefs.GetParserSettings().autoLoadLastFile);
2659 m_showParseWarnings->SetValue(prefs.GetParserSettings().showParseWarnings);
2660
2661 // Find encoding in list
2662 wxString encoding = prefs.GetParserSettings().defaultFileEncoding;
2663 int encodingIdx = m_fileEncoding->FindString(encoding);
2664 if (encodingIdx != wxNOT_FOUND) {
2665 m_fileEncoding->SetSelection(encodingIdx);
2666 } else {
2667 m_fileEncoding->SetSelection(0); // Default to UTF-8
2668 }
2669
2670 // Performance settings
2671 m_enableVSync->SetValue(prefs.GetPerformanceSettings().enableVSync);
2672 m_hardwareAcceleration->SetValue(prefs.GetPerformanceSettings().hardwareAcceleration);
2673 m_enableDoubleBuffering->SetValue(prefs.GetPerformanceSettings().enableDoubleBuffering);
2674 m_enableAntiAliasing->SetValue(prefs.GetPerformanceSettings().enableAntiAliasing);
2675 m_enableTextAntiAliasing->SetValue(prefs.GetPerformanceSettings().enableTextAntiAliasing);
2676 m_enablePartialRedraws->SetValue(prefs.GetPerformanceSettings().enablePartialRedraws);
2677 m_enableBackgroundErase->SetValue(prefs.GetPerformanceSettings().enableBackgroundErase);
2678 m_enableViewportCulling->SetValue(prefs.GetPerformanceSettings().enableViewportCulling);
2679 m_viewportCullingMargin->SetValue(prefs.GetPerformanceSettings().viewportCullingMargin);
2680 m_fpsLimit->SetSelection(static_cast<int>(prefs.GetPerformanceSettings().fpsLimit));
2681 m_enableIdleProcessing->SetValue(prefs.GetPerformanceSettings().enableIdleProcessing);
2682}
2683
2685 using namespace EmberForge;
2686 auto &prefs = AppPreferencesManager::GetInstance().GetPreferences();
2687
2688 // Window settings
2689 prefs.GetWindowSettings().theme = static_cast<AppPreferences::ThemeMode>(m_themeChoice->GetSelection());
2690 wxColour accentColor = m_accentColorPicker->GetColour();
2691 prefs.GetWindowSettings().accentColor =
2692 EmberCore::Color(accentColor.Red(), accentColor.Green(), accentColor.Blue());
2693 prefs.GetWindowSettings().startupMode =
2694 static_cast<AppPreferences::StartupMode>(m_startupModeChoice->GetSelection());
2695
2696 // File menu hotkeys
2697 prefs.GetWindowSettings().newProjectHotkey = m_newProjectHotkeyTextCtrl->GetValue().ToStdString();
2698 prefs.GetWindowSettings().openProjectHotkey = m_openProjectHotkeyTextCtrl->GetValue().ToStdString();
2699 prefs.GetWindowSettings().openFileHotkey = m_openFileHotkeyTextCtrl->GetValue().ToStdString();
2700 prefs.GetWindowSettings().saveHotkey = m_saveHotkeyTextCtrl->GetValue().ToStdString();
2701 prefs.GetWindowSettings().saveAsHotkey = m_saveAsHotkeyTextCtrl->GetValue().ToStdString();
2702
2703 // View menu hotkeys
2704 prefs.GetWindowSettings().maximizeHotkey = m_maximizeHotkeyTextCtrl->GetValue().ToStdString();
2705 prefs.GetWindowSettings().resetUIHotkey = m_resetUIHotkeyTextCtrl->GetValue().ToStdString();
2706
2707 // Settings menu hotkeys
2708 prefs.GetWindowSettings().preferencesHotkey = m_preferencesHotkeyTextCtrl->GetValue().ToStdString();
2709 prefs.GetWindowSettings().parserConfigHotkey = m_parserConfigHotkeyTextCtrl->GetValue().ToStdString();
2710
2711 // Window appearance
2712 prefs.GetWindowSettings().showStatusBar = m_showStatusBar->GetValue();
2713 prefs.GetWindowSettings().showPanelCaptions = m_showPanelCaptions->GetValue();
2714 prefs.GetWindowSettings().alwaysOnTop = m_alwaysOnTop->GetValue();
2715
2716 // Window constraints (percentage of screen)
2717 prefs.GetWindowSettings().minWindowWidthPct = m_minWindowWidth->GetValue();
2718 prefs.GetWindowSettings().minWindowHeightPct = m_minWindowHeight->GetValue();
2719 if (m_maxWindowUnlimited->GetValue()) {
2720 prefs.GetWindowSettings().maxWindowWidthPct = -1;
2721 prefs.GetWindowSettings().maxWindowHeightPct = -1;
2722 } else {
2723 prefs.GetWindowSettings().maxWindowWidthPct = m_maxWindowWidth->GetValue();
2724 prefs.GetWindowSettings().maxWindowHeightPct = m_maxWindowHeight->GetValue();
2725 }
2726 prefs.GetWindowSettings().enforceAspectRatio = m_enforceAspectRatio->GetValue();
2727
2728 // Parse aspect ratio from text fields
2729 long widthVal = 16, heightVal = 9;
2730 m_aspectRatioWidth->GetValue().ToLong(&widthVal);
2731 m_aspectRatioHeight->GetValue().ToLong(&heightVal);
2732 if (heightVal > 0) {
2733 prefs.GetWindowSettings().aspectRatio = static_cast<float>(widthVal) / static_cast<float>(heightVal);
2734 }
2735
2736 // Main panel settings
2737 prefs.GetMainPanelSettings().defaultZoomLevel = m_defaultZoomSlider->GetValue() / 100.0f;
2738 prefs.GetMainPanelSettings().showGrid = m_showGrid->GetValue();
2739 prefs.GetMainPanelSettings().gridSize = m_gridSize->GetValue();
2740 wxColour gridBg = m_gridBackgroundPicker->GetColour();
2741 prefs.GetMainPanelSettings().gridBackgroundColor = EmberCore::Color(gridBg.Red(), gridBg.Green(), gridBg.Blue());
2742 wxColour gridLineColor = m_gridLineColorPicker->GetColour();
2743 prefs.GetMainPanelSettings().gridLineColor =
2744 EmberCore::Color(gridLineColor.Red(), gridLineColor.Green(), gridLineColor.Blue());
2745 wxColour canvasBg = m_canvasBackgroundPicker->GetColour();
2746 prefs.GetMainPanelSettings().canvasBackgroundColor =
2747 EmberCore::Color(canvasBg.Red(), canvasBg.Green(), canvasBg.Blue());
2748 wxColour connectionLineColor = m_connectionLineColorPicker->GetColour();
2749 prefs.GetMainPanelSettings().connectionLineColor =
2750 EmberCore::Color(connectionLineColor.Red(), connectionLineColor.Green(), connectionLineColor.Blue());
2751 prefs.GetMainPanelSettings().highlightPathToSelected = m_highlightPathToSelected->GetValue();
2752 wxColour pathHighlightColor = m_pathHighlightColorPicker->GetColour();
2753 prefs.GetMainPanelSettings().pathHighlightColor =
2754 EmberCore::Color(pathHighlightColor.Red(), pathHighlightColor.Green(), pathHighlightColor.Blue());
2755 wxColour idleNodeBg = m_idleNodeBgColorPicker->GetColour();
2756 prefs.GetMainPanelSettings().idleNodeBgColor =
2757 EmberCore::Color(idleNodeBg.Red(), idleNodeBg.Green(), idleNodeBg.Blue());
2758 wxColour idleNodeBorder = m_idleNodeBorderColorPicker->GetColour();
2759 prefs.GetMainPanelSettings().idleNodeBorderColor =
2760 EmberCore::Color(idleNodeBorder.Red(), idleNodeBorder.Green(), idleNodeBorder.Blue());
2761 wxColour idleNodeText = m_idleNodeTextColorPicker->GetColour();
2762 prefs.GetMainPanelSettings().idleNodeTextColor =
2763 EmberCore::Color(idleNodeText.Red(), idleNodeText.Green(), idleNodeText.Blue());
2764 prefs.GetMainPanelSettings().selectedNodeBgTint = m_selectedNodeBgTint->GetValue() / 100.0f;
2765 prefs.GetMainPanelSettings().hoveredNodeBgTint = m_hoveredNodeBgTint->GetValue() / 100.0f;
2766 wxColour selectedNode = m_selectedNodeColorPicker->GetColour();
2767 prefs.GetMainPanelSettings().selectedNodeColor =
2768 EmberCore::Color(selectedNode.Red(), selectedNode.Green(), selectedNode.Blue());
2769 wxColour hoveredNode = m_hoveredNodeColorPicker->GetColour();
2770 prefs.GetMainPanelSettings().hoveredNodeColor =
2771 EmberCore::Color(hoveredNode.Red(), hoveredNode.Green(), hoveredNode.Blue());
2772 wxColour selectedNodeText = m_selectedNodeTextColorPicker->GetColour();
2773 prefs.GetMainPanelSettings().selectedNodeTextColor =
2774 EmberCore::Color(selectedNodeText.Red(), selectedNodeText.Green(), selectedNodeText.Blue());
2775 wxColour hoveredNodeText = m_hoveredNodeTextColorPicker->GetColour();
2776 prefs.GetMainPanelSettings().hoveredNodeTextColor =
2777 EmberCore::Color(hoveredNodeText.Red(), hoveredNodeText.Green(), hoveredNodeText.Blue());
2778 wxColour selectedNodeInfo = m_selectedNodeInfoColorPicker->GetColour();
2779 prefs.GetMainPanelSettings().selectedNodeInfoColor =
2780 EmberCore::Color(selectedNodeInfo.Red(), selectedNodeInfo.Green(), selectedNodeInfo.Blue());
2781 wxColour hoveredNodeInfo = m_hoveredNodeInfoColorPicker->GetColour();
2782 prefs.GetMainPanelSettings().hoveredNodeInfoColor =
2783 EmberCore::Color(hoveredNodeInfo.Red(), hoveredNodeInfo.Green(), hoveredNodeInfo.Blue());
2784
2785 // Scene management
2786 if (m_maxScenesUnlimited->GetValue()) {
2787 prefs.GetMainPanelSettings().maxScenes = -1;
2788 } else {
2789 prefs.GetMainPanelSettings().maxScenes = m_maxScenes->GetValue();
2790 }
2791
2792 prefs.GetMainPanelSettings().closeConfirmation =
2793 static_cast<AppPreferences::CloseConfirmationMode>(m_closeConfirmation->GetSelection());
2794
2795 prefs.GetMainPanelSettings().nextSceneHotkey = m_nextSceneHotkeyTextCtrl->GetValue().ToStdString();
2796 prefs.GetMainPanelSettings().previousSceneHotkey = m_previousSceneHotkeyTextCtrl->GetValue().ToStdString();
2797
2798 // Behavior tree view settings
2799 auto &btViewSettings = prefs.GetBehaviorTreeViewSettings();
2800
2801 // Convert zoom step size from percentage (1-50) to float (0.01-0.5)
2802 btViewSettings.zoomStepSize = m_zoomStepSize->GetValue() / 100.0f;
2803
2804 btViewSettings.mouseWheelSensitivity = m_mouseWheelSensitivity->GetValue() / 100.0f;
2805 btViewSettings.zoomFollowsCursor = m_zoomFollowsCursor->GetValue();
2806 btViewSettings.resetViewHotkey = m_resetViewHotkeyTextCtrl->GetValue().ToStdString();
2807 btViewSettings.panSensitivity = m_panSensitivity->GetValue() / 100.0f;
2808 btViewSettings.panKey = m_panKeyTextCtrl->GetValue().ToStdString();
2809 btViewSettings.enableSmoothPanning = m_enableSmoothPanning->GetValue();
2810 btViewSettings.panSmoothness = static_cast<float>(m_panSmoothness->GetValue());
2811 btViewSettings.panStepSize = static_cast<float>(m_panStepSize->GetValue());
2812 btViewSettings.centerOnNodeHotkey = m_centerOnNodeHotkeyTextCtrl->GetValue().ToStdString();
2813 btViewSettings.deleteNodeHotkey = m_deleteNodeHotkeyTextCtrl->GetValue().ToStdString();
2814 btViewSettings.panUpHotkey = m_panUpHotkeyTextCtrl->GetValue().ToStdString();
2815 btViewSettings.panDownHotkey = m_panDownHotkeyTextCtrl->GetValue().ToStdString();
2816 btViewSettings.panLeftHotkey = m_panLeftHotkeyTextCtrl->GetValue().ToStdString();
2817 btViewSettings.panRightHotkey = m_panRightHotkeyTextCtrl->GetValue().ToStdString();
2818
2819 // Debug text settings - Coordinate System Info
2821 btViewSettings.showCoordinateInfo = m_showCoordinateInfo->GetValue();
2823 btViewSettings.coordinateInfoFontSize = m_coordinateInfoFontSize->GetValue();
2825 wxColour coordColor = m_coordinateInfoColorPicker->GetColour();
2826 btViewSettings.coordinateInfoColor = EmberCore::Color(coordColor.Red(), coordColor.Green(), coordColor.Blue());
2827 }
2829 btViewSettings.coordinateInfoAnchor =
2832 btViewSettings.coordinateInfoX = m_coordinateInfoX->GetValue();
2834 btViewSettings.coordinateInfoY = m_coordinateInfoY->GetValue();
2835
2836 // Debug text settings - Selected Node Info
2838 btViewSettings.showSelectedNodeInfo = m_showSelectedNodeInfo->GetValue();
2840 btViewSettings.selectedNodeInfoFontSize = m_selectedNodeInfoFontSize->GetValue();
2842 wxColour selColor = m_selectedNodeDebugInfoColorPicker->GetColour();
2843 btViewSettings.selectedNodeInfoColor = EmberCore::Color(selColor.Red(), selColor.Green(), selColor.Blue());
2844 }
2846 btViewSettings.selectedNodeInfoAnchor =
2849 btViewSettings.selectedNodeInfoX = m_selectedNodeInfoX->GetValue();
2851 btViewSettings.selectedNodeInfoY = m_selectedNodeInfoY->GetValue();
2852
2853 // Debug text settings - Tree Statistics Info
2854 if (m_showTreeInfo)
2855 btViewSettings.showTreeInfo = m_showTreeInfo->GetValue();
2857 btViewSettings.treeInfoFontSize = m_treeInfoFontSize->GetValue();
2859 wxColour treeColor = m_treeInfoColorPicker->GetColour();
2860 btViewSettings.treeInfoColor = EmberCore::Color(treeColor.Red(), treeColor.Green(), treeColor.Blue());
2861 }
2862 if (m_treeInfoAnchor)
2863 btViewSettings.treeInfoAnchor =
2864 static_cast<EmberForge::AppPreferences::TextAnchor>(m_treeInfoAnchor->GetSelection());
2865 if (m_treeInfoX)
2866 btViewSettings.treeInfoX = m_treeInfoX->GetValue();
2867 if (m_treeInfoY)
2868 btViewSettings.treeInfoY = m_treeInfoY->GetValue();
2869
2870 // Debug text settings - FPS Display
2871 if (m_showFPS)
2872 btViewSettings.showFPS = m_showFPS->GetValue();
2873 if (m_fpsFontSize)
2874 btViewSettings.fpsFontSize = m_fpsFontSize->GetValue();
2875 if (m_fpsColorPicker) {
2876 wxColour fpsColor = m_fpsColorPicker->GetColour();
2877 btViewSettings.fpsColor = EmberCore::Color(fpsColor.Red(), fpsColor.Green(), fpsColor.Blue());
2878 }
2879 if (m_fpsAnchor)
2880 btViewSettings.fpsAnchor = static_cast<EmberForge::AppPreferences::TextAnchor>(m_fpsAnchor->GetSelection());
2881 if (m_fpsX)
2882 btViewSettings.fpsX = m_fpsX->GetValue();
2883 if (m_fpsY)
2884 btViewSettings.fpsY = m_fpsY->GetValue();
2885
2886 // Debug text settings - Controls Help Text
2888 btViewSettings.showControlsHelp = m_showControlsHelp->GetValue();
2890 btViewSettings.controlsHelpFontSize = m_controlsHelpFontSize->GetValue();
2892 wxColour ctrlColor = m_controlsHelpColorPicker->GetColour();
2893 btViewSettings.controlsHelpColor = EmberCore::Color(ctrlColor.Red(), ctrlColor.Green(), ctrlColor.Blue());
2894 }
2896 btViewSettings.controlsHelpAnchor =
2898 if (m_controlsHelpX)
2899 btViewSettings.controlsHelpX = m_controlsHelpX->GetValue();
2900 if (m_controlsHelpY)
2901 btViewSettings.controlsHelpY = m_controlsHelpY->GetValue();
2902
2903 // Bottom panel container settings
2904 auto &bottomSettings = prefs.GetBottomPanelSettings();
2905 bottomSettings.defaultPanelHeightPct = m_bottomPanelHeight->GetValue();
2906 bottomSettings.defaultPanelHeightEnabled = m_bottomPanelHeightEnabled->GetValue();
2907 bottomSettings.minimumPanelHeightPct = m_bottomPanelMinHeight->GetValue();
2908 bottomSettings.minimumPanelHeightEnabled = m_bottomPanelMinHeightEnabled->GetValue();
2909 bottomSettings.panelStartupState =
2910 static_cast<AppPreferences::PanelStartupState>(m_bottomPanelStartup->GetSelection());
2911 bottomSettings.showTabCloseButtons = m_showTabCloseButtons->GetValue();
2912 bottomSettings.rememberLastTab = m_rememberLastTab->GetValue();
2913 bottomSettings.allowPanelCollapse = m_allowPanelCollapse->GetValue();
2914
2915 // File Explorer tab general settings
2916 bottomSettings.showBreadcrumb = m_showBreadcrumb->GetValue();
2917 bottomSettings.showHistory = m_showHistory->GetValue();
2918
2919 // Start Path Mode
2920 bottomSettings.startPathMode = static_cast<AppPreferences::StartPathMode>(m_startPathMode->GetSelection());
2921 bottomSettings.customStartPath = m_customStartPath->GetValue().ToStdString();
2922
2923 // Tree View settings
2924 bottomSettings.treeView.showHiddenFiles = m_treeShowHiddenFiles->GetValue();
2925 bottomSettings.treeView.showFileExtensions = m_treeShowFileExtensions->GetValue();
2926 bottomSettings.treeView.sortFilesBy = static_cast<AppPreferences::SortBy>(m_treeSortFilesBy->GetSelection());
2927
2928 // Tree Item Size
2929 int treeItemSizeSelection = m_treeItemSize->GetSelection();
2930 switch (treeItemSizeSelection) {
2931 case 0:
2932 bottomSettings.treeView.itemSize = AppPreferences::TreeItemSize::Small;
2933 break;
2934 case 1:
2935 bottomSettings.treeView.itemSize = AppPreferences::TreeItemSize::Medium;
2936 break;
2937 case 2:
2938 bottomSettings.treeView.itemSize = AppPreferences::TreeItemSize::Large;
2939 break;
2940 default:
2941 bottomSettings.treeView.itemSize = AppPreferences::TreeItemSize::Small;
2942 break;
2943 }
2944
2945 // Grid View settings
2946 bottomSettings.gridView.showHiddenFiles = m_gridShowHiddenFiles->GetValue();
2947 bottomSettings.gridView.showFileExtensions = m_gridShowFileExtensions->GetValue();
2948 bottomSettings.gridView.sortFilesBy = static_cast<AppPreferences::SortBy>(m_gridSortFilesBy->GetSelection());
2949
2950 // Icon Size
2951 int iconSizeSelection = m_gridIconSize->GetSelection();
2952 switch (iconSizeSelection) {
2953 case 0:
2954 bottomSettings.gridView.iconSize = AppPreferences::IconSize::Small;
2955 break;
2956 case 1:
2957 bottomSettings.gridView.iconSize = AppPreferences::IconSize::Medium;
2958 break;
2959 case 2:
2960 bottomSettings.gridView.iconSize = AppPreferences::IconSize::Large;
2961 break;
2962 default:
2963 bottomSettings.gridView.iconSize = AppPreferences::IconSize::Medium;
2964 break;
2965 }
2966
2967 // Log Tab settings
2968 bottomSettings.logTab.defaultLevelFilter = m_logDefaultLevelFilter->GetSelection();
2969 bottomSettings.logTab.autoScrollEnabled = m_logAutoScrollEnabled->GetValue();
2970 bottomSettings.logTab.maxLogEntries = m_logMaxEntries->GetValue();
2971 bottomSettings.logTab.enableGuiColors = m_logEnableGuiColors->GetValue();
2972 bottomSettings.logTab.enableConsoleColors = m_logEnableConsoleColors->GetValue();
2973
2974 int logFontSizeSelection = m_logFontSize->GetSelection();
2975 switch (logFontSizeSelection) {
2976 case 0:
2977 bottomSettings.logTab.fontSize = AppPreferences::LogFontSize::Small;
2978 break;
2979 case 1:
2980 bottomSettings.logTab.fontSize = AppPreferences::LogFontSize::Medium;
2981 break;
2982 case 2:
2983 bottomSettings.logTab.fontSize = AppPreferences::LogFontSize::Large;
2984 break;
2985 default:
2986 bottomSettings.logTab.fontSize = AppPreferences::LogFontSize::Medium;
2987 break;
2988 }
2989
2990 // Log level colors
2991 wxColour traceCol = m_logTraceColor->GetColour();
2992 bottomSettings.logTab.traceColor = {traceCol.Red(), traceCol.Green(), traceCol.Blue()};
2993 wxColour infoCol = m_logInfoColor->GetColour();
2994 bottomSettings.logTab.infoColor = {infoCol.Red(), infoCol.Green(), infoCol.Blue()};
2995 wxColour warningCol = m_logWarningColor->GetColour();
2996 bottomSettings.logTab.warningColor = {warningCol.Red(), warningCol.Green(), warningCol.Blue()};
2997 wxColour errorCol = m_logErrorColor->GetColour();
2998 bottomSettings.logTab.errorColor = {errorCol.Red(), errorCol.Green(), errorCol.Blue()};
2999 wxColour criticalCol = m_logCriticalColor->GetColour();
3000 bottomSettings.logTab.criticalColor = {criticalCol.Red(), criticalCol.Green(), criticalCol.Blue()};
3001
3002 // Left Panel Settings
3003 auto &leftSettings = prefs.GetLeftPanelSettings();
3004 leftSettings.defaultPanelWidthEnabled = m_leftPanelWidthEnabled->GetValue();
3005 leftSettings.defaultPanelWidthPct = m_leftPanelWidth->GetValue();
3006 leftSettings.minimumPanelWidthEnabled = m_leftPanelMinWidthEnabled->GetValue();
3007 leftSettings.minimumPanelWidthPct = m_leftPanelMinWidth->GetValue();
3008
3009 int leftPanelStartupSelection = m_leftPanelStartup->GetSelection();
3011 switch (leftPanelStartupSelection) {
3012 case 0:
3013 leftStartupState = AppPreferences::PanelStartupState::Show;
3014 break;
3015 case 1:
3016 leftStartupState = AppPreferences::PanelStartupState::Hide;
3017 break;
3018 case 2:
3020 break;
3021 default:
3022 leftStartupState = AppPreferences::PanelStartupState::Show;
3023 break;
3024 }
3025 leftSettings.panelStartupState = leftStartupState;
3026
3027 leftSettings.showTabCloseButtons = m_leftPanelShowTabCloseButtons->GetValue();
3028 leftSettings.rememberLastTab = m_leftPanelRememberLastTab->GetValue();
3029 leftSettings.allowPanelCollapse = m_leftPanelAllowCollapse->GetValue();
3030
3031 // Right Panel Settings
3032 auto &rightSettings = prefs.GetRightPanelSettings();
3033 rightSettings.defaultPanelWidthEnabled = m_rightPanelWidthEnabled->GetValue();
3034 rightSettings.defaultPanelWidthPct = m_rightPanelWidth->GetValue();
3035 rightSettings.minimumPanelWidthEnabled = m_rightPanelMinWidthEnabled->GetValue();
3036 rightSettings.minimumPanelWidthPct = m_rightPanelMinWidth->GetValue();
3037
3038 int rightPanelStartupSelection = m_rightPanelStartup->GetSelection();
3040 switch (rightPanelStartupSelection) {
3041 case 0:
3042 rightStartupState = AppPreferences::PanelStartupState::Show;
3043 break;
3044 case 1:
3045 rightStartupState = AppPreferences::PanelStartupState::Hide;
3046 break;
3047 case 2:
3049 break;
3050 default:
3051 rightStartupState = AppPreferences::PanelStartupState::Show;
3052 break;
3053 }
3054 rightSettings.panelStartupState = rightStartupState;
3055
3056 rightSettings.showTabCloseButtons = m_rightPanelShowTabCloseButtons->GetValue();
3057 rightSettings.rememberLastTab = m_rightPanelRememberLastTab->GetValue();
3058 rightSettings.allowPanelCollapse = m_rightPanelAllowCollapse->GetValue();
3059
3060 // Parser settings
3061 prefs.GetParserSettings().autoLoadLastFile = m_autoLoadLastFile->GetValue();
3062 prefs.GetParserSettings().showParseWarnings = m_showParseWarnings->GetValue();
3063 prefs.GetParserSettings().defaultFileEncoding = m_fileEncoding->GetStringSelection().ToStdString();
3064
3065 // Performance settings
3066 prefs.GetPerformanceSettings().enableVSync = m_enableVSync->GetValue();
3067 prefs.GetPerformanceSettings().hardwareAcceleration = m_hardwareAcceleration->GetValue();
3068 prefs.GetPerformanceSettings().enableDoubleBuffering = m_enableDoubleBuffering->GetValue();
3069 prefs.GetPerformanceSettings().enableAntiAliasing = m_enableAntiAliasing->GetValue();
3070 prefs.GetPerformanceSettings().enableTextAntiAliasing = m_enableTextAntiAliasing->GetValue();
3071 prefs.GetPerformanceSettings().enablePartialRedraws = m_enablePartialRedraws->GetValue();
3072 prefs.GetPerformanceSettings().enableBackgroundErase = m_enableBackgroundErase->GetValue();
3073 prefs.GetPerformanceSettings().enableViewportCulling = m_enableViewportCulling->GetValue();
3074 prefs.GetPerformanceSettings().viewportCullingMargin = m_viewportCullingMargin->GetValue();
3075 prefs.GetPerformanceSettings().fpsLimit = static_cast<AppPreferences::FPSLimit>(m_fpsLimit->GetSelection());
3076 prefs.GetPerformanceSettings().enableIdleProcessing = m_enableIdleProcessing->GetValue();
3077
3078 // Save to file
3080 if (prefs.SaveToFile(configPath)) {
3081 LOG_INFO("Preferences", "Settings saved successfully");
3082 } else {
3083 LOG_ERROR("Preferences", "Failed to save settings");
3084 wxMessageBox("Failed to save preferences to file.", "Error", wxOK | wxICON_ERROR, this);
3085 }
3086}
3087
3089 using namespace EmberForge;
3090 AppPreferences defaultPrefs;
3091
3092 // Load defaults into controls
3093 auto &winSettings = defaultPrefs.GetWindowSettings();
3094 m_themeChoice->SetSelection(static_cast<int>(winSettings.theme));
3095 wxColour accentColor(winSettings.accentColor.r, winSettings.accentColor.g, winSettings.accentColor.b);
3096 m_accentColorPicker->SetColour(accentColor);
3097 m_startupModeChoice->SetSelection(static_cast<int>(winSettings.startupMode));
3098
3099 // File menu hotkeys defaults
3100 m_newProjectHotkeyTextCtrl->SetValue(wxString(winSettings.newProjectHotkey));
3101 m_openProjectHotkeyTextCtrl->SetValue(wxString(winSettings.openProjectHotkey));
3102 m_openFileHotkeyTextCtrl->SetValue(wxString(winSettings.openFileHotkey));
3103 m_saveHotkeyTextCtrl->SetValue(wxString(winSettings.saveHotkey));
3104 m_saveAsHotkeyTextCtrl->SetValue(wxString(winSettings.saveAsHotkey));
3105
3106 // View menu hotkeys defaults
3107 m_maximizeHotkeyTextCtrl->SetValue(wxString(winSettings.maximizeHotkey));
3108 m_resetUIHotkeyTextCtrl->SetValue(wxString(winSettings.resetUIHotkey));
3109
3110 // Settings menu hotkeys defaults
3111 m_preferencesHotkeyTextCtrl->SetValue(wxString(winSettings.preferencesHotkey));
3112 m_parserConfigHotkeyTextCtrl->SetValue(wxString(winSettings.parserConfigHotkey));
3113
3114 // Window appearance defaults
3115 m_showStatusBar->SetValue(winSettings.showStatusBar);
3116 m_showPanelCaptions->SetValue(winSettings.showPanelCaptions);
3117 m_alwaysOnTop->SetValue(winSettings.alwaysOnTop);
3118
3119 // Window constraints defaults (percentage of screen)
3120 m_minWindowWidth->SetValue(winSettings.minWindowWidthPct);
3121 m_minWindowHeight->SetValue(winSettings.minWindowHeightPct);
3122 bool maxUnlimited = (winSettings.maxWindowWidthPct == -1);
3123 m_maxWindowUnlimited->SetValue(maxUnlimited);
3124 m_maxWindowWidth->SetValue(winSettings.maxWindowWidthPct);
3125 m_maxWindowHeight->SetValue(winSettings.maxWindowHeightPct);
3126 m_maxWindowWidth->Enable(!maxUnlimited);
3127 m_maxWindowHeight->Enable(!maxUnlimited);
3128
3129 m_enforceAspectRatio->SetValue(winSettings.enforceAspectRatio);
3130 int width = 16, height = 9;
3131 float ratio = winSettings.aspectRatio;
3132 if (std::abs(ratio - 16.0f / 9.0f) < 0.01f) {
3133 width = 16;
3134 height = 9;
3135 } else if (std::abs(ratio - 4.0f / 3.0f) < 0.01f) {
3136 width = 4;
3137 height = 3;
3138 } else if (std::abs(ratio - 21.0f / 9.0f) < 0.01f) {
3139 width = 21;
3140 height = 9;
3141 }
3142 m_aspectRatioWidth->SetValue(wxString::Format("%d", width));
3143 m_aspectRatioHeight->SetValue(wxString::Format("%d", height));
3144
3145 auto &mainSettings = defaultPrefs.GetMainPanelSettings();
3146 int zoomPercent = static_cast<int>(mainSettings.defaultZoomLevel * 100);
3147 m_defaultZoomSlider->SetValue(zoomPercent);
3148 m_zoomLabel->SetLabel(wxString::Format("%d%%", zoomPercent));
3149 m_showGrid->SetValue(mainSettings.showGrid);
3150 m_gridSize->SetValue(mainSettings.gridSize);
3151 wxColour gridBg(mainSettings.gridBackgroundColor.r, mainSettings.gridBackgroundColor.g,
3152 mainSettings.gridBackgroundColor.b);
3153 m_gridBackgroundPicker->SetColour(gridBg);
3154 wxColour gridLineColor(mainSettings.gridLineColor.r, mainSettings.gridLineColor.g, mainSettings.gridLineColor.b);
3155 m_gridLineColorPicker->SetColour(gridLineColor);
3156 wxColour canvasBg(mainSettings.canvasBackgroundColor.r, mainSettings.canvasBackgroundColor.g,
3157 mainSettings.canvasBackgroundColor.b);
3158 m_canvasBackgroundPicker->SetColour(canvasBg);
3159 wxColour connectionLineColor(mainSettings.connectionLineColor.r, mainSettings.connectionLineColor.g,
3160 mainSettings.connectionLineColor.b);
3161 m_connectionLineColorPicker->SetColour(connectionLineColor);
3162 m_highlightPathToSelected->SetValue(mainSettings.highlightPathToSelected);
3163 wxColour pathHighlightColor(mainSettings.pathHighlightColor.r, mainSettings.pathHighlightColor.g,
3164 mainSettings.pathHighlightColor.b);
3165 m_pathHighlightColorPicker->SetColour(pathHighlightColor);
3166 wxColour idleNodeBg(mainSettings.idleNodeBgColor.r, mainSettings.idleNodeBgColor.g, mainSettings.idleNodeBgColor.b);
3167 m_idleNodeBgColorPicker->SetColour(idleNodeBg);
3168 wxColour idleNodeBorder(mainSettings.idleNodeBorderColor.r, mainSettings.idleNodeBorderColor.g,
3169 mainSettings.idleNodeBorderColor.b);
3170 m_idleNodeBorderColorPicker->SetColour(idleNodeBorder);
3171 wxColour idleNodeText(mainSettings.idleNodeTextColor.r, mainSettings.idleNodeTextColor.g,
3172 mainSettings.idleNodeTextColor.b);
3173 m_idleNodeTextColorPicker->SetColour(idleNodeText);
3174 int selectedTint = static_cast<int>(mainSettings.selectedNodeBgTint * 100);
3175 m_selectedNodeBgTint->SetValue(selectedTint);
3176 m_selectedNodeBgTintLabel->SetLabel(wxString::Format("%d%%", selectedTint));
3177 int hoveredTint = static_cast<int>(mainSettings.hoveredNodeBgTint * 100);
3178 m_hoveredNodeBgTint->SetValue(hoveredTint);
3179 m_hoveredNodeBgTintLabel->SetLabel(wxString::Format("%d%%", hoveredTint));
3180 wxColour selectedNode(mainSettings.selectedNodeColor.r, mainSettings.selectedNodeColor.g,
3181 mainSettings.selectedNodeColor.b);
3182 m_selectedNodeColorPicker->SetColour(selectedNode);
3183 wxColour hoveredNode(mainSettings.hoveredNodeColor.r, mainSettings.hoveredNodeColor.g,
3184 mainSettings.hoveredNodeColor.b);
3185 m_hoveredNodeColorPicker->SetColour(hoveredNode);
3186 wxColour selectedNodeText(mainSettings.selectedNodeTextColor.r, mainSettings.selectedNodeTextColor.g,
3187 mainSettings.selectedNodeTextColor.b);
3188 m_selectedNodeTextColorPicker->SetColour(selectedNodeText);
3189 wxColour hoveredNodeText(mainSettings.hoveredNodeTextColor.r, mainSettings.hoveredNodeTextColor.g,
3190 mainSettings.hoveredNodeTextColor.b);
3191 m_hoveredNodeTextColorPicker->SetColour(hoveredNodeText);
3192 wxColour selectedNodeInfo(mainSettings.selectedNodeInfoColor.r, mainSettings.selectedNodeInfoColor.g,
3193 mainSettings.selectedNodeInfoColor.b);
3194 m_selectedNodeInfoColorPicker->SetColour(selectedNodeInfo);
3195 wxColour hoveredNodeInfo(mainSettings.hoveredNodeInfoColor.r, mainSettings.hoveredNodeInfoColor.g,
3196 mainSettings.hoveredNodeInfoColor.b);
3197 m_hoveredNodeInfoColorPicker->SetColour(hoveredNodeInfo);
3198
3199 // Scene management defaults
3200 bool scenesUnlimited = (mainSettings.maxScenes == -1);
3201 m_maxScenesUnlimited->SetValue(scenesUnlimited);
3202 m_maxScenes->SetValue(mainSettings.maxScenes > 0 ? mainSettings.maxScenes : 10);
3203 m_maxScenes->Enable(!scenesUnlimited);
3204
3205 m_closeConfirmation->SetSelection(static_cast<int>(mainSettings.closeConfirmation));
3206
3207 m_nextSceneHotkeyTextCtrl->SetValue(wxString(mainSettings.nextSceneHotkey));
3208 m_previousSceneHotkeyTextCtrl->SetValue(wxString(mainSettings.previousSceneHotkey));
3209
3210 // Behavior tree view defaults
3211 auto &btViewSettings = defaultPrefs.GetBehaviorTreeViewSettings();
3212 int zoomStepPercent = static_cast<int>(btViewSettings.zoomStepSize * 100);
3213 m_zoomStepSize->SetValue(zoomStepPercent);
3214 m_zoomStepSizeLabel->SetLabel(wxString::Format("%d%%", zoomStepPercent));
3215 int wheelSensitivity = static_cast<int>(btViewSettings.mouseWheelSensitivity * 100);
3216 m_mouseWheelSensitivity->SetValue(wheelSensitivity);
3217 m_mouseWheelSensitivityLabel->SetLabel(wxString::Format("%.1fx", btViewSettings.mouseWheelSensitivity));
3218 m_zoomFollowsCursor->SetValue(btViewSettings.zoomFollowsCursor);
3219 m_resetViewHotkeyTextCtrl->SetValue(wxString(btViewSettings.resetViewHotkey));
3220 int panSensitivity = static_cast<int>(btViewSettings.panSensitivity * 100);
3221 m_panSensitivity->SetValue(panSensitivity);
3222 m_panSensitivityLabel->SetLabel(wxString::Format("%.1fx", btViewSettings.panSensitivity));
3223 m_panKeyTextCtrl->SetValue(wxString(btViewSettings.panKey));
3224 m_enableSmoothPanning->SetValue(btViewSettings.enableSmoothPanning);
3225 m_panSmoothness->SetValue(static_cast<int>(btViewSettings.panSmoothness));
3226 m_panSmoothnessLabel->SetLabel(wxString::Format("%d%%", static_cast<int>(btViewSettings.panSmoothness)));
3227 m_centerOnNodeHotkeyTextCtrl->SetValue(wxString(btViewSettings.centerOnNodeHotkey));
3228 m_deleteNodeHotkeyTextCtrl->SetValue(wxString(btViewSettings.deleteNodeHotkey));
3229 m_panUpHotkeyTextCtrl->SetValue(wxString(btViewSettings.panUpHotkey));
3230 m_panDownHotkeyTextCtrl->SetValue(wxString(btViewSettings.panDownHotkey));
3231 m_panLeftHotkeyTextCtrl->SetValue(wxString(btViewSettings.panLeftHotkey));
3232 m_panRightHotkeyTextCtrl->SetValue(wxString(btViewSettings.panRightHotkey));
3233
3234 auto &bottomSettings = defaultPrefs.GetBottomPanelSettings();
3235 // Bottom panel container settings
3236 m_bottomPanelHeight->SetValue(bottomSettings.defaultPanelHeightPct);
3237 m_bottomPanelHeightEnabled->SetValue(bottomSettings.defaultPanelHeightEnabled);
3238 m_bottomPanelHeight->Enable(bottomSettings.defaultPanelHeightEnabled);
3239 m_bottomPanelMinHeight->SetValue(bottomSettings.minimumPanelHeightPct);
3240 m_bottomPanelMinHeightEnabled->SetValue(bottomSettings.minimumPanelHeightEnabled);
3241 m_bottomPanelMinHeight->Enable(bottomSettings.minimumPanelHeightEnabled);
3242 m_bottomPanelStartup->SetSelection(static_cast<int>(bottomSettings.panelStartupState));
3243 m_showTabCloseButtons->SetValue(bottomSettings.showTabCloseButtons);
3244 m_rememberLastTab->SetValue(bottomSettings.rememberLastTab);
3245 m_allowPanelCollapse->SetValue(bottomSettings.allowPanelCollapse);
3246
3247 // File Explorer tab general settings
3248 m_showBreadcrumb->SetValue(bottomSettings.showBreadcrumb);
3249 m_showHistory->SetValue(bottomSettings.showHistory);
3250
3251 // Start Path Mode
3252 int defStartPathModeIndex = static_cast<int>(bottomSettings.startPathMode);
3253 m_startPathMode->SetSelection(defStartPathModeIndex);
3254 m_customStartPath->SetValue(wxString(bottomSettings.customStartPath));
3255 bool defEnableCustomPath = (defStartPathModeIndex == 1); // CustomPath (second option)
3256 m_customStartPath->Enable(defEnableCustomPath);
3257 m_browseStartPath->Enable(defEnableCustomPath);
3258
3259 // Tree View settings
3260 m_treeShowHiddenFiles->SetValue(bottomSettings.treeView.showHiddenFiles);
3261 m_treeShowFileExtensions->SetValue(bottomSettings.treeView.showFileExtensions);
3262 m_treeSortFilesBy->SetSelection(static_cast<int>(bottomSettings.treeView.sortFilesBy));
3263
3264 // Tree Item Size
3265 int defTreeItemSizeIndex = 1; // Default to Medium
3266 switch (bottomSettings.treeView.itemSize) {
3268 defTreeItemSizeIndex = 0;
3269 break;
3271 defTreeItemSizeIndex = 1;
3272 break;
3274 defTreeItemSizeIndex = 2;
3275 break;
3276 }
3277 m_treeItemSize->SetSelection(defTreeItemSizeIndex);
3278
3279 // Grid View settings
3280 m_gridShowHiddenFiles->SetValue(bottomSettings.gridView.showHiddenFiles);
3281 m_gridShowFileExtensions->SetValue(bottomSettings.gridView.showFileExtensions);
3282 m_gridSortFilesBy->SetSelection(static_cast<int>(bottomSettings.gridView.sortFilesBy));
3283
3284 // Icon Size
3285 int defIconSizeIndex = 1; // Default to Medium
3286 switch (bottomSettings.gridView.iconSize) {
3288 defIconSizeIndex = 0;
3289 break;
3291 defIconSizeIndex = 1;
3292 break;
3294 defIconSizeIndex = 2;
3295 break;
3296 }
3297 m_gridIconSize->SetSelection(defIconSizeIndex);
3298
3299 // Log Tab settings
3300 m_logDefaultLevelFilter->SetSelection(bottomSettings.logTab.defaultLevelFilter);
3301 m_logAutoScrollEnabled->SetValue(bottomSettings.logTab.autoScrollEnabled);
3302 m_logMaxEntries->SetValue(bottomSettings.logTab.maxLogEntries);
3303 m_logEnableGuiColors->SetValue(bottomSettings.logTab.enableGuiColors);
3304 m_logEnableConsoleColors->SetValue(bottomSettings.logTab.enableConsoleColors);
3305
3306 int defLogFontSizeIndex = 1; // Default to Medium
3307 switch (bottomSettings.logTab.fontSize) {
3309 defLogFontSizeIndex = 0;
3310 break;
3312 defLogFontSizeIndex = 1;
3313 break;
3315 defLogFontSizeIndex = 2;
3316 break;
3317 }
3318 m_logFontSize->SetSelection(defLogFontSizeIndex);
3319
3320 // Log level colors (defaults)
3321 m_logTraceColor->SetColour(wxColour(bottomSettings.logTab.traceColor.r, bottomSettings.logTab.traceColor.g,
3322 bottomSettings.logTab.traceColor.b));
3323 m_logInfoColor->SetColour(wxColour(bottomSettings.logTab.infoColor.r, bottomSettings.logTab.infoColor.g,
3324 bottomSettings.logTab.infoColor.b));
3325 m_logWarningColor->SetColour(wxColour(bottomSettings.logTab.warningColor.r, bottomSettings.logTab.warningColor.g,
3326 bottomSettings.logTab.warningColor.b));
3327 m_logErrorColor->SetColour(wxColour(bottomSettings.logTab.errorColor.r, bottomSettings.logTab.errorColor.g,
3328 bottomSettings.logTab.errorColor.b));
3329 m_logCriticalColor->SetColour(wxColour(bottomSettings.logTab.criticalColor.r, bottomSettings.logTab.criticalColor.g,
3330 bottomSettings.logTab.criticalColor.b));
3331
3332 // Left Panel Settings (defaults)
3333 const auto &defLeftSettings = defaultPrefs.GetLeftPanelSettings();
3334 m_leftPanelWidthEnabled->SetValue(defLeftSettings.defaultPanelWidthEnabled);
3335 m_leftPanelWidth->SetValue(defLeftSettings.defaultPanelWidthPct);
3336 m_leftPanelWidth->Enable(defLeftSettings.defaultPanelWidthEnabled);
3337 m_leftPanelMinWidthEnabled->SetValue(defLeftSettings.minimumPanelWidthEnabled);
3338 m_leftPanelMinWidth->SetValue(defLeftSettings.minimumPanelWidthPct);
3339 m_leftPanelMinWidth->Enable(defLeftSettings.minimumPanelWidthEnabled);
3340
3341 int defLeftPanelStartupIndex = 0;
3342 switch (defLeftSettings.panelStartupState) {
3344 defLeftPanelStartupIndex = 0;
3345 break;
3347 defLeftPanelStartupIndex = 1;
3348 break;
3350 defLeftPanelStartupIndex = 2;
3351 break;
3352 }
3353 m_leftPanelStartup->SetSelection(defLeftPanelStartupIndex);
3354
3355 m_leftPanelShowTabCloseButtons->SetValue(defLeftSettings.showTabCloseButtons);
3356 m_leftPanelRememberLastTab->SetValue(defLeftSettings.rememberLastTab);
3357 m_leftPanelAllowCollapse->SetValue(defLeftSettings.allowPanelCollapse);
3358
3359 // Right Panel Settings (defaults)
3360 const auto &defRightSettings = defaultPrefs.GetRightPanelSettings();
3361 m_rightPanelWidthEnabled->SetValue(defRightSettings.defaultPanelWidthEnabled);
3362 m_rightPanelWidth->SetValue(defRightSettings.defaultPanelWidthPct);
3363 m_rightPanelWidth->Enable(defRightSettings.defaultPanelWidthEnabled);
3364 m_rightPanelMinWidthEnabled->SetValue(defRightSettings.minimumPanelWidthEnabled);
3365 m_rightPanelMinWidth->SetValue(defRightSettings.minimumPanelWidthPct);
3366 m_rightPanelMinWidth->Enable(defRightSettings.minimumPanelWidthEnabled);
3367
3368 int defRightPanelStartupIndex = 0;
3369 switch (defRightSettings.panelStartupState) {
3371 defRightPanelStartupIndex = 0;
3372 break;
3374 defRightPanelStartupIndex = 1;
3375 break;
3377 defRightPanelStartupIndex = 2;
3378 break;
3379 }
3380 m_rightPanelStartup->SetSelection(defRightPanelStartupIndex);
3381
3382 m_rightPanelShowTabCloseButtons->SetValue(defRightSettings.showTabCloseButtons);
3383 m_rightPanelRememberLastTab->SetValue(defRightSettings.rememberLastTab);
3384 m_rightPanelAllowCollapse->SetValue(defRightSettings.allowPanelCollapse);
3385
3386 auto &parserSettings = defaultPrefs.GetParserSettings();
3387 m_autoLoadLastFile->SetValue(parserSettings.autoLoadLastFile);
3388 m_showParseWarnings->SetValue(parserSettings.showParseWarnings);
3389 m_fileEncoding->SetSelection(0); // UTF-8
3390
3391 auto &perfSettings = defaultPrefs.GetPerformanceSettings();
3392 m_enableVSync->SetValue(perfSettings.enableVSync);
3393 m_hardwareAcceleration->SetValue(perfSettings.hardwareAcceleration);
3394 m_enableDoubleBuffering->SetValue(perfSettings.enableDoubleBuffering);
3395 m_enableAntiAliasing->SetValue(perfSettings.enableAntiAliasing);
3396 m_enableTextAntiAliasing->SetValue(perfSettings.enableTextAntiAliasing);
3397 m_enablePartialRedraws->SetValue(perfSettings.enablePartialRedraws);
3398 m_enableBackgroundErase->SetValue(perfSettings.enableBackgroundErase);
3399 m_enableViewportCulling->SetValue(perfSettings.enableViewportCulling);
3400 m_viewportCullingMargin->SetValue(perfSettings.viewportCullingMargin);
3401 m_fpsLimit->SetSelection(static_cast<int>(perfSettings.fpsLimit));
3402 m_enableIdleProcessing->SetValue(perfSettings.enableIdleProcessing);
3403
3404 LOG_INFO("Preferences", "Settings restored to defaults (not saved yet)");
3405}
3406
3408 wxTreeItemId itemId = event.GetItem();
3409 if (!itemId.IsOk())
3410 return;
3411
3412 SectionTreeItemData *data = dynamic_cast<SectionTreeItemData *>(m_sectionTree->GetItemData(itemId));
3413 if (data && data->GetPanel()) {
3414 ShowPanel(data->GetPanel());
3415 }
3416}
3417
3418void PreferencesDialog::OnZoomSliderChanged(wxCommandEvent &event) {
3419 // Update labels depending on which slider triggered the event
3420 if (event.GetId() == ID_DEFAULT_ZOOM) {
3421 int zoomPercent = m_defaultZoomSlider->GetValue();
3422 m_zoomLabel->SetLabel(wxString::Format("%d%%", zoomPercent));
3423 } else if (event.GetId() == ID_ZOOM_STEP_SIZE) {
3424 int zoomStepPercent = m_zoomStepSize->GetValue();
3425 m_zoomStepSizeLabel->SetLabel(wxString::Format("%d%%", zoomStepPercent));
3426 } else if (event.GetId() == ID_SELECTED_NODE_BG_TINT) {
3427 int tintPercent = m_selectedNodeBgTint->GetValue();
3428 m_selectedNodeBgTintLabel->SetLabel(wxString::Format("%d%%", tintPercent));
3429 } else if (event.GetId() == ID_HOVERED_NODE_BG_TINT) {
3430 int tintPercent = m_hoveredNodeBgTint->GetValue();
3431 m_hoveredNodeBgTintLabel->SetLabel(wxString::Format("%d%%", tintPercent));
3432 }
3433}
3434
3436 // Update mouse wheel sensitivity label
3437 int value = m_mouseWheelSensitivity->GetValue();
3438 float sensitivity = value / 100.0f;
3439 m_mouseWheelSensitivityLabel->SetLabel(wxString::Format("%.1fx", sensitivity));
3440}
3441
3443 // Update pan sensitivity label
3444 int value = m_panSensitivity->GetValue();
3445 float sensitivity = value / 100.0f;
3446 m_panSensitivityLabel->SetLabel(wxString::Format("%.1fx", sensitivity));
3447}
3448
3450 // Update pan smoothness label
3451 int value = m_panSmoothness->GetValue();
3452 m_panSmoothnessLabel->SetLabel(wxString::Format("%d%%", value));
3453}
3454
3455void PreferencesDialog::OnPanStepSizeChanged(wxCommandEvent &event) {
3456 // Update pan step size label
3457 int value = m_panStepSize->GetValue();
3458 m_panStepSizeLabel->SetLabel(wxString::Format("%dpx", value));
3459}
3460
3461void PreferencesDialog::OnSliderMouseWheel(wxMouseEvent &event) {
3462 // Only allow mouse wheel events if the slider has focus (was clicked on)
3463 // This prevents sliders from intercepting scroll events meant for the page
3464 wxWindow *eventWindow = dynamic_cast<wxWindow *>(event.GetEventObject());
3465 if (eventWindow && eventWindow->HasFocus()) {
3466 // Allow the slider to handle the mouse wheel event
3467 event.Skip();
3468 }
3469 // If slider doesn't have focus, don't skip - this blocks the event
3470 // and allows it to propagate to the parent scroll window
3471}
3472
3473void PreferencesDialog::OnDialogMouseDown(wxMouseEvent &event) {
3474 // Only process if we're in capture mode (for hotkey capture)
3475 if (!m_capturingTextCtrl) {
3476 event.Skip();
3477 return;
3478 }
3479
3480 // Only capture if the text shows we're in capture mode
3481 wxString currentValue = m_capturingTextCtrl->GetValue();
3482 if (currentValue != "Press a key...") {
3483 // Capture mode ended
3484 if (HasCapture()) {
3485 ReleaseMouse();
3486 }
3487 m_capturingTextCtrl = nullptr;
3488 // Remove focus to stop capturing
3489 if (m_okButton) {
3490 m_okButton->SetFocus();
3491 }
3492 event.Skip();
3493 return;
3494 }
3495
3496 // Determine which mouse button was pressed
3497 wxString buttonName;
3498 wxString warningMessage;
3499
3500 if (event.LeftDown()) {
3501 buttonName = "Left Mouse Button";
3502 // Check if this is the pan key control
3504 warningMessage = "Warning: Left Mouse Button is the default for node selection.\n\n"
3505 "Setting it as the pan button will disable click-to-select functionality.\n\n"
3506 "Are you sure you want to use Left Mouse Button for panning?";
3507 }
3508 } else if (event.MiddleDown()) {
3509 buttonName = "Middle Mouse Button";
3510 } else if (event.RightDown()) {
3511 buttonName = "Right Mouse Button";
3512 // Check if this is the pan key control
3514 warningMessage = "Warning: Right Mouse Button is reserved for context menus.\n\n"
3515 "Setting it as the pan button may interfere with future context menu functionality.\n\n"
3516 "Are you sure you want to use Right Mouse Button for panning?";
3517 }
3518 }
3519
3520 if (!buttonName.IsEmpty()) {
3521 // Release mouse capture before showing message box
3522 // (modal dialogs don't work well with active mouse capture)
3523 if (HasCapture()) {
3524 ReleaseMouse();
3525 }
3526
3527 // Show warning if applicable
3528 if (!warningMessage.IsEmpty()) {
3529 int response = wxMessageBox(warningMessage, "Panning Button Warning", wxYES_NO | wxICON_WARNING, this);
3530 if (response != wxYES) {
3531 // User declined, reset capture state and clear the field
3532 m_capturingTextCtrl->SetValue("");
3533 m_capturingTextCtrl = nullptr;
3534 // Remove focus to stop capturing
3535 if (m_okButton) {
3536 m_okButton->SetFocus();
3537 }
3538 return;
3539 }
3540 }
3541
3542 // Set the value and clear capture state
3543 m_capturingTextCtrl->SetValue(buttonName);
3544 m_capturingTextCtrl = nullptr;
3545
3546 // Remove focus to stop capturing
3547 if (m_okButton) {
3548 m_okButton->SetFocus();
3549 }
3550 }
3551
3552 // Don't skip the event to prevent it from propagating further
3553}
3554
3556 // Enable/disable max window size controls based on checkbox
3557 bool unlimited = m_maxWindowUnlimited->GetValue();
3558 m_maxWindowWidth->Enable(!unlimited);
3559 m_maxWindowHeight->Enable(!unlimited);
3560}
3561
3563 // Enable/disable max scenes control based on checkbox
3564 bool unlimited = m_maxScenesUnlimited->GetValue();
3565 m_maxScenes->Enable(!unlimited);
3566}
3567
3569 // Enable/disable default panel height control based on checkbox
3570 bool enabled = m_bottomPanelHeightEnabled->GetValue();
3571 m_bottomPanelHeight->Enable(enabled);
3572}
3573
3575 // Enable/disable minimum panel height control based on checkbox
3576 bool enabled = m_bottomPanelMinHeightEnabled->GetValue();
3577 m_bottomPanelMinHeight->Enable(enabled);
3578}
3579
3581 // Enable/disable default panel width control based on checkbox
3582 bool enabled = m_leftPanelWidthEnabled->GetValue();
3583 m_leftPanelWidth->Enable(enabled);
3584}
3585
3587 // Enable/disable minimum panel width control based on checkbox
3588 bool enabled = m_leftPanelMinWidthEnabled->GetValue();
3589 m_leftPanelMinWidth->Enable(enabled);
3590}
3591
3593 // Enable/disable default panel width control based on checkbox
3594 bool enabled = m_rightPanelWidthEnabled->GetValue();
3595 m_rightPanelWidth->Enable(enabled);
3596}
3597
3599 // Enable/disable minimum panel width control based on checkbox
3600 bool enabled = m_rightPanelMinWidthEnabled->GetValue();
3601 m_rightPanelMinWidth->Enable(enabled);
3602}
3603
3605 wxButton *button = dynamic_cast<wxButton *>(event.GetEventObject());
3606 if (!button)
3607 return;
3608
3609 // Determine which hotkey is being captured
3610 wxTextCtrl *textCtrl = nullptr;
3611 // File menu hotkeys
3612 if (button == m_newProjectHotkeyCaptureButton) {
3613 textCtrl = m_newProjectHotkeyTextCtrl;
3614 } else if (button == m_openProjectHotkeyCaptureButton) {
3615 textCtrl = m_openProjectHotkeyTextCtrl;
3616 } else if (button == m_openFileHotkeyCaptureButton) {
3617 textCtrl = m_openFileHotkeyTextCtrl;
3618 } else if (button == m_saveHotkeyCaptureButton) {
3619 textCtrl = m_saveHotkeyTextCtrl;
3620 } else if (button == m_saveAsHotkeyCaptureButton) {
3621 textCtrl = m_saveAsHotkeyTextCtrl;
3622 // View menu hotkeys
3623 } else if (button == m_maximizeHotkeyCaptureButton) {
3624 textCtrl = m_maximizeHotkeyTextCtrl;
3625 } else if (button == m_resetUIHotkeyCaptureButton) {
3626 textCtrl = m_resetUIHotkeyTextCtrl;
3627 // Settings menu hotkeys
3628 } else if (button == m_preferencesHotkeyCaptureButton) {
3629 textCtrl = m_preferencesHotkeyTextCtrl;
3630 } else if (button == m_parserConfigHotkeyCaptureButton) {
3632 // Main panel hotkeys
3633 } else if (button == m_nextSceneHotkeyCaptureButton) {
3634 textCtrl = m_nextSceneHotkeyTextCtrl;
3635 } else if (button == m_previousSceneHotkeyCaptureButton) {
3637 } else if (button == m_resetViewHotkeyCaptureButton) {
3638 textCtrl = m_resetViewHotkeyTextCtrl;
3639 } else if (button == m_panKeyCaptureButton) {
3640 textCtrl = m_panKeyTextCtrl;
3641 } else if (button == m_centerOnNodeHotkeyCaptureButton) {
3643 } else if (button == m_deleteNodeHotkeyCaptureButton) {
3644 textCtrl = m_deleteNodeHotkeyTextCtrl;
3645 } else if (button == m_panUpHotkeyCaptureButton) {
3646 textCtrl = m_panUpHotkeyTextCtrl;
3647 } else if (button == m_panDownHotkeyCaptureButton) {
3648 textCtrl = m_panDownHotkeyTextCtrl;
3649 } else if (button == m_panLeftHotkeyCaptureButton) {
3650 textCtrl = m_panLeftHotkeyTextCtrl;
3651 } else if (button == m_panRightHotkeyCaptureButton) {
3652 textCtrl = m_panRightHotkeyTextCtrl;
3653 }
3654
3655 if (textCtrl) {
3656 textCtrl->SetValue("Press a key...");
3657 textCtrl->SetFocus();
3658
3659 // Set the capturing control and capture mouse at dialog level
3660 m_capturingTextCtrl = textCtrl;
3661 if (!HasCapture()) {
3662 CaptureMouse();
3663 }
3664 }
3665}
3666
3668 wxTextCtrl *textCtrl = dynamic_cast<wxTextCtrl *>(event.GetEventObject());
3669 if (!textCtrl) {
3670 event.Skip();
3671 return;
3672 }
3673
3674 // Only process if this is the text control we're capturing for
3675 // (prevents issues if focus somehow moves to a different control)
3676 if (m_capturingTextCtrl && m_capturingTextCtrl != textCtrl) {
3677 event.Skip();
3678 return;
3679 }
3680
3681 int keyCode = event.GetKeyCode();
3682
3683 // Handle Escape key specially - cancel capture mode without changing value
3684 if (keyCode == WXK_ESCAPE && textCtrl->GetValue() == "Press a key...") {
3685 textCtrl->SetValue(""); // Clear the field
3686 if (HasCapture()) {
3687 ReleaseMouse();
3688 }
3689 m_capturingTextCtrl = nullptr;
3690 // Remove focus to stop capturing
3691 if (m_okButton) {
3692 m_okButton->SetFocus();
3693 }
3694 return;
3695 }
3696
3697 wxString hotkeyStr;
3698
3699 // Build modifier string
3700 if (event.ControlDown())
3701 hotkeyStr += "Ctrl+";
3702 if (event.AltDown())
3703 hotkeyStr += "Alt+";
3704 if (event.ShiftDown())
3705 hotkeyStr += "Shift+";
3706
3707 // Add key name
3708 if (keyCode >= WXK_F1 && keyCode <= WXK_F12) {
3709 hotkeyStr += wxString::Format("F%d", keyCode - WXK_F1 + 1);
3710 } else if (keyCode >= 'A' && keyCode <= 'Z') {
3711 hotkeyStr += wxChar(keyCode);
3712 } else if (keyCode >= '0' && keyCode <= '9') {
3713 hotkeyStr += wxChar(keyCode);
3714 } else {
3715 // Map special keys
3716 switch (keyCode) {
3717 case WXK_ESCAPE:
3718 hotkeyStr += "Esc";
3719 break;
3720 case WXK_SPACE:
3721 hotkeyStr += "Space";
3722 break;
3723 case WXK_RETURN:
3724 hotkeyStr += "Enter";
3725 break;
3726 case WXK_TAB:
3727 hotkeyStr += "Tab";
3728 break;
3729 case WXK_BACK:
3730 hotkeyStr += "Backspace";
3731 break;
3732 case WXK_DELETE:
3733 hotkeyStr += "Delete";
3734 break;
3735 case WXK_INSERT:
3736 hotkeyStr += "Insert";
3737 break;
3738 case WXK_HOME:
3739 hotkeyStr += "Home";
3740 break;
3741 case WXK_END:
3742 hotkeyStr += "End";
3743 break;
3744 case WXK_PAGEUP:
3745 hotkeyStr += "PageUp";
3746 break;
3747 case WXK_PAGEDOWN:
3748 hotkeyStr += "PageDown";
3749 break;
3750 case WXK_LEFT:
3751 hotkeyStr += "Left";
3752 break;
3753 case WXK_RIGHT:
3754 hotkeyStr += "Right";
3755 break;
3756 case WXK_UP:
3757 hotkeyStr += "Up";
3758 break;
3759 case WXK_DOWN:
3760 hotkeyStr += "Down";
3761 break;
3762 default:
3763 textCtrl->SetValue("Unsupported key");
3764 if (HasCapture()) {
3765 ReleaseMouse();
3766 }
3767 m_capturingTextCtrl = nullptr;
3768 // Remove focus to stop capturing
3769 if (m_okButton) {
3770 m_okButton->SetFocus();
3771 }
3772 return;
3773 }
3774 }
3775
3776 textCtrl->SetValue(hotkeyStr);
3777
3778 // Release the mouse capture after successfully capturing a key
3779 if (HasCapture()) {
3780 ReleaseMouse();
3781 }
3782 m_capturingTextCtrl = nullptr;
3783
3784 // Remove focus from the text control to stop capturing further keys
3785 // Transfer focus to the OK button (or any other safe control)
3786 if (m_okButton) {
3787 m_okButton->SetFocus();
3788 }
3789}
3790
3791void PreferencesDialog::OnOK(wxCommandEvent &event) {
3792 // Release mouse capture if active
3793 if (HasCapture()) {
3794 ReleaseMouse();
3795 }
3796 m_capturingTextCtrl = nullptr;
3797
3798 ApplySettings();
3799 EndModal(wxID_OK);
3800}
3801
3802void PreferencesDialog::OnCancel(wxCommandEvent &event) {
3803 // Release mouse capture if active
3804 if (HasCapture()) {
3805 ReleaseMouse();
3806 }
3807 m_capturingTextCtrl = nullptr;
3808
3809 EndModal(wxID_CANCEL);
3810}
3811
3812void PreferencesDialog::OnApply(wxCommandEvent &event) {
3813 ApplySettings();
3814
3815 // Notify parent frame to refresh UI with new settings
3816 MainFrame *mainFrame = dynamic_cast<MainFrame *>(GetParent());
3817 if (mainFrame) {
3818 mainFrame->RefreshPreferences();
3819 }
3820}
3821
3822void PreferencesDialog::OnRestoreDefaults(wxCommandEvent &event) {
3823 int result = wxMessageBox("This will restore all settings to their default values. Continue?", "Restore Defaults",
3824 wxYES_NO | wxICON_QUESTION, this);
3825 if (result == wxYES) {
3827 }
3828}
3829
3830void PreferencesDialog::OnConfigureParser(wxCommandEvent &event) {
3831 ParserConfigDialog dialog(this);
3832 dialog.ShowModal();
3833}
3834
3836 // Enable/disable custom path controls based on selection
3838 int selection = m_startPathMode->GetSelection();
3839 bool enableCustomPath = (selection == 1); // "Custom Path" is the second option
3840 m_customStartPath->Enable(enableCustomPath);
3841 m_browseStartPath->Enable(enableCustomPath);
3842 }
3843}
3844
3845void PreferencesDialog::OnBrowseStartPath(wxCommandEvent &event) {
3846 wxDirDialog dialog(this, "Choose Start Directory", m_customStartPath->GetValue(),
3847 wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
3848
3849 if (dialog.ShowModal() == wxID_OK) {
3850 m_customStartPath->SetValue(dialog.GetPath());
3851 }
3852}
BehaviorTreeProjectDialog::OnProjectNameChanged BehaviorTreeProjectDialog::OnRemoveFiles wxEND_EVENT_TABLE() BehaviorTreeProjectDialog
#define LOG_ERROR(category, message)
Definition Logger.h:116
#define LOG_INFO(category, message)
Definition Logger.h:114
MainFrame::OnExit MainFrame::OnNewProject MainFrame::OnCloseProject MainFrame::OnToggleMaximize MainFrame::OnPreviousScene MainFrame::OnPreferences MainFrame::OnEditorTool EVT_BUTTON(ID_MonitorTool, MainFrame::OnMonitorTool) EVT_PAINT(MainFrame
Definition MainFrame.cpp:63
ParserConfigDialog::OnProfileSelected ParserConfigDialog::OnCloneProfile ParserConfigDialog::OnImportProfile ParserConfigDialog::OnSetActiveProfile ParserConfigDialog::OnRemoveControlType ParserConfigDialog::OnRemoveDecoratorType ParserConfigDialog::OnRemoveActionType EVT_CHECKBOX(ID_TOGGLE_CUSTOM_VALIDATION, ParserConfigDialog::OnToggleCustomValidation) EVT_TIMER(ID_PULSE_TIMER
wxBEGIN_EVENT_TABLE(PreferencesDialog, EmberUI::ScalableDialog) EVT_BUTTON(wxID_OK
static AppPreferencesManager & GetInstance()
Application preferences configuration.
PerformanceSettings & GetPerformanceSettings()
BehaviorTreeViewSettings & GetBehaviorTreeViewSettings()
StartupMode
Startup mode enumeration.
FPSLimit
Frame rate limit options.
PanelStartupState
Panel startup state options.
LeftPanelSettings & GetLeftPanelSettings()
SortBy
File sorting criteria.
CloseConfirmationMode
Close confirmation behavior for scenes.
MainPanelSettings & GetMainPanelSettings()
RightPanelSettings & GetRightPanelSettings()
TextAnchor
Text anchor position for debug info overlay.
BottomPanelSettings & GetBottomPanelSettings()
ParserSettings & GetParserSettings()
ThemeMode
Theme mode enumeration.
StartPathMode
Default start path behavior.
WindowSettings & GetWindowSettings()
static EmberCore::String GetDefaultConfigPath()
DPI-aware dialog base class for scalable layouts.
Main application window for EmberForge.
Definition MainFrame.h:67
void RefreshPreferences()
Comprehensive dialog for managing parser configuration profiles.
Preferences dialog for configuring EmberForge application settings.
wxTextCtrl * m_customStartPath
wxSlider * m_hoveredNodeBgTint
wxCheckBox * m_treeShowHiddenFiles
wxCheckBox * m_rightPanelShowTabCloseButtons
wxButton * m_preferencesHotkeyCaptureButton
wxPanel * CreateParserSettings(wxWindow *parent)
wxCheckBox * m_allowPanelCollapse
wxCheckBox * m_zoomFollowsCursor
wxSpinCtrl * m_coordinateInfoX
wxColourPickerCtrl * m_coordinateInfoColorPicker
wxChoice * m_startupModeChoice
wxCheckBox * m_rightPanelWidthEnabled
wxCheckBox * m_showPanelCaptions
wxCheckBox * m_leftPanelRememberLastTab
void OnCancel(wxCommandEvent &event)
wxBoxSizer * m_settingsSizer
wxCheckBox * m_logAutoScrollEnabled
wxCheckBox * m_leftPanelWidthEnabled
wxColourPickerCtrl * m_hoveredNodeTextColorPicker
wxColourPickerCtrl * m_treeInfoColorPicker
void OnLeftPanelMinWidthEnabledChanged(wxCommandEvent &event)
wxTextCtrl * m_panUpHotkeyTextCtrl
wxChoice * m_rightPanelStartup
wxPanel * CreateRightPanelSettings(wxWindow *parent)
wxSpinCtrl * m_minWindowHeight
wxColourPickerCtrl * m_logErrorColor
wxButton * m_previousSceneHotkeyCaptureButton
wxSpinCtrl * m_bottomPanelMinHeight
wxChoice * m_selectedNodeInfoAnchor
wxCheckBox * m_enableAntiAliasing
wxCheckBox * m_bottomPanelMinHeightEnabled
wxPanel * CreateLogTabSettings(wxWindow *parent)
void OnPanSensitivityChanged(wxCommandEvent &event)
wxTextCtrl * m_aspectRatioHeight
void OnApply(wxCommandEvent &event)
wxStaticText * m_hoveredNodeBgTintLabel
wxColourPickerCtrl * m_canvasBackgroundPicker
wxCheckBox * m_showTreeInfo
wxCheckBox * m_logEnableGuiColors
wxButton * m_panRightHotkeyCaptureButton
void OnDialogMouseDown(wxMouseEvent &event)
wxSpinCtrl * m_rightPanelMinWidth
wxButton * m_centerOnNodeHotkeyCaptureButton
wxCheckBox * m_autoLoadLastFile
wxTextCtrl * m_preferencesHotkeyTextCtrl
wxButton * m_maximizeHotkeyCaptureButton
wxButton * m_nextSceneHotkeyCaptureButton
wxCheckBox * m_leftPanelMinWidthEnabled
wxColourPickerCtrl * m_controlsHelpColorPicker
wxSpinCtrl * m_controlsHelpFontSize
void OnBrowseStartPath(wxCommandEvent &event)
wxStaticText * m_panSmoothnessLabel
wxCheckBox * m_showControlsHelp
wxCheckBox * m_showSelectedNodeInfo
void OnPanSmoothnessChanged(wxCommandEvent &event)
wxColourPickerCtrl * m_logInfoColor
wxColourPickerCtrl * m_gridBackgroundPicker
wxTextCtrl * m_centerOnNodeHotkeyTextCtrl
void ShowPanel(wxPanel *panel)
wxCheckBox * m_showHistory
wxTextCtrl * m_previousSceneHotkeyTextCtrl
wxStaticText * m_selectedNodeBgTintLabel
wxChoice * m_controlsHelpAnchor
wxColourPickerCtrl * m_logTraceColor
wxColourPickerCtrl * m_idleNodeTextColorPicker
wxButton * m_resetViewHotkeyCaptureButton
wxColourPickerCtrl * m_hoveredNodeColorPicker
wxCheckBox * m_showCoordinateInfo
wxCheckBox * m_maxScenesUnlimited
wxCheckBox * m_hardwareAcceleration
wxSpinCtrl * m_coordinateInfoFontSize
wxColourPickerCtrl * m_idleNodeBorderColorPicker
wxButton * m_newProjectHotkeyCaptureButton
wxCheckBox * m_alwaysOnTop
void OnPanStepSizeChanged(wxCommandEvent &event)
wxButton * m_panLeftHotkeyCaptureButton
void OnMaxScenesUnlimitedChanged(wxCommandEvent &event)
wxSpinCtrl * m_controlsHelpX
wxButton * m_panUpHotkeyCaptureButton
wxButton * m_configureParserButton
PreferencesDialog(wxWindow *parent)
wxCheckBox * m_rightPanelMinWidthEnabled
wxChoice * m_coordinateInfoAnchor
wxSpinCtrl * m_selectedNodeInfoY
wxSpinCtrl * m_maxWindowWidth
wxSpinCtrl * m_selectedNodeInfoX
wxButton * m_panKeyCaptureButton
wxColourPickerCtrl * m_pathHighlightColorPicker
wxTextCtrl * m_parserConfigHotkeyTextCtrl
wxTextCtrl * m_maximizeHotkeyTextCtrl
wxCheckBox * m_leftPanelShowTabCloseButtons
wxSpinCtrl * m_selectedNodeInfoFontSize
wxStaticText * m_zoomStepSizeLabel
wxCheckBox * m_enforceAspectRatio
wxStaticText * m_mouseWheelSensitivityLabel
wxCheckBox * m_treeShowFileExtensions
wxCheckBox * m_enableIdleProcessing
void OnMaxWindowUnlimitedChanged(wxCommandEvent &event)
wxPanel * CreateTabsSubSettings(wxWindow *parent)
void OnStartPathModeChanged(wxCommandEvent &event)
wxCheckBox * m_highlightPathToSelected
wxTextCtrl * m_panDownHotkeyTextCtrl
wxCheckBox * m_showParseWarnings
wxCheckBox * m_bottomPanelHeightEnabled
wxSlider * m_mouseWheelSensitivity
wxButton * m_parserConfigHotkeyCaptureButton
void OnHotkeyTextKeyDown(wxKeyEvent &event)
wxColourPickerCtrl * m_logCriticalColor
void OnHotkeyCaptureClicked(wxCommandEvent &event)
void OnSectionSelected(wxTreeEvent &event)
wxColourPickerCtrl * m_hoveredNodeInfoColorPicker
wxCheckBox * m_enableTextAntiAliasing
wxCheckBox * m_enableVSync
wxStaticText * m_panStepSizeLabel
wxSpinCtrl * m_rightPanelWidth
wxButton * m_resetUIHotkeyCaptureButton
void OnOK(wxCommandEvent &event)
wxButton * m_openFileHotkeyCaptureButton
wxColourPickerCtrl * m_fpsColorPicker
wxCheckBox * m_logEnableConsoleColors
wxPanel * CreatePerformanceSettings(wxWindow *parent)
wxSlider * m_selectedNodeBgTint
wxTextCtrl * m_panLeftHotkeyTextCtrl
wxButton * m_deleteNodeHotkeyCaptureButton
wxTextCtrl * m_openProjectHotkeyTextCtrl
void OnRightPanelMinWidthEnabledChanged(wxCommandEvent &event)
wxPanel * CreateBehaviorTreeViewSettings(wxWindow *parent)
wxTextCtrl * m_saveAsHotkeyTextCtrl
wxCheckBox * m_leftPanelAllowCollapse
wxTextCtrl * m_panKeyTextCtrl
wxCheckBox * m_enableDoubleBuffering
wxCheckBox * m_maxWindowUnlimited
bool SelectSection(const wxString &sectionName)
Select a section in the preferences tree by name.
wxColourPickerCtrl * m_selectedNodeInfoColorPicker
wxPanel * CreateMainPanelSettings(wxWindow *parent)
wxCheckBox * m_enableBackgroundErase
void OnBottomPanelHeightEnabledChanged(wxCommandEvent &event)
wxPanel * CreateBottomPanelSettings(wxWindow *parent)
wxStaticText * m_panSensitivityLabel
wxSpinCtrl * m_leftPanelMinWidth
wxPanel * CreateSidePanelSettings(wxWindow *parent)
wxCheckBox * m_gridShowFileExtensions
wxPanel * m_behaviorTreeViewPanel
wxColourPickerCtrl * m_accentColorPicker
wxTextCtrl * m_capturingTextCtrl
wxChoice * m_closeConfirmation
wxTextCtrl * m_resetViewHotkeyTextCtrl
wxColourPickerCtrl * m_selectedNodeDebugInfoColorPicker
wxColourPickerCtrl * m_selectedNodeTextColorPicker
wxScrolledWindow * m_settingsPanel
wxButton * m_openProjectHotkeyCaptureButton
wxSpinCtrl * m_coordinateInfoY
void OnLeftPanelWidthEnabledChanged(wxCommandEvent &event)
wxCheckBox * m_showTabCloseButtons
wxTextCtrl * m_resetUIHotkeyTextCtrl
wxButton * m_panDownHotkeyCaptureButton
wxColourPickerCtrl * m_selectedNodeColorPicker
wxButton * m_restoreDefaultsButton
wxButton * m_saveAsHotkeyCaptureButton
wxTextCtrl * m_nextSceneHotkeyTextCtrl
wxCheckBox * m_gridShowHiddenFiles
wxSpinCtrl * m_minWindowWidth
wxTextCtrl * m_panRightHotkeyTextCtrl
wxChoice * m_bottomPanelStartup
wxSpinCtrl * m_fpsFontSize
wxTextCtrl * m_saveHotkeyTextCtrl
void OnZoomSliderChanged(wxCommandEvent &event)
void OnBottomPanelMinHeightEnabledChanged(wxCommandEvent &event)
wxSpinCtrl * m_maxWindowHeight
wxSplitterWindow * m_splitter
wxSpinCtrl * m_viewportCullingMargin
wxSpinCtrl * m_controlsHelpY
wxSpinCtrl * m_leftPanelWidth
wxTextCtrl * m_newProjectHotkeyTextCtrl
wxSlider * m_defaultZoomSlider
wxColourPickerCtrl * m_idleNodeBgColorPicker
wxColourPickerCtrl * m_logWarningColor
wxButton * m_saveHotkeyCaptureButton
wxCheckBox * m_showStatusBar
wxTextCtrl * m_aspectRatioWidth
wxPanel * CreateFileExplorerTabSettings(wxWindow *parent)
wxChoice * m_leftPanelStartup
wxTreeCtrl * m_sectionTree
wxTextCtrl * m_openFileHotkeyTextCtrl
void OnConfigureParser(wxCommandEvent &event)
wxCheckBox * m_enableSmoothPanning
wxCheckBox * m_rightPanelAllowCollapse
wxColourPickerCtrl * m_gridLineColorPicker
wxTextCtrl * m_deleteNodeHotkeyTextCtrl
wxCheckBox * m_rightPanelRememberLastTab
wxStaticText * m_zoomLabel
wxSpinCtrl * m_treeInfoFontSize
wxCheckBox * m_showBreadcrumb
void OnRightPanelWidthEnabledChanged(wxCommandEvent &event)
void OnMouseWheelSensitivityChanged(wxCommandEvent &event)
wxCheckBox * m_rememberLastTab
void OnRestoreDefaults(wxCommandEvent &event)
wxCheckBox * m_enableViewportCulling
wxSpinCtrl * m_bottomPanelHeight
wxCheckBox * m_enablePartialRedraws
wxPanel * CreateLeftPanelSettings(wxWindow *parent)
wxSpinCtrl * m_logMaxEntries
wxColourPickerCtrl * m_connectionLineColorPicker
void OnSliderMouseWheel(wxMouseEvent &event)
wxPanel * CreateWindowSettings(wxWindow *parent)
wxChoice * m_logDefaultLevelFilter
std::string String
Framework-agnostic string type.
Definition String.h:14
Definition Panel.h:8
RGBA color with 8-bit components.
Definition Color.h:10