yaze 0.2.0
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
settings_editor.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_SETTINGS_EDITOR_H
2#define YAZE_APP_EDITOR_SETTINGS_EDITOR_H
3
4#include "imgui/imgui.h"
5
6#include "absl/status/status.h"
8
9namespace yaze {
10namespace app {
11namespace editor {
12
13// Simple representation for a tree
14// (this is designed to be simple to understand for our demos, not to be
15// efficient etc.)
17 char Name[28];
18 ImGuiID UID = 0;
20 ImVector<ExampleTreeNode*> Childs;
21
22 // Data
23 bool HasData = false; // All leaves have data
24 bool DataIsEnabled = false;
25 int DataInt = 128;
26 ImVec2 DataVec2 = ImVec2(0.0f, 3.141592f);
27};
28
29// Simple representation of struct metadata/serialization data.
30// (this is a minimal version of what a typical advanced application may
31// provide)
33 const char* Name;
34 ImGuiDataType DataType;
36 int Offset;
37};
38
39// Metadata description of ExampleTreeNode struct.
40static const ExampleMemberInfo ExampleTreeNodeMemberInfos[]{
41 {"Enabled", ImGuiDataType_Bool, 1,
42 offsetof(ExampleTreeNode, DataIsEnabled)},
43 {"MyInt", ImGuiDataType_S32, 1, offsetof(ExampleTreeNode, DataInt)},
44 {"MyVec2", ImGuiDataType_Float, 2, offsetof(ExampleTreeNode, DataVec2)},
45};
46
47static ExampleTreeNode* ExampleTree_CreateNode(const char* name,
48 const ImGuiID uid,
49 ExampleTreeNode* parent) {
50 ExampleTreeNode* node = IM_NEW(ExampleTreeNode);
51 snprintf(node->Name, IM_ARRAYSIZE(node->Name), "%s", name);
52 node->UID = uid;
53 node->Parent = parent;
54 if (parent) parent->Childs.push_back(node);
55 return node;
56}
57
58// Create example tree data
59static ExampleTreeNode* ExampleTree_CreateDemoTree() {
60 static const char* root_names[] = {"Apple", "Banana", "Cherry",
61 "Kiwi", "Mango", "Orange",
62 "Pineapple", "Strawberry", "Watermelon"};
63 char name_buf[32];
64 ImGuiID uid = 0;
65 ExampleTreeNode* node_L0 = ExampleTree_CreateNode("<ROOT>", ++uid, NULL);
66 for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * 2; idx_L0++) {
67 snprintf(name_buf, 32, "%s %d", root_names[idx_L0 / 2], idx_L0 % 2);
68 ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0);
69 const int number_of_childs = (int)strlen(node_L1->Name);
70 for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++) {
71 snprintf(name_buf, 32, "Child %d", idx_L1);
72 ExampleTreeNode* node_L2 =
73 ExampleTree_CreateNode(name_buf, ++uid, node_L1);
74 node_L2->HasData = true;
75 if (idx_L1 == 0) {
76 snprintf(name_buf, 32, "Sub-child %d", 0);
77 ExampleTreeNode* node_L3 =
78 ExampleTree_CreateNode(name_buf, ++uid, node_L2);
79 node_L3->HasData = true;
80 }
81 }
82 }
83 return node_L0;
84}
85
87 ImGuiTextFilter Filter;
88
89 void Draw(ExampleTreeNode* root_node) {
90 ImGui::SetNextItemWidth(-FLT_MIN);
91 ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F,
92 ImGuiInputFlags_Tooltip);
93 ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true);
94 if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf,
95 IM_ARRAYSIZE(Filter.InputBuf),
96 ImGuiInputTextFlags_EscapeClearsAll))
97 Filter.Build();
98 ImGui::PopItemFlag();
99
100 ImGuiTableFlags table_flags = ImGuiTableFlags_Resizable |
101 ImGuiTableFlags_ScrollY |
102 ImGuiTableFlags_RowBg;
103 if (ImGui::BeginTable("##split", 2, table_flags)) {
104 ImGui::TableSetupColumn("Object", ImGuiTableColumnFlags_WidthStretch,
105 1.0f);
106 ImGui::TableSetupColumn("Contents", ImGuiTableColumnFlags_WidthStretch,
107 2.0f); // Default twice larger
108 // ImGui::TableSetupScrollFreeze(0, 1);
109 // ImGui::TableHeadersRow();
110
111 for (ExampleTreeNode* node : root_node->Childs)
112 if (Filter.PassFilter(node->Name)) // Filter root node
113 DrawTreeNode(node);
114 ImGui::EndTable();
115 }
116 }
117
119 // Object tree node
120 ImGui::PushID((int)node->UID);
121 ImGui::TableNextRow();
122 ImGui::TableSetColumnIndex(0);
123 ImGui::AlignTextToFramePadding();
124 ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None;
125 tree_flags |=
126 ImGuiTreeNodeFlags_SpanAllColumns |
127 ImGuiTreeNodeFlags_AllowOverlap; // Highlight whole row for visibility
128 tree_flags |=
129 ImGuiTreeNodeFlags_OpenOnArrow |
130 ImGuiTreeNodeFlags_OpenOnDoubleClick; // Standard opening mode as we
131 // are likely to want to add
132 // selection afterwards
133 tree_flags |=
134 ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Left arrow support
135 bool node_open =
136 ImGui::TreeNodeEx("##Object", tree_flags, "%s", node->Name);
137 ImGui::TableSetColumnIndex(1);
138 ImGui::TextDisabled("UID: 0x%08X", node->UID);
139
140 // Display child and data
141 if (node_open)
142 for (ExampleTreeNode* child : node->Childs) DrawTreeNode(child);
143 if (node_open && node->HasData) {
144 // In a typical application, the structure description would be derived
145 // from a data-driven system.
146 // - We try to mimic this with our ExampleMemberInfo structure and the
147 // ExampleTreeNodeMemberInfos[] array.
148 // - Limits and some details are hard-coded to simplify the demo.
149 // - Text and Selectable are less high than framed widgets, using
150 // AlignTextToFramePadding() we add vertical spacing to make the
151 // selectable lines equal high.
152 for (const ExampleMemberInfo& field_desc : ExampleTreeNodeMemberInfos) {
153 ImGui::TableNextRow();
154 ImGui::TableSetColumnIndex(0);
155 ImGui::AlignTextToFramePadding();
156 ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop | ImGuiItemFlags_NoNav,
157 true);
158 ImGui::Selectable(field_desc.Name, false,
159 ImGuiSelectableFlags_SpanAllColumns |
160 ImGuiSelectableFlags_AllowOverlap);
161 ImGui::PopItemFlag();
162 ImGui::TableSetColumnIndex(1);
163 ImGui::PushID(field_desc.Name);
164 void* field_ptr = (void*)(((unsigned char*)node) + field_desc.Offset);
165 switch (field_desc.DataType) {
166 case ImGuiDataType_Bool: {
167 IM_ASSERT(field_desc.DataCount == 1);
168 ImGui::Checkbox("##Editor", (bool*)field_ptr);
169 break;
170 }
171 case ImGuiDataType_S32: {
172 int v_min = INT_MIN, v_max = INT_MAX;
173 ImGui::SetNextItemWidth(-FLT_MIN);
174 ImGui::DragScalarN("##Editor", field_desc.DataType, field_ptr,
175 field_desc.DataCount, 1.0f, &v_min, &v_max);
176 break;
177 }
178 case ImGuiDataType_Float: {
179 float v_min = 0.0f, v_max = 1.0f;
180 ImGui::SetNextItemWidth(-FLT_MIN);
181 ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr,
182 field_desc.DataCount, &v_min, &v_max);
183 break;
184 }
185 }
186 ImGui::PopID();
187 }
188 }
189 if (node_open) ImGui::TreePop();
190 ImGui::PopID();
191 }
192};
193
194// Demonstrate creating a simple property editor.
195static void ShowExampleAppPropertyEditor(bool* p_open) {
196 ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver);
197 if (!ImGui::Begin("Example: Property editor", p_open)) {
198 ImGui::End();
199 return;
200 }
201
202 static ExampleAppPropertyEditor property_editor;
203 static ExampleTreeNode* tree_data = ExampleTree_CreateDemoTree();
204 property_editor.Draw(tree_data);
205
206 ImGui::End();
207}
208
209class SettingsEditor : public Editor {
210 public:
212
213 absl::Status Update() override;
214
215 absl::Status Undo() override { return absl::UnimplementedError("Undo"); }
216 absl::Status Redo() override { return absl::UnimplementedError("Redo"); }
217 absl::Status Cut() override { return absl::UnimplementedError("Cut"); }
218 absl::Status Copy() override { return absl::UnimplementedError("Copy"); }
219 absl::Status Paste() override { return absl::UnimplementedError("Paste"); }
220 absl::Status Find() override { return absl::UnimplementedError("Find"); }
221
222 private:
223 void DrawGeneralSettings();
224
225 absl::Status DrawKeyboardShortcuts();
226};
227
228} // namespace editor
229} // namespace app
230} // namespace yaze
231
232#endif // YAZE_APP_EDITOR_SETTINGS_EDITOR_H_
Interface for editor classes.
Definition editor.h:39
Definition common.cc:21
void Draw(ExampleTreeNode *root_node)
ImVector< ExampleTreeNode * > Childs