using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using F10.StreamDeckIntegration.Attributes;
using JetBrains.Annotations;
using UnityEngine;
namespace F10.StreamDeckIntegration {
///
/// Handles adding and removing members that can be executed by Stream Deck.
///
#if UNITY_2018_1_OR_NEWER
[ExecuteAlways]
#else
[ExecuteInEditMode]
#endif
public static class StreamDeck {
internal const string MainGroup = "StreamDeck_Main";
internal static readonly Dictionary> Groups = new Dictionary>();
internal static readonly List Dials = new List();
static StreamDeck() {
if (!Groups.ContainsKey(MainGroup)) {
Groups.Add(MainGroup, new List());
}
}
///
/// Adds the given type as a static member to the list of available and .
///
/// Type of the static member to add.
public static void AddStatic(Type type) {
Internal_Add(type, null);
}
///
/// Adds the given object member instance to the list of available and .
///
/// Boxed member to add.
public static void Add(object obj) {
var type = obj.GetType();
Internal_Add(type, obj);
}
///
/// Removes the given object member instance to the list of available and .
///
/// Boxed member to remove.
public static void Remove(object obj) {
var type = obj.GetType();
if (Attribute.IsDefined(type, typeof(StreamDeckGroupAttribute), false)) {
var attribute = Attribute.GetCustomAttribute(type, typeof(StreamDeckGroupAttribute), false) as StreamDeckGroupAttribute;
// ReSharper disable once PossibleNullReferenceException
var id = attribute.Id ?? type.Name;
Groups.Remove(id);
}
var members = type.GetMembers(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
foreach (var member in members) {
if (Attribute.IsDefined(member, typeof(StreamDeckButtonAttribute), false)) {
var attribute = Attribute.GetCustomAttribute(member, typeof(StreamDeckButtonAttribute), false) as StreamDeckButtonAttribute;
// ReSharper disable once PossibleNullReferenceException
RemoveAction(MainGroup, attribute.Id ?? member.Name);
}
if (Attribute.IsDefined(member, typeof(StreamDeckDialAttribute), false)) {
var attribute = Attribute.GetCustomAttribute(member, typeof(StreamDeckDialAttribute), false) as StreamDeckDialAttribute;
// ReSharper disable once PossibleNullReferenceException
RemoveDial(attribute.Id ?? member.Name);
}
}
}
[CanBeNull]
internal static StreamDeckButtonData FindButtonById([CanBeNull]string groupId, [NotNull]string memberId) {
if (groupId == null || string.IsNullOrEmpty(groupId.Trim())) {
groupId = MainGroup;
}
List group;
if (!Groups.TryGetValue(groupId, out group)) {
Log.Debug("Unable to find the group with ID \"" +groupId + "\". The instance may not have been registered in time.");
return null;
}
StreamDeckButtonData buttonData = group.FirstOrDefault(button => button.Id == memberId);
if (buttonData != null) return buttonData;
Log.Debug("Unable to find the button with ID \"" + memberId + "\" inside the group with ID \"" + groupId + "\". The instance may not have been registered in time.");
return null;
}
internal static StreamDeckButtonData AddAction(object target, [NotNull] MemberInfo member, string group, string id = null) {
var buttonData = new StreamDeckButtonData(target, member, id);
if (!Groups.ContainsKey(group)) {
Groups.Add(group, new List());
}
Groups[group].Add(buttonData);
return buttonData;
}
internal static void RemoveAction(string group, string id = null) {
if (!Groups.ContainsKey(group)) return;
var index = Groups[group].FindIndex(x => x.Id == id);
if (index >= 0) {
Groups[MainGroup].RemoveAt(index);
}
}
internal static StreamDeckButtonData AddDial(object target, [NotNull] MemberInfo member, string id) {
var dialData = new StreamDeckButtonData(target, member, id);
Dials.Add(dialData);
return dialData;
}
internal static void RemoveDial(string id) {
var index = Dials.FindIndex(x => x.Id == id);
if (index >= 0) {
Dials.RemoveAt(index);
}
}
private static void Internal_Add(Type type, object obj) {
var members = type.GetMembers(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
// [StreamDeckGroup]
if (Attribute.IsDefined(type, typeof(StreamDeckGroupAttribute), false)) {
var attribute = Attribute.GetCustomAttribute(type, typeof(StreamDeckGroupAttribute), false) as StreamDeckGroupAttribute;
// ReSharper disable once PossibleNullReferenceException
var groupId = attribute.Id ?? type.Name;
if (Groups.ContainsKey(groupId)) {
Log.Warning("The group ID \"" + groupId + "\" is already defined and added to active groups!\nEach StreamDeckGroup must have a unique ID. Custom ID's can be added as part of the attribute.\nThis group will be ignored.");
return;
}
foreach (var member in members) {
AddAction(obj, member, groupId);
}
return;
}
// [StreamDeckButton], [StreamDeckDial]
foreach (var member in members) {
if (Attribute.IsDefined(member, typeof(StreamDeckButtonAttribute), false)) {
var attribute = Attribute.GetCustomAttribute(member, typeof(StreamDeckButtonAttribute), false) as StreamDeckButtonAttribute;
// ReSharper disable once PossibleNullReferenceException
var id = attribute.Id ?? member.Name;
if (Groups[MainGroup].Any(x => x.Id == id)) {
Log.Warning("The ID \"" + id + "\" is already defined and added to active buttons!\nEach StreamDeckButton must have a unique ID. Custom ID's can be added as part of the attribute.\nThis button will be ignored.");
return;
}
AddAction(obj, member, MainGroup, id);
}
if (Attribute.IsDefined(member, typeof(StreamDeckDialAttribute), false)) {
var attribute = Attribute.GetCustomAttribute(member, typeof(StreamDeckDialAttribute), false) as StreamDeckDialAttribute;
// ReSharper disable once PossibleNullReferenceException
var id = attribute.Id ?? member.Name;
AddDial(obj, member, id);
}
}
}
}
}