1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 00:47:24 +08:00
osu-lazer/osu.Game/Configuration/SettingSourceAttribute.cs
2020-02-09 21:37:40 -08:00

148 lines
5.3 KiB
C#

// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Overlays.Settings;
namespace osu.Game.Configuration
{
/// <summary>
/// An attribute to mark a bindable as being exposed to the user via settings controls.
/// Can be used in conjunction with <see cref="SettingSourceExtensions.CreateSettingsControls"/> to automatically create UI controls.
/// </summary>
[MeansImplicitUse]
[AttributeUsage(AttributeTargets.Property)]
public class SettingSourceAttribute : Attribute
{
public enum OrderMode
{
FIRST,
ORDERED_RELATIVE,
UNORDERED,
LAST
}
public string Label { get; }
public string Description { get; }
public OrderMode OrderingMode { get; }
public int OrderPosition { get; }
public SettingSourceAttribute(string label, string description = null, OrderMode order = OrderMode.UNORDERED, int orderPosition = 0)
{
Label = label ?? string.Empty;
Description = description ?? string.Empty;
OrderingMode = order;
OrderPosition = orderPosition;
}
}
public static class SettingSourceExtensions
{
public static IEnumerable<Drawable> CreateSettingsControls(this object obj)
{
foreach (var (attr, property) in obj.GetOrderedSettingsSourceProperties())
{
object value = property.GetValue(obj);
switch (value)
{
case BindableNumber<float> bNumber:
yield return new SettingsSlider<float>
{
LabelText = attr.Label,
Bindable = bNumber,
KeyboardStep = 0.1f,
};
break;
case BindableNumber<double> bNumber:
yield return new SettingsSlider<double>
{
LabelText = attr.Label,
Bindable = bNumber,
KeyboardStep = 0.1f,
};
break;
case BindableNumber<int> bNumber:
yield return new SettingsSlider<int>
{
LabelText = attr.Label,
Bindable = bNumber
};
break;
case Bindable<bool> bBool:
yield return new SettingsCheckbox
{
LabelText = attr.Label,
Bindable = bBool
};
break;
case Bindable<string> bString:
yield return new SettingsTextBox
{
LabelText = attr.Label,
Bindable = bString
};
break;
case IBindable bindable:
var dropdownType = typeof(SettingsEnumDropdown<>).MakeGenericType(bindable.GetType().GetGenericArguments()[0]);
var dropdown = (Drawable)Activator.CreateInstance(dropdownType);
dropdown.GetType().GetProperty(nameof(IHasCurrentValue<object>.Current))?.SetValue(dropdown, obj);
yield return dropdown;
break;
default:
throw new InvalidOperationException($"{nameof(SettingSourceAttribute)} was attached to an unsupported type ({value})");
}
}
}
public static IEnumerable<(SettingSourceAttribute, PropertyInfo)> GetSettingsSourceProperties(this object obj)
{
foreach (var property in obj.GetType().GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance))
{
var attr = property.GetCustomAttribute<SettingSourceAttribute>(true);
if (attr == null)
continue;
yield return (attr, property);
}
}
public static IEnumerable<(SettingSourceAttribute, PropertyInfo)> GetOrderedSettingsSourceProperties(this object obj)
{
var original = obj.GetSettingsSourceProperties();
var first = original.Where(attr => attr.Item1.OrderingMode == SettingSourceAttribute.OrderMode.FIRST);
var orderedRelative = original.Where(attr => attr.Item1.OrderingMode == SettingSourceAttribute.OrderMode.ORDERED_RELATIVE).OrderBy(attr => attr.Item1.OrderPosition);
var unordered = original.Where(attr => attr.Item1.OrderingMode == SettingSourceAttribute.OrderMode.UNORDERED);
var last = original.Where(attr => attr.Item1.OrderingMode == SettingSourceAttribute.OrderMode.LAST);
return first.Concat(orderedRelative).Concat(unordered).Concat(last);
}
}
}