Cthulhu  0.2.10
Cthulhu compiler collection
config.cpp
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-3.0-only
3 #include "stdafx.hpp"
4 
5 #include "editor/config.hpp"
6 #include "editor/utils.hpp"
7 
8 #include "std/typed/vector.h"
9 #include "std/vector.h"
10 
11 using namespace ed;
12 
14 
15 static const ImGuiTableFlags kConfigTableFlags
16  = ImGuiTableFlags_BordersV
17  | ImGuiTableFlags_BordersOuterH
18  | ImGuiTableFlags_Resizable
19  | ImGuiTableFlags_RowBg
20  | ImGuiTableFlags_NoHostExtendX
21  | ImGuiTableFlags_NoBordersInBody;
22 
23 static const ImGuiTreeNodeFlags kConfigGroupNodeFlags
24  = ImGuiTreeNodeFlags_SpanAllColumns
25  | ImGuiTreeNodeFlags_AllowOverlap;
26 
27 static const ImGuiTreeNodeFlags kConfigValueNodeFlags
28  = kConfigGroupNodeFlags
29  | ImGuiTreeNodeFlags_Leaf
30  | ImGuiTreeNodeFlags_Bullet
31  | ImGuiTreeNodeFlags_NoTreePushOnOpen;
32 
33 const char *get_name(const cfg_field_t *field)
34 {
35  const cfg_info_t *info = cfg_get_info(field);
36  return info->name;
37 }
38 
40 {
41  return ed::strfmt<64>("##%s", get_name(field));
42 }
43 
44 void draw_info_preamble(const cfg_info_t *info)
45 {
46  const char *brief = info->brief != nullptr ? info->brief : "no brief";
47  ImGui::Text("brief: %s", brief);
48 }
49 
50 void draw_field_info(const cfg_field_t *field)
51 {
52  const cfg_info_t *info = cfg_get_info(field);
53  ImGui::TextDisabled("%s", info->name);
54  if (ImGui::BeginItemTooltip())
55  {
56  ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.f);
57  draw_info_preamble(info);
58 
59  ImGui::TextUnformatted("args: ");
60 
61  cfg_arg_array_t args = info->args;
62  for (size_t i = 0; i < args.count; i++)
63  {
64  ImGui::SameLine();
65  ImGui::Text("%s", args.args[i]);
66  }
67 
68  ImGui::PopTextWrapPos();
69  ImGui::EndTooltip();
70  }
71 }
72 
73 void draw_group_info(const cfg_group_t *group)
74 {
75  const cfg_info_t *info = cfg_group_info(group);
76 
77  ImGui::TextDisabled("%s", info->name);
78  if (ImGui::BeginItemTooltip())
79  {
80  ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.f);
81  draw_info_preamble(info);
82 
83  typevec_t *child_groups = cfg_get_groups(group);
84  vector_t *child_fields = cfg_get_fields(group);
85 
86  size_t group_count = typevec_len(child_groups);
87  size_t field_count = vector_len(child_fields);
88 
89  ImGui::SeparatorText("Children");
90  ImGui::Text("%zu groups, %zu fields", group_count, field_count);
91 
92  ImGui::PopTextWrapPos();
93  ImGui::EndTooltip();
94  }
95 }
96 
97 void draw_bool(cfg_field_t *field)
98 {
99  bool value = cfg_bool_value(field);
100  if (ImGui::Checkbox(get_label(field), &value))
101  {
102  cfg_set_bool(field, value);
103  }
104 }
105 
106 void draw_int(cfg_field_t *field)
107 {
108  const cfg_int_t *cfg = cfg_int_info(field);
109  int value = cfg_int_value(field);
110  if (ImGui::DragInt(get_label(field), &value, 1.f, cfg->min, cfg->max))
111  {
112  // we know that the value is in range because of the drag constraints
113  (void)cfg_set_int(field, value);
114  }
115 }
116 
118 {
119  const char *value = cfg_string_value(field);
120  char buffer[256] = { 0 };
121  strncpy_s(buffer, value, std::size(buffer));
122  if (ImGui::InputText(get_label(field), buffer, std::size(buffer)))
123  {
124  cfg_set_string(field, buffer);
125  }
126 }
127 
128 void draw_enum(cfg_field_t *field)
129 {
130  const cfg_enum_t *cfg = cfg_enum_info(field);
131  size_t value = cfg_enum_value(field);
132 
133  size_t current = SIZE_MAX;
134  for (size_t i = 0; i < cfg->count; i++)
135  {
136  if (cfg->options[i].value == value)
137  {
138  current = i;
139  break;
140  }
141  }
142 
143  CTASSERTF(current != SIZE_MAX, "invalid enum value %zu for field %s", value, get_name(field));
144 
145  if (ImGui::BeginCombo(get_label(field), cfg->options[current].text))
146  {
147  for (size_t i = 0; i < cfg->count; i++)
148  {
149  bool is_selected = (current == i);
150  if (ImGui::Selectable(cfg->options[i].text, is_selected))
151  {
152  // we know that the value is in range because of the selectable constraints
153  (void)cfg_set_enum(field, cfg->options[i].text);
154  }
155 
156  if (is_selected)
157  {
158  ImGui::SetItemDefaultFocus();
159  }
160  }
161 
162  ImGui::EndCombo();
163  }
164 }
165 
167 {
168  const char *edit_flags_popup = "Edit Flags";
169 
170  const cfg_enum_t *cfg = cfg_flags_info(field);
171  ImU64 value = cfg_flags_value(field);
172 
173  if (ImGui::Button("Edit"))
174  {
175  ImGui::OpenPopup(edit_flags_popup);
176  }
177 
178  if (ImGui::BeginPopup(edit_flags_popup))
179  {
180  bool changed = false;
181  for (size_t i = 0; i < cfg->count; i++)
182  {
183  const cfg_choice_t *choice = &cfg->options[i];
184  ImU64 flag = choice->value;
185  if (ImGui::CheckboxFlags(choice->text, &value, flag))
186  {
187  changed = true;
188  }
189  }
190 
191  if (changed)
192  {
193  cfg_set_flag_value(field, value);
194  }
195 
196  ImGui::EndPopup();
197  }
198 }
199 
201 {
202  cfg_type_t type = cfg_get_type(field);
203  switch (type)
204  {
205  case eConfigBool:
206  draw_bool(field);
207  break;
208 
209  case eConfigInt:
210  draw_int(field);
211  break;
212 
213  case eConfigString:
214  draw_string(field);
215  break;
216 
217  case eConfigEnum:
218  draw_enum(field);
219  break;
220 
221  case eConfigFlags:
222  draw_flags(field);
223  break;
224 
225  default:
226  ImGui::TextDisabled("Unknown type");
227  break;
228  }
229 }
230 
232 {
233  const cfg_int_t *cfg = cfg_int_info(field);
234 
235  if (cfg->min == INT_MIN && cfg->max == INT_MAX)
236  {
237  ImGui::TextDisabled("no constraints");
238  return;
239  }
240  else if (cfg->min == INT_MIN)
241  {
242  ImGui::Text("min (%d)", cfg->max);
243  return;
244  }
245  else if (cfg->max == INT_MAX)
246  {
247  ImGui::Text("max (%d)", cfg->min);
248  return;
249  }
250  else
251  {
252  ImGui::Text("range (%d, %d)", cfg->min, cfg->max);
253  }
254 }
255 
256 void draw_constraints(const cfg_field_t *field)
257 {
258  cfg_type_t type = cfg_get_type(field);
259  switch (type)
260  {
261  case eConfigBool:
262  case eConfigString:
263  case eConfigEnum:
264  case eConfigFlags:
265  break;
266 
267  case eConfigInt:
268  draw_int_constraints(field);
269  break;
270 
271  default:
272  ImGui::TextDisabled("Unknown type");
273  break;
274  }
275 }
276 
278 {
279  const cfg_info_t *info = cfg_get_info(field);
280  cfg_type_t type = cfg_get_type(field);
281 
282  ImGui::TableNextColumn();
283  ImGui::AlignTextToFramePadding();
284  ImGui::TreeNodeEx(info->name, kConfigValueNodeFlags);
285 
286  ImGui::TableNextColumn();
287  ImGui::TextUnformatted(cfg_type_string(type));
288 
289  ImGui::TableNextColumn();
290  draw_value(field);
291 
292  ImGui::TableNextColumn();
293  draw_constraints(field);
294 
295  ImGui::TableNextColumn();
296  draw_field_info(field);
297 }
298 
299 void draw_config_group(cfg_group_t *group);
300 
302 {
303  typevec_t *children = cfg_get_groups(group);
304  size_t child_count = typevec_len(children);
305  for (size_t i = 0; i < child_count; ++i)
306  {
307  ImGui::TableNextRow();
308  cfg_group_t *child = reinterpret_cast<cfg_group_t*>(typevec_offset(children, i));
309  draw_config_group(child);
310  }
311 }
312 
314 {
315  vector_t *fields = cfg_get_fields(group);
316  size_t field_count = vector_len(fields);
317  for (size_t i = 0; i < field_count; ++i)
318  {
319  ImGui::TableNextRow();
320  cfg_field_t *field = reinterpret_cast<cfg_field_t*>(vector_get(fields, i));
321  draw_config_entry(field);
322  }
323 }
324 
326 {
327  ScopeID id(group);
328 
329  ImGui::TableNextColumn();
330 
331  const cfg_info_t *info = cfg_group_info(group);
332  bool is_group_open = ImGui::TreeNodeEx(info->name, kConfigGroupNodeFlags);
333 
334  ImGui::TableNextColumn();
335  ImGui::TextDisabled("--");
336 
337  ImGui::TableNextColumn();
338  ImGui::TableNextColumn();
339  ImGui::TableNextColumn();
340  draw_group_info(group);
341 
342  if (is_group_open)
343  {
346 
347  ImGui::TreePop();
348  }
349 }
350 
352 {
353  if (ImGui::BeginTable("Config", 5, kConfigTableFlags))
354  {
355  ImGui::TableSetupColumn("Name");
356  ImGui::TableSetupColumn("Type");
357  ImGui::TableSetupColumn("Value");
358  ImGui::TableSetupColumn("Constraints");
359  ImGui::TableSetupColumn("Info");
360 
361  ImGui::TableHeadersRow();
362 
364 
365  ImGui::EndTable();
366  }
367 }
CT_NODISCARD size_t size
Definition: scan.h:128
void draw_group_info(const cfg_group_t *group)
Definition: config.cpp:73
void draw_config_group(cfg_group_t *group)
Definition: config.cpp:325
void draw_config_group_children(cfg_group_t *group)
Definition: config.cpp:301
void draw_enum(cfg_field_t *field)
Definition: config.cpp:128
void draw_int_constraints(const cfg_field_t *field)
Definition: config.cpp:231
void draw_config_entry(cfg_field_t *field)
Definition: config.cpp:277
ed::SmallString< 64 > get_label(const cfg_field_t *field)
Definition: config.cpp:39
void draw_info_preamble(const cfg_info_t *info)
Definition: config.cpp:44
void draw_flags(cfg_field_t *field)
Definition: config.cpp:166
void draw_constraints(const cfg_field_t *field)
Definition: config.cpp:256
const char * get_name(const cfg_field_t *field)
Definition: config.cpp:33
void draw_value(cfg_field_t *field)
Definition: config.cpp:200
void draw_int(cfg_field_t *field)
Definition: config.cpp:106
void draw_config_group_fields(cfg_group_t *group)
Definition: config.cpp:313
void draw_field_info(const cfg_field_t *field)
Definition: config.cpp:50
void draw_bool(cfg_field_t *field)
Definition: config.cpp:97
void draw_string(cfg_field_t *field)
Definition: config.cpp:117
CT_PUREFN CT_CONFIG_API const char * cfg_string_value(const cfg_field_t *field)
get the current string value of a configuration field
Definition: reflect.c:151
CT_PUREFN CT_CONFIG_API size_t cfg_flags_value(const cfg_field_t *field)
get the current flags value of a configuration field
Definition: reflect.c:175
CT_PUREFN CT_CONFIG_API bool cfg_bool_value(const cfg_field_t *field)
get the current boolean value of a configuration field
Definition: reflect.c:143
CT_PUREFN CT_CONFIG_API int cfg_int_value(const cfg_field_t *field)
get the current integer value of a configuration field
Definition: reflect.c:135
CT_PUREFN CT_CONFIG_API size_t cfg_enum_value(const cfg_field_t *field)
get the current enum value of a configuration field
Definition: reflect.c:167
CT_PUREFN CT_CONFIG_API const cfg_info_t * cfg_group_info(const cfg_group_t *config)
get the information about a configuration group
Definition: reflect.c:22
CT_CONSTFN CT_CONFIG_API const char * cfg_type_string(cfg_type_t type)
get the name of a configuration type
Definition: reflect.c:99
CT_PUREFN CT_CONFIG_API typevec_t * cfg_get_groups(const cfg_group_t *config)
get all subgroups in a configuration group
Definition: reflect.c:30
CT_PUREFN CT_CONFIG_API const cfg_int_t * cfg_int_info(const cfg_field_t *field)
get the information about an integer field
Definition: reflect.c:46
CT_PUREFN CT_CONFIG_API const cfg_enum_t * cfg_enum_info(const cfg_field_t *field)
get the information about a choice field
Definition: reflect.c:78
CT_PUREFN CT_CONFIG_API const cfg_enum_t * cfg_flags_info(const cfg_field_t *field)
get the information about a flags field
Definition: reflect.c:86
CT_PUREFN CT_CONFIG_API vector_t * cfg_get_fields(const cfg_group_t *config)
get all fields in a configuration group
Definition: reflect.c:38
CT_PUREFN CT_CONFIG_API cfg_type_t cfg_get_type(const cfg_field_t *field)
get the type of a configuration field
Definition: reflect.c:6
CT_PUREFN CT_CONFIG_API const cfg_info_t * cfg_get_info(const cfg_field_t *field)
get the information about a configuration field
Definition: reflect.c:14
CT_NODISCARD CT_CONFIG_API bool cfg_set_int(cfg_field_t *field, int value)
set the current value of an int field
Definition: update.c:9
CT_CONFIG_API void cfg_set_string(cfg_field_t *field, char *value)
set the current value of a string field
Definition: update.c:35
CT_CONFIG_API bool cfg_set_enum(cfg_field_t *field, const char *choice)
set the current value of an enum field set the value via a string name
Definition: update.c:51
CT_CONFIG_API void cfg_set_bool(cfg_field_t *field, bool value)
set the current value of a bool field
Definition: update.c:27
CT_CONFIG_API void cfg_set_flag_value(cfg_field_t *field, size_t value)
set the current value of a flags field set the value via an integer value
Definition: update.c:155
cfg_type_t
the type of a configuration field
Definition: config.h:27
#define CTASSERTF(expr,...)
assert a condition with a message and optional format arguments
Definition: panic.h:116
CT_NODISCARD CT_PUREFN CT_STD_API size_t typevec_len(const typevec_t *vec)
get the length of a vector
Definition: vector.c:120
CT_NODISCARD CT_PUREFN CT_STD_API void * typevec_offset(const typevec_t *vec, size_t index)
get a pointer to the value at the given index
Definition: vector.c:191
CT_NODISCARD CT_PUREFN CT_STD_API void * vector_get(const vector_t *vector, size_t index)
get a value from a vector
Definition: vector.c:134
CT_NODISCARD CT_PUREFN CT_STD_API size_t vector_len(const vector_t *vector)
get the length of a vector
Definition: vector.c:152
Definition: compile.hpp:13
void draw_config_panel(cfg_group_t *config)
Definition: config.cpp:351
const cfg_arg_t * args
Definition: config.h:61
size_t count
Definition: config.h:62
a choice in a set of options
Definition: config.h:97
STA_FIELD_STRING const char * text
the name of this choice
Definition: config.h:99
size_t value
the value of this choice
Definition: config.h:102
a choice from a set of options
Definition: config.h:107
size_t count
the number of choices in this set
Definition: config.h:112
information about a configuration field
Definition: config.h:69
STA_FIELD_STRING const char * brief
a brief description of this field
Definition: config.h:74
cfg_arg_array_t args
the spellings to use for this field
Definition: config.h:77
STA_FIELD_STRING const char * name
the name of this field
Definition: config.h:71
an integer field
Definition: config.h:82
A vector with a fixed type size.
Definition: vector.h:24
a generic vector of pointers
Definition: vector.c:16