diff --git a/RecrownedAthenaeum/UI/Skin/SkinManager.cs b/RecrownedAthenaeum/UI/Skin/SkinManager.cs
index 74585f7..03a1de3 100644
--- a/RecrownedAthenaeum/UI/Skin/SkinManager.cs
+++ b/RecrownedAthenaeum/UI/Skin/SkinManager.cs
@@ -4,21 +4,56 @@ using Newtonsoft.Json;
using RecrownedAthenaeum.Pipeline;
using RecrownedAthenaeum.Data;
using RecrownedAthenaeum.SpecialTypes;
-using RecrownedAthenaeum.UI.Skin.Definitions;
using System;
using System.Collections.Generic;
using System.IO;
+using System.Threading;
namespace RecrownedAthenaeum.UI.Skin
{
+ ///
+ /// Called when the skin manager has completed a async action.
+ ///
+ /// The completed action.
+ public delegate void AsyncComplete(SkinManager.Action actionCompleted);
+
///
/// Manages reference to default and loading of custom skins.
///
public class SkinManager
{
private const string EXTENSION = ".rbskin";
-
private readonly MergedSkin mergedSkin = new MergedSkin();
+ private Thread thread;
+ private Action action;
+ private GraphicsDevice graphicsDevice;
+ private string selectedSkinPath;
+ private SkinData skinDataToUse;
+
+ ///
+ /// The list of paths for all found skins by . May be null.
+ ///
+ public volatile List skinPaths;
+
+ ///
+ /// The event that is called when a state changes.
+ ///
+ public event AsyncComplete AsyncCompleteEvent;
+
+ ///
+ /// The various possible states a skin manager could be in.
+ ///
+ public enum Action
+ {
+ ///
+ /// After a search has completed.
+ ///
+ SEARCH,
+ ///
+ /// Having the skin generated to be in a useable state.
+ ///
+ GENERATE
+ }
///
/// the skin that favors the selected skin, but still has a fallback to the default skin in case anything is missing.
@@ -40,15 +75,13 @@ namespace RecrownedAthenaeum.UI.Skin
///
public string skinsDirectory;
- List skinPaths = new List();
-
///
- /// Updates list of skins by searching recursively in the set .
+ /// Performs a recursive asynchronous search of the directory given in a path set by .
///
- public void SearchForSkins()
+ public void SearchSkinDirectory()
{
- skinPaths.Clear();
- skinPaths = RecursiveSkinSearch(skinsDirectory);
+ action = Action.SEARCH;
+ AttemptAsync();
}
///
@@ -66,13 +99,49 @@ namespace RecrownedAthenaeum.UI.Skin
}
///
- /// Generate skin from skin data.
+ /// Generates a skin asynchronously.
///
- /// The skin data to generate skin from.
+ /// Graphics device to use for texture creation.
+ /// The data to generate from.
/// The path pointing to the file with the extension "".
- /// The graphics device to generate the texture.
- /// The skin generated from the skin data.
- public Skin GenerateSkinFromData(SkinData skinData, string path, GraphicsDevice graphicsDevice)
+ public void GenerateSkin(GraphicsDevice graphicsDevice, SkinData skinData, string path)
+ {
+ action = Action.GENERATE;
+ this.graphicsDevice = graphicsDevice;
+ this.selectedSkinPath = path;
+ this.skinDataToUse = skinData;
+
+ AttemptAsync();
+ }
+
+ private void AttemptAsync()
+ {
+ if (thread != null && thread.IsAlive) throw new InvalidOperationException("Already performing task: " + action);
+ thread = new Thread(ThreadStart);
+ }
+
+ private void ThreadStart()
+ {
+ switch (action)
+ {
+ case Action.SEARCH:
+ SearchForSkins();
+ OnAsyncComplete(action);
+ break;
+ case Action.GENERATE:
+ SelectedSkin = GenerateSkinFromData(skinDataToUse, selectedSkinPath, graphicsDevice);
+ OnAsyncComplete(action);
+ break;
+ }
+ }
+
+ private void SearchForSkins()
+ {
+ skinPaths.Clear();
+ skinPaths = RecursiveSkinSearch(skinsDirectory);
+ }
+
+ private Skin GenerateSkinFromData(SkinData skinData, string path, GraphicsDevice graphicsDevice)
{
TextureAtlasDataReader textureAtlasDataReader = new TextureAtlasDataReader();
FileInfo[] skinFiles = Directory.GetParent(path).GetFiles();
@@ -96,7 +165,8 @@ namespace RecrownedAthenaeum.UI.Skin
{
cursorTexture = Texture2D.FromStream(graphicsDevice, stream);
}
- } else
+ }
+ else
{
cursorTexture = textureAtlas[skinData.cursorTextureName].AsTexture2D(graphicsDevice);
}
@@ -137,5 +207,9 @@ namespace RecrownedAthenaeum.UI.Skin
return skins;
}
+ private void OnAsyncComplete(Action newState)
+ {
+ AsyncCompleteEvent?.Invoke(newState);
+ }
}
}