diff --git a/CHANGELOG.md b/CHANGELOG.md index da291f6..ccb035b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.0] - 2020-07-25 + +### Added +- Navigator +- Screen + +## [0.1.42] - 2020-07-21 + +### Added +- ChildView +- StateMonobehaviour + ## [0.1.0] - 2020-07-19 ### Added diff --git a/Editor/ScreenEditor.cs b/Editor/ScreenEditor.cs index f173432..d0d323b 100644 --- a/Editor/ScreenEditor.cs +++ b/Editor/ScreenEditor.cs @@ -15,15 +15,10 @@ public static class ScreenEditor { private static GUIStyle singleStyle, leftStyle, rightStyle; static Navigator navigator; - static Color violet = new Color(0.898f, 0.745f, 0.935f); - static Color saturatedViolet; static ScreenEditor() { EditorApplication.hierarchyWindowItemOnGUI -= DrawHierarchyItem; EditorApplication.hierarchyWindowItemOnGUI += DrawHierarchyItem; - float h,s,v; - Color.RGBToHSV(violet, out h, out s, out v); - saturatedViolet = Color.HSVToRGB(h, 1f, 1f); } static void DrawHierarchyItem(int instanceID, Rect rect) { @@ -86,7 +81,7 @@ static bool Button(Rect rect, string label, bool isActive = false) { // set color to violet if active var originalColor = GUI.color; - GUI.color = isActive ? violet : originalColor; + GUI.color = isActive ? Violet.Hue : originalColor; var response = GUI.Button(rect, new GUIContent(label), style); GUI.color = originalColor; diff --git a/Runtime/Exceptions.cs b/Runtime/Exceptions.cs index 8d112c3..5f5f38f 100644 --- a/Runtime/Exceptions.cs +++ b/Runtime/Exceptions.cs @@ -7,7 +7,8 @@ public Bail(string message) : base(message) { } } public class VioletException : Exception { - public VioletException(string message) : base(message) { } + public VioletException(string message) : + base($"{Violet.Color("VioletUI")} | {message}") { } } public class VioletEnumException : VioletException { diff --git a/Runtime/Navigation/Navigator.cs b/Runtime/Navigation/Navigator.cs index 1787896..e079dda 100644 --- a/Runtime/Navigation/Navigator.cs +++ b/Runtime/Navigation/Navigator.cs @@ -11,9 +11,9 @@ namespace VioletUI { /// - /// Screens maintains a map of enum to menu screens. + /// Navigator maintains a map of enum to menu screens. /// - /// It is primarily used to navigate between screens, and also exposes the and lifecycle events. + /// It is used to navigate between screens and exposes , , , and . /// [ExecuteAlways] public class Navigator : TidyBehaviour { @@ -46,15 +46,14 @@ void Awake() { VisitFirstScreen(); } void LoadScreens() { - if (transform.childCount == 0) { - throw new Exception($"Tried to create a NavigationController with no children - try adding some NavigationScreens to {gameObject.name}"); - } + if (transform.childCount == 0) { return; } ScreenId screenId = ScreenId.None; foreach (Screen screen in GetComponentsInChildren(true)) { var isValid = Enum.TryParse(screen.name, out screenId); if (!isValid) { - throw new VioletException($"{screen.name} does not have a valid ScreenId. Make sure this screen is added to MenuBuilder."); + RegenerateEnums(); + throw new VioletException($"{screen.name} does not have a valid ScreenId."); } if (hasCamera) { @@ -82,7 +81,7 @@ void LoadScreens() { /// public async void Visit(ScreenId screenId) { if (!screens.ContainsKey(screenId)) { - throw new Exception($"Tried to visit {screenId} but it doesn't exist in the current scene. You'll want to add the {screenId} prefab to this scene or to the MenuBuilder prefab. Or change the Home Screen to the screen you want."); + throw new VioletException($"Tried to visit {screenId} but it doesn't exist in the current scene. You'll want to add the {screenId} prefab to this scene or to the MenuBuilder prefab. Or change the Home Screen to the screen you want."); } // if we're currently in a transition, cancel the transition and run OnHide/OnShow immediately @@ -142,7 +141,7 @@ public void Visit(string screenIdString) { ScreenId screenId; var isValid = Enum.TryParse(screenIdString.Replace(" ", ""), out screenId); if (!isValid) { - throw new Exception($"Couldn't find a screen with the id {screenIdString.Replace(" ", "")}. Please check the spelling."); + throw new VioletException($"Couldn't find a screen with the id {screenIdString.Replace(" ", "")}. Please check the spelling."); } Visit(screenId); } @@ -151,7 +150,7 @@ public void ShowModal (string screenIdString) { ScreenId screenId; var isValid = Enum.TryParse(screenIdString.Replace(" ", ""), out screenId); if (!isValid) { - throw new Exception($"Couldn't find a screen with the id {screenIdString.Replace(" ", "")}. Please check the spelling."); + throw new VioletException($"Couldn't find a screen with the id {screenIdString.Replace(" ", "")}. Please check the spelling."); } ShowModal(screenId); @@ -181,7 +180,7 @@ public void Edit(Screen screen) { homeScreen = ScreenToScreenId(screen); } catch (VioletEnumException) { ScreenIdGenerator.Generate(screen); - Debug.LogWarning($"VioletUI - Couldn't find {screen.name} in the ScreenId enum. This should be fixed if you try your action again. If not, please report a bug."); + Violet.LogWarning($"Couldn't find {screen.name} in the ScreenId enum. This should be fixed if you hit edit again. If not, please report a bug."); return; } diff --git a/Runtime/Navigation/ScreenId.cs b/Runtime/Navigation/ScreenId.cs index eed3b1c..77ecd3f 100644 --- a/Runtime/Navigation/ScreenId.cs +++ b/Runtime/Navigation/ScreenId.cs @@ -1,6 +1,6 @@ //Names are automatically added through ScreenIdGenerator.cs, deletions are done manually :) namespace VioletUI { public enum ScreenId { - None = 0 + None = 0, } } diff --git a/Runtime/Navigation/ScreenIdGenerator.cs b/Runtime/Navigation/ScreenIdGenerator.cs index 4fb550e..ef75869 100644 --- a/Runtime/Navigation/ScreenIdGenerator.cs +++ b/Runtime/Navigation/ScreenIdGenerator.cs @@ -2,8 +2,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection; using System.Text; using UnityEditor; +using UnityEditor.Compilation; using UnityEngine; namespace VioletUI { @@ -30,10 +32,11 @@ public static void Generate(List screens) { static List Filter(List screens) { var ret = new List(); - foreach (var screen in screens) { + foreach (var screen in screens.Distinct()) { if (screen == null) { continue; } var name = sanitize(screen); - if (Enum.TryParse(screen, out _)) { continue; } + if (Enum.TryParse(name, out _)) { continue; } + Violet.Log($"Adding new screen to enum - {name}"); ret.Add(name); } return ret; @@ -60,13 +63,31 @@ static void AddScreens(List screens) { } sb.AppendLine("\t}"); sb.AppendLine("}"); - string path = Path.GetFullPath("Packages/violetui/Runtime/Navigation/ScreenId.cs"); + string path = $"{packagePath()}/Runtime/Navigation/ScreenId.cs"; File.WriteAllText(path, sb.ToString()); + Violet.Log("Regenerating the ScreenId enum, this may take a second to recompile."); AssetDatabase.Refresh(); } static string sanitize(string s) { return s.Replace(" ", ""); } + + static string scriptPath() { + return null; + } + static string packagePath() { + foreach (var path in packagePaths) { + var paths = Directory.GetDirectories(path, "*violetui*", SearchOption.TopDirectoryOnly); + if (paths.Length > 0) { return paths[0];} + } + throw new VioletException("Can't find violetui in Library/PackageCache or Packages. Please report a bug."); + } + static string[] packagePaths = new string[] { + Path.GetFullPath("Library/PackageCache"), + Path.GetFullPath("Packages") + }; } } + + diff --git a/Runtime/StateMonoBehaviour.cs b/Runtime/StateMonoBehaviour.cs index 2bc8962..04e3cc1 100644 --- a/Runtime/StateMonoBehaviour.cs +++ b/Runtime/StateMonoBehaviour.cs @@ -10,8 +10,8 @@ namespace VioletUI { [ExecuteAlways] - public abstract class StateMonoBehaviour : TidyBehaviour where TState : class, IState { - public static StateMonoBehaviour Singleton; + public abstract class StateMonobehaviour : TidyBehaviour where TState : class, IState { + public static StateMonobehaviour Singleton; public TState State; [NonSerialized, HideInInspector] public TState LastState; @@ -30,16 +30,19 @@ public Dispatcher Dispatcher { public class View : View { protected override TState State => Singleton?.State; protected override TState LastState => Singleton?.LastState; + protected override Dispatcher Dispatcher => Dispatcher; } public abstract class RepeatView : RepeatView { protected override TState State => Singleton?.State; protected override TState LastState => Singleton?.LastState; + protected override Dispatcher Dispatcher => Dispatcher; } public abstract class ChildView : ChildView { protected override TState State => Singleton?.State; protected override TState LastState => Singleton?.LastState; + protected override Dispatcher Dispatcher => Dispatcher; } void Awake() { diff --git a/Runtime/Views/View.cs b/Runtime/Views/View.cs index 44fa932..4bb0f15 100644 --- a/Runtime/Views/View.cs +++ b/Runtime/Views/View.cs @@ -6,6 +6,10 @@ namespace VioletUI { [ExecuteAlways] public abstract class View : TidyBehaviour where TState : class, IState { + /// + /// A view requires a reference to State and LastState. + /// + /// protected abstract TState State { get; } protected abstract TState LastState { get; } @@ -18,7 +22,7 @@ protected virtual void OnShow() { } /// protected virtual void OnHide() { } /// - /// ShouldRender is used to short circuit expensive render calls by focusing on parts of the state you care about. + /// IsDirty is used to short circuit expensive render calls by focusing on parts of the state you care about. /// /// return `false` to avoid rendering /// @@ -32,13 +36,21 @@ protected virtual void OnHide() { } /// protected virtual void Render(TState state) { } - Dispatcher m_dispatcher; - protected Dispatcher dispatcher { + /// + /// dispatcher allows you to send Actions that + /// + protected virtual Dispatcher Dispatcher { get { - if (m_dispatcher == null) { m_dispatcher = new Dispatcher(State, LastState); } - return m_dispatcher; + if (dispatcher == null) { dispatcher = new Dispatcher(State, LastState); } + return dispatcher; } } + Dispatcher dispatcher; + + // convenience methods for logging in views + protected void Log(string s) { Violet.Log(s); } + protected void LogWarning(string s) { Violet.LogWarning(s); } + protected void LogError(string s) { Violet.LogError(s); } // Internal methods are so that callers don't have to remember to call base. at the beginning of their implementations internal virtual void OnShowInternal() {} @@ -96,20 +108,20 @@ void OnDisable() { void Warn(string msg) { #if VIOLETDEV - UnityEngine.Debug.LogWarning(msg); + Violet.LogWarning(msg); #endif } void Verbose(string msg) { #if VIOLETDEV && VIOLET_VERBOSE - UnityEngine.Debug.Log(msg); + Violet.Log(msg); #endif } #if UNITY_EDITOR public virtual void Update() { if (Application.isPlaying) { return; } - if (State == null) { Debug.LogWarning("State is null"); return; } + if (State == null) { Warn("State is null"); return; } State.OnChange -= State_OnChange; State.OnChange += State_OnChange; } diff --git a/Runtime/Violet.cs b/Runtime/Violet.cs new file mode 100644 index 0000000..6d09063 --- /dev/null +++ b/Runtime/Violet.cs @@ -0,0 +1,36 @@ +using UnityEngine; + +/// +/// Static utility methods +/// +public static class Violet { + public static void Log(string s) { + Debug.Log($"{Color("VioletUI")} | {s}"); + } + + public static void LogWarning(string s) { + Debug.LogWarning($"{Color("VioletUI")} | {s}"); + } + + public static void LogError(string s) { + Debug.LogError($"{Color("VioletUI")} | {s}"); + } + + // #ceb2da + // hsl(282, 35%, 78%) + public static Color Hue = new Color(0.898f, 0.745f, 0.935f); + + // #b300ff + // rgb(179, 0, 255) + // hsl(282, 100%, 50%) + public static Color BrightHue = new Color(179/255, 0, 1); + /// + /// Wraps `s` in tags for printing to unity console + /// + /// + /// + public static string Color(string s, string hex = "b300ff") { + return $"{s}"; + } + +} \ No newline at end of file diff --git a/Runtime/Violet.cs.meta b/Runtime/Violet.cs.meta new file mode 100644 index 0000000..cca7456 --- /dev/null +++ b/Runtime/Violet.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d99eca75c51084b3d9908a751ba74a14 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: