Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
BlueprintEditorGUI.cpp
Go to the documentation of this file.
1/*
2 * Olympe Blueprint Editor GUI - Frontend Implementation
3 * All data operations delegate to BlueprintEditor backend
4 */
5
7#include "BlueprintEditor.h"
9#include "HistoryPanel.h"
10#include "../third_party/imgui/imgui.h"
11#include "../third_party/imnodes/imnodes.h"
12#include <iostream>
13
14using namespace Olympe::Blueprint;
15
16namespace Olympe
17{
19 : m_SelectedComponentIndex(-1)
20 , m_NextNodeId(0)
21 , m_ShowDemoWindow(false)
22 , m_ShowAddComponentDialog(false)
23 , m_ShowAboutDialog(false)
24 , m_SelectedComponentType(0)
25 , m_ShowAssetBrowser(true) // Main panel 1
26 , m_ShowAssetInfo(false) // Deprecated - merged into Inspector
27 , m_ShowInspector(true) // Main panel 3
28 , m_ShowNodeGraph(true) // Main panel 2
29 , m_ShowEntities(false) // Deprecated - merged into Asset Browser tab
30 , m_ShowEntityProperties(false) // Deprecated - merged into Inspector
31 , m_ShowComponentGraph(false) // Deprecated
32 , m_ShowPropertyPanel(false) // Deprecated - merged into Inspector
33 , m_ShowTemplateBrowser(false)
34 , m_ShowHistory(false)
35 , m_ShowPreferences(false)
36 , m_ShowShortcuts(false)
37 , m_TemplateBrowserPanel(nullptr)
38 , m_HistoryPanel(nullptr)
39 {
41 m_FilepathBuffer[0] = '\0';
42 }
43
45 {
47 {
48 delete m_HistoryPanel;
49 m_HistoryPanel = nullptr;
50 }
51
53 {
55 m_TemplateBrowserPanel = nullptr;
56 }
57 }
58
60 {
61 // Initialize ImNodes
62 ImNodes::CreateContext();
63 ImNodes::StyleColorsDark();
64
65 // Configure ImNodes style
66 ImNodesStyle& style = ImNodes::GetStyle();
68
69 // Initialize Asset Browser with Blueprints directory
70 m_AssetBrowser.Initialize("Blueprints");
71
72 // Set up callback for asset selection
73 m_AssetBrowser.SetAssetOpenCallback([this](const std::string& path) {
74 LoadBlueprint(path);
75 });
76
77 // Initialize new panels
81
82 // Initialize template browser panel
85
86 // Initialize history panel
89 }
90
92 {
93 // Shutdown panels
95 {
97 delete m_HistoryPanel;
98 m_HistoryPanel = nullptr;
99 }
100
102 {
105 m_TemplateBrowserPanel = nullptr;
106 }
107
111
112 ImNodes::DestroyContext();
113 }
114
116 {
117 // Only render if the backend is active
118 if (!BlueprintEditor::Get().IsActive())
119 {
120 return;
121 }
122
123 // Handle keyboard shortcuts
125
126 // Get backend reference for data access
128 const auto& blueprint = backend.GetCurrentBlueprint();
129
130 // Render menu bar in main viewport
131 if (ImGui::BeginMainMenuBar())
132 {
133 // ===== D) FILE MENU =====
134 if (ImGui::BeginMenu("File"))
135 {
136 // New Blueprint submenu with all types
137 if (ImGui::BeginMenu("New Blueprint"))
138 {
139 if (ImGui::BeginMenu("AI"))
140 {
141 if (ImGui::MenuItem("Behavior Tree", "Ctrl+Shift+B"))
142 {
143 // TODO: Create new BehaviorTree
144 std::cout << "Creating new Behavior Tree..." << std::endl;
145 }
146 if (ImGui::MenuItem("Hierarchical FSM", "Ctrl+Shift+H"))
147 {
148 std::cout << "Creating new HFSM..." << std::endl;
149 }
150 ImGui::EndMenu();
151 }
152
153 ImGui::Separator();
154
155 if (ImGui::MenuItem("Entity Prefab", "Ctrl+Shift+E"))
156 {
157 std::cout << "Creating new Entity Prefab..." << std::endl;
158 }
159
160 if (ImGui::MenuItem("Animation Graph", "Ctrl+Shift+A"))
161 {
162 std::cout << "Creating new Animation Graph..." << std::endl;
163 }
164
165 if (ImGui::MenuItem("Scripted Event", "Ctrl+Shift+S"))
166 {
167 std::cout << "Creating new Scripted Event..." << std::endl;
168 }
169
170 ImGui::Separator();
171
172 if (ImGui::MenuItem("Level Definition", "Ctrl+Shift+L"))
173 {
174 std::cout << "Creating new Level Definition..." << std::endl;
175 }
176
177 if (ImGui::MenuItem("UI Menu", "Ctrl+Shift+U"))
178 {
179 std::cout << "Creating new UI Menu..." << std::endl;
180 }
181
182 ImGui::EndMenu();
183 }
184
185 if (ImGui::MenuItem("New Blueprint (Legacy)", "Ctrl+N"))
186 NewBlueprint();
187
188 if (ImGui::MenuItem("Open Blueprint...", "Ctrl+O"))
189 {
190 // TODO: File dialog - for now use example
191 LoadBlueprint("Blueprints/AI/guard_patrol.json");
192 }
193
194 ImGui::Separator();
195
196 if (ImGui::MenuItem("Save", "Ctrl+S", false, backend.HasBlueprint()))
198
199 if (ImGui::MenuItem("Save As...", "Ctrl+Shift+S", false, backend.HasBlueprint()))
201
202 ImGui::Separator();
203
204 // Phase 5: Template menu items
205 if (ImGui::MenuItem("Save as Template...", "Ctrl+Shift+T", false, backend.HasBlueprint()))
206 {
208 {
210 // Trigger the modal by accessing the panel
211 }
212 }
213
214 if (ImGui::MenuItem("Template Browser", nullptr, &m_ShowTemplateBrowser))
215 {
216 // Toggle template browser visibility
217 }
218
219 ImGui::Separator();
220
221 if (ImGui::MenuItem("Reload Assets"))
222 {
223 backend.RefreshAssets();
224 }
225
226 ImGui::Separator();
227
228 if (ImGui::MenuItem("Exit Editor", "F2"))
229 backend.SetActive(false);
230
231 ImGui::EndMenu();
232 }
233
234 // ===== D) EDIT MENU =====
235 if (ImGui::BeginMenu("Edit"))
236 {
237 // Phase 6: Undo/Redo
238 bool canUndo = backend.CanUndo();
239 bool canRedo = backend.CanRedo();
240
241 std::string undoLabel = "Undo";
242 if (canUndo)
243 {
244 undoLabel += ": " + backend.GetLastCommandDescription();
245 }
246
247 if (ImGui::MenuItem(undoLabel.c_str(), "Ctrl+Z", false, canUndo))
248 {
249 backend.Undo();
250 }
251
252 std::string redoLabel = "Redo";
253 if (canRedo)
254 {
255 redoLabel += ": " + backend.GetNextRedoDescription();
256 }
257
258 if (ImGui::MenuItem(redoLabel.c_str(), "Ctrl+Y", false, canRedo))
259 {
260 backend.Redo();
261 }
262
263 ImGui::Separator();
264
265 // Component operations
266 if (ImGui::MenuItem("Add Component", "Insert", false, backend.HasBlueprint()))
268
269 if (ImGui::MenuItem("Remove Component", "Delete", false,
271 {
273 }
274
275 ImGui::Separator();
276
277 if (ImGui::MenuItem("Preferences..."))
278 {
279 m_ShowPreferences = true;
280 }
281
282 ImGui::EndMenu();
283 }
284
285 // ===== TOOLS MENU =====
286 if (ImGui::BeginMenu("Tools"))
287 {
288 if (ImGui::MenuItem("Migrate Blueprints v1 -> v2"))
289 {
290 backend.SetShowMigrationDialog(true);
291 }
292
293 ImGui::Separator();
294
295 if (ImGui::MenuItem("Validate All Blueprints"))
296 {
297 std::cout << "Validating all blueprints..." << std::endl;
298 }
299
300 ImGui::EndMenu();
301 }
302
303 // ===== D) VIEW MENU =====
304 if (ImGui::BeginMenu("View"))
305 {
306 ImGui::Text("Main Panels:");
307 ImGui::Separator();
308
309 // Three main panels only
310 ImGui::MenuItem("Asset Browser", nullptr, &m_ShowAssetBrowser);
311 ImGui::MenuItem("Node Graph Editor", nullptr, &m_ShowNodeGraph);
312 ImGui::MenuItem("Inspector", nullptr, &m_ShowInspector);
313
314 ImGui::Separator();
315
316 ImGui::Text("Additional:");
317 ImGui::Separator();
318 ImGui::MenuItem("Template Browser", nullptr, &m_ShowTemplateBrowser); // Phase 5
319 ImGui::MenuItem("History", nullptr, &m_ShowHistory); // Phase 6
320
321 ImGui::Separator();
322
323 ImGui::Text("Debug:");
324 ImGui::Separator();
325 ImGui::MenuItem("ImGui Demo", nullptr, &m_ShowDemoWindow);
326
327 ImGui::Separator();
328
329 if (ImGui::MenuItem("Reset Layout"))
330 {
331 // Reset main panels to visible
332 m_ShowAssetBrowser = true;
333 m_ShowNodeGraph = true;
334 m_ShowInspector = true;
335 // Keep optional panels in their current state
336 }
337
338 ImGui::EndMenu();
339 }
340
341 // ===== D) HELP MENU =====
342 if (ImGui::BeginMenu("Help"))
343 {
344 if (ImGui::MenuItem("Documentation"))
345 {
346 // TODO: Open documentation URL or local help
347 std::cout << "Opening documentation..." << std::endl;
348 }
349
350 if (ImGui::MenuItem("Keyboard Shortcuts"))
351 {
352 m_ShowShortcuts = true;
353 }
354
355 ImGui::Separator();
356
357 if (ImGui::MenuItem("About Olympe Engine"))
358 m_ShowAboutDialog = true;
359
360 ImGui::EndMenu();
361 }
362
363 ImGui::EndMainMenuBar();
364 }
365
366 // D) Render panels conditionally based on visibility flags
367
368 // === Main Panel 1: Asset Browser (with tabs for files + runtime entities) ===
371
372 // === Main Panel 2: Node Graph Editor ===
373 if (m_ShowNodeGraph)
375
376 // === Main Panel 3: Inspector (contextual - entity OR asset) ===
377 if (m_ShowInspector)
379
380 // === Phase 5: Template Browser (optional) ===
383
384 // === Phase 6: History Panel (optional) ===
387
388 // Status bar at bottom
390
391 // Dialogs
394
397
398 if (m_ShowShortcuts)
400
401 // Migration dialog
402 if (backend.ShowMigrationDialog())
404
405 // About dialog
407 {
408 ImGui::OpenPopup("About");
409 if (ImGui::BeginPopupModal("About", &m_ShowAboutDialog, ImGuiWindowFlags_AlwaysAutoResize))
410 {
411 ImGui::Text("Olympe Blueprint Editor");
412 ImGui::Separator();
413 ImGui::Text("Visual node-based editor for entity blueprints");
414 ImGui::Text("Version: 2.0");
415 ImGui::Text("Status: Interactive panels, entity synchronization, full menus");
416 ImGui::Separator();
417 ImGui::Text("Libraries:");
418 ImGui::BulletText("ImGui for UI");
419 ImGui::BulletText("ImNodes for node editing");
420 ImGui::BulletText("SDL3 for window/rendering");
421 ImGui::Separator();
422 ImGui::Text("Features:");
423 ImGui::BulletText("Interactive, dockable panels");
424 ImGui::BulletText("Runtime entity tracking");
425 ImGui::BulletText("Synchronized panel selection");
426 ImGui::BulletText("Full menu system");
427 if (ImGui::Button("Close", ImVec2(120, 0)))
428 m_ShowAboutDialog = false;
429 ImGui::EndPopup();
430 }
431 }
432
433 // Demo window for testing
435 ImGui::ShowDemoWindow(&m_ShowDemoWindow);
436 }
437
438 // Menu bar is now integrated in the main Render() function
439
443
445 {
446 // Get backend reference
448 const auto& blueprint = backend.GetCurrentBlueprint();
449
450 ImGui::Begin("Entity Properties");
451
452 if (backend.HasBlueprint())
453 {
454 ImGui::Text("Blueprint: %s", blueprint.name.c_str());
455 if (backend.HasUnsavedChanges())
456 {
457 ImGui::SameLine();
458 ImGui::TextColored(ImVec4(1.0f, 0.7f, 0.0f, 1.0f), "*");
459 }
460
461 ImGui::Separator();
462
463 // Description
464 ImGui::Text("Description:");
465 ImGui::TextWrapped("%s", blueprint.description.c_str());
466
467 ImGui::Separator();
468
469 // Component list
470 ImGui::Text("Components (%zu)", blueprint.components.size());
471
472 for (size_t i = 0; i < blueprint.components.size(); ++i)
473 {
474 const auto& comp = blueprint.components[i];
476
477 if (ImGui::Selectable(comp.type.c_str(), selected))
478 {
480 }
481
482 // Right-click context menu
483 if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(1))
484 {
485 ImGui::OpenPopup("component_context");
487 }
488 }
489
490 // Context menu
491 if (ImGui::BeginPopup("component_context"))
492 {
493 if (ImGui::MenuItem("Remove"))
494 {
496 }
497 ImGui::EndPopup();
498 }
499
500 ImGui::Separator();
501
502 if (ImGui::Button("Add Component", ImVec2(-1, 0)))
503 {
505 }
506 }
507 else
508 {
509 ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "No blueprint loaded");
510 ImGui::Text("");
511 ImGui::Text("Use File > New or File > Open");
512 ImGui::Text("to get started");
513 }
514
515 ImGui::End();
516 }
517
519 {
520 // Get backend reference
522 const auto& blueprint = backend.GetCurrentBlueprint();
523
524 ImGui::Begin("Component Graph");
525
526 if (backend.HasBlueprint())
527 {
528 ImNodes::BeginNodeEditor();
529
530 // Render each component as a node
531 for (size_t i = 0; i < blueprint.components.size(); ++i)
532 {
533 const auto& comp = blueprint.components[i];
534 int node_id = (int)i;
535
536 ImNodes::BeginNode(node_id);
537
538 ImNodes::BeginNodeTitleBar();
539 ImGui::TextUnformatted(comp.type.c_str());
540 ImNodes::EndNodeTitleBar();
541
542 // Node content - show key properties
543 ImGui::PushItemWidth(120.0f);
544
545 // Display type only (minimal JSON doesn't support iteration)
546 ImGui::TextDisabled("Type: %s", comp.type.c_str());
547 ImGui::TextDisabled("Click to view properties");
548
549 ImGui::PopItemWidth();
550
551 ImNodes::EndNode();
552
553 // Store or initialize node position
554 if (m_NodePositions.find(node_id) == m_NodePositions.end())
555 {
556 // Initial positioning in a grid
557 float x = 100.0f + (i % 3) * 250.0f;
558 float y = 100.0f + (i / 3) * 150.0f;
560 ImNodes::SetNodeGridSpacePos(node_id, m_NodePositions[node_id]);
561 }
562 }
563
564 ImNodes::EndNodeEditor();
565
566 // Handle node selection
567 int num_selected = ImNodes::NumSelectedNodes();
568 if (num_selected > 0)
569 {
570 int* selected_nodes = new int[num_selected];
571 ImNodes::GetSelectedNodes(selected_nodes);
573 delete[] selected_nodes;
574 }
575 }
576 else
577 {
578 ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "No blueprint loaded");
579 ImGui::Text("");
580 ImGui::Text("Components will appear as nodes here");
581 }
582
583 ImGui::End();
584 }
585
587 {
588 // Get backend reference
590 const auto& blueprint = backend.GetCurrentBlueprint();
591
592 ImGui::Begin("Properties");
593
594 if (m_SelectedComponentIndex >= 0 &&
595 m_SelectedComponentIndex < (int)blueprint.components.size())
596 {
597 const auto& comp = blueprint.components[m_SelectedComponentIndex];
598
599 ImGui::Text("Component: %s", comp.type.c_str());
600 ImGui::Separator();
601
602 // Display properties as JSON (minimal JSON doesn't support iteration)
603 ImGui::Text("Properties:");
604 std::string props_json = comp.properties.dump(2);
605 ImGui::TextWrapped("%s", props_json.c_str());
606
607 ImGui::Separator();
608 ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.0f, 1.0f),
609 "Note: Use console editor (Phase 1) for property editing");
610 ImGui::Text("Phase 2 property editing requires full JSON library");
611 }
612 else
613 {
614 ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f),
615 "Select a component to view properties");
616 }
617
618 ImGui::End();
619 }
620
622 {
623 // Get backend reference
625 const auto& blueprint = backend.GetCurrentBlueprint();
626
627 ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0));
628 ImGui::Begin("##StatusBar", nullptr,
631
632 if (backend.HasBlueprint())
633 {
634 ImGui::Text("Blueprint: %s", blueprint.name.c_str());
635 ImGui::SameLine();
636 ImGui::Text(" | Components: %zu", blueprint.components.size());
637
638 if (backend.HasUnsavedChanges())
639 {
640 ImGui::SameLine();
641 ImGui::TextColored(ImVec4(1.0f, 0.7f, 0.0f, 1.0f), "| Modified");
642 }
643
644 const std::string& filepath = backend.GetCurrentFilepath();
645 if (!filepath.empty())
646 {
647 ImGui::SameLine();
648 ImGui::TextDisabled("| %s", filepath.c_str());
649 }
650 }
651 else
652 {
653 ImGui::Text("Ready | No blueprint loaded");
654 }
655
656 ImGui::End();
657 ImGui::PopStyleVar();
658 }
659
661 {
662 ImGui::OpenPopup("Add Component");
663
664 ImVec2 center = ImGui::GetMainViewport()->GetCenter();
665 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
666
667 if (ImGui::BeginPopupModal("Add Component", &m_ShowAddComponentDialog,
669 {
670 ImGui::Text("Select component type:");
671 ImGui::Separator();
672
673 const char* component_types[] = {
674 "Position", "BoundingBox", "VisualSprite", "Movement",
675 "PhysicsBody", "Health", "AIBehavior", "TriggerZone",
676 "Animation", "AudioSource", "Inventory", "PlayerController"
677 };
678
679 ImGui::ListBox("##component_types", &m_SelectedComponentType,
681
682 ImGui::Separator();
683
684 if (ImGui::Button("Add", ImVec2(120, 0)))
685 {
688 }
689
690 ImGui::SameLine();
691
692 if (ImGui::Button("Cancel", ImVec2(120, 0)))
693 {
695 }
696
697 ImGui::EndPopup();
698 }
699 }
700
702 {
703 // Delegate to backend
704 BlueprintEditor::Get().NewBlueprint("NewBlueprint", "A new entity blueprint");
705
706 // Reset UI state
708 m_NodePositions.clear();
709 }
710
711 void BlueprintEditorGUI::LoadBlueprint(const std::string& filepath)
712 {
713 // Delegate to backend
714 if (BlueprintEditor::Get().LoadBlueprint(filepath))
715 {
716 // Reset UI state on successful load
718 m_NodePositions.clear();
719 }
720 }
721
723 {
725
726 if (backend.GetCurrentFilepath().empty())
727 {
728 // Default save location if no filepath set
729 const std::string& name = backend.GetCurrentBlueprint().name;
730 std::string filepath = "../Blueprints/" + name + ".json";
731 backend.SaveBlueprintAs(filepath);
732 }
733 else
734 {
735 backend.SaveBlueprint();
736 }
737 }
738
740 {
742
743 // For now, use a default pattern (in real implementation, would show file dialog)
744 const std::string& name = backend.GetCurrentBlueprint().name;
745 std::string filepath = "../Blueprints/" + name + "_copy.json";
746 backend.SaveBlueprintAs(filepath);
747 }
748
749 void BlueprintEditorGUI::AddComponent(const std::string& type)
750 {
751 // Get mutable blueprint from backend
753
755 newComp.type = type;
756
757 // Create default properties based on type
758 if (type == "Position")
759 {
761 }
762 else if (type == "BoundingBox")
763 {
764 newComp = CreateBoundingBoxComponent(0, 0, 32, 32);
765 }
766 else if (type == "VisualSprite")
767 {
768 newComp = CreateVisualSpriteComponent("Resources/sprite.png", 0, 0, 32, 32);
769 }
770 else if (type == "Movement")
771 {
772 newComp = CreateMovementComponent(1, 0, 0, 0);
773 }
774 else if (type == "PhysicsBody")
775 {
776 newComp = CreatePhysicsBodyComponent(1.0f, 100.0f);
777 }
778 else if (type == "Health")
779 {
780 newComp = CreateHealthComponent(100, 100);
781 }
782 else if (type == "AIBehavior")
783 {
785 }
786 else
787 {
788 // Generic component
789 newComp.type = type;
790 newComp.properties = json::object();
791 }
792
793 // Add to backend blueprint
794 blueprint.AddComponent(newComp.type, newComp.properties);
795
796 // Mark as modified in backend
798 }
799
801 {
802 // Get mutable blueprint from backend
804
805 if (index >= 0 && index < (int)blueprint.components.size())
806 {
807 blueprint.components.erase(
808 blueprint.components.begin() + index
809 );
811
812 // Mark as modified in backend
814 }
815 }
816
817 // D) Additional dialog implementations
819 {
820 ImGui::OpenPopup("Preferences");
821
822 ImVec2 center = ImGui::GetMainViewport()->GetCenter();
823 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
824 ImGui::SetNextWindowSize(ImVec2(400, 300), ImGuiCond_Appearing);
825
826 if (ImGui::BeginPopupModal("Preferences", &m_ShowPreferences))
827 {
828 ImGui::Text("Editor Preferences");
829 ImGui::Separator();
830
831 ImGui::TextWrapped("Preferences coming soon...");
832 ImGui::Spacing();
833
834 ImGui::Text("Planned settings:");
835 ImGui::BulletText("Auto-save interval");
836 ImGui::BulletText("Theme selection");
837 ImGui::BulletText("Grid snap settings");
838 ImGui::BulletText("Default component properties");
839
840 ImGui::Separator();
841
842 if (ImGui::Button("Close", ImVec2(120, 0)))
843 {
844 m_ShowPreferences = false;
845 }
846
847 ImGui::EndPopup();
848 }
849 }
850
852 {
853 ImGui::OpenPopup("Keyboard Shortcuts");
854
855 ImVec2 center = ImGui::GetMainViewport()->GetCenter();
856 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
857 ImGui::SetNextWindowSize(ImVec2(450, 400), ImGuiCond_Appearing);
858
859 if (ImGui::BeginPopupModal("Keyboard Shortcuts", &m_ShowShortcuts))
860 {
861 ImGui::Text("Keyboard Shortcuts");
862 ImGui::Separator();
863
864 ImGui::Columns(2, "shortcuts");
865 ImGui::SetColumnWidth(0, 200);
866
867 ImGui::Text("Editor Control:");
868 ImGui::Separator();
869 ImGui::Text("F2"); ImGui::NextColumn(); ImGui::Text("Toggle Blueprint Editor"); ImGui::NextColumn();
870 ImGui::Text("Escape"); ImGui::NextColumn(); ImGui::Text("Exit Application"); ImGui::NextColumn();
871
872 ImGui::Spacing();
873 ImGui::Text("File Operations:");
874 ImGui::Separator();
875 ImGui::Text("Ctrl+N"); ImGui::NextColumn(); ImGui::Text("New Blueprint"); ImGui::NextColumn();
876 ImGui::Text("Ctrl+O"); ImGui::NextColumn(); ImGui::Text("Open Blueprint"); ImGui::NextColumn();
877 ImGui::Text("Ctrl+S"); ImGui::NextColumn(); ImGui::Text("Save"); ImGui::NextColumn();
878 ImGui::Text("Ctrl+Shift+S"); ImGui::NextColumn(); ImGui::Text("Save As"); ImGui::NextColumn();
879
880 ImGui::Spacing();
881 ImGui::Text("Edit Operations:");
882 ImGui::Separator();
883 ImGui::Text("Ctrl+Z"); ImGui::NextColumn(); ImGui::Text("Undo"); ImGui::NextColumn();
884 ImGui::Text("Ctrl+Y"); ImGui::NextColumn(); ImGui::Text("Redo"); ImGui::NextColumn();
885 ImGui::Text("Insert"); ImGui::NextColumn(); ImGui::Text("Add Component"); ImGui::NextColumn();
886 ImGui::Text("Delete"); ImGui::NextColumn(); ImGui::Text("Remove Component"); ImGui::NextColumn();
887
888 ImGui::Columns(1);
889 ImGui::Separator();
890
891 if (ImGui::Button("Close", ImVec2(120, 0)))
892 {
893 m_ShowShortcuts = false;
894 }
895
896 ImGui::EndPopup();
897 }
898 }
899
901 {
903
904 ImGui::OpenPopup("Migrate Blueprints");
905 ImVec2 center = ImGui::GetMainViewport()->GetCenter();
906 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
907 ImGui::SetNextWindowSize(ImVec2(500, 300), ImGuiCond_Appearing);
908
909 bool isOpen = true;
910 if (ImGui::BeginPopupModal("Migrate Blueprints", &isOpen, ImGuiWindowFlags_AlwaysAutoResize))
911 {
912 ImGui::TextWrapped("This will migrate all v1 blueprints to v2 format:");
913 ImGui::Spacing();
914
915 ImGui::BulletText("Add schema_version and blueprintType fields");
916 ImGui::BulletText("Calculate and save node positions");
917 ImGui::BulletText("Unify parameters structure");
918 ImGui::BulletText("Create .v1.backup files");
919
920 ImGui::Spacing();
921 ImGui::Separator();
922 ImGui::Spacing();
923
924 ImGui::TextWrapped("Scanning: Blueprints/");
925 ImGui::TextColored(ImVec4(1.0f, 0.7f, 0.0f, 1.0f),
926 "Warning: This will modify your blueprint files!");
927
928 ImGui::Spacing();
929 ImGui::Separator();
930
931 if (ImGui::Button("Migrate All", ImVec2(150, 0)))
932 {
933 backend.MigrateAllBlueprints();
934 backend.SetShowMigrationDialog(false);
935 }
936
937 ImGui::SameLine();
938
939 if (ImGui::Button("Cancel", ImVec2(150, 0)))
940 {
941 backend.SetShowMigrationDialog(false);
942 }
943
944 ImGui::EndPopup();
945 }
946
947 if (!isOpen)
948 {
949 backend.SetShowMigrationDialog(false);
950 }
951 }
952
953 // Phase 6: Keyboard shortcuts handler
955 {
956 ImGuiIO& io = ImGui::GetIO();
958
959 // Don't process shortcuts if typing in a text field
960 if (io.WantTextInput)
961 {
962 return;
963 }
964
965 // Ctrl+Z : Undo
966 if (io.KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_Z) && !io.KeyShift)
967 {
968 if (backend.CanUndo())
969 {
970 backend.Undo();
971 }
972 }
973
974 // Ctrl+Y or Ctrl+Shift+Z : Redo
975 if ((io.KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_Y)) ||
976 (io.KeyCtrl && io.KeyShift && ImGui::IsKeyPressed(ImGuiKey_Z)))
977 {
978 if (backend.CanRedo())
979 {
980 backend.Redo();
981 }
982 }
983
984 // Ctrl+S : Save
985 if (io.KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_S) && !io.KeyShift)
986 {
987 if (backend.HasBlueprint())
988 {
990 }
991 }
992
993 // Ctrl+Shift+S : Save As
994 if (io.KeyCtrl && io.KeyShift && ImGui::IsKeyPressed(ImGuiKey_S))
995 {
996 if (backend.HasBlueprint())
997 {
999 }
1000 }
1001
1002 // Ctrl+N : New Blueprint
1003 if (io.KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_N))
1004 {
1005 NewBlueprint();
1006 }
1007
1008 // Ctrl+O : Open Blueprint
1009 if (io.KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_O))
1010 {
1011 // TODO: File dialog
1012 LoadBlueprint("../Blueprints/example_entity_simple.json");
1013 }
1014
1015 // Ctrl+Shift+T : Save as Template
1016 if (io.KeyCtrl && io.KeyShift && ImGui::IsKeyPressed(ImGuiKey_T))
1017 {
1018 if (backend.HasBlueprint())
1019 {
1020 m_ShowTemplateBrowser = true;
1021 }
1022 }
1023 }
1024}
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
void Initialize(const std::string &assetsRootPath)
void SetAssetOpenCallback(std::function< void(const std::string &)> callback)
void AddComponent(const std::string &type)
class HistoryPanel * m_HistoryPanel
void LoadBlueprint(const std::string &filepath)
std::map< int, ImVec2 > m_NodePositions
class TemplateBrowserPanel * m_TemplateBrowserPanel
void NewBlueprint(const std::string &name, const std::string &description="")
Blueprint::EntityBlueprint & GetCurrentBlueprintMutable()
static BlueprintEditor & Get()
HistoryPanel - ImGui panel for command history visualization Shows undo/redo stacks with command desc...
TemplateBrowserPanel - ImGui panel for template management Provides interface for browsing,...
ComponentData CreateVisualSpriteComponent(const std::string &spritePath, float srcX, float srcY, float srcWidth, float srcHeight, float hotSpotX, float hotSpotY)
ComponentData CreateBoundingBoxComponent(float x, float y, float width, float height)
ComponentData CreateMovementComponent(float dirX, float dirY, float velX, float velY)
ComponentData CreateAIBehaviorComponent(const std::string &behaviorType)
ComponentData CreatePositionComponent(float x, float y)
ComponentData CreatePhysicsBodyComponent(float mass, float speed)
ComponentData CreateHealthComponent(int current, int max)
std::vector< ComponentData > components