WKLib 0.2.3
A modding library for White Knuckle
Loading...
Searching...
No Matches
DemoWindow.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using Imui.Controls;
4using Imui.Core;
5using Imui.Rendering;
6using Imui.Style;
7using UnityEngine;
8
10
11[Flags]
12internal enum DemoEnumFlags
13{
14 None = 0,
15 Flag1 = 1,
16 Flag2 = 2,
17 Flag3 = 4,
18 Flag1And3 = Flag1 | Flag3
19}
20
21internal struct DemoTreeNode
22{
23 public string Name;
24 public DemoTreeNode[] Childrens;
25
26 public DemoTreeNode(string name, params DemoTreeNode[] childrens)
27 {
28 Name = name;
29 Childrens = childrens;
30 }
31}
32
33public static class DemoWindow
34{
35 private static char[] formatBuffer = new char[256];
36
37 private static bool checkboxValue;
38 private static int selectedValue = -1;
39 private static float bouncingBallSize = 22;
40 private static float bouncingBallSpeed = 1;
41 private static int bouncingBallTrail = 32;
42 private static float bouncingBallTime;
43
44 private static string[] values =
45 {
46 "Value 1", "Value 2", "Value 3", "Value 4", "Value 5", "Value 6", "Value 7", "Value 8", "Value 9", "Value 10", "Value 11", "Value 12"
47 };
48
49 private static string textWithHint = string.Empty;
50 private static string singleLineText = "Single line text edit";
51 private static string multiLineText = "Multiline text\nedit";
52 private static float floatValue = 10.5f;
53 private static int intValue = 105;
54 private static bool isReadOnly;
55 private static bool customDropdownOpen;
56 private static ImDropdownPreviewType dropdownPreview;
57 private static bool[] checkboxes = new bool[4];
58 private static int clicks;
59 private static int nestedFoldouts;
60 private static bool showPlusMinusButtons = true;
61 private static bool useNumericSlider = false;
62 private static DemoEnumFlags demoFlags;
63 private static int largeTableRows = 1024 * 128;
64 private static int largeTableColumns = 512;
65 private static float largeTableColumnSize = 150;
66 private static bool largeTableScrollable = true;
67 private static bool largeTableResizable = true;
68 private static Vector2 vec2 = new Vector2(1.0f, 2.0f);
69 private static Vector3 vec3 = new Vector3(1.0f, 2.0f, 3.0f);
70 private static Vector4 vec4 = new Vector4(1.0f, 2.0f, 3.0f, 4.0f);
71 private static Vector2Int vec2int = new Vector2Int(1, 2);
72 private static Vector3Int vec3int = new Vector3Int(1, 2, 3);
73 private static bool textEditWrap;
74
75 private static bool selectMultipleValues = false;
76 private static HashSet<string> selectedNodes = new HashSet<string>(8);
77
78 private static readonly DemoTreeNode[] treeNodes = new[]
79 {
80 new DemoTreeNode("Node 0",
81 new DemoTreeNode("Node 1"),
82 new DemoTreeNode("Node 2")),
83 new DemoTreeNode("Node 3"), new DemoTreeNode("Node 4",
84 new DemoTreeNode("Node 5",
85 new DemoTreeNode("Node 6"),
86 new DemoTreeNode("Node 7")))
87 };
88
89 private static HashSet<int> selectedValues = new HashSet<int>(values.Length);
90
91 public static void Draw(ImGui gui, ref bool open)
92 {
93 if (!gui.BeginWindow("Demo", ref open, (700, 700), ImWindowFlag.HasMenuBar))
94 {
95 return;
96 }
97
98 gui.BeginMenuBar();
99 DrawMenuBarItems(gui, ref open);
100 gui.EndMenuBar();
101
102 if (gui.BeginFoldout("Controls"))
103 {
104 gui.BeginIndent();
105 DrawControlsPage(gui, ref open);
106 gui.EndIndent();
107
108 gui.EndFoldout();
109 }
110
111 gui.BeginReadOnly(isReadOnly);
112
113 if (gui.BeginFoldout("Layout"))
114 {
115 gui.BeginIndent();
116 DrawLayoutPage(gui);
117 gui.EndIndent();
118
119 gui.EndFoldout();
120 }
121
122 if (gui.BeginFoldout("Tables"))
123 {
124 gui.BeginIndent();
125 DrawTablesPage(gui);
126 gui.EndIndent();
127 gui.EndFoldout();
128 }
129
130 gui.EndReadOnly();
131
132 gui.EndWindow();
133 }
134
135 private static void DrawControlsPage(ImGui gui, ref bool open)
136 {
137 gui.Checkbox(ref isReadOnly, "Read Only");
138
139 gui.BeginReadOnly(isReadOnly);
140
141 gui.AddSpacingIfLayoutFrameNotEmpty();
142 gui.BeginHorizontal();
143 if (gui.Button(Format("Clicks ", clicks, "0"), ImSizeMode.Fit))
144 {
145 clicks++;
146 }
147
148 if (gui.Button("Reset Clicks", ImSizeMode.Auto))
149 {
150 clicks = 0;
151 }
152
153 gui.EndHorizontal();
154
155 gui.Checkbox(ref checkboxValue, "Checkbox");
156 gui.AddSpacingIfLayoutFrameNotEmpty();
157 gui.BeginHorizontal();
158 gui.Text("Dropdown preview mode: ");
159 gui.Radio(ref dropdownPreview);
160 gui.EndHorizontal();
161 gui.Dropdown(ref selectedValue, values, defaultLabel: "Dropdown without value selected", preview: dropdownPreview);
162 if (gui.BeginDropdown("Custom Dropdown", preview: dropdownPreview))
163 {
164 if (gui.Menu("Menu Item"))
165 {
166 gui.CloseDropdown();
167 }
168 gui.TooltipAtLastControl("Will close dropdown on click");
169
170 if (gui.BeginMenu("Sub Menu Inside Dropdown"))
171 {
172 gui.Text("Hello there");
173 gui.EndMenu();
174 }
175 gui.Checkbox(ref checkboxValue, "Checkbox");
176 gui.Separator("Nested dropdown, if that's want you really want");
177 gui.Dropdown(ref selectedValue, values, defaultLabel: "Nothing", preview: dropdownPreview);
178 gui.EndDropdown();
179 }
180 gui.Separator("Text editors");
181 gui.TextEdit(ref textWithHint, hint: "Write something here");
182 gui.TextEdit(ref singleLineText, multiline: false);
183 gui.Checkbox(ref textEditWrap, "Wrap Text");
184 using (gui.StyleScope(ref gui.Style.TextEdit.TextWrap, textEditWrap))
185 {
186 gui.TextEdit(ref multiLineText, multiline: true);
187 }
188 gui.Separator("Sliders (with tooltips)");
189 DrawSlidersDemo(gui);
190 gui.Separator("Selection list (you can select multiple values)");
191 gui.BeginList((gui.GetLayoutWidth(), ImList.GetEnclosingHeight(gui, gui.GetRowsHeightWithSpacing(3))));
192 for (int i = 0; i < values.Length; ++i)
193 {
194 var wasSelected = selectedValues.Contains(i);
195 if (gui.ListItem(wasSelected, values[i]))
196 {
197 if (wasSelected)
198 {
199 selectedValues.Remove(i);
200 }
201 else
202 {
203 selectedValues.Add(i);
204 }
205 }
206 }
207
208 gui.EndList();
209
210 gui.Separator("Numeric editors");
211 gui.BeginReadOnly(useNumericSlider);
212 gui.Checkbox(ref showPlusMinusButtons, "Enable Plus/Minus buttons");
213 gui.EndReadOnly();
214 gui.Checkbox(ref useNumericSlider, "Enable Slider");
215
216 var numericFlag = ImNumericEditFlag.None;
217 numericFlag |= showPlusMinusButtons ? ImNumericEditFlag.PlusMinus : ImNumericEditFlag.None;
218 numericFlag |= useNumericSlider ? ImNumericEditFlag.Slider : ImNumericEditFlag.None;
219
220
221 gui.NumericEdit(ref floatValue, step: 0.05f, flags: numericFlag, format: "0.0### kg");
222 gui.NumericEdit(ref intValue, flags: numericFlag, format: "0 miles");
223
224 gui.AddSpacingIfLayoutFrameNotEmpty();
225 gui.Separator("Radio buttons (enum flags)");
226 gui.Radio(ref demoFlags);
227
228 gui.Separator("Dropdown (enum flags)");
229 gui.Dropdown(ref demoFlags);
230
231 gui.Separator("Trees");
232 DrawTreeDemo(gui);
233
234 gui.Separator("Nested Foldout");
235 NestedFoldout(gui, 0, ref nestedFoldouts);
236
237 gui.Separator("Floating menu");
238 var rect = gui.AddLayoutRect(gui.GetLayoutWidth(), gui.GetRowHeight());
239 gui.BeginMenuBar(rect);
240 DrawMenuBarItems(gui, ref open);
241 gui.EndMenuBar();
242
243 gui.Separator("Tabs");
244 gui.AddSpacing();
245 gui.BeginTabsPane(gui.AddLayoutRect(gui.GetLayoutWidth(), gui.GetRowsHeightWithSpacing(2)));
246 for (int i = 0; i < 4; ++i)
247 {
248 var label = gui.Formatter.Concat("Tab ", i);
249 if (gui.BeginTab(label))
250 {
251 gui.Text(label);
252 gui.EndTab();
253 }
254 }
255 gui.EndTabsPane();
256
257 gui.Separator("Vectors (float)");
258 gui.Text("Two component vector");
259 gui.Vector(ref vec2);
260 gui.Text("Three component vector");
261 gui.Vector(ref vec3);
262 gui.Text("Four component vector");
263 gui.Vector(ref vec4);
264 gui.Separator("Vectors (int)");
265 gui.Text("Two component vector");
266 gui.Vector(ref vec2int);
267 gui.Text("Three component vector");
268 gui.Vector(ref vec3int);
269
270 gui.EndReadOnly();
271 }
272
273 private static void DrawSelectableTreeDemo(ImGui gui)
274 {
275 gui.Checkbox(ref selectMultipleValues, "Select multiple values");
276
277 gui.BeginHorizontal();
278 gui.Text("Selected nodes: ");
279 foreach (var name in selectedNodes)
280 {
281 gui.Text(name);
282 gui.AddSpacing();
283 }
284 gui.EndHorizontal();
285
286 void SetSelected(string name, bool selected)
287 {
288 if (selected)
289 {
290 if (!selectMultipleValues)
291 {
292 selectedNodes.Clear();
293 }
294
295 selectedNodes.Add(name);
296 }
297 else
298 {
299 selectedNodes.Remove(name);
300 }
301 }
302
303 void Node(ref DemoTreeNode node)
304 {
305 var flags = (selectMultipleValues ? ImTreeNodeFlags.UnselectOnClick : ImTreeNodeFlags.None) |
306 (node.Childrens.Length == 0 ? ImTreeNodeFlags.NonExpandable : 0);
307 var isSelected = selectedNodes.Contains(node.Name);
308 var expanded = gui.BeginTreeNode(ref isSelected, node.Name, flags: flags);
309
310 SetSelected(node.Name, isSelected);
311
312 if (expanded)
313 {
314 for (int i = 0; i < node.Childrens.Length; ++i)
315 {
316 Node(ref node.Childrens[i]);
317 }
318
319 gui.EndTreeNode();
320 }
321 }
322
323 for (int i = 0; i < treeNodes.Length; ++i)
324 {
325 Node(ref treeNodes[i]);
326 }
327 }
328
329 private static void DrawTreeDemo(ImGui gui)
330 {
331 gui.TreeNode("Node 0");
332 if (gui.BeginTreeNode("Node 1"))
333 {
334 gui.TreeNode("Node 3");
335 if (gui.BeginTreeNode("Node 4"))
336 {
337 gui.TreeNode("Node 5");
338 gui.EndTreeNode();
339 }
340 gui.EndTreeNode();
341 }
342 gui.TreeNode("Node 5");
343 if (gui.BeginTreeNode("Selectable nodes demo"))
344 {
345 DrawSelectableTreeDemo(gui);
346 gui.EndTreeNode();
347 }
348 }
349
350 private static void DrawSlidersDemo(ImGui gui)
351 {
352 DrawBouncingBall(gui);
353 gui.SliderHeader("Size", bouncingBallSize, "0.00 px");
354 gui.Slider(ref bouncingBallSize, 1f, gui.GetRowHeight());
355 gui.TooltipAtLastControl("Size of the circles in pixels");
356 gui.SliderHeader("Speed", bouncingBallSpeed, "0.##");
357 gui.Slider(ref bouncingBallSpeed, -2f, 2f);
358 gui.TooltipAtLastControl("Speed of moving circles");
359 gui.SliderHeader("Trail Length", bouncingBallTrail);
360 gui.Slider(ref bouncingBallTrail, 1, 256, step: 32, flags: ImSliderFlag.DynamicHandle);
361 gui.TooltipAtLastControl("Number of circles drawn");
362 }
363
364 private static void DrawMenuBarItems(ImGui gui, ref bool windowOpen)
365 {
366 if (gui.BeginMenu("Demo"))
367 {
368 if (gui.BeginMenu("Custom Menus"))
369 {
370 gui.BeginVertical(width: 300);
371 DrawSlidersDemo(gui);
372 gui.EndVertical();
373
374 gui.EndMenu();
375 }
376
377 if (gui.BeginMenu("Recursive"))
378 {
379 DrawMenuBarItems(gui, ref windowOpen);
380 gui.EndMenu();
381 }
382
383 gui.Separator();
384
385 if (gui.BeginMenu("Test"))
386 {
387 if (gui.BeginMenu("Same name submenu"))
388 {
389 gui.Menu("Item");
390 gui.EndMenu();
391 }
392
393 gui.PushId("Next Menu");
394
395 if (gui.BeginMenu("Same name submenu"))
396 {
397 gui.Menu("Item");
398 gui.EndMenu();
399 }
400
401 gui.PopId();
402
403 gui.EndMenu();
404 }
405
406 gui.Separator();
407
408 if (gui.Menu("Close"))
409 {
410 windowOpen = false;
411 }
412
413 gui.EndMenu();
414 }
415 }
416
417 private static void DrawLayoutPage(ImGui gui)
418 {
419 gui.AddSpacing();
420
421 gui.BeginHorizontal();
422 for (int i = 0; i < 3; ++i)
423 {
424 gui.Button("Horizontal", ImSizeMode.Fit);
425 }
426
427 gui.EndHorizontal();
428
429 gui.AddSpacing();
430
431 gui.BeginVertical();
432 for (int i = 0; i < 3; ++i)
433 {
434 gui.Button("Vertical", ImSizeMode.Fit);
435 }
436
437 gui.EndVertical();
438
439 gui.AddSpacing();
440
441 var grid = gui.BeginGrid(5, gui.GetRowHeight());
442 for (int i = 0; i < 12; ++i)
443 {
444 gui.TextAutoSize(Format("Grid cell ", i, "0"), gui.GridNextCell(ref grid));
445 }
446
447 gui.EndGrid(in grid);
448 }
449
450 private static void DrawTablesPage(ImGui gui)
451 {
452 if (gui.BeginTreeNode("Simple"))
453 {
454 gui.BeginTable(4);
455 for (int row = 0; row < 5; ++row)
456 {
457 gui.TableNextRow();
458 for (int col = 0; col < 4; ++col)
459 {
460 gui.TableNextColumn();
461 gui.Text(gui.Formatter.Concat("Hello At ", gui.Formatter.Format(col), ":", gui.Formatter.Format(row)));
462 }
463 }
464 gui.EndTable();
465
466 gui.Separator("Resizable Columns");
467
468 gui.BeginTable(4, flags: ImTableFlag.ResizableColumns);
469 for (int row = 0; row < 5; ++row)
470 {
471 gui.TableNextRow();
472 for (int col = 0; col < 4; ++col)
473 {
474 gui.TableNextColumn();
475 gui.Text(gui.Formatter.Concat("Hello At ", gui.Formatter.Format(col), ":", gui.Formatter.Format(row)), wrap: true);
476 }
477 }
478 gui.EndTable();
479
480 gui.EndTreeNode();
481 }
482
483 if (gui.BeginTreeNode("With Scroll Bars"))
484 {
485 gui.BeginTable(4, (gui.GetLayoutWidth(), 200));
486 for (int row = 0; row < 12; ++row)
487 {
488 gui.TableNextRow();
489 for (int col = 0; col < 4; ++col)
490 {
491 gui.TableNextColumn();
492 gui.Text(gui.Formatter.Concat("Hello At ", gui.Formatter.Format(col), ":", gui.Formatter.Format(row)), true);
493 }
494 }
495 gui.EndTable();
496
497 gui.EndTreeNode();
498 }
499
500 if (gui.BeginTreeNode("Large Tables"))
501 {
502 NumEditWithLabel(gui, ref largeTableRows, "Rows", min: 1, max: 1024 * 1024 * 4);
503 NumEditWithLabel(gui, ref largeTableColumns, "Columns", min: 1, max: 4096);
504 NumEditWithLabel(gui, ref largeTableColumnSize, "Col. Size", min: 50, max: 300);
505
506 gui.Checkbox(ref largeTableResizable, "Resizable Columns");
507 gui.Checkbox(ref largeTableScrollable, "Scrollable");
508
509 var size = largeTableScrollable ? new ImSize(gui.GetLayoutWidth(), 300) : new ImSize(ImSizeMode.Auto);
510 var flags = largeTableResizable ? ImTableFlag.ResizableColumns : ImTableFlag.None;
511
512 ref var state = ref gui.BeginTable(largeTableColumns, size, flags);
513
514 gui.TableSetRowsHeight(gui.GetTextLineHeight() + gui.Style.Table.CellPadding.Vertical);
515 for (int i = 0; i < largeTableColumns; ++i)
516 {
517 gui.TableSetColumnWidth(i, largeTableColumnSize);
518 }
519
520 var textSettings = new ImTextSettings(gui.Style.Layout.TextSize, new ImAlignment(0.5f, 0.5f), overflow: ImTextOverflow.Ellipsis);
521 var rowsRange = gui.TableGetVisibleRows(largeTableRows);
522 var colsRange = gui.TableGetVisibleColumns();
523
524 for (int row = rowsRange.Min; row < rowsRange.Max; ++row)
525 {
526 gui.TableSetRow(row, ref state);
527
528 for (int col = colsRange.Min; col < colsRange.Max; ++col)
529 {
530 gui.TableSetColumn(col, ref state);
531 gui.Text(gui.Formatter.Concat(gui.Formatter.Format(col), "x", gui.Formatter.Format(row)), textSettings);
532 }
533 }
534
535 gui.EndTable();
536
537 gui.EndTreeNode();
538 }
539 }
540
541 private static void NumEditWithLabel(ImGui gui, ref int value, ReadOnlySpan<char> label, int min, int max)
542 {
543 gui.AddSpacingIfLayoutFrameNotEmpty();
544 gui.BeginHorizontal();
545 gui.Text(label, gui.Layout.AddRect(150, gui.GetRowHeight()));
546 gui.NumericEdit(ref value, min: min, max: max, flags: ImNumericEditFlag.PlusMinus);
547 gui.EndHorizontal();
548 }
549
550 private static void NumEditWithLabel(ImGui gui, ref float value, ReadOnlySpan<char> label, float min, float max)
551 {
552 gui.AddSpacingIfLayoutFrameNotEmpty();
553 gui.BeginHorizontal();
554 gui.Text(label, gui.Layout.AddRect(150, gui.GetRowHeight()));
555 gui.NumericEdit(ref value, min: min, max: max, flags: ImNumericEditFlag.PlusMinus);
556 gui.EndHorizontal();
557 }
558
559 public static void DrawBouncingBall(ImGui gui)
560 {
561 float mod(float x, float y)
562 {
563 return ((x % y) + y) % y;
564 }
565
566 var bounds = gui
567 .AddLayoutRectWithSpacing(gui.GetLayoutWidth(), gui.GetRowHeight() * 1.25f)
568 .WithPadding(left: bouncingBallSize / 2.0f, right: bouncingBallSize / 2.0f);
569 var dt = Time.unscaledDeltaTime * bouncingBallSpeed;
570
571 bouncingBallTime += dt;
572
573 for (int i = 0; i < bouncingBallTrail; ++i)
574 {
575 var t = mod((bouncingBallTime + (i * 0.01f * bouncingBallSpeed)), 2.0f);
576 var x = t <= 1.0f ? t : 1 - (t - 1);
577 var y = 0.5f + Mathf.Sin((bouncingBallTime + (i * 0.01f * bouncingBallSpeed)) * Mathf.PI * 2) * 0.25f;
578 var p = bounds.GetPointAtNormalPosition(x, y);
579 var c = gui.Style.Text.Color.WithAlpha(Mathf.Pow((i + 1) / (float)bouncingBallTrail, 6));
580
581 gui.Canvas.Circle(p, bouncingBallSize * 0.5f, c);
582 }
583 }
584
585 public static void NestedFoldout(ImGui gui, int current, ref int total)
586 {
587 const int MAX = 8;
588
589 var label = current == 0 ? "Nested Foldout" : Format("Nested Foldout ", current, "0");
590
591 if (!gui.BeginFoldout(label))
592 {
593 return;
594 }
595
596 gui.BeginIndent();
597 if (current < total)
598 {
599 NestedFoldout(gui, current + 1, ref total);
600 }
601 else if (current == total)
602 {
603 if (total == MAX)
604 {
605 gui.Text("Let's just stop here");
606 if (gui.Button("Reset"))
607 {
608 total = 0;
609 }
610 }
611 else if (gui.Button("Add one more"))
612 {
613 total++;
614 }
615 }
616 gui.EndIndent();
617
618 gui.EndFoldout();
619 }
620
621 private static ReadOnlySpan<char> Format(ReadOnlySpan<char> prefix, float value, ReadOnlySpan<char> format = default)
622 {
623 var dst = new Span<char>(formatBuffer);
624 prefix.CopyTo(dst);
625 value.TryFormat(dst[prefix.Length..], out var written, format);
626 return dst[..(prefix.Length + written)];
627 }
628}
static void NestedFoldout(ImGui gui, int current, ref int total)
static void DrawBouncingBall(ImGui gui)
static void Draw(ImGui gui, ref bool open)
Definition DemoWindow.cs:91