SpiecsEngine
 
Loading...
Searching...
No Matches
ImguiStage.cpp
Go to the documentation of this file.
1/**
2* @file ImguiStage.h
3* @brief The ImguiStage Class Implementation.
4* @author Spices.
5*/
6
7#include "Pchheader.h"
8#include "ImguiStage.h"
9
10#include "Core/Library/StringLibrary.h"
11#include "World/World/World.h"
12#include "World/Entity.h"
13#include "World/Components/EntityComponent.h"
14#include "Core/Input/Input.h"
15#include "Core/Thread/ThreadModel.h"
16
17namespace Spices {
18
20 const std::string& panelName ,
21 FrameInfo& frameInfo
22 )
23 : ImguiSlate(panelName, frameInfo)
24 {}
25
27 {
29
30 /**
31 * @brief Begin render Stage Slate.
32 */
33 Begin();
34
35 /**
36 * @brief Search String.
37 */
38 static std::string searchString;
39 static bool isEnableSearch = false;
40
41 /**
42 * @brief Begin render Search Input Text.
43 */
44 {
45 SPICES_PROFILE_ZONEN("ImguiStage::Search");
46
47 ImGui::Spacing();
48 ImGui::Spacing();
49 ImGui::PushItemWidth(m_PanelSize.x - ImGuiH::GetLineItemSize().x * 2.0f - ImGui::GetStyle().WindowPadding.x);
50 static char search[256] = {};
51 if (ImGui::InputTextWithHint("##", ICON_TEXT(ICON_MD_SEARCH, Search), search, 128))
52 {
53 searchString = std::string(search);
54 if (searchString.size() == 0) isEnableSearch = false;
55 else isEnableSearch = true;
56 }
57 ImGui::PopItemWidth();
58
59 ImGui::SameLine(m_PanelSize.x - ImGuiH::GetLineItemSize().x * 2.0f);
60 ImGui::Button(ICON_MD_FILTER_ALT, ImGuiH::GetLineItemSize());
61 ImGui::SameLine(m_PanelSize.x - ImGuiH::GetLineItemSize().x * 1.0f);
62 ImGui::Button(ICON_MD_REORDER, ImGuiH::GetLineItemSize());
63 ImGui::Spacing();
64 }
65
66 /**
67 * @brief Begin render entity (tree)list.
68 */
69 {
70 SPICES_PROFILE_ZONEN("ImguiStage::Entity (tree)list");
71
72 static ImGuiTableFlags flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_NoBordersInBody |
73 ImGuiTableFlags_Sortable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_SortMulti | ImGuiTableFlags_Hideable |
74 ImGuiTableFlags_ScrollY | ImGuiTableFlags_SortTristate;
75 static constexpr ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap;
76
77 /**
78 * @brief 0: NoSort, 1: Ascending, 2: Descending.
79 */
80 static int sortState = 0;
81
82 static std::function<void(bool, Entity, uint32_t)> ClickSelect = [&](bool selected, Entity& entity, uint32_t e) {
83
84 if (ImGui::IsItemHovered() && ImGui::IsItemClicked(ImGuiMouseButton_Left))
85 {
86 auto& tagComp = entity.GetComponent<TagComponent>();
87
88 if (ImGui::GetIO().KeyShift)
89 {
90 if (!selected)
91 {
92 /**
93 * @brief Add select entity.
94 */
95 m_FrameInfo.m_PickEntityID.push_back((int)e, (*tagComp.GetTag().begin()));
96 }
97 }
98 else if (ImGui::GetIO().KeyCtrl)
99 {
100 if (selected)
101 {
102 /**
103 * @brief Remove select entity.
104 */
105 m_FrameInfo.m_PickEntityID.erase((int)e);
106 }
107 }
108 else
109 {
110 /**
111 * @brief Set a select entity.
112 */
113 m_FrameInfo.m_PickEntityID.clear();
114 m_FrameInfo.m_PickEntityID.push_back((int)e, (*tagComp.GetTag().begin()));
115 }
116 }
117 };
118
119 static std::function<void(uint32_t, uint32_t, uint32_t)> DragDrop = [&](uint32_t e, uint32_t p, uint32_t depth) {
120
121 if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_AcceptNoDrawDefaultRect))
122 {
123 ImGui::SetDragDropPayload("Stage_Drag", &e, sizeof(e), ImGuiCond_Once);
124 ImGui::EndDragDropSource();
125
126 if (depth > 0)
127 {
128 AsyncTask(ThreadPoolEnum::Game, [=]() {
129
130 /**
131 * @brief remove source from source's parent.
132 */
133 Entity parent((entt::entity)p, FrameInfo::Get().m_World.get());
134 EntityComponent& comp = parent.GetComponent<EntityComponent>();
135 comp.RemoveEntity(e);
136 if (comp.GetEntities().empty())
137 {
138 parent.RemoveComponent<EntityComponent>();
139 }
140 });
141 }
142 }
143 if (ImGui::BeginDragDropTarget())
144 {
145 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("Stage_Drag"))
146 {
147 uint32_t sourceEntity = *(uint32_t*)payload->Data;
148
149 AsyncTask(ThreadPoolEnum::Game, [=]() {
150
151 /**
152 * @brief Add source to this EntityComponent.
153 */
154 Entity((entt::entity)e, FrameInfo::Get().m_World.get()).AddComponent<EntityComponent>().AddEntity(sourceEntity);
155
156 });
157 }
158 ImGui::EndDragDropTarget();
159 }
160 };
161
162 static std::function<void(uint32_t, uint32_t, uint32_t)> DrawStageTree = [&](uint32_t e, uint32_t p, uint32_t depth) {
163
164 Entity entity((entt::entity)e, FrameInfo::Get().m_World.get());
165
166 auto& tagComp = entity.GetComponent<TagComponent>();
167 bool hasChild = entity.HasComponent<EntityComponent>();
168
169 /**
170 * @brief Search Filter here.
171 */
172 if (isEnableSearch)
173 {
174 if ((*tagComp.GetTag().begin()).find(searchString) == std::string::npos)
175 {
176 if (hasChild)
177 {
178 auto& entityComp = entity.GetComponent<EntityComponent>();
179 for (auto& child : entityComp.GetEntities())
180 {
181 DrawStageTree(child, e, depth + 1);
182 }
183 }
184
185 return;
186 }
187 }
188
189 std::stringstream ss;
190 ss << (*tagComp.GetTag().begin()).c_str() << "##" << (uint32_t)entity;
191
192 ImGui::PushID(ss.str().c_str());
193
194 ImGui::TableNextRow();
195 ImGui::TableNextColumn();
196
197 ImGuiTreeNodeFlags tree_node_flags = 0;
198 const bool item_is_selected = m_FrameInfo.m_PickEntityID.has_key((int)e);
199 if (item_is_selected)
200 {
201 tree_node_flags |= ImGuiTreeNodeFlags_Selected;
202 }
203
204 std::stringstream space;
205 for (int i = 0; i < depth; i++)
206 {
207 space << " ";
208 }
209 ImGui::Text(space.str().c_str());
210 ImGui::SameLine();
211
212 if (hasChild)
213 {
214 bool open = ImGui::TreeNodeEx(ss.str().c_str(), tree_node_flags);
215 ClickSelect(item_is_selected, entity, e);
216 DragDrop(e, p, depth);
217 ImGui::TableNextColumn();
218 ImGui::Button(ICON_MD_REMOVE_RED_EYE, ImGuiH::GetLineItemSize());
219 ImGui::TableNextColumn();
220 ImGui::Text("Entity");
221 if (open)
222 {
223 auto& entityComp = entity.GetComponent<EntityComponent>();
224 for (auto& child : entityComp.GetEntities())
225 {
226 DrawStageTree(child, e, depth + 1);
227 }
228
229 ImGui::TreePop();
230 }
231 }
232 else
233 {
234 ImGui::TreeNodeEx(ss.str().c_str(), tree_node_flags | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Leaf);
235 ClickSelect(item_is_selected, entity, e);
236 DragDrop(e, p, depth);
237 ImGui::TableNextColumn();
238 ImGui::Button(ICON_MD_REMOVE_RED_EYE, ImGuiH::GetLineItemSize());
239 ImGui::TableNextColumn();
240 ImGui::Text("Entity");
241 }
242
243 ImGui::PopID();
244 };
245
246 ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f);
247 ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.196f, 0.204f, 0.2f, 1.0f));
248 ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.164f, 0.18f, 0.184f, 1.0f));
249 ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.164f, 0.18f, 0.184f, 1.0f));
250 ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.196f, 0.204f, 0.2f, 1.0f));
251
252 if (ImGui::BeginTable("EntityTree", 3, flags))
253 {
254 // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On
255 ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide);
256 ImGui::TableSetupColumn(ICON_MD_REMOVE_RED_EYE, ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_NoResize, ImGuiH::GetLineItemSize().x);
257 ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_NoResize, ImGuiH::GetLineItemSize().x * 3.0f);
258 ImGui::TableHeadersRow();
259
260 // Sort our data if sort specs have been changed!
261 if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
262 {
263 // State changed since last frame.
264 if (sort_specs->SpecsDirty)
265 {
266 sortState = 0;
267
268 // Need sort this frame.
269 if (sort_specs->SpecsCount > 0)
270 {
271 sortState = sort_specs->Specs->SortDirection;
272 }
273
274 sort_specs->SpecsDirty = false;
275 }
276 }
277
278 FrameInfo::Get().m_World->ViewRoot([&](Entity& entity) {
279 DrawStageTree(entity, 0, 0);
280 });
281
282 /**
283 * @brief Begin render add entity panel.
284 */
285 {
286 SPICES_PROFILE_ZONEN("ImguiStage::Add Entity");
287
288 if (ImGui::BeginPopupContextWindow(0, ImGuiPopupFlags_MouseButtonRight))
289 {
290 if (ImGui::MenuItem("Create Empty Entity"))
291 {
292 AsyncTask(ThreadPoolEnum::Game, [=]() {
293
294 FrameInfo::Get().m_World->CreateEntity("Entity");
295
296 });
297 }
298 ImGui::EndPopup();
299 }
300 }
301
302 ImGui::EndTable();
303 }
304 ImGui::PopStyleColor(4);
305 ImGui::PopStyleVar();
306 }
307
308 /**
309 * @brief End render Visualizer.
310 */
311 End();
312 }
313}
#define ICON_TEXT(icon, text)
Definition ImguiHelper.h:24
#define SPICES_PROFILE_ZONEN(...)
#define SPICES_PROFILE_ZONE
Entity Class. This class defines the specific behaves of Entity.
Definition Entity.h:20
static FrameInfo & Get()
Get FrameInfo.
Definition FrameInfo.cpp:14
FrameInfo Class. This class defines the FrameInfo data.
Definition FrameInfo.h:32
void End()
End a slate.
ImguiSlate(const std::string &panelName, FrameInfo &frameInfo)
Constructor Function. Init with Slate's name.
Definition ImguiUtils.h:35
This Class defines the basic behaves of specific slate. When we add an new Slate, we need inherit fro...
Definition ImguiUtils.h:27
virtual void OnRender() override
This interface is called On SlateRenderer Render.
ImguiStage(const std::string &panelName, FrameInfo &frameInfo)
Constructor Function.
The ImguiStage Class. This class defines how to render a Stage.
Definition ImguiStage.h:18