private static void Parse(ISettings settings, List <ISettingsHolder> draws, int id, ref int nextAvailableKey) { if (settings == null) { DebugWindow.LogError("Cant parse null settings."); return; } var props = settings.GetType().GetProperties(); foreach (var property in props) { if (property.GetCustomAttribute <IgnoreMenuAttribute>() != null) { continue; } var menuAttribute = property.GetCustomAttribute <MenuAttribute>(); if (property.Name == "Enable" && menuAttribute == null) { continue; } menuAttribute ??= new MenuAttribute(Regex.Replace(property.Name, "(\\B[A-Z])", " $1")); var holder = new SettingsHolder { Name = menuAttribute.MenuName, Tooltip = menuAttribute.Tooltip, ID = menuAttribute.index == -1 ? nextAvailableKey-- : menuAttribute.index }; if (property.PropertyType.GetInterfaces().ContainsF(typeof(ISettings))) { var innerSettings = (ISettings)property.GetValue(settings); if (menuAttribute.index == -1) { Parse(innerSettings, draws, id, ref nextAvailableKey); continue; } holder.Type = HolderChildType.Tab; draws.Add(holder); Parse(innerSettings, draws, menuAttribute.index, ref nextAvailableKey); var parent = GetAllDrawers(draws).Find(x => x.ID == menuAttribute.parentIndex); parent?.Children.Add(holder); continue; } if (IsISettingsList(property, settings)) { if (!(property.GetValue(settings) is IList list)) { continue; } foreach (var item in list) { Parse(item as ISettings, draws, id, ref nextAvailableKey); } continue; } if (menuAttribute.parentIndex != -1) { var parent = GetAllDrawers(draws).Find(x => x.ID == menuAttribute.parentIndex); if (parent != null) { // TODO - Check if the new setting index collides with any children. parent.Children.Add(holder); } else { DebugWindow.LogDebug( $"SettingsParser => ParentIndex used before created. [Menu(\"{menuAttribute.MenuName}\", ..., {menuAttribute.parentIndex})] added as a top-level setting."); draws.Add(holder); } } else if (id != -1) { var parent = GetAllDrawers(draws).Find(x => x.ID == id); if (parent != null) { // debug log spam during startup due to HealthBars, temporarly disabled for now //DebugWindow.LogDebug( // $"SettingsParser => Index collision. '[Menu(\"{menuAttribute.MenuName}\", ..., {id}, ...)] added as sub-setting of \"{parent.Name}\"."); parent.Children.Add(holder); } else { draws.Add(holder); } } else { draws.Add(holder); } var type = property.GetValue(settings); HandleType(holder, type, property.ToString()); } }
private static void HandleType(SettingsHolder holder, object type, string propertyInfo) { switch (type) { case ButtonNode buttonNode: holder.DrawDelegate = () => { if (ImGui.Button(holder.Unique)) { buttonNode.OnPressed(); } }; return; case null: case EmptyNode _: holder.DrawDelegate = () => { }; return; case HotkeyNode hotkeyNode: holder.DrawDelegate = () => { var str = $"{holder.Name} {hotkeyNode.Value}##{hotkeyNode.Value}"; var popupOpened = true; if (ImGui.Button(str)) { ImGui.OpenPopup(str); popupOpened = true; } if (!ImGui.BeginPopupModal(str, ref popupOpened, ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoCollapse)) { return; } if (Input.GetKeyState(Keys.Escape)) { ImGui.CloseCurrentPopup(); ImGui.EndPopup(); return; } foreach (var key in Enum.GetValues(typeof(Keys))) { if (!Input.GetKeyState((Keys)key)) { continue; } hotkeyNode.Value = (Keys)key; ImGui.CloseCurrentPopup(); break; } ImGui.Text($"Press new key to change '{hotkeyNode.Value}' or Esc for exit."); ImGui.EndPopup(); }; return; case ToggleNode toggleNode: holder.DrawDelegate = () => { var isChecked = toggleNode.Value; ImGui.Checkbox(holder.Unique, ref isChecked); toggleNode.Value = isChecked; }; return; case ColorNode colorNode: holder.DrawDelegate = () => { var color = colorNode.Value.ToVector4().ToVector4Num(); if (ImGui.ColorEdit4(holder.Unique, ref color, ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.AlphaBar | ImGuiColorEditFlags.AlphaPreviewHalf)) { colorNode.Value = color.ToSharpColor(); } }; return; case ListNode listNode: holder.DrawDelegate = () => { if (!ImGui.BeginCombo(holder.Unique, listNode.Value)) { return; } foreach (var value in listNode.Values) { if (!ImGui.Selectable(value)) { continue; } listNode.Value = value; break; } ImGui.EndCombo(); }; return; case FileNode fileNode: holder.DrawDelegate = () => { if (!ImGui.TreeNode(holder.Unique)) { return; } var value = fileNode.Value; if (ImGui.BeginChildFrame(1, new Vector2(0f, 300f))) { var directoryInfo = new DirectoryInfo("config"); if (directoryInfo.Exists) { var files = directoryInfo.GetFiles(); foreach (var fileInfo in files) { if (ImGui.Selectable(fileInfo.Name, value == fileInfo.FullName)) { fileNode.Value = fileInfo.FullName; } } } ImGui.EndChildFrame(); } ImGui.TreePop(); }; return; case RangeNode <int> iRangeNode: holder.DrawDelegate = () => { var value = iRangeNode.Value; ImGui.SliderInt(holder.Unique, ref value, iRangeNode.Min, iRangeNode.Max); iRangeNode.Value = value; }; return; case RangeNode <float> fRangeNode: holder.DrawDelegate = () => { var value = fRangeNode.Value; ImGui.SliderFloat(holder.Unique, ref value, fRangeNode.Min, fRangeNode.Max); fRangeNode.Value = value; }; return; case RangeNode <long> lRangeNode: holder.DrawDelegate = () => { var value = (int)lRangeNode.Value; ImGui.SliderInt(holder.Unique, ref value, (int)lRangeNode.Min, (int)lRangeNode.Max); lRangeNode.Value = value; }; return; case RangeNode <Vector2> vRangeNode: holder.DrawDelegate = () => { var value = vRangeNode.Value; ImGui.SliderFloat2(holder.Unique, ref value, vRangeNode.Min.X, vRangeNode.Max.X); vRangeNode.Value = value; }; return; case TextNode textNode: holder.DrawDelegate = () => { var value = textNode.Value; ImGui.InputText(holder.Unique, ref value, 200); textNode.Value = value; }; return; } DebugWindow.LogDebug( $"SettingsParser => DrawDelegate not auto-generated for '{propertyInfo}'."); }
private static void HandleType(SettingsHolder holder, object type, string propertyInfo) { switch (type) { case ButtonNode buttonNode: holder.DrawDelegate = () => { if (ImGui.Button(holder.Unique)) { buttonNode.OnPressed(); } }; return; case null: case EmptyNode _: holder.DrawDelegate = () => { }; return; case HotkeyNode hotkeyNode: holder.DrawDelegate = () => { var str = $"{holder.Name} {hotkeyNode.Value}##{hotkeyNode.Value}"; if (ImGui.Button(str)) { // Clear async buffer state Input.ClearAsyncBuffer(); // Begin pop up ImGui.OpenPopup(str); } // Create modal var popupOpened = true; if (ImGui.BeginPopupModal(str, ref popupOpened, ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoCollapse)) { ButtonPopupVisible = true; } else { return; } // Close popup if escape was pressed if (Input.GetKeyState(Keys.Escape)) { ImGui.CloseCurrentPopup(); ImGui.EndPopup(); ButtonPopupVisible = false; return; } // Get prssed keys Keys key = Input.GetPressedKeys(true); // If a key was pressed, set value and close popup if ((key & Keys.KeyCode) != Keys.None) { // Set the node's value to the keys that were pressed and close the popup hotkeyNode.Value = key; ImGui.CloseCurrentPopup(); ButtonPopupVisible = false; } // End popup ImGui.Text($"Press new key to change '{hotkeyNode.Value}' or Esc for exit."); ImGui.EndPopup(); }; return; case ToggleNode toggleNode: holder.DrawDelegate = () => { var isChecked = toggleNode.Value; ImGui.Checkbox(holder.Unique, ref isChecked); toggleNode.Value = isChecked; }; return; case ColorNode colorNode: holder.DrawDelegate = () => { var color = colorNode.Value.ToVector4().ToVector4Num(); if (ImGui.ColorEdit4(holder.Unique, ref color, ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.AlphaBar | ImGuiColorEditFlags.AlphaPreviewHalf)) { colorNode.Value = color.ToSharpColor(); } }; return; case ListNode listNode: holder.DrawDelegate = () => { if (!ImGui.BeginCombo(holder.Unique, listNode.Value)) { return; } foreach (var value in listNode.Values) { if (!ImGui.Selectable(value)) { continue; } listNode.Value = value; break; } ImGui.EndCombo(); }; return; case FileNode fileNode: holder.DrawDelegate = () => { if (!ImGui.TreeNode(holder.Unique)) { return; } var value = fileNode.Value; if (ImGui.BeginChildFrame(1, new Vector2(0f, 300f))) { var directoryInfo = new DirectoryInfo("config"); if (directoryInfo.Exists) { var files = directoryInfo.GetFiles(); foreach (var fileInfo in files) { if (ImGui.Selectable(fileInfo.Name, value == fileInfo.FullName)) { fileNode.Value = fileInfo.FullName; } } } ImGui.EndChildFrame(); } ImGui.TreePop(); }; return; case RangeNode <int> iRangeNode: holder.DrawDelegate = () => { var value = iRangeNode.Value; ImGui.SliderInt(holder.Unique, ref value, iRangeNode.Min, iRangeNode.Max); iRangeNode.Value = value; }; return; case RangeNode <float> fRangeNode: holder.DrawDelegate = () => { var value = fRangeNode.Value; ImGui.SliderFloat(holder.Unique, ref value, fRangeNode.Min, fRangeNode.Max); fRangeNode.Value = value; }; return; case RangeNode <long> lRangeNode: holder.DrawDelegate = () => { var value = (int)lRangeNode.Value; ImGui.SliderInt(holder.Unique, ref value, (int)lRangeNode.Min, (int)lRangeNode.Max); lRangeNode.Value = value; }; return; case RangeNode <Vector2> vRangeNode: holder.DrawDelegate = () => { var value = vRangeNode.Value; ImGui.SliderFloat2(holder.Unique, ref value, vRangeNode.Min.X, vRangeNode.Max.X); vRangeNode.Value = value; }; return; case TextNode textNode: holder.DrawDelegate = () => { var value = textNode.Value; ImGui.InputText(holder.Unique, ref value, 200); textNode.Value = value; }; return; } }
public static void Parse(ISettings settings, List <ISettingsHolder> draws, int id = -1) { if (settings == null) { DebugWindow.LogError("Cant parse null settings."); return; } var props = settings.GetType().GetProperties(); foreach (var property in props) { if (property.GetCustomAttribute <IgnoreMenuAttribute>() != null) { continue; } var menuAttribute = property.GetCustomAttribute <MenuAttribute>(); var isSettings = property.PropertyType.GetInterfaces().ContainsF(typeof(ISettings)); if (property.Name == "Enable" && menuAttribute == null) { continue; } if (menuAttribute == null) { menuAttribute = new MenuAttribute(Regex.Replace(property.Name, "(\\B[A-Z])", " $1")); } var holder = new SettingsHolder { Name = menuAttribute.MenuName, Tooltip = menuAttribute.Tooltip, ID = menuAttribute.index == -1 ? MathHepler.Randomizer.Next(int.MaxValue) : menuAttribute.index }; if (isSettings) { HandleSubSettings(settings, draws, property, menuAttribute, holder); continue; } if (IsISettingsList(property, settings)) { IList list = property.GetValue(settings) as IList; foreach (var item in list) { Parse(item as ISettings, draws); } continue; } if (menuAttribute.parentIndex != -1) { var parent = GetAllDrawers(draws).Find(x => x.ID == menuAttribute.parentIndex); parent?.Children.Add(holder); } else if (id != -1) { var parent = GetAllDrawers(draws).Find(x => x.ID == id); parent?.Children.Add(holder); } else { draws.Add(holder); } var type = property.GetValue(settings); HandleType(menuAttribute, holder, type); } }
private static void HandleType(MenuAttribute menuAttribute, SettingsHolder holder, object type) { switch (type) { case ButtonNode n: holder.DrawDelegate = () => { if (ImGui.Button(holder.Unique)) { n.OnPressed(); } }; break; case EmptyNode n: break; case HotkeyNode n: holder.DrawDelegate = () => { var holderName = $"{holder.Name} {n.Value}##{n.Value}"; var open = true; if (ImGui.Button(holderName)) { ImGui.OpenPopup(holderName); open = true; } if (ImGui.BeginPopupModal(holderName, ref open, (ImGuiWindowFlags)35)) { if (Input.GetKeyState(Keys.Escape)) { ImGui.CloseCurrentPopup(); ImGui.EndPopup(); return; } foreach (var key in Enum.GetValues(typeof(Keys))) { var keyState = Input.GetKeyState((Keys)key); if (keyState) { n.Value = (Keys)key; ImGui.CloseCurrentPopup(); break; } } ImGui.Text($" Press new key to change '{n.Value}' or Esc for exit."); ImGui.EndPopup(); } }; break; case ToggleNode n: holder.DrawDelegate = () => { var value = n.Value; ImGui.Checkbox(holder.Unique, ref value); n.Value = value; }; break; case ColorNode n: holder.DrawDelegate = () => { var vector4 = n.Value.ToVector4().ToVector4Num(); if (ImGui.ColorEdit4(holder.Unique, ref vector4, ImGuiColorEditFlags.AlphaBar | ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.AlphaPreviewHalf)) { n.Value = vector4.ToSharpColor(); } }; break; case ListNode n: holder.DrawDelegate = () => { if (ImGui.BeginCombo(holder.Unique, n.Value)) { foreach (var t in n.Values) { if (ImGui.Selectable(t)) { n.Value = t; ImGui.EndCombo(); return; } } ImGui.EndCombo(); } }; break; case FileNode n: holder.DrawDelegate = () => { if (ImGui.TreeNode(holder.Unique)) { var selected = n.Value; if (ImGui.BeginChildFrame(1, new Vector2(0, 300))) { var di = new DirectoryInfo("config"); if (di.Exists) { foreach (var file in di.GetFiles()) { if (ImGui.Selectable(file.Name, selected == file.FullName)) { n.Value = file.FullName; } } } ImGui.EndChildFrame(); } ImGui.TreePop(); } }; break; case RangeNode <int> n: holder.DrawDelegate = () => { var r = n.Value; ImGui.SliderInt(holder.Unique, ref r, n.Min, n.Max); n.Value = r; }; break; case RangeNode <float> n: holder.DrawDelegate = () => { var r = n.Value; ImGui.SliderFloat(holder.Unique, ref r, n.Min, n.Max); n.Value = r; }; break; case RangeNode <long> n: holder.DrawDelegate = () => { var r = (int)n.Value; ImGui.SliderInt(holder.Unique, ref r, (int)n.Min, (int)n.Max); n.Value = r; }; break; case RangeNode <Vector2> n: holder.DrawDelegate = () => { var vect = n.Value; ImGui.SliderFloat2(holder.Unique, ref vect, n.Min.X, n.Max.X); n.Value = vect; }; break; case TextNode n: holder.DrawDelegate = () => { var input = n.Value; ImGui.InputText(holder.Unique, ref input, 200); n.Value = input; }; break; default: DebugWindow.LogDebug($"{type} not supported for menu now. Ask developers to add this type."); break; } }
private static void HandleSubSettings(ISettings settings, List <ISettingsHolder> draws, PropertyInfo property, MenuAttribute menuAttribute, SettingsHolder holder) { var innerSettings = (ISettings)property.GetValue(settings); if (menuAttribute.index != -1) { holder.Type = HolderChildType.Tab; draws.Add(holder); Parse(innerSettings, draws, menuAttribute.index); var parent = GetAllDrawers(draws).Find(x => x.ID == menuAttribute.parentIndex); parent?.Children.Add(holder); } else { Parse(innerSettings, draws); } }