Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
BlackboardPanel.cpp
Go to the documentation of this file.
1/**
2 * @file BlackboardPanel.cpp
3 * @brief Implementation of BlackboardPanel ImGui panel (Phase 2.1)
4 * @author Olympe Engine
5 * @date 2026-02-19
6 */
7
8#include "BlackboardPanel.h"
9#include "../../third_party/imgui/imgui.h"
10#include "../../system/system_utils.h"
11#include <cstring>
12#include <cstdio>
13
14namespace Olympe {
15namespace AI {
16
17// ============================================================================
18// Constructor
19// ============================================================================
20
22 : m_showAddDialog(false)
23 , m_showEditPopup(false)
24 , m_newEntryTypeIndex(0)
25{
26 std::memset(m_newEntryName, 0, sizeof(m_newEntryName));
27 std::memset(m_editStringBuf, 0, sizeof(m_editStringBuf));
28 std::memset(m_renameBuffer, 0, sizeof(m_renameBuffer));
29}
30
31// ============================================================================
32// Render
33// ============================================================================
34
36{
38 if (!ImGui::Begin("Blackboard", pOpen, flags))
39 {
40 ImGui::End();
41 return;
42 }
43
44 if (blackboard == nullptr)
45 {
46 ImGui::Text("No active graph.");
47 ImGui::End();
48 return;
49 }
50
51 ImGui::Text("Blackboard Variables");
52 ImGui::Separator();
53
54 if (ImGui::Button("Add Variable"))
55 {
56 m_showAddDialog = true;
57 std::memset(m_newEntryName, 0, sizeof(m_newEntryName));
60 std::memset(m_editStringBuf, 0, sizeof(m_editStringBuf));
61 }
62
63 ImGui::Separator();
65
67 {
69 }
70
72 {
74 }
75
76 ImGui::End();
77}
78
79// ============================================================================
80// Entry list
81// ============================================================================
82
83static const char* s_typeNames[] = { "Int", "Float", "Bool", "String", "Vector3" };
84static const int s_typeCount = 5;
85
87{
88 const auto& entries = blackboard->GetAll();
89
90 if (entries.empty())
91 {
92 ImGui::TextDisabled("(no variables)");
93 return;
94 }
95
96 // Column headers
97 ImGui::Columns(3, "bb_cols");
98 ImGui::SetColumnWidth(0, 140.0f);
99 ImGui::SetColumnWidth(1, 70.0f);
100 ImGui::Text("Name"); ImGui::NextColumn();
101 ImGui::Text("Type"); ImGui::NextColumn();
102 ImGui::Text("Value"); ImGui::NextColumn();
103 ImGui::Separator();
104
105 std::string toDelete;
106 std::string toEdit;
107
108 for (auto it = entries.begin(); it != entries.end(); ++it)
109 {
110 const std::string& name = it->first;
111 const NodeGraph::BlackboardValue& val = it->second;
112
113 ImGui::PushID(name.c_str());
114
115 // Name column
116 ImGui::Text("%s", name.c_str());
117 ImGui::NextColumn();
118
119 // Type column
120 int typeIdx = static_cast<int>(val.type);
121 if (typeIdx >= 0 && typeIdx < s_typeCount)
122 {
123 ImGui::Text("%s", s_typeNames[typeIdx]);
124 }
125 ImGui::NextColumn();
126
127 // Value column with inline editing
128 char valueBuf[256];
129 std::memset(valueBuf, 0, sizeof(valueBuf));
130
131 switch (val.type)
132 {
133 case NodeGraph::BlackboardType::Int:
134 std::snprintf(valueBuf, sizeof(valueBuf), "%d", val.intValue);
135 break;
136 case NodeGraph::BlackboardType::Float:
137 std::snprintf(valueBuf, sizeof(valueBuf), "%.3f", val.floatValue);
138 break;
139 case NodeGraph::BlackboardType::Bool:
140 std::snprintf(valueBuf, sizeof(valueBuf), "%s", val.boolValue ? "true" : "false");
141 break;
142 case NodeGraph::BlackboardType::String:
143 std::snprintf(valueBuf, sizeof(valueBuf), "%s", val.stringValue.c_str());
144 break;
145 case NodeGraph::BlackboardType::Vector3:
146 std::snprintf(valueBuf, sizeof(valueBuf), "(%.2f, %.2f, %.2f)",
147 val.vec3X, val.vec3Y, val.vec3Z);
148 break;
149 default:
150 break;
151 }
152 ImGui::Text("%s", valueBuf);
153
154 // Context menu for edit/delete
155 if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(1))
156 {
157 ImGui::OpenPopup("EntryCtx");
158 }
159 if (ImGui::BeginPopup("EntryCtx"))
160 {
161 if (ImGui::MenuItem("Edit"))
162 {
163 toEdit = name;
164 }
165 if (ImGui::MenuItem("Delete"))
166 {
167 toDelete = name;
168 }
169 ImGui::EndPopup();
170 }
171
172 ImGui::NextColumn();
173 ImGui::PopID();
174 }
175
176 ImGui::Columns(1);
177
178 if (!toDelete.empty())
179 {
180 blackboard->RemoveEntry(toDelete);
181 }
182
183 if (!toEdit.empty())
184 {
187 if (ev != nullptr)
188 {
189 m_editBuffer = *ev;
190 std::memset(m_editStringBuf, 0, sizeof(m_editStringBuf));
191 std::memset(m_renameBuffer, 0, sizeof(m_renameBuffer));
192 std::snprintf(m_renameBuffer, sizeof(m_renameBuffer), "%s", toEdit.c_str());
193 if (ev->type == NodeGraph::BlackboardType::String)
194 {
195 std::snprintf(m_editStringBuf, sizeof(m_editStringBuf),
196 "%s", ev->stringValue.c_str());
197 }
198 }
199 m_showEditPopup = true;
200 }
201}
202
203// ============================================================================
204// Add dialog
205// ============================================================================
206
208{
209 ImGui::OpenPopup("Add Variable");
210
211 if (ImGui::BeginPopupModal("Add Variable", &m_showAddDialog,
213 {
214 ImGui::InputText("Name", m_newEntryName, sizeof(m_newEntryName));
215 ImGui::Combo("Type", &m_newEntryTypeIndex, s_typeNames, s_typeCount);
216
217 NodeGraph::BlackboardType selectedType =
218 static_cast<NodeGraph::BlackboardType>(m_newEntryTypeIndex);
219
220 ImGui::Separator();
221 ImGui::Text("Initial value:");
222
223 switch (selectedType)
224 {
225 case NodeGraph::BlackboardType::Int:
226 ImGui::InputInt("##int", &m_editBuffer.intValue);
227 break;
228 case NodeGraph::BlackboardType::Float:
229 ImGui::InputFloat("##float", &m_editBuffer.floatValue);
230 break;
231 case NodeGraph::BlackboardType::Bool:
232 ImGui::Checkbox("##bool", &m_editBuffer.boolValue);
233 break;
234 case NodeGraph::BlackboardType::String:
235 ImGui::InputText("##string", m_editStringBuf, sizeof(m_editStringBuf));
236 break;
237 case NodeGraph::BlackboardType::Vector3:
238 {
240 if (ImGui::InputFloat3("##vec3", v))
241 {
242 m_editBuffer.vec3X = v[0];
243 m_editBuffer.vec3Y = v[1];
244 m_editBuffer.vec3Z = v[2];
245 }
246 break;
247 }
248 default:
249 break;
250 }
251
252 ImGui::Separator();
253
254 if (ImGui::Button("Create"))
255 {
256 if (m_newEntryName[0] != '\0')
257 {
260 if (selectedType == NodeGraph::BlackboardType::String)
261 {
262 initVal.stringValue = std::string(m_editStringBuf);
263 }
264 blackboard->CreateEntry(std::string(m_newEntryName), selectedType, initVal);
265 }
266 m_showAddDialog = false;
267 }
268
269 ImGui::SameLine();
270 if (ImGui::Button("Cancel"))
271 {
272 m_showAddDialog = false;
273 }
274
275 ImGui::EndPopup();
276 }
277}
278
279// ============================================================================
280// Edit popup
281// ============================================================================
282
284{
285 ImGui::OpenPopup("Edit Variable");
286
287 if (ImGui::BeginPopupModal("Edit Variable", &m_showEditPopup,
289 {
290 ImGui::InputText("Rename", m_renameBuffer, sizeof(m_renameBuffer));
291
292 ImGui::Separator();
293 ImGui::Text("Value:");
294
295 switch (m_editBuffer.type)
296 {
297 case NodeGraph::BlackboardType::Int:
298 ImGui::InputInt("##int", &m_editBuffer.intValue);
299 break;
300 case NodeGraph::BlackboardType::Float:
301 ImGui::InputFloat("##float", &m_editBuffer.floatValue);
302 break;
303 case NodeGraph::BlackboardType::Bool:
304 ImGui::Checkbox("##bool", &m_editBuffer.boolValue);
305 break;
306 case NodeGraph::BlackboardType::String:
307 ImGui::InputText("##string", m_editStringBuf, sizeof(m_editStringBuf));
308 break;
309 case NodeGraph::BlackboardType::Vector3:
310 {
312 if (ImGui::InputFloat3("##vec3", v))
313 {
314 m_editBuffer.vec3X = v[0];
315 m_editBuffer.vec3Y = v[1];
316 m_editBuffer.vec3Z = v[2];
317 }
318 break;
319 }
320 default:
321 break;
322 }
323
324 ImGui::Separator();
325
326 if (ImGui::Button("Apply"))
327 {
328 // Apply value change
329 if (m_editBuffer.type == NodeGraph::BlackboardType::String)
330 {
332 }
334
335 // Handle rename
336 std::string newName(m_renameBuffer);
337 if (!newName.empty() && newName != m_editTargetName)
338 {
339 blackboard->RenameEntry(m_editTargetName, newName);
340 }
341
342 m_showEditPopup = false;
343 }
344
345 ImGui::SameLine();
346 if (ImGui::Button("Cancel"))
347 {
348 m_showEditPopup = false;
349 }
350
351 ImGui::EndPopup();
352 }
353}
354
355} // namespace AI
356} // namespace Olympe
ImGui panel for editing blackboard variables (Phase 2.1)
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
void Render(NodeGraph::BlackboardSystem *blackboard, bool *pOpen=nullptr)
Render the panel.
NodeGraph::BlackboardValue m_editBuffer
void RenderAddDialog(NodeGraph::BlackboardSystem *blackboard)
void RenderEditPopup(NodeGraph::BlackboardSystem *blackboard)
void RenderEntryList(NodeGraph::BlackboardSystem *blackboard)
Manages named blackboard variables for a graph.
static const int s_typeCount
static const char * s_typeNames[]
< Provides AssetID and INVALID_ASSET_ID
Stores a typed value for a blackboard entry.