Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
ConditionPresetEditDialog.cpp
Go to the documentation of this file.
1/**
2 * @file ConditionPresetEditDialog.cpp
3 * @brief Implementation of ConditionPresetEditDialog (Phase 24.1).
4 * @author Olympe Engine
5 * @date 2026-03-16
6 *
7 * C++14 compliant - no std::optional, structured bindings, std::filesystem.
8 */
9
11
12#include <algorithm>
13#include "../../NodeGraphCore/GlobalTemplateBlackboard.h"
14
15#ifndef OLYMPE_HEADLESS
16#include "../../third_party/imgui/imgui.h"
17#endif
18
19namespace Olympe {
20
21namespace {
22
23const std::vector<std::string>& GetValidOperators()
24{
25 static const std::vector<std::string> ops = { "==", "!=", "<", "<=", ">", ">=" };
26 return ops;
27}
28
29const std::vector<std::string>& GetValidModes()
30{
31 static const std::vector<std::string> modes = { "Variable", "Const", "Pin" };
32 return modes;
33}
34
35} // anonymous namespace
36
44
60
65
66void ConditionPresetEditDialog::SetLeftMode(const std::string& mode)
67{
68 if (mode == "Variable")
70 else if (mode == "Const")
72 else if (mode == "Pin")
74}
75
80
85
90
95
96void ConditionPresetEditDialog::SetRightMode(const std::string& mode)
97{
98 if (mode == "Variable")
100 else if (mode == "Const")
102 else if (mode == "Pin")
104}
105
110
115
120
121void ConditionPresetEditDialog::SetName(const std::string& name)
122{
123 m_workingCopy.name = name;
124}
125
127{
128 return m_workingCopy.GetPreview();
129}
130
132{
133 const auto& ops = GetValidOperators();
134 return std::find(ops.begin(), ops.end(), op) != ops.end();
135}
136
137bool ConditionPresetEditDialog::IsValidMode(const std::string& mode)
138{
139 const auto& modes = GetValidModes();
140 return std::find(modes.begin(), modes.end(), mode) != modes.end();
141}
142
144{
145 if (operand.IsVariable())
146 return !operand.stringValue.empty();
147 if (operand.IsPin())
148 return !operand.stringValue.empty();
149 if (operand.IsConst())
150 return true;
151 return false;
152}
153
155{
157 return false;
159 return false;
160 return true;
161}
162
164{
165 if (!IsValid()) { return false; }
166
167 m_isConfirmed = true;
168 m_isOpen = false;
169 return true;
170}
171
173{
174#ifndef OLYMPE_HEADLESS
175 if (!m_isOpen) { return; }
176
177 const char* title = (m_mode == Mode::Create)
178 ? "Create Condition Preset"
179 : "Edit Condition Preset";
180
181 ImGui::SetNextWindowSize(ImVec2(400, 300), ImGuiCond_FirstUseEver);
182 ImGui::OpenPopup(title);
183
184 if (ImGui::BeginPopupModal(title, &m_isOpen,
186 {
187 char nameBuf[128] = {};
188 if (m_workingCopy.name.size() < sizeof(nameBuf))
189 {
191 }
192 if (ImGui::InputText("Name", nameBuf, sizeof(nameBuf)))
193 {
195 }
196
197 ImGui::Separator();
198
199 RenderOperandSelector("Left", true);
201 RenderOperandSelector("Right", false);
202
203 ImGui::Separator();
205 ImGui::Separator();
207
208 ImGui::EndPopup();
209 }
210#endif
211}
212
214{
215#ifndef OLYMPE_HEADLESS
217
218 ImGui::PushID(label);
219 ImGui::Text("%s:", label);
220
221 const char* const modeItems[] = { "Variable", "Const", "Pin" };
222 int modeIdx = 0;
223 if (operand.IsConst()) { modeIdx = 1; }
224 else if (operand.IsPin()) { modeIdx = 2; }
225
226 ImGui::SetNextItemWidth(90.f);
227 if (ImGui::Combo("##mode", &modeIdx, modeItems, 3))
228 {
229 if (modeIdx == 0)
231 else if (modeIdx == 1)
233 else if (modeIdx == 2)
235 }
236
237 ImGui::SameLine();
238
239 if (operand.IsVariable())
240 {
241 // Phase 24: Populate variable combo from both local and global variables
243 const std::vector<GlobalEntryDefinition>& globalVars = gtb.GetAllVariables();
244
245 // Build combined list: local variables first, then global variables
246 std::vector<std::string> allVarNames;
247 int currentIdx = -1;
248
249 // Add local variables
250 for (const auto& localVar : m_localVariables)
251 {
252 allVarNames.push_back(localVar.Key);
253 if (localVar.Key == operand.stringValue)
254 currentIdx = static_cast<int>(allVarNames.size()) - 1;
255 }
256
257 // Add separator if we have both local and global
258 if (!m_localVariables.empty() && !globalVars.empty())
259 {
260 allVarNames.push_back("--- Global Variables ---");
261 }
262
263 // Add global variables
264 for (const auto& globalVar : globalVars)
265 {
266 allVarNames.push_back(globalVar.Key);
267 if (globalVar.Key == operand.stringValue)
268 currentIdx = static_cast<int>(allVarNames.size()) - 1;
269 }
270
271 // Convert to const char* for ImGui
272 std::vector<const char*> varNamePtrs;
273 for (const auto& name : allVarNames)
274 {
275 varNamePtrs.push_back(name.c_str());
276 }
277
278 if (allVarNames.empty())
279 {
280 ImGui::TextDisabled("(no variables)");
281 }
282 else
283 {
284 ImGui::SetNextItemWidth(120.f);
285 int selectedIdx = (currentIdx >= 0) ? currentIdx : 0;
286
287 // Skip separator when selecting
288 if (selectedIdx >= 0 && selectedIdx < static_cast<int>(allVarNames.size()) &&
289 allVarNames[selectedIdx] == "--- Global Variables ---")
290 {
291 selectedIdx = 0;
292 }
293
294 if (ImGui::Combo("##var", &selectedIdx, varNamePtrs.data(), static_cast<int>(varNamePtrs.size())))
295 {
296 // Don't select the separator
297 if (selectedIdx >= 0 && selectedIdx < static_cast<int>(allVarNames.size()) &&
298 allVarNames[selectedIdx] != "--- Global Variables ---")
299 {
300 operand.stringValue = allVarNames[selectedIdx];
301 }
302 }
303 }
304 }
305 else if (operand.IsConst())
306 {
307 float fval = static_cast<float>(operand.constValue);
308 ImGui::SetNextItemWidth(80.f);
309 if (ImGui::InputFloat("##const", &fval, 0.f, 0.f, "%.2f"))
310 {
311 operand.constValue = static_cast<double>(fval);
312 }
313 }
314 else if (operand.IsPin())
315 {
316 char buf[64] = {};
317 if (operand.stringValue.size() < sizeof(buf))
318 {
319 operand.stringValue.copy(buf, operand.stringValue.size());
320 }
321 ImGui::SetNextItemWidth(120.f);
322 if (ImGui::InputText("##pin", buf, sizeof(buf)))
323 {
324 operand.stringValue = buf;
325 }
326 }
327
328 ImGui::PopID();
329#endif
330}
331
333{
334#ifndef OLYMPE_HEADLESS
335 const auto& ops = GetValidOperators();
337
338 int opIdx = 0;
339 for (int i = 0; i < static_cast<int>(ops.size()); ++i)
340 {
341 if (ops[i] == current) { opIdx = i; break; }
342 }
343
344 const char* items[] = { "==", "!=", "<", "<=", ">", ">=" };
345 ImGui::SetNextItemWidth(70.f);
346 if (ImGui::Combo("Operator", &opIdx, items, static_cast<int>(ops.size())))
347 {
349 }
350#endif
351}
352
354{
355#ifndef OLYMPE_HEADLESS
356 const std::string preview = GetPreview();
357 ImGui::Text("Preview: %s", preview.c_str());
358#endif
359}
360
362{
363#ifndef OLYMPE_HEADLESS
364 const bool canSave = IsValid();
365 if (!canSave) { ImGui::BeginDisabled(); }
366
367 if (ImGui::Button("Save"))
368 {
369 m_isConfirmed = true;
370 m_isOpen = false;
371 ImGui::CloseCurrentPopup();
372 }
373
374 if (!canSave) { ImGui::EndDisabled(); }
375
376 ImGui::SameLine();
377 if (ImGui::Button("Cancel"))
378 {
379 m_isOpen = false;
380 ImGui::CloseCurrentPopup();
381 }
382#endif
383}
384
385} // namespace Olympe
Modal dialog for creating and editing Condition Presets (Phase 24.1).
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
void SetOperator(const std::string &op)
Sets the comparison operator.
void SetName(const std::string &name)
Sets the display name of the working preset.
ConditionPresetEditDialog()
Constructs the dialog in Create mode with a blank preset.
ConditionPreset m_workingCopy
In-progress edits.
bool Confirm()
Confirms the dialog programmatically (equivalent to pressing Save).
ConditionPreset GetResult() const
Returns a copy of the working preset (contains the current form state).
static bool IsValidOperator(const std::string &op)
Returns true if the given operator string is recognised.
void SetRightVariable(const std::string &varName)
Sets the right variable name.
void SetRightPin(const std::string &pinRef)
Sets the right pin reference (relevant when rightMode == "Pin").
std::vector< BlackboardEntry > m_localVariables
Local variables from entity (Phase 24)
static bool IsOperandFilled(const Operand &operand)
Returns true if the operand is sufficiently filled.
static bool IsValidMode(const std::string &mode)
Returns true if the given mode string is recognised.
void SetLeftPin(const std::string &pinRef)
Sets the left pin reference.
std::string GetPreview() const
Returns a live preview string of the current condition.
void RenderOperandSelector(const char *label, bool isLeft)
void SetLeftVariable(const std::string &varName)
Sets the left variable name (relevant when leftMode == "Variable").
void SetLeftConst(double value)
Sets the left constant value.
bool IsValid() const
Returns true if the current condition is valid and can be saved.
void Render()
Renders the modal dialog using ImGui.
Mode
Whether the dialog creates a new preset or edits an existing one.
@ Create
New preset (form starts empty)
@ Edit
Existing preset (form pre-populated)
void SetRightMode(const std::string &mode)
Sets the right operand mode.
void SetLeftMode(const std::string &mode)
Sets the left operand mode.
void SetRightConst(double value)
Sets the right constant value.
static GlobalTemplateBlackboard & Get()
< Provides AssetID and INVALID_ASSET_ID
A globally-stored, reusable condition expression.
std::string GetPreview() const
Returns a human-readable preview string.
static std::string OpToString(ComparisonOp o)
Returns the operator as a display string (e.g. "<=").
static ComparisonOp OpFromString(const std::string &s)
Parses a display string back to a ComparisonOp.
std::string name
Human-readable display name (e.g. "Condition #1")
One side of a ConditionPreset comparison expression.
Definition Operand.h:45
static Operand CreateVariable(const std::string &variableID)
Factory — creates a Variable-mode operand.
Definition Operand.cpp:33
static Operand CreatePin(const std::string &pinLabel)
Factory — creates a Pin-mode operand.
Definition Operand.cpp:53
static Operand CreateConst(double constVal)
Factory — creates a Const-mode operand.
Definition Operand.cpp:43