Procházet zdrojové kódy

Feature: SpriteTexture inspector now allows you to set sprite texture animation and has a preview box

BearishSun před 6 roky
rodič
revize
56b55091e6

+ 117 - 0
Source/EditorManaged/GUI/GUILayoutWithBackground.cs

@@ -0,0 +1,117 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2019 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Collections.Generic;
+using bs;
+
+namespace bs.Editor
+{
+    /** @addtogroup GUI-Editor
+     *  @{
+     */
+
+    /// <summary>
+    /// Helper class that creates a GUI layout with a texture background.
+    /// </summary>
+    public class GUILayoutWithBackground
+    {
+        /// <summary>
+        /// Content layout into which you should add your own GUI elements.
+        /// </summary>
+        public GUILayout Layout { get; }
+
+        /// <summary>
+        /// Root panel of the content layout, background panel and any helper backgrounds. Can be used for changing size,
+        /// destroying or hiding the GUI elements. You should not add or remove GUI elements from the panel.
+        /// </summary>
+        public GUIPanel MainPanel { get; }
+
+        /// <summary>
+        /// Constructs a new object.
+        /// </summary>
+        /// <param name="mainPanel">Root panel in which all the child GUI elements of this object belong to.</param>
+        /// <param name="layout">Content layout that's to be provided to the user.</param>
+        private GUILayoutWithBackground(GUIPanel mainPanel, GUILayout layout)
+        {
+            MainPanel = mainPanel;
+            Layout = layout;
+        }
+
+        /// <summary>
+        /// Creates a new GUI layout of the specified type, with a texture background.
+        /// </summary>
+        /// <typeparam name="T">Type of layout to create.</typeparam>
+        /// <param name="layout">Parent layout to add the layout to.</param>
+        /// <param name="background">Texture to display on the background.</param>
+        /// <param name="backgroundColor">Color to apply to the background texture.</param>
+        /// <param name="padding">Optional padding to apply between element borders and content.</param>
+        /// <returns>New GUI layout with background object.</returns>
+        public static GUILayoutWithBackground Create<T>(GUILayout layout, SpriteTexture background, Color backgroundColor,
+            RectOffset padding = new RectOffset()) where T : GUILayout, new()
+        {
+            GUIPanel mainPanel = layout.AddPanel();
+            GUILayoutX mainLayout = mainPanel.AddLayoutX();
+
+            GUILayout contentLayout;
+            if (padding.top > 0 || padding.bottom > 0)
+            {
+                GUILayoutY paddingVertLayout = mainLayout.AddLayoutY();
+
+                if (padding.top > 0)
+                    paddingVertLayout.AddSpace(padding.top);
+
+                if (padding.left > 0 || padding.right > 0)
+                {
+                    GUILayoutX paddingHorzLayout = paddingVertLayout.AddLayoutX();
+
+                    if (padding.left > 0)
+                        paddingHorzLayout.AddSpace(padding.left);
+
+                    contentLayout = new T();
+                    paddingHorzLayout.AddElement(contentLayout);
+
+                    if (padding.right > 0)
+                        paddingHorzLayout.AddSpace(padding.right);
+                }
+                else
+                {
+                    contentLayout = new T();
+                    paddingVertLayout.AddElement(contentLayout);
+                }
+
+                if (padding.bottom > 0)
+                    paddingVertLayout.AddSpace(padding.bottom);
+            }
+            else
+            {
+                if (padding.left > 0 || padding.right > 0)
+                {
+                    GUILayoutX paddingHorzLayout = mainLayout.AddLayoutX();
+
+                    if (padding.left > 0)
+                        paddingHorzLayout.AddSpace(padding.left);
+
+                    contentLayout = new T();
+                    paddingHorzLayout.AddElement(contentLayout);
+
+                    if (padding.right > 0)
+                        paddingHorzLayout.AddSpace(padding.right);
+                }
+                else
+                {
+                    contentLayout = new T();
+                    mainLayout.AddElement(contentLayout);
+                }
+            }
+
+            GUIPanel bgPanel = mainPanel.AddPanel(1);
+            GUITexture bgTexture = new GUITexture(Builtin.WhiteTexture);
+            bgTexture.SetTint(backgroundColor);
+            bgPanel.AddElement(bgTexture);
+
+            return new GUILayoutWithBackground(mainPanel, contentLayout);
+        }
+    }
+
+    /** @} */
+}

+ 34 - 25
Source/EditorManaged/Inspectors/SpriteTextureInspector.cs

@@ -1,5 +1,7 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+
+using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using bs;
 using bs;
 
 
@@ -15,9 +17,12 @@ namespace bs.Editor
     [CustomInspector(typeof(SpriteTexture))]
     [CustomInspector(typeof(SpriteTexture))]
     internal class SpriteTextureInspector : Inspector
     internal class SpriteTextureInspector : Inspector
     {
     {
-        private GUITextureField textureField = new GUITextureField(new LocEdString("Atlas"));
-        private GUIVector2Field offsetField = new GUIVector2Field(new LocEdString("Offset"));
-        private GUIVector2Field scaleField = new GUIVector2Field(new LocEdString("Scale"));
+        private GenericInspectorDrawer genericDrawer;
+
+        private GUILayoutWithBackground previewTitleLayout;
+        private GUILayoutWithBackground previewContentLayout;
+
+        private GUITexture previewTexture;
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
         protected internal override void Initialize()
         protected internal override void Initialize()
@@ -28,27 +33,23 @@ namespace bs.Editor
             if (spriteTexture == null)
             if (spriteTexture == null)
                 return;
                 return;
 
 
-            textureField.OnChanged += (x) =>
-            {
-                spriteTexture.Texture = x.As<Texture>();
-                EditorApplication.SetDirty(spriteTexture);
-            };
+            genericDrawer = new GenericInspectorDrawer(spriteTexture, this, Layout);
 
 
-            offsetField.OnChanged += (x) =>
-            {
-                spriteTexture.Offset = x;
-                EditorApplication.SetDirty(spriteTexture);
-            };
+            previewTitleLayout = GUILayoutWithBackground.Create<GUILayoutX>(Layout, Builtin.WhiteTexture,
+                new Color(0.129f, 0.129f, 0.129f), new RectOffset(11, 0, 2, 0));
 
 
-            scaleField.OnChanged += (x) =>
-            {
-                spriteTexture.Scale = x;
-                EditorApplication.SetDirty(spriteTexture);
-            };
+            GUILabel title = new GUILabel(new LocEdString("Preview"));
+            previewTitleLayout.Layout.AddElement(title);
+            previewTitleLayout.Layout.AddFlexibleSpace();
+
+            previewContentLayout = GUILayoutWithBackground.Create<GUILayoutX>(Layout, Builtin.WhiteTexture,
+                new Color(0.09f, 0.09f, 0.09f), new RectOffset(5, 5, 5, 5));
+
+            previewContentLayout.MainPanel.SetHeight(250);
 
 
-            Layout.AddElement(textureField);
-            Layout.AddElement(offsetField);
-            Layout.AddElement(scaleField);
+            previewTexture = new GUITexture(spriteTexture, GUITextureScaleMode.ScaleToFit,
+                GUIOption.FlexibleWidth(), GUIOption.FlexibleHeight());
+            previewContentLayout.Layout.AddElement(previewTexture);
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
@@ -58,11 +59,19 @@ namespace bs.Editor
             if (spriteTexture == null)
             if (spriteTexture == null)
                 return InspectableState.NotModified;
                 return InspectableState.NotModified;
 
 
-            textureField.TextureRef = spriteTexture.Texture;
-            offsetField.Value = spriteTexture.Offset;
-            scaleField.Value = spriteTexture.Scale;
+            InspectableState state = genericDrawer.Refresh();
+            if (state != InspectableState.NotModified)
+            {
+                // The inspector will by default just assign a resource reference without loading it, make sure we load it
+                // so it can be previewed
+                if (spriteTexture.Texture != null && !spriteTexture.Texture.IsLoaded)
+                    Resources.Load<Texture>(spriteTexture.Texture.UUID);
+
+                // Make sure GUI redraws as the sprite texture properties were updated
+                previewTexture.SetTexture(spriteTexture);
+            }
 
 
-            return InspectableState.NotModified;
+            return state;
         }
         }
     }
     }
 
 

+ 54 - 15
Source/EditorManaged/Windows/Inspector/GenericInspector.cs

@@ -16,7 +16,7 @@ namespace bs.Editor
     internal sealed class GenericInspector : Inspector
     internal sealed class GenericInspector : Inspector
     {
     {
         private bool isEmpty = true;
         private bool isEmpty = true;
-        private List<InspectableField> inspectableFields = new List<InspectableField>();
+        private GenericInspectorDrawer drawer;
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
         protected internal override void Initialize()
         protected internal override void Initialize()
@@ -24,23 +24,68 @@ namespace bs.Editor
             if (InspectedObject == null)
             if (InspectedObject == null)
                 LoadResource();
                 LoadResource();
 
 
-            if (InspectedObject != null)
-            {
-                SerializableObject serializableObject = new SerializableObject(InspectedObject.GetType(), InspectedObject);
-                inspectableFields = InspectableField.CreateFields(serializableObject, this, "", 0, Layout);
-                isEmpty = inspectableFields.Count == 0;
+            drawer = new GenericInspectorDrawer(InspectedObject, this, Layout);
 
 
-                base.SetVisible(!isEmpty);
-            }
+            isEmpty = drawer.Fields.Count == 0;
+            base.SetVisible(!isEmpty);
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
         protected internal override InspectableState Refresh()
         protected internal override InspectableState Refresh()
+        {
+            return drawer.Refresh();
+        }
+
+        /// <inheritdoc/>
+        internal override void SetVisible(bool visible)
+        {
+            base.SetVisible(!isEmpty && visible);
+        }
+    }
+
+    /// <summary>
+    /// Helper class that draws the default inspector elements for an object, with an optional callback to render custom
+    /// inspectors for certain types.
+    /// </summary>
+    internal sealed class GenericInspectorDrawer
+    {
+        /// <summary>
+        /// List of fields created and updated by the drawer.
+        /// </summary>
+        public List<InspectableField> Fields { get; } = new List<InspectableField>();
+
+        /// <summary>
+        /// Creates new generic inspector field drawer for the specified object.
+        /// </summary>
+        /// <param name="obj">Object whose fields to create the GUI for.</param>
+        /// <param name="parent">Parent Inspector to draw in.</param>
+        /// <param name="layout">Parent layout that all the field GUI elements will be added to.</param>
+        /// <param name="overrideCallback">
+        /// Optional callback that allows you to override the look of individual fields in the object. If non-null the
+        /// callback will be called with information about every field in the provided object. If the callback returns
+        /// non-null that inspectable field will be used for drawing the GUI, otherwise the default inspector field type
+        /// will be used.
+        /// </param>
+        public GenericInspectorDrawer(object obj, Inspector parent, GUILayoutY layout, 
+            InspectableField.FieldOverrideCallback overrideCallback = null)
+        {
+            if (obj == null)
+                return;
+
+            SerializableObject serializableObject = new SerializableObject(obj.GetType(), obj);
+            Fields = InspectableField.CreateFields(serializableObject, parent, "", 0, layout, overrideCallback);
+        }
+
+        /// <summary>
+        /// Checks if contents of the inspector fields have been modified, and updates them if needed.
+        /// </summary>
+        /// <returns>State representing was anything modified between two last calls to <see cref="Refresh"/>.</returns>
+        public InspectableState Refresh()
         {
         {
             InspectableState state = InspectableState.NotModified;
             InspectableState state = InspectableState.NotModified;
 
 
             int currentIndex = 0;
             int currentIndex = 0;
-            foreach (var field in inspectableFields)
+            foreach (var field in Fields)
             {
             {
                 state |= field.Refresh(currentIndex);
                 state |= field.Refresh(currentIndex);
                 currentIndex += field.GetNumLayoutElements();
                 currentIndex += field.GetNumLayoutElements();
@@ -48,12 +93,6 @@ namespace bs.Editor
 
 
             return state;
             return state;
         }
         }
-
-        /// <inheritdoc/>
-        internal override void SetVisible(bool visible)
-        {
-            base.SetVisible(!isEmpty && visible);
-        }
     }
     }
 
 
     /** @} */
     /** @} */

+ 1 - 3
Source/EditorManaged/Windows/Inspector/InspectableResource.cs

@@ -29,9 +29,7 @@ namespace bs.Editor
         public InspectableResource(Inspector parent, string title, string path, int depth, InspectableFieldLayout layout,
         public InspectableResource(Inspector parent, string title, string path, int depth, InspectableFieldLayout layout,
             SerializableProperty property)
             SerializableProperty property)
             : base(parent, title, path, SerializableProperty.FieldType.Resource, depth, layout, property)
             : base(parent, title, path, SerializableProperty.FieldType.Resource, depth, layout, property)
-        {
-
-        }
+        { }
 
 
         /// <inheritoc/>
         /// <inheritoc/>
         protected internal override void Initialize(int layoutIndex)
         protected internal override void Initialize(int layoutIndex)

+ 76 - 0
Source/EditorManaged/Windows/Inspector/InspectableTexture.cs

@@ -0,0 +1,76 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+namespace bs.Editor
+{
+    /** @addtogroup Inspector
+     *  @{
+     */
+
+    /// <summary>
+    /// Displays GUI for a serializable property containing a <see cref="Texture"/> reference.
+    /// </summary>
+    [CustomInspector(typeof(Texture))]
+    public class InspectableTexture : InspectableField
+    {
+        private GUITextureField guiField;
+        private InspectableState state;
+
+        /// <summary>
+        /// Creates a new inspectable texture reference GUI for the specified property.
+        /// </summary>
+        /// <param name="parent">Parent Inspector this field belongs to.</param>
+        /// <param name="title">Name of the property, or some other value to set as the title.</param>
+        /// <param name="path">Full path to this property (includes name of this property and all parent properties).</param>
+        /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field. Some fields may
+        ///                     contain other fields, in which case you should increase this value by one.</param>
+        /// <param name="layout">Parent layout that all the field elements will be added to.</param>
+        /// <param name="property">Serializable property referencing the field whose contents to display.</param>
+        public InspectableTexture(Inspector parent, string title, string path, int depth, InspectableFieldLayout layout,
+            SerializableProperty property, InspectableFieldStyleInfo style)
+            : base(parent, title, path, property.Type, depth, layout, property)
+        { }
+
+        /// <inheritoc/>
+        protected internal override void Initialize(int layoutIndex)
+        {
+            guiField = new GUITextureField(GUITextureFieldType.Texture, new GUIContent(title));
+            guiField.OnChanged += OnFieldValueChanged;
+
+            layout.AddElement(layoutIndex, guiField);
+        }
+
+        /// <inheritdoc/>
+        public override InspectableState Refresh(int layoutIndex)
+        {
+            if (guiField != null)
+            {
+                if (property.Type == SerializableProperty.FieldType.Resource)
+                    guiField.Texture = property.GetValue<Texture>();
+                else
+                    guiField.TextureRef = property.GetValue<RRef<Texture>>();
+            }
+
+            InspectableState oldState = state;
+            if (state.HasFlag(InspectableState.Modified))
+                state = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Triggered when the user drops a new resource onto the field, or clears the current value.
+        /// </summary>
+        /// <param name="newValue">New resource to reference.</param>
+        private void OnFieldValueChanged(RRefBase newValue)
+        {
+            if (property.Type == SerializableProperty.FieldType.Resource)
+                property.SetValue(newValue.GenericValue);
+            else
+                property.SetValue(newValue);
+
+            state = InspectableState.Modified;
+        }
+    }
+
+    /** @} */
+}

+ 1 - 1
Source/bsf

@@ -1 +1 @@
-Subproject commit aa1b8d9d6af8e90c3d310c073b3fe0a8e8ff5e1b
+Subproject commit b43a083b58874cec1d7e84a40c40e978725d9423