Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions ImGui.Widgets/Combo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ public static partial class ImGuiWidgets
/// <returns>If a combo value was selected.</returns>
public static bool Combo<TEnum>(string label, ref TEnum selectedValue) where TEnum : Enum
{
Array possibleValues = Enum.GetValues(typeof(TEnum));
TEnum[] possibleValues = EnumCache<TEnum>.Values;
int currentIndex = Array.IndexOf(possibleValues, selectedValue);
string[] possibleValuesNames = Enum.GetNames(typeof(TEnum));
string[] possibleValuesNames = EnumCache<TEnum>.Names;
bool changed = ImGui.Combo(label, ref currentIndex, possibleValuesNames, possibleValuesNames.Length);
ImGuiProbes.MarkItem(label);
if (changed)
{
selectedValue = (TEnum)possibleValues.GetValue(currentIndex)!;
selectedValue = possibleValues[currentIndex];
return true;
}

Expand Down
9 changes: 9 additions & 0 deletions ImGui.Widgets/EnumCache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.ImGui.Widgets;

internal static class EnumCache<TEnum> where TEnum : Enum
{
internal static readonly TEnum[] Values = (TEnum[])Enum.GetValues(typeof(TEnum));
internal static readonly string[] Names = Enum.GetNames(typeof(TEnum));
}
29 changes: 18 additions & 11 deletions ImGui.Widgets/EnumCombo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,7 @@
/// </summary>
/// <typeparam name="T">The enum type to enumerate.</typeparam>
/// <returns>The display name of every declared member of <typeparamref name="T"/>.</returns>
internal static IReadOnlyList<string> Names<T>() where T : struct, Enum
{
T[] values = Enum.GetValues<T>();
List<string> names = new(values.Length);
foreach (T value in values)
{
names.Add(Hexa.NET.ImGui.Widgets.ComboEnumHelper<T>.GetName(value));
}

return names;
}
internal static IReadOnlyList<string> Names<T>() where T : struct, Enum => EnumComboNamesCache<T>.Names;

/// <summary>
/// Draws a combo box listing every member of an enum type.
Expand All @@ -59,10 +49,27 @@
/// <param name="value">The selected value, updated in place when a new member is chosen.</param>
/// <returns><see langword="true"/> if a new value was selected this frame.</returns>
/// <exception cref="ArgumentNullException"><paramref name="label"/> is <see langword="null"/>.</exception>
internal static bool Combo<T>(string label, ref T value) where T : struct, Enum

Check warning on line 52 in ImGui.Widgets/EnumCombo.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Rename this method to not shadow the outer class' member with the same name.

Check warning on line 52 in ImGui.Widgets/EnumCombo.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Rename this method to not shadow the outer class' member with the same name.

Check warning on line 52 in ImGui.Widgets/EnumCombo.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Rename this method to not shadow the outer class' member with the same name.

Check warning on line 52 in ImGui.Widgets/EnumCombo.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Rename this method to not shadow the outer class' member with the same name.

Check warning on line 52 in ImGui.Widgets/EnumCombo.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Rename this method to not shadow the outer class' member with the same name.

Check warning on line 52 in ImGui.Widgets/EnumCombo.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Rename this method to not shadow the outer class' member with the same name.
{
Ensure.NotNull(label);
return Hexa.NET.ImGui.Widgets.ComboEnumHelper<T>.Combo(label, ref value);
}
}

internal static class EnumComboNamesCache<T> where T : struct, Enum
{
internal static readonly string[] Names = BuildNames();

Check warning on line 61 in ImGui.Widgets/EnumCombo.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

A static field in a generic type is not shared among instances of different close constructed types.

Check warning on line 61 in ImGui.Widgets/EnumCombo.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

A static field in a generic type is not shared among instances of different close constructed types.

Check warning on line 61 in ImGui.Widgets/EnumCombo.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

A static field in a generic type is not shared among instances of different close constructed types.

Check warning on line 61 in ImGui.Widgets/EnumCombo.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

A static field in a generic type is not shared among instances of different close constructed types.

Check warning on line 61 in ImGui.Widgets/EnumCombo.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

A static field in a generic type is not shared among instances of different close constructed types.

See more on https://sonarcloud.io/project/issues?id=ktsu-dev_ImGuiApp&issues=AaCaw3gzre9coQVt4aUN&open=AaCaw3gzre9coQVt4aUN&pullRequest=397

private static string[] BuildNames()
{
T[] values = EnumCache<T>.Values;
string[] names = new string[values.Length];
for (int index = 0; index < values.Length; index++)
{
names[index] = Hexa.NET.ImGui.Widgets.ComboEnumHelper<T>.GetName(values[index]);
}

return names;
}
}
}
4 changes: 2 additions & 2 deletions ImGui.Widgets/PropertyGridRows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -339,8 +339,8 @@ public bool Enum<TEnum>(string label, ref TEnum value) where TEnum : struct, Sys
return false;
}

string[] names = System.Enum.GetNames<TEnum>();
TEnum[] values = System.Enum.GetValues<TEnum>();
string[] names = EnumCache<TEnum>.Names;
TEnum[] values = EnumCache<TEnum>.Values;
int index = Array.IndexOf(values, value);

bool changed = ImGui.Combo(Hidden(label), ref index, names, names.Length);
Expand Down
21 changes: 21 additions & 0 deletions tests/ImGui.Widgets.Tests/HexaWidgetTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,27 @@ public void EnumComboNames_FlagsEnum_ReturnsDeclaredMembersNotCombinations()
CollectionAssert.AreEqual(expected, names.ToArray());
}

[TestMethod]
public void EnumComboNames_RepeatedCalls_ReturnTheSameCachedInstance()
{
IReadOnlyList<string> first = ImGuiWidgets.EnumComboNames<PlainEnum>();
IReadOnlyList<string> second = ImGuiWidgets.EnumComboNames<PlainEnum>();

Assert.AreSame(first, second);
}

[TestMethod]
public void EnumCache_ReusesValuesAndNamesArraysPerEnumType()
{
PlainEnum[] valuesFirst = EnumCache<PlainEnum>.Values;
PlainEnum[] valuesSecond = EnumCache<PlainEnum>.Values;
string[] namesFirst = EnumCache<PlainEnum>.Names;
string[] namesSecond = EnumCache<PlainEnum>.Names;

Assert.AreSame(valuesFirst, valuesSecond);
Assert.AreSame(namesFirst, namesSecond);
}

[TestMethod]
public void EnumCombo_NullLabel_ThrowsBeforeTouchingImGui()
{
Expand Down