TazGraph Project v0.1.0
Loading...
Searching...
No Matches
PythonCodeComponent.h
1#pragma once
2
3#include "../Components.h"
4
5#pragma GCC diagnostic push
6#pragma GCC diagnostic ignored "-Wattributes"
7
9{
10private:
11 char _pythonBuffer[1024] = "";
12 char _updateBuffer[4096] = "";
13
14 std::string _outputText;
15 std::string _updateOutputText;
16
17 py::object _stdout_buffer;
18 py::module_ sys;
19
20 enum console_state {
21 Collapsed,
22 Expanded
23 };
24
25 enum class ScriptType {
26 OneOff,
27 OnUpdate
28 };
29
30 ScriptType currentScriptType = ScriptType::OneOff;
31
32 console_state state = console_state::Collapsed;
33 console_state last_state = console_state::Collapsed;
34
35public:
36
37 float intervalSec = 1.0f;
38 double lastExecTime = 0.0;
39 bool useInterval = false;
40 bool updatePaused = true;
41
42 bool inputActive = false;
43
44 bool readyToClear = false;
45 bool readyToExecute = false;
46
48 {
49 }
50
51
52 void init()
53 {
54 }
55 void update(float deltaTime)
56 {
57 py::gil_scoped_acquire gil;
58 if (readyToExecute) {
59 runScript();
60 readyToExecute = false;
61 }
62
63 if (readyToClear) {
64 clearOutput();
65 readyToClear = false;
66 }
67
68 double now = ImGui::GetTime();
69
70 if (!updatePaused &&
71 currentScriptType == ScriptType::OnUpdate
72 && now - lastExecTime >= intervalSec) {
73 runUpdateScript(deltaTime);
74 lastExecTime = now;
75 }
76
77 sys = py::module_::import("sys");
78 _stdout_buffer = sys.attr("stdout");
79 _stdout_buffer = sys.attr("stdout");
80 }
81
82 std::string GetComponentName() {
83 return "PythonCodeComponent";
84 }
85
86 void showGUI(std::vector<BaseComponent*> otherComponents = {}) {
87 ImGui::Text("Script Type:");
88 ImGui::SameLine();
89 if (ImGui::RadioButton("One-Off", currentScriptType == ScriptType::OneOff)) {
90 currentScriptType = ScriptType::OneOff;
91 }
92 ImGui::SameLine();
93 if (ImGui::RadioButton("On Update", currentScriptType == ScriptType::OnUpdate)) {
94 currentScriptType = ScriptType::OnUpdate;
95 }
96
97 ImGui::Separator();
98 bool childActive = ImGui::BeginChild("Python Interpreter");
99 if (childActive) {
100 ImGuiChildFlags flags = ImGuiChildFlags_ResizeY;
101 bool nestedChildActive = ImGui::BeginChild("Python Input", ImVec2(0.0f, 300.0f), flags);
102 if (nestedChildActive) {
103 ImGui::Text("Python Script");
104 if (currentScriptType == ScriptType::OneOff) {
105 ImGui::Text("One-Off Script (Execute on demand)");
106 }
107 else {
108 ImGui::Text("Update Script (Execute every frame)");
109 ImGui::Checkbox("Pause Update", &updatePaused);
110 }
111 float originalScale = ImGui::GetFont()->Scale;
112 ImGui::GetFont()->Scale = 1.5f;
113 ImGui::PushFont(ImGui::GetFont());
114
115 if (currentScriptType == ScriptType::OneOff) {
116 ImGui::InputTextMultiline("##pythonInput",
117 _pythonBuffer, IM_ARRAYSIZE(_pythonBuffer),
118 ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 4 * 1.5f));
119 }
120 else {
121 ImGui::InputTextMultiline("##updateInput",
122 _updateBuffer, IM_ARRAYSIZE(_updateBuffer),
123 ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 4 * 1.5f));
124 }
125
126 inputActive = ImGui::IsItemActive() || ImGui::IsItemFocused();
127
128 ImGui::PopFont();
129 ImGui::GetFont()->Scale = originalScale;
130
131 }
132 ImGui::EndChild(); //? Needs to be outside
133
134 if (currentScriptType == ScriptType::OneOff) {
135 if (ImGui::Button("Run")) {
136 readyToExecute = true;
137 }
138 ImGui::SameLine();
139 if (ImGui::Button("Clear Output")) {
140 readyToClear = true;
141 }
142 }
143 else {
144 ImGui::Text("Auto-run settings:");
145 ImGui::Checkbox("Use Interval", &useInterval);
146 if (useInterval) {
147 ImGui::InputFloat("Interval (s)", &intervalSec, 0.1f, 1.0f, "%.2f");
148 }
149 else {
150 intervalSec = 0.0f;
151 ImGui::TextDisabled("(Runs every frame)");
152 }
153
154 if (ImGui::Button("Clear Output")) {
155 readyToClear = true;
156 }
157 }
158 nestedChildActive = ImGui::BeginChild("Python Output");
159 if (nestedChildActive) {
160 ImGui::Text("Output:");
161 bool nestedNestedChildActive = ImGui::BeginChild("OutputChild", ImVec2(0.0f, 100.0f), true);
162 if (nestedNestedChildActive)
163 {
164 if (currentScriptType == ScriptType::OneOff) {
165 ImGui::TextWrapped("%s", _outputText.c_str());
166 }
167 else {
168 ImGui::TextWrapped("%s", _updateOutputText.c_str());
169 }
170 }
171 ImGui::EndChild(); //? Needs to be outside
172 }
173 ImGui::EndChild(); //? Needs to be outside
174 }
175 ImGui::EndChild(); //? Needs to be outside
176 };
177
178 void clearOutput() {
179 try {
180 _stdout_buffer.attr("truncate")(0);
181 _stdout_buffer.attr("seek")(0);
182 }
183 catch (const std::exception& e) {
184 std::cerr << "Failed to clear StringIO: " << e.what() << std::endl;
185 }
186 }
187
188 void runScript() {
190 try {
191
192 py::exec(_pythonBuffer);
193 py::object output = _stdout_buffer.attr("getvalue")();
194 _outputText = output.cast<std::string>();
195
196 }
197 catch (const std::exception& e) {
198 _outputText = std::string("Python error: ") + e.what();
199 }
200 }
201
202 void runUpdateScript(float deltaTime) {
203 try {
204
205 py::globals()["deltaTime"] = deltaTime;
206
207 py::exec(_updateBuffer);
208
209 py::object output = _stdout_buffer.attr("getvalue")();
210 _updateOutputText = output.cast<std::string>();
211
212 }
213 catch (const std::exception& e) {
214 _updateOutputText = std::string("Python error: ") + e.what();
215 }
216 }
217};
218
219#pragma GCC diagnostic pop
Definition PythonCodeComponent.h:9
void update(float deltaTime)
Definition PythonCodeComponent.h:55
void runScript()
Definition PythonCodeComponent.h:188