mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
273 lines
9.7 KiB
C#
273 lines
9.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Windows;
|
|
using System.Windows.Media;
|
|
using Artemis.DeviceProviders;
|
|
using Artemis.Events;
|
|
using Artemis.Managers;
|
|
using Artemis.Models;
|
|
using Artemis.Modules.Abstract;
|
|
using Artemis.Profiles.Layers.Interfaces;
|
|
using Artemis.Profiles.Layers.Models;
|
|
using Artemis.Utilities.ParentChild;
|
|
using Newtonsoft.Json;
|
|
|
|
namespace Artemis.Profiles
|
|
{
|
|
public class ProfileModel
|
|
{
|
|
private readonly char[] _invalidFileNameChars;
|
|
|
|
public ProfileModel()
|
|
{
|
|
_invalidFileNameChars = Path.GetInvalidFileNameChars();
|
|
Layers = new ChildItemCollection<ProfileModel, LayerModel>(this);
|
|
OnProfileUpdatedEvent += OnOnProfileUpdatedEvent;
|
|
}
|
|
|
|
public ChildItemCollection<ProfileModel, LayerModel> Layers { get; }
|
|
public string Name { get; set; }
|
|
public bool IsDefault { get; set; }
|
|
public string KeyboardSlug { get; set; }
|
|
public string GameName { get; set; }
|
|
public int Width { get; set; }
|
|
public int Height { get; set; }
|
|
public string LuaScript { get; set; }
|
|
|
|
[JsonIgnore]
|
|
public string Slug => new string(Name.Where(ch => !_invalidFileNameChars.Contains(ch)).ToArray());
|
|
|
|
private void OnOnProfileUpdatedEvent(object sender, EventArgs e)
|
|
{
|
|
ApplyKeybinds();
|
|
}
|
|
|
|
public event EventHandler<ProfileDeviceEventsArg> OnDeviceUpdatedEvent;
|
|
public event EventHandler<ProfileDeviceEventsArg> OnDeviceDrawnEvent;
|
|
public event EventHandler<EventArgs> OnProfileUpdatedEvent;
|
|
|
|
public void FixOrder()
|
|
{
|
|
Layers.Sort(l => l.Order);
|
|
for (var i = 0; i < Layers.Count; i++)
|
|
Layers[i].Order = i;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gives all the layers and their children in a flat list
|
|
/// </summary>
|
|
public List<LayerModel> GetLayers()
|
|
{
|
|
var layers = new List<LayerModel>();
|
|
foreach (var layerModel in Layers.OrderBy(l => l.Order))
|
|
{
|
|
layers.Add(layerModel);
|
|
layers.AddRange(layerModel.GetLayers());
|
|
}
|
|
|
|
return layers;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generates a flat list containing all layers that must be rendered on the keyboard,
|
|
/// the first mouse layer to be rendered and the first headset layer to be rendered
|
|
/// </summary>
|
|
/// <param name="dataModel">Instance of said game data model</param>
|
|
/// <param name="keyboardOnly">Whether or not to ignore anything but keyboards</param>
|
|
/// <param name="ignoreConditions"></param>
|
|
/// <returns>A flat list containing all layers that must be rendered</returns>
|
|
public List<LayerModel> GetRenderLayers(ModuleDataModel dataModel, bool keyboardOnly,
|
|
bool ignoreConditions = false)
|
|
{
|
|
var layers = new List<LayerModel>();
|
|
foreach (var layerModel in Layers.OrderByDescending(l => l.Order))
|
|
{
|
|
if (!layerModel.Enabled || keyboardOnly && layerModel.LayerType.DrawType != DrawType.Keyboard)
|
|
continue;
|
|
|
|
if (!ignoreConditions)
|
|
if (!layerModel.ConditionsMet(dataModel))
|
|
continue;
|
|
|
|
layers.Add(layerModel);
|
|
layers.AddRange(layerModel.GetRenderLayers(dataModel, keyboardOnly, ignoreConditions));
|
|
}
|
|
|
|
return layers;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Draw all the given layers on the given rect
|
|
/// </summary>
|
|
/// <param name="deviceVisualModel"></param>
|
|
/// <param name="renderLayers">The layers to render</param>
|
|
/// <param name="dataModel">The data model to base the layer's properties on</param>
|
|
/// <param name="preview">Indicates wheter the layer is drawn as a preview, ignoring dynamic properties</param>
|
|
internal void DrawLayers(DeviceVisualModel deviceVisualModel, List<LayerModel> renderLayers,
|
|
ModuleDataModel dataModel, bool preview)
|
|
{
|
|
renderLayers = renderLayers.Where(rl => rl.LayerType.DrawType == deviceVisualModel.DrawType).ToList();
|
|
if (!renderLayers.Any())
|
|
return;
|
|
|
|
// Setup the DrawingVisual's size
|
|
var c = deviceVisualModel.GetDrawingContext();
|
|
|
|
c.PushClip(new RectangleGeometry(deviceVisualModel.Rect));
|
|
c.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, deviceVisualModel.Rect);
|
|
|
|
// Update the layers
|
|
foreach (var layerModel in renderLayers)
|
|
layerModel.Update(dataModel, preview, true);
|
|
RaiseDeviceUpdatedEvent(new ProfileDeviceEventsArg(deviceVisualModel.DrawType, dataModel, preview, null));
|
|
|
|
// Draw the layers
|
|
foreach (var layerModel in renderLayers)
|
|
layerModel.Draw(dataModel, c, preview, true);
|
|
RaiseDeviceDrawnEvent(new ProfileDeviceEventsArg(deviceVisualModel.DrawType, dataModel, preview, c));
|
|
|
|
// Remove the clip
|
|
c.Pop();
|
|
}
|
|
|
|
private void RaiseDeviceUpdatedEvent(ProfileDeviceEventsArg e)
|
|
{
|
|
OnDeviceUpdatedEvent?.Invoke(this, e);
|
|
}
|
|
|
|
public void RaiseDeviceDrawnEvent(ProfileDeviceEventsArg e)
|
|
{
|
|
OnDeviceDrawnEvent?.Invoke(this, e);
|
|
}
|
|
|
|
public virtual void OnOnProfileUpdatedEvent()
|
|
{
|
|
OnProfileUpdatedEvent?.Invoke(this, EventArgs.Empty);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Looks at all the layers wthin the profile and makes sure they are within boundaries of the given rectangle
|
|
/// </summary>
|
|
/// <param name="keyboardRectangle"></param>
|
|
public void FixBoundaries(Rect keyboardRectangle)
|
|
{
|
|
foreach (var layer in GetLayers())
|
|
{
|
|
if (!layer.LayerType.ShowInEdtor)
|
|
continue;
|
|
|
|
var props = layer.Properties;
|
|
var layerRect = new Rect(new Point(props.X, props.Y), new Size(props.Width, props.Height));
|
|
if (keyboardRectangle.Contains(layerRect))
|
|
continue;
|
|
|
|
props.X = 0;
|
|
props.Y = 0;
|
|
layer.Properties = props;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resizes layers that are shown in the editor and match exactly the full keyboard widht and height
|
|
/// </summary>
|
|
/// <param name="target">The new keyboard to adjust the layers for</param>
|
|
public void ResizeLayers(KeyboardProvider target)
|
|
{
|
|
foreach (var layer in GetLayers())
|
|
{
|
|
if (!layer.LayerType.ShowInEdtor ||
|
|
!(Math.Abs(layer.Properties.Width - Width) < 0.01) ||
|
|
!(Math.Abs(layer.Properties.Height - Height) < 0.01))
|
|
continue;
|
|
|
|
layer.Properties.Width = target.Width;
|
|
layer.Properties.Height = target.Height;
|
|
}
|
|
}
|
|
|
|
public void Activate(LuaManager luaManager)
|
|
{
|
|
ApplyKeybinds();
|
|
luaManager.SetupLua(this);
|
|
}
|
|
|
|
public void Deactivate(LuaManager luaManager)
|
|
{
|
|
foreach (var layerModel in Layers)
|
|
{
|
|
for (var index = 0; index < layerModel.Properties.Conditions.Count; index++)
|
|
KeybindManager.Remove($"{GameName}-{Name}-{layerModel.Name}-{index}");
|
|
}
|
|
|
|
luaManager.ClearLua();
|
|
}
|
|
|
|
public LayerModel AddLayer(LayerModel afterLayer)
|
|
{
|
|
// Create a new layer
|
|
var layer = LayerModel.CreateLayer();
|
|
|
|
if (afterLayer != null)
|
|
{
|
|
afterLayer.InsertAfter(layer);
|
|
}
|
|
else
|
|
{
|
|
Layers.Add(layer);
|
|
FixOrder();
|
|
}
|
|
|
|
return layer;
|
|
}
|
|
|
|
public void ApplyKeybinds()
|
|
{
|
|
foreach (var layerModel in Layers)
|
|
{
|
|
for (var index = 0; index < layerModel.Properties.Conditions.Count; index++)
|
|
{
|
|
var condition = layerModel.Properties.Conditions[index];
|
|
if (condition.Field == null || !condition.Field.Contains("hotkey"))
|
|
continue;
|
|
|
|
// Create an action for the layer, the layer's specific condition type handles activation
|
|
var action = new Action(() => layerModel.LayerCondition.KeybindTask(condition));
|
|
var kb = new KeybindModel($"{GameName}-{Name}-{layerModel.Name}-{index}", condition.HotKey, action);
|
|
KeybindManager.AddOrUpdate(kb);
|
|
}
|
|
}
|
|
}
|
|
|
|
#region Compare
|
|
|
|
protected bool Equals(ProfileModel other)
|
|
{
|
|
return string.Equals(Slug, other.Slug) &&
|
|
string.Equals(KeyboardSlug, other.KeyboardSlug) &&
|
|
string.Equals(GameName, other.GameName);
|
|
}
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
if (ReferenceEquals(null, obj)) return false;
|
|
if (ReferenceEquals(this, obj)) return true;
|
|
if (obj.GetType() != GetType()) return false;
|
|
return Equals((ProfileModel) obj);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
unchecked
|
|
{
|
|
var hashCode = Slug?.GetHashCode() ?? 0;
|
|
hashCode = (hashCode * 397) ^ (KeyboardSlug?.GetHashCode() ?? 0);
|
|
hashCode = (hashCode * 397) ^ (GameName?.GetHashCode() ?? 0);
|
|
return hashCode;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |