alexguirre / RAGENativeUI

MIT License
115 stars 38 forks source link

Implement Generic version of UIListMenuItem #48

Closed pnwparksfan closed 4 years ago

pnwparksfan commented 4 years ago

Using object for the underlying values on UIListMenuItem breaks the C# type system. It would be preferable to have a generic version of UIListMenuItem and IDisplayItem.


interface IDisplayItem<T>
{
    T Value { get; }
    string DisplayText { get; }
}

class UIMenuListItem<T> 
{
    public UIMenuListItem<T>(string text, string description, IEnumerable<IDisplayItem<T>> items) {}
} 
alexguirre commented 4 years ago

I like the idea. Good opportunity to make the mess that is UIMenuListItem right now obsolete.

pnwparksfan commented 4 years ago

I've been working on some fairly complex RNUI extensions, I'll have it up on github soon and will let you know. I think a lot of the ideas could be borrowed but done more cleanly if directly built into RNUI. The difficult thing is how to keep it backwards-compatible, or whether to just implement it in RNUI2 and have it as a separate assembly name for compatibility.

alexguirre commented 4 years ago

Sure, we can look into how to add them to RNUI while keeping compatibility. At this point, I don't think RNUI2 will happen, don't have the motivation anymore to work on it. I would like to fix some of the existing issues in the current version and backport some stuff from RNUI2 to RNUI1.

alexguirre commented 4 years ago

I've been working on the following classes. Any feedback?

UIMenuScrollerItem: the base class for items with left/right arrows.

public abstract class UIMenuScrollerItem : UIMenuItem
{
    public const int EmptyIndex = -1;

    public UIMenuScrollerItem(string text, string description);

    public virtual int Index { get; set; }
    public abstract int OptionCount { get; }
    public abstract string OptionText { get; }
    public bool IsEmpty { get; }
    public bool ScrollingEnabled { get; set; }

    public event ItemScrollerEvent IndexChanged;

    public override void Draw(float x, float y, float width, float height);
    protected virtual void OnSelectedIndexChanged(int oldIndex, int newIndex);
    protected internal virtual void ScrollToNextOption();
    protected internal virtual void ScrollToPreviousOption();
}

UIMenuListScrollerItem: scroller with a list of items. Equivalent to UIMenuListItem. Instead of IDisplayItem it uses the Formatter property, a delegate that accepts the selected item and returns a string. By default, it just calls ToString.

public class UIMenuListScrollerItem<T> : UIMenuScrollerItem
{
    public UIMenuListScrollerItem(string text, string description);
    public UIMenuListScrollerItem(string text, string description, IEnumerable<T> items);

    public T SelectedItem { get; }
    public IList<T> Items { get; set; }
    public Func<T, string> Formatter { get; set; }

    public static string DefaultFormatter(T value);
}

UIMenuNumericScrollerItem: scroller where T can be any built-in numeric type and the user can choose any value between Minimum and Maximum at the interval specified by Step. Format and FormatProvider can be used to specify how the selected value is displayed (they are just passed to the ToString of T).

public class UIMenuNumericScrollerItem<T> : UIMenuScrollerItem where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
{
    public UIMenuNumericScrollerItem(string text, string description, T minimum, T maximum, T step);

    public T Value { get; set; }
    public T Minimum { get; set; }
    public T Maximum { get; set; }
    public T Step { get; set; }
    public string Format { get; set; }
    public IFormatProvider FormatProvider { get; set; }
}

Example:

// Item with a list of strings.
var stringListItem = new UIMenuListScrollerItem<string>("string", null,
                                                        new[] { "Hello", "World", "Foo", "Bar" });

// Item with a list of bools (true/false) with a custom formatter
// that converts the bools to On/Off with green/red colors.
var onOffItem = new UIMenuListScrollerItem<bool>("bool", null, new[] { true, false })
{
    Formatter = v => v ? $"~{HudColor.Green.GetName()}~~h~On" :
                         $"~{HudColor.Red.GetName()}~~h~Off"
};

// Item with a float in the range [-500, 500] and a step of 0.25,
// formatted with 2 decimals places
var floatNumItem = new UIMenuNumericScrollerItem<float>("float", null, -500.0f, 500.0f, 0.25f)
{
    Format = "0.00"
};