Add quick interactions locally

This commit is contained in:
2025-03-31 04:02:39 +02:00
parent 5bb7a207f2
commit b7d4531ec8
134 changed files with 15494 additions and 0 deletions

View File

@@ -0,0 +1,210 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Barotrauma;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
namespace QICrabUI
{
/// <summary>
/// Contains all logic for resolving styles in the framework
/// </summary>
public static class CUIGlobalStyleResolver
{
public static void OnComponentStyleChanged(CUIComponent host)
{
CUITypeMetaData meta = CUITypeMetaData.Get(host.GetType());
host.ResolvedStyle = CUIStyle.Merge(meta.ResolvedDefaultStyle, host.Style);
ApplyStyleOn(host.ResolvedStyle, host);
host.InvokeOnStyleApplied();
}
public static void OnComponentStylePropChanged(CUIComponent host, string key)
{
CUITypeMetaData meta = CUITypeMetaData.Get(host.GetType());
if (meta.ResolvedDefaultStyle.Props.ContainsKey(key))
{
host.ResolvedStyle[key] = meta.ResolvedDefaultStyle[key];
}
if (host.Style.Props.ContainsKey(key))
{
host.ResolvedStyle[key] = host.Style[key];
}
ApplyStylePropOn(host.ResolvedStyle, key, host, meta);
host.InvokeOnStyleApplied();
}
public static void OnPaletteChange(CUIPalette palette)
{
foreach (Type CUIType in CUIReflection.CUITypes.Values)
{
foreach (CUIComponent c in CUIComponent.ComponentsByType.GetPage(CUIType))
{
ApplyStyleOn(c.ResolvedStyle, c);
}
}
}
public static void OnDefaultStyleChanged(Type CUIType)
{
try
{
// Merge default styles
CUIReflection.CUITypeTree[CUIType].RunRecursive((node) =>
{
node.Meta.ResolvedDefaultStyle = CUIStyle.Merge(
node.Parent?.Meta.ResolvedDefaultStyle,
node.Meta.DefaultStyle
);
});
// Apply default styles
CUIReflection.CUITypeTree[CUIType].RunRecursive((node) =>
{
foreach (CUIComponent c in CUIComponent.ComponentsByType.GetPage(node.T))
{
OnComponentStyleChanged(c);
}
});
}
catch (Exception e)
{
CUI.Warning($"OnDefaultStyleChanged| {e}");
}
}
public static void OnDefaultStylePropChanged(Type CUIType, string key)
{
try
{
// Merge default styles
CUIReflection.CUITypeTree[CUIType].RunRecursive((node) =>
{
if (node.Parent != null)
{
if (node.Parent.Meta.ResolvedDefaultStyle.Props.ContainsKey(key))
{
node.Meta.ResolvedDefaultStyle[key] = node.Parent.Meta.ResolvedDefaultStyle[key];
}
}
if (node.Meta.DefaultStyle.Props.ContainsKey(key))
{
node.Meta.ResolvedDefaultStyle[key] = node.Meta.DefaultStyle[key];
}
});
// Apply default styles
CUIReflection.CUITypeTree[CUIType].RunRecursive((node) =>
{
foreach (CUIComponent c in CUIComponent.ComponentsByType.GetPage(node.T))
{
OnComponentStylePropChanged(c, key);
}
});
}
catch (Exception e)
{
CUI.Warning(e);
}
}
public static void ApplyStyleOn(CUIStyle style, CUIComponent target)
{
if (target == null)
{
CUI.Warning($"Style target is null");
return;
}
CUITypeMetaData meta = CUITypeMetaData.Get(target.GetType());
foreach (string name in style.Props.Keys)
{
ApplyStylePropOn(style, name, target, meta);
}
}
public static string CUIPalettePrefix = "CUIPalette.";
/// <summary>
/// Applies 1 prop with name on the target
/// </summary>
public static void ApplyStylePropOn(CUIStyle style, string name, CUIComponent target, CUITypeMetaData meta = null)
{
if (target.Unreal) return;
if (target == null) { CUI.Warning($"Style target is null"); return; }
meta ??= CUITypeMetaData.Get(target.GetType());
PropertyInfo pi = meta.Assignable.GetValueOrDefault(name);
if (pi == null)
{
if (CUIPalette.NotifyExcessivePropStyles) CUI.Warning($"Can't apply style: Couldn't find {name} prop in {target}");
return;
}
string raw = style[name];
if (raw.StartsWith(CUIPalettePrefix))
{
PaletteExtractResult result = CUIPalette.Extract(raw.Substring(CUIPalettePrefix.Length), target.Palette);
if (result.Ok)
{
raw = result.Value;
}
else
{
if (CUIPalette.NotifiMissingPropStyles)
{
CUI.Warning($"Can't find {raw.Substring(CUIPalettePrefix.Length)} palette style for {target}");
}
return;
}
}
MethodInfo parse = CUIExtensions.Parse.GetValueOrDefault(pi.PropertyType);
parse ??= pi.PropertyType.GetMethod(
"Parse",
BindingFlags.Public | BindingFlags.Static,
new Type[] { typeof(string) }
);
if (parse == null)
{
CUI.Warning($"Can't parse style prop {name} for {target} because it's type {pi.PropertyType.Name} is missing Parse method");
return;
}
try
{
pi.SetValue(target, parse.Invoke(null, new object[] { raw }));
}
catch (Exception e)
{
CUI.Warning($"Can't parse {raw} into {pi.PropertyType.Name} for {target}");
CUI.Warning(e);
}
}
}
}

View File

@@ -0,0 +1,189 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Barotrauma;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using System.Xml;
using System.Xml.Linq;
namespace QICrabUI
{
/// <summary>
/// In Fact just an observable dict
/// </summary>
public partial class CUIStyle : IEnumerable<KeyValuePair<string, string>>, ICloneable
{
public static CUIStyle DefaultFor(Type T) => CUITypeMetaData.Get(T).DefaultStyle;
public static CUIStyle DefaultFor<T>() where T : CUIComponent => CUITypeMetaData.Get(typeof(T)).DefaultStyle;
IEnumerator<KeyValuePair<string, string>> IEnumerable<KeyValuePair<string, string>>.GetEnumerator()
=> Props.GetEnumerator();
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
=> Props.GetEnumerator();
public void Add(string key, string value)
{
Props[key] = value;
OnPropChanged?.Invoke(key, value);
}
public void Clear() => Props.Clear();
/// <summary>
/// Prop name -> value
/// </summary>
public Dictionary<string, string> Props = new();
public event Action<string, string> OnPropChanged;
public event Action<CUIStyle> OnUse;
public virtual string this[string name]
{
get => Props.ContainsKey(name) ? Props[name] : "";
set => Add(name, value);
}
public object Clone()
{
CUIStyle style = new CUIStyle();
style.Props = new Dictionary<string, string>(Props);
return style;
}
public static CUIStyle Merge(CUIStyle baseStyle, CUIStyle addedStyle)
{
CUIStyle result = new CUIStyle();
if (baseStyle != null)
{
foreach (string key in baseStyle.Props.Keys)
{
result[key] = baseStyle.Props[key];
}
}
if (addedStyle != null)
{
foreach (string key in addedStyle.Props.Keys)
{
result[key] = addedStyle.Props[key];
}
}
return result;
}
public void Use(CUIStyle source)
{
Props = new Dictionary<string, string>(source.Props);
OnUse?.Invoke(this);
}
public void UseString(string raw)
{
Clear();
try
{
string content = raw.Split('{', '}')[1];
if (content.Trim() == "") return;
var pairs = content.Split(',').Select(s => s.Split(':').Select(sub => sub.Trim()).ToArray());
foreach (var pair in pairs)
{
Props[pair[0]] = pair[1];
}
}
catch (Exception e) { CUI.Warning($"Style.UseString failed: {e.Message}"); }
OnUse?.Invoke(this);
}
public void UseXML(XElement element)
{
Clear();
foreach (XElement prop in element.Elements())
{
Props[prop.Name.ToString()] = prop.Value;
}
OnUse?.Invoke(this);
}
public static CUIStyle FromXML(XElement element)
{
CUIStyle style = new CUIStyle();
style.UseXML(element);
return style;
}
public override string ToString()
{
return "{ " + String.Join(", ", Props.Select(kvp => $"{kvp.Key} : {kvp.Value}")) + " }";
}
public static CUIStyle Parse(string raw)
{
CUIStyle style = new CUIStyle();
style.UseString(raw);
return style;
}
public override bool Equals(object obj)
{
if (!(obj is CUIStyle styleB)) return false;
CUIStyle styleA = this;
if (styleA is null && styleB is null) return true;
if (styleA is null || styleB is null) return false;
if (styleA.Props is null || styleB.Props is null) return false;
if (styleA.Props.Count != styleB.Props.Count) return false;
foreach (var (key, value) in styleA.Props)
{
if (!styleB.Props.ContainsKey(key)) return false;
if (styleA[key] != styleB[key]) return false;
}
return true;
}
public static CUIStyle operator +(CUIStyle styleA, CUIStyle styleB) => Merge(styleA, styleB);
public static bool operator ==(CUIStyle styleA, CUIStyle styleB)
{
if (styleA is null && styleB is null) return true;
if (styleA is null || styleB is null) return false;
if (styleA.Props is null || styleB.Props is null) return false;
if (styleA.Props.Count != styleB.Props.Count) return false;
foreach (var (key, value) in styleA.Props)
{
if (!styleB.Props.ContainsKey(key)) return false;
if (styleA[key] != styleB[key]) return false;
}
return true;
}
public static bool operator !=(CUIStyle styleA, CUIStyle styleB)
{
if (styleA is null && styleB is null) return false;
if (styleA is null || styleB is null) return true;
if (styleA.Props is null || styleB.Props is null) return true;
if (styleA.Props.Count != styleB.Props.Count) return true;
foreach (var (key, value) in styleA.Props)
{
if (!styleB.Props.ContainsKey(key)) return true;
if (styleA[key] != styleB[key]) return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Diagnostics;
using Barotrauma;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using System.Xml;
using System.Xml.Linq;
using System.IO;
using System.Diagnostics;
namespace QICrabUI
{
public class CUIStyleLoader
{
internal static void InitStatic()
{
CUI.OnInit += () => LoadDefaultStyles();
}
public static string DefaultStylesPath => Path.Combine(CUI.AssetsPath, "Default Styles.xml");
public static void LoadDefaultStyles()
{
Stopwatch sw = Stopwatch.StartNew();
if (CUI.AssetsPath == null) return;
if (!File.Exists(DefaultStylesPath)) return;
Dictionary<Type, CUIStyle> DefaultStyles = new();
XDocument xdoc = XDocument.Load(DefaultStylesPath);
XElement root = xdoc.Element("DefaultStyles");
foreach (XElement componentStyle in root.Elements())
{
Type componentType = CUIReflection.GetComponentTypeByName(componentStyle.Name.ToString());
if (componentType == null)
{
CUI.Warning($"Couldn't find type for default style {componentStyle.Name}");
continue;
}
DefaultStyles[componentType] = CUIStyle.FromXML(componentStyle);
}
sw.Stop();
CUIDebug.Log($"Parsing default styles took {sw.ElapsedMilliseconds}ms");
sw.Restart();
// It's heavy because CUITypeMetaData.Get creates defaults here
foreach (Type T in DefaultStyles.Keys)
{
CUITypeMetaData.Get(T).DefaultStyle = DefaultStyles[T];
}
sw.Stop();
CUIDebug.Log($"Applying default styles took {sw.ElapsedMilliseconds}ms");
}
}
}