Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
SubGraphFilePickerModal.cpp
Go to the documentation of this file.
1/**
2 * @file SubGraphFilePickerModal.cpp
3 * @brief Implementation of SubGraphFilePickerModal (Phase 26).
4 * @author Olympe Engine
5 * @date 2026-03-10
6 */
7
9#include "../../third_party/imgui/imgui.h"
10#include "../../system/system_consts.h"
11#include "../../system/system_utils.h"
12
13#ifdef _WIN32
14#include <windows.h>
15#endif
16
17#include <algorithm>
18#include <cstring>
19
20namespace Olympe {
21
23{
24 // Initialize path to blueprints directory
25 m_currentPath = "Blueprints";
28}
29
30// ============================================================================
31// Modal Lifecycle
32// ============================================================================
33
34void SubGraphFilePickerModal::Open(const std::string& currentPath)
35{
36 m_isOpen = true;
37 m_confirmed = false;
38 m_selectedFile = "";
39 m_selectedIndex = -1;
40
41 if (!currentPath.empty())
42 {
43 m_currentPath = currentPath;
44 strncpy_s(m_pathBuffer, sizeof(m_pathBuffer), currentPath.c_str(), _TRUNCATE);
45 }
46
49}
50
52{
53 m_isOpen = false;
54 m_confirmed = false;
55 m_selectedFile = "";
56}
57
59{
60 if (!m_isOpen)
61 return;
62
63 // Center the modal on screen
64 ImVec2 center = ImGui::GetMainViewport()->GetCenter();
65 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
66 ImGui::SetNextWindowSize(ImVec2(700.0f, 500.0f), ImGuiCond_Appearing);
67 ImGui::SetNextWindowSizeConstraints(ImVec2(500.0f, 300.0f), ImVec2(1200.0f, 800.0f));
68
69 bool open = true;
70 if (ImGui::BeginPopupModal("Select SubGraph File##modal", &open, ImGuiWindowFlags_AlwaysAutoResize))
71 {
72 ImGui::TextColored(ImVec4(0.8f, 0.95f, 1.0f, 1.0f), "Select a Blueprint file (.ats) to use as SubGraph");
73 ImGui::Separator();
74
75 // ====================================================================
76 // Path Navigation
77 // ====================================================================
78
79 ImGui::TextDisabled("Path:");
80 ImGui::SameLine();
81 ImGui::SetNextItemWidth(-100.0f);
82 if (ImGui::InputText("##path", m_pathBuffer, sizeof(m_pathBuffer)))
83 {
86 }
87
88 ImGui::SameLine();
89 if (ImGui::Button("Refresh##refresh", ImVec2(90, 0)))
90 {
92 }
93
94 ImGui::Separator();
95
96 // ====================================================================
97 // Search Filter
98 // ====================================================================
99
100 ImGui::TextDisabled("Filter:");
101 ImGui::SameLine();
102 ImGui::SetNextItemWidth(-1.0f);
103 ImGui::InputText("##search", m_searchBuffer, sizeof(m_searchBuffer));
104
105 ImGui::Separator();
106
107 // ====================================================================
108 // File List
109 // ====================================================================
110
112
113 ImGui::Separator();
114
115 // ====================================================================
116 // Selected File Display
117 // ====================================================================
118
119 ImGui::TextDisabled("Selected:");
120 ImGui::SameLine();
121 if (m_selectedIndex >= 0 && m_selectedIndex < static_cast<int>(m_blueprintFiles.size()))
122 {
123 ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.5f, 1.0f), "%s", m_blueprintFiles[m_selectedIndex].c_str());
124 }
125 else
126 {
127 ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.5f, 1.0f), "(none)");
128 }
129
130 ImGui::Separator();
131
132 // ====================================================================
133 // Action Buttons
134 // ====================================================================
135
137
138 ImGui::EndPopup();
139 }
140
141 if (!open)
142 {
143 m_isOpen = false;
144 ImGui::OpenPopup("Select SubGraph File##modal");
145 }
146}
147
148// ============================================================================
149// Helper Methods
150// ============================================================================
151
153{
154 m_blueprintFiles.clear();
155 m_selectedIndex = -1;
156
157#ifdef _WIN32
159 std::string searchPath = m_currentPath + "\\*.ats";
161
163 {
164 SYSTEM_LOG << "[SubGraphFilePicker] Directory not found or inaccessible: " << m_currentPath << "\n";
165 return;
166 }
167
168 do
169 {
170 std::string filename = findData.cFileName;
171
172 // Skip directories, only get files
173 if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
174 {
175 m_blueprintFiles.push_back(filename);
176 }
177 } while (FindNextFileA(hFind, &findData) != 0);
178
180
181 // Sort alphabetically
182 std::sort(m_blueprintFiles.begin(), m_blueprintFiles.end());
183
184 SYSTEM_LOG << "[SubGraphFilePicker] Found " << m_blueprintFiles.size()
185 << " blueprint files (.ats) in " << m_currentPath << "\n";
186#else
187 SYSTEM_LOG << "[SubGraphFilePicker] Platform not supported (Windows only)\n";
188#endif
189}
190
192{
193 std::vector<std::string> filteredFiles = GetFilteredFiles();
194
195 ImGui::TextDisabled("Available Blueprints:");
196
197 ImGui::BeginChild("##file_list", ImVec2(0, 250), true);
198
199 for (int i = 0; i < static_cast<int>(filteredFiles.size()); ++i)
200 {
201 const std::string& filename = filteredFiles[i];
202
203 // Find the actual index in the unfiltered list
204 int actualIndex = -1;
205 for (int j = 0; j < static_cast<int>(m_blueprintFiles.size()); ++j)
206 {
208 {
209 actualIndex = j;
210 break;
211 }
212 }
213
214 bool isSelected = (actualIndex == m_selectedIndex);
215
216 ImGui::PushID(i);
217
218 if (ImGui::Selectable(filename.c_str(), isSelected, ImGuiSelectableFlags_DontClosePopups))
219 {
221 }
222
223 ImGui::PopID();
224 }
225
226 if (filteredFiles.empty())
227 {
228 ImGui::TextDisabled("(no blueprint files found)");
229 }
230
231 ImGui::EndChild();
232}
233
235{
237
238 if (!canSelect)
239 ImGui::BeginDisabled(true);
240
241 if (ImGui::Button("Select##select", ImVec2(100, 0)))
242 {
243 if (canSelect)
244 {
245 // Build full path: currentPath / filename
247 m_confirmed = true;
248 m_isOpen = false;
249 ImGui::CloseCurrentPopup();
250 }
251 }
252
253 if (!canSelect)
254 ImGui::EndDisabled();
255
256 ImGui::SameLine();
257
258 if (ImGui::Button("Cancel##cancel", ImVec2(100, 0)))
259 {
260 m_isOpen = false;
261 m_confirmed = false;
262 ImGui::CloseCurrentPopup();
263 }
264}
265
266std::vector<std::string> SubGraphFilePickerModal::GetFilteredFiles() const
267{
268 std::string searchLower(m_searchBuffer);
269 std::transform(searchLower.begin(), searchLower.end(), searchLower.begin(), ::tolower);
270
271 std::vector<std::string> filtered;
272
273 for (const auto& filename : m_blueprintFiles)
274 {
275 std::string filenameLower(filename);
276 std::transform(filenameLower.begin(), filenameLower.end(), filenameLower.begin(), ::tolower);
277
278 if (searchLower.empty() || filenameLower.find(searchLower) != std::string::npos)
279 {
280 filtered.push_back(filename);
281 }
282 }
283
284 return filtered;
285}
286
287} // namespace Olympe
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
ImGui modal for selecting SubGraph files (Phase 26).
void RenderFileList()
Renders the file list with scrolling support.
void Open(const std::string &currentPath="")
Opens the modal with optional initial path.
std::vector< std::string > GetFilteredFiles() const
Filters file list by search term.
void RefreshFileList()
Scans current directory for .json blueprint files.
void Close()
Closes the modal without confirming changes.
int m_selectedIndex
Currently highlighted file (-1 = none)
bool m_isOpen
Is modal currently displayed.
std::string m_selectedFile
The file path user selected.
std::vector< std::string > m_blueprintFiles
.json files in current directory
void RenderActionButtons()
Renders action buttons (Select, Cancel).
bool m_confirmed
Did user click Select button.
char m_searchBuffer[128]
Search filter text.
std::string m_currentPath
Current browse directory.
char m_pathBuffer[512]
Directory path input buffer.
< Provides AssetID and INVALID_ASSET_ID
#define SYSTEM_LOG