BearishSun преди 9 години
родител
ревизия
c195d0e7ae

+ 4 - 0
Source/BansheeEditor/Include/BsBuiltinEditorResources.h

@@ -72,6 +72,9 @@ namespace BansheeEngine
 		/** Returns the default font used by the editor. */
 		const HFont& getDefaultFont() const { return mDefaultFont; }
 
+		/** Returns the default antialiased font used by the editor. */
+		const HFont& getDefaultAAFont() const { return mDefaultAAFont; }
+
 		/**	Creates a material used for docking drop overlay used by the editor. */
 		HMaterial createDockDropOverlayMaterial() const;
 
@@ -207,6 +210,7 @@ namespace BansheeEngine
 		HShader mShaderSelection;
 
 		HFont mDefaultFont;
+		HFont mDefaultAAFont;
 		HGUISkin mSkin;
 
 		SPtr<ResourceManifest> mResourceManifest;

+ 15 - 14
Source/BansheeEditor/Source/BsBuiltinEditorResources.cpp

@@ -357,7 +357,8 @@ namespace BansheeEngine
 		mShaderHandleLine = getShader(ShaderLineHandleFile);
 		mShaderSelection = getShader(ShaderSelectionFile);
 
-		mDefaultFont = gResources().load<Font>(BuiltinDataFolder + (DefaultAAFontFilename + L".asset"));
+		mDefaultFont = gResources().load<Font>(BuiltinDataFolder + (DefaultFontFilename + L".asset"));
+		mDefaultAAFont = gResources().load<Font>(BuiltinDataFolder + (DefaultAAFontFilename + L".asset"));
 		mSkin = gResources().load<GUISkin>(BuiltinDataFolder + (GUISkinFile + L".asset"));
 	}
 
@@ -1213,19 +1214,19 @@ namespace BansheeEngine
 		/************************************************************************/
 
 		// Expand button
-		GUIElementStyle treeViewExpandButtonStyle;
-		treeViewExpandButtonStyle.normal.texture = getGUITexture(TreeViewExpandButtonOffNormal);
-		treeViewExpandButtonStyle.hover.texture = getGUITexture(TreeViewExpandButtonOffHover);
-		treeViewExpandButtonStyle.active.texture = treeViewExpandButtonStyle.hover.texture;
-		treeViewExpandButtonStyle.normalOn.texture = getGUITexture(TreeViewExpandButtonOnNormal);
-		treeViewExpandButtonStyle.hoverOn.texture = getGUITexture(TreeViewExpandButtonOnHover);
-		treeViewExpandButtonStyle.activeOn.texture = treeViewExpandButtonStyle.hoverOn.texture;
-		treeViewExpandButtonStyle.fixedHeight = true;
-		treeViewExpandButtonStyle.fixedWidth = true;
-		treeViewExpandButtonStyle.height = 10;
-		treeViewExpandButtonStyle.width = 10;
-
-		skin->setStyle("TreeViewFoldoutBtn", treeViewExpandButtonStyle);
+		GUIElementStyle expandButtonStyle;
+		expandButtonStyle.normal.texture = getGUITexture(TreeViewExpandButtonOffNormal);
+		expandButtonStyle.hover.texture = getGUITexture(TreeViewExpandButtonOffHover);
+		expandButtonStyle.active.texture = expandButtonStyle.hover.texture;
+		expandButtonStyle.normalOn.texture = getGUITexture(TreeViewExpandButtonOnNormal);
+		expandButtonStyle.hoverOn.texture = getGUITexture(TreeViewExpandButtonOnHover);
+		expandButtonStyle.activeOn.texture = expandButtonStyle.hoverOn.texture;
+		expandButtonStyle.fixedHeight = true;
+		expandButtonStyle.fixedWidth = true;
+		expandButtonStyle.height = 10;
+		expandButtonStyle.width = 10;
+
+		skin->setStyle("Expand", expandButtonStyle);
 
 		// Entry
 		GUIElementStyle treeViewEntryStyle;

+ 1 - 1
Source/BansheeEditor/Source/BsGUITreeView.cpp

@@ -98,7 +98,7 @@ namespace BansheeEngine
 			mElementBtnStyle = "TreeViewElementBtn";
 
 		if(mFoldoutBtnStyle == StringUtil::BLANK)
-			mFoldoutBtnStyle = "TreeViewFoldoutBtn";
+			mFoldoutBtnStyle = "Expand";
 
 		if(mSelectionBackgroundStyle == StringUtil::BLANK)
 			mSelectionBackgroundStyle = "TreeViewSelectionBackground";

+ 1 - 1
Source/BansheeEditor/Source/BsGizmoManager.cpp

@@ -402,7 +402,7 @@ namespace BansheeEngine
 	{
 		HFont myFont = font;
 		if (myFont == nullptr)
-			myFont = BuiltinEditorResources::instance().getDefaultFont();
+			myFont = BuiltinEditorResources::instance().getDefaultAAFont();
 
 		mTextData.push_back(TextData());
 		TextData& textData = mTextData.back();

+ 1 - 1
Source/BansheeEditor/Source/BsHandleDrawManager.cpp

@@ -177,7 +177,7 @@ namespace BansheeEngine
 
 		HFont myFont = font;
 		if (myFont == nullptr)
-			myFont = BuiltinEditorResources::instance().getDefaultFont();
+			myFont = BuiltinEditorResources::instance().getDefaultAAFont();
 
 		mDrawHelper->text(position, text, myFont, fontSize);
 	}

+ 1 - 1
Source/BansheeFBXImporter/Source/BsFBXImporter.cpp

@@ -1597,7 +1597,7 @@ namespace BansheeEngine
 		Vector<FBXKeyFrame> newKeyframes[3];
 
 		bool lastWasEqual = false;
-		for (int i = 0; i < keyCount; i++)
+		for (UINT32 i = 0; i < keyCount; i++)
 		{
 			bool isEqual = true;
 

+ 1 - 0
Source/MBansheeEditor/GUI/EditorStyles.cs

@@ -25,6 +25,7 @@ namespace BansheeEditor
         public const string Toggle = "Toggle";
         public const string InputBox = "InputBox";
         public const string Foldout = "Foldout";
+        public const string Expand = "Expand";
         public const string ColorSliderHorz = "ColorSliderHorz";
         public const string ColorSliderVert = "ColorSliderVert";
         public const string ColorSlider2DHandle = "ColorSlider2DHandle";

+ 1 - 0
Source/MBansheeEditor/MBansheeEditor.csproj

@@ -48,6 +48,7 @@
     <Compile Include="Inspectors\PostProcessSettingsInspector.cs" />
     <Compile Include="Windows\AboutBox.cs" />
     <Compile Include="Windows\AnimationWindow.cs" />
+    <Compile Include="Windows\Animation\GUIFieldSelector.cs" />
     <Compile Include="Windows\Animation\GUITimeline.cs" />
     <Compile Include="Windows\BrowseDialog.cs" />
     <Compile Include="Windows\Build\BuildManager.cs" />

+ 11 - 0
Source/MBansheeEditor/Utility/EditorBuiltin.cs

@@ -74,6 +74,14 @@ namespace BansheeEditor
         /// <summary>Returns text contained in the default "empty" C# script.</summary>
         public static string EmptyCSScriptCode { get { return Internal_GetEmptyCSScriptCode(); } }
 
+        /// <summary>
+        /// Returns the default Font used in the editor.
+        /// </summary>
+        public static Font DefaultFont
+        {
+            get { return Internal_GetDefaultFont(); }
+        }
+
         /// <summary>
         /// Retrieves an icon used for displaying an entry in the library window.
         /// </summary>
@@ -164,6 +172,9 @@ namespace BansheeEditor
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern SpriteTexture Internal_GetLogIcon(LogIcon icon, int size, bool dark);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern Font Internal_GetDefaultFont();
     }
 
     /** @} */

+ 349 - 0
Source/MBansheeEditor/Windows/Animation/GUIFieldSelector.cs

@@ -0,0 +1,349 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Collections.Generic;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /** @addtogroup AnimationEditor
+     *  @{
+     */
+
+    /// <summary>
+    /// Renders GUI elements that display a Scene Object, its transform, components and child objects, as well as all of
+    /// their fields. User can then select one of the fields and the class will output a path to the selected field, as
+    /// well as its parent scene object and component.
+    /// </summary>
+    public class GUIFieldSelector
+    {
+        private const int INDENT_AMOUNT = 5;
+
+        private SpriteTexture ICON_SO; // TODO
+        private SpriteTexture ICON_COMPONENT; // TODO
+
+        private GUILayoutY mainLayout;
+
+        private SceneObject rootSO;
+        private Element rootElement;
+
+        /// <summary>
+        /// Stores a single entry in the field hierarchy.
+        /// </summary>
+        private struct Element
+        {
+            public Element(SceneObject so, Component comp, string path)
+            {
+                this.so = so;
+                this.comp = comp;
+                this.path = path;
+
+                toggle = null;
+                childLayout = null;
+                indentLayout = null;
+
+                children = null;
+            }
+
+            public SceneObject so;
+            public Component comp;
+            public string path;
+
+            public GUIToggle toggle;
+            public GUILayoutY childLayout;
+            public GUILayoutX indentLayout;
+
+            public Element[] children;
+        }
+
+        /// <summary>
+        /// Triggers when the user selects a field. The subscriber will be receive a scene object the field is part of,
+        /// component the field is part of, and a path to the field, each entry separated by "/". Component can be null
+        /// in which case it is assumed the field is part of the SceneObject itself.
+        /// </summary>
+        public Action<SceneObject, Component, string> OnElementSelected;
+
+        /// <summary>
+        /// Creates a new GUIFieldSelector and registers its GUI elements in the provided layout.
+        /// </summary>
+        /// <param name="layout">Layout into which to add the selector GUI hierarchy.</param>
+        /// <param name="so">Scene object to inspect the fields for.</param>
+        public GUIFieldSelector(GUILayout layout, SceneObject so)
+        {
+            rootSO = so;
+            mainLayout = layout.AddLayoutY();
+
+            Rebuild();
+        }
+
+        /// <summary>
+        /// Rebuilds all of the selection GUI.
+        /// </summary>
+        private void Rebuild()
+        {
+            mainLayout.Clear();
+            rootElement = new Element();
+
+            if (rootSO == null)
+                return;
+
+            rootElement.so = rootSO;
+            AddSceneObjectRows(rootElement);
+        }
+
+        /// <summary>
+        /// Registers a set of rows for all components in a <see cref="SceneObject"/>, as well as its transform and
+        /// child objects.
+        /// </summary>
+        /// <param name="parent">Row element under which to create the new rows.</param>
+        private void AddSceneObjectRows(Element parent)
+        {
+            Component[] components = parent.so.GetComponents();
+
+            parent.children = new Element[components.Length + 2];
+
+            // Add transform
+            parent.children[0] = AddFoldoutRow(mainLayout, ICON_COMPONENT, "Transform", parent.so, 
+                null, "", ToggleTransformFoldout);
+
+            // Add components
+            for (int i = 0; i < components.Length; i++)
+            {
+                Component childComponent = components[i];
+                Action<Element, bool> toggleCallback = 
+                    (toggleParent, expand) =>
+                {
+                    SerializableObject componentObject = new SerializableObject(childComponent.GetType(), null);
+                    ToggleObjectFoldout(toggleParent, componentObject, expand);
+                };
+
+                string name = childComponent.GetType().Name;
+                parent.children[i + 1] = AddFoldoutRow(mainLayout, ICON_COMPONENT, name, parent.so, childComponent, "", 
+                    toggleCallback);
+            }
+
+            // Add children
+            parent.children[parent.children.Length - 1] = AddFoldoutRow(mainLayout, ICON_SO, "Children", parent.so, null, "",
+                ToggleChildFoldout);
+        }
+
+        /// <summary>
+        /// Registers a set of rows for all child fields of the provided object.
+        /// </summary>
+        /// <param name="parent">Parent foldout row to which to append the new elements.</param>
+        /// <param name="serializableObject">Type of the object whose fields to display.</param>
+        private void AddObjectRows(Element parent, SerializableObject serializableObject)
+        {
+            List<Element> elements = new List<Element>(); 
+            foreach (var field in serializableObject.Fields)
+            {
+                if (!field.Inspectable)
+                    continue;
+
+                string propertyPath = parent.path + "/" + field.Name;
+
+                switch (field.Type)
+                {
+                    case SerializableProperty.FieldType.Bool:
+                    case SerializableProperty.FieldType.Float:
+                    case SerializableProperty.FieldType.Int:
+                    case SerializableProperty.FieldType.Color:
+                    case SerializableProperty.FieldType.Vector2:
+                    case SerializableProperty.FieldType.Vector3:
+                    case SerializableProperty.FieldType.Vector4:
+                        elements.Add(AddFieldRow(parent.childLayout, field.Name, parent.so, parent.comp, propertyPath));
+                        break;
+                    case SerializableProperty.FieldType.Object:
+                        Action<Element, bool> toggleCallback = 
+                            (toggleParent, expand) =>
+                        {
+                            SerializableObject childObject = new SerializableObject(field.InternalType, null);
+                            ToggleObjectFoldout(toggleParent, childObject, expand);
+                        };
+                        elements.Add(AddFoldoutRow(parent.childLayout, null, field.Name, parent.so, parent.comp, 
+                            propertyPath, toggleCallback));
+                        break;
+                }
+            }
+
+            parent.children = elements.ToArray();
+        }
+
+        /// <summary>
+        /// Registers a new row in the layout. The row cannot have any further children and can be selected as the output
+        /// field.
+        /// </summary>
+        /// <param name="layout">Layout to append the row GUI elements to.</param>
+        /// <param name="name">Name of the field.</param>
+        /// <param name="so">Parent scene object of the field.</param>
+        /// <param name="component">Parent component of the field. Can be null if field belongs to <see cref="SceneObject"/>.
+        ///                         </param>
+        /// <param name="path">Slash separated path to the field from its parent object.</param>
+        /// <returns>Element object storing all information about the added field.</returns>
+        private Element AddFieldRow(GUILayout layout, string name, SceneObject so, Component component, string path)
+        {
+            Element element = new Element(so, component, path);
+
+            GUILayoutX elementLayout = layout.AddLayoutX();
+           
+            GUILabel label = new GUILabel(new LocEdString(name));
+            elementLayout.AddElement(label);
+
+            GUIButton selectBtn = new GUIButton(new LocEdString("Select"));
+            selectBtn.OnClick += () => { DoOnElementSelected(element); };
+
+            elementLayout.AddFlexibleSpace();
+            elementLayout.AddElement(selectBtn);
+
+            element.path = path;
+
+            return element;
+        }
+
+        /// <summary>
+        /// Registers a new row in the layout. The row cannot be selected as the output field, but rather can be expanded
+        /// so it displays child elements.
+        /// </summary>
+        /// <param name="layout">Layout to append the row GUI elements to.</param>
+        /// <param name="icon">Optional icon to display next to the name. Can be null.</param>
+        /// <param name="name">Name of the field.</param>
+        /// <param name="so">Parent scene object of the field.</param>
+        /// <param name="component">Parent component of the field. Can be null if field belongs to <see cref="SceneObject"/>.
+        ///                         </param>
+        /// <param name="path">Slash separated path to the field from its parent object.</param>
+        /// <param name="toggleCallback">Callback to trigger when the user expands or collapses the foldout.</param>
+        /// <returns>Element object storing all information about the added field.</returns>
+        private Element AddFoldoutRow(GUILayout layout, SpriteTexture icon, string name, SceneObject so, Component component,
+            string path, Action<Element, bool> toggleCallback)
+        {
+            Element element = new Element(so, component, path);
+
+            GUILayoutY elementLayout = layout.AddLayoutY();
+            GUILayoutX foldoutLayout = elementLayout.AddLayoutX();
+
+            element.toggle = new GUIToggle(EditorStyles.Expand);
+            element.toggle.OnToggled += x => toggleCallback(element, x);
+
+            foldoutLayout.AddElement(element.toggle);
+
+            if (icon != null)
+            {
+                GUITexture guiIcon = new GUITexture(icon, GUIOption.FixedWidth(16), GUIOption.FixedWidth(16));
+                foldoutLayout.AddElement(guiIcon);
+            }
+
+            GUILabel label = new GUILabel(new LocEdString(name));
+            foldoutLayout.AddElement(label);
+            foldoutLayout.AddFlexibleSpace();
+
+            element.indentLayout = elementLayout.AddLayoutX();
+            element.indentLayout.AddSpace(INDENT_AMOUNT);
+            element.childLayout = element.indentLayout.AddLayoutY();
+
+            element.indentLayout.Active = false;
+
+            return element;
+        }
+
+        /// <summary>
+        /// Expands or collapses the set of rows displaying a <see cref="SceneObject"/>'s transform (position, rotation, 
+        /// scale).
+        /// </summary>
+        /// <param name="parent">Parent row element whose children to expand/collapse.</param>
+        /// <param name="expand">True to expand, false to collapse.</param>
+        private void ToggleTransformFoldout(Element parent, bool expand)
+        {
+            parent.childLayout.Clear();
+            parent.children = null;
+
+            parent.indentLayout.Active = expand;
+
+            if (expand)
+            {
+                parent.children = new Element[3];
+
+                parent.children[0] = AddFieldRow(parent.childLayout, "Position", parent.so, null, parent.path + "/Position");
+                parent.children[1] = AddFieldRow(parent.childLayout, "Rotation", parent.so, null, parent.path + "/Rotation");
+                parent.children[2] = AddFieldRow(parent.childLayout, "Scale", parent.so, null, parent.path + "/Scale");
+            }
+        }
+
+        /// <summary>
+        /// Expands or collapses the set of rows displaying all <see cref="SceneObject"/> children of a 
+        /// <see cref="SceneObject"/>.
+        /// </summary>
+        /// <param name="parent">Parent row element whose children to expand/collapse.</param>
+        /// <param name="expand">True to expand, false to collapse.</param>
+        private void ToggleChildFoldout(Element parent, bool expand)
+        {
+            parent.childLayout.Clear();
+            parent.children = null;
+
+            parent.indentLayout.Active = expand;
+
+            if (expand)
+            {
+                int numChildren = parent.so.GetNumChildren();
+
+                parent.children = new Element[numChildren];
+
+                for (int i = 0; i < numChildren; i++)
+                {
+                    SceneObject child = parent.so.GetChild(i);
+
+                    parent.children[i] = AddFoldoutRow(parent.childLayout, ICON_SO, child.Name, child, null, "",
+                        ToggleSceneObjectFoldout);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Expands or collapses the set of rows displaying all children of a <see cref="SceneObject"/>. This includes
+        /// it's components, transform and child scene objects.
+        /// </summary>
+        /// <param name="parent">Parent row element whose children to expand/collapse.</param>
+        /// <param name="expand">True to expand, false to collapse.</param>
+        private void ToggleSceneObjectFoldout(Element parent, bool expand)
+        {
+            parent.childLayout.Clear();
+            parent.children = null;
+
+            parent.indentLayout.Active = expand;
+
+            if (expand)
+            {
+                AddSceneObjectRows(parent);
+            }
+        }
+
+        /// <summary>
+        /// Expands or collapses the set of rows displaying all fields of a serializable object.
+        /// </summary>
+        /// <param name="parent">Parent row element whose children to expand/collapse.</param>
+        /// <param name="obj">Object describing the type of the object whose fields to display.</param>
+        /// <param name="expand">True to expand, false to collapse.</param>
+        private void ToggleObjectFoldout(Element parent, SerializableObject obj,
+            bool expand)
+        {
+            parent.childLayout.Clear();
+            parent.children = null;
+
+            parent.indentLayout.Active = expand;
+
+            if (expand)
+                AddObjectRows(parent, obj);
+        }
+
+        /// <summary>
+        /// Triggered when the user selects a field.
+        /// </summary>
+        /// <param name="element">Row element for the field that was selected.</param>
+        private void DoOnElementSelected(Element element)
+        {
+            if (OnElementSelected != null)
+                OnElementSelected(element.so, element.comp, element.path);
+        }
+    }
+
+    /** @} */
+}

+ 27 - 22
Source/MBansheeEditor/Windows/Animation/GUITimeline.cs

@@ -12,15 +12,18 @@ namespace BansheeEditor
     // TODO DOC
     public class GUITimeline
     {
-        private const float LARGE_TICK_HEIGHT_PCT = 0.5f;
-        private const float SMALL_TICK_HEIGHT_PCT = 0.25f;
+        private const float LARGE_TICK_HEIGHT_PCT = 0.4f;
+        private const float SMALL_TICK_HEIGHT_PCT = 0.2f;
+        private const int PADDING = 30;
+        private const int TEXT_PADDING = 2;
+        private const int MIN_TICK_DISTANCE = 10;
 
         private GUICanvas canvas;
         private int width;
         private int height;
         private float rangeStart = 0.0f;
         private float rangeEnd = 60.0f;
-        private int fps = 60;
+        private int fps = 1;
 
         public GUITimeline(GUILayout layout, int width, int height)
         {
@@ -60,17 +63,18 @@ namespace BansheeEditor
         {
             canvas.Clear();
 
-            canvas.DrawLine(new Vector2I(50, 20), new Vector2I(50, 40), Color.White);
-            canvas.DrawLine(new Vector2I(100, 20), new Vector2I(100, 40), Color.White);
-
-            return;
-
             // TODO - Calculate interval sizes based on set range, width and FPS
             //      - Dynamically change tick heights?
-            //      - Draw text (and convert seconds to minutes/hours as needed)
 
-            float largeTickInterval = 50.0f; // TODO - Must be multiple of small tick interval
-            float smallTickInterval = 10.0f; // TODO
+            int drawableWidth = Math.Max(0, width - PADDING * 2);
+            float rangeLength = rangeEnd - rangeStart;
+            float numSmallTicksPerLarge = 5.0f;
+
+            int totalNumFrames = MathEx.FloorToInt(rangeLength*fps);
+            int numVisibleTicks = Math.Min(totalNumFrames, MathEx.FloorToInt(drawableWidth / (float) MIN_TICK_DISTANCE));
+
+            float smallTickInterval = rangeLength / numVisibleTicks;
+            float largeTickInterval = smallTickInterval * numSmallTicksPerLarge;
 
             float offsetLarge = MathEx.CeilToInt(rangeStart / largeTickInterval) * largeTickInterval - rangeStart;
             float offsetSmall = MathEx.CeilToInt(rangeStart / smallTickInterval) * smallTickInterval - rangeStart;
@@ -80,20 +84,18 @@ namespace BansheeEditor
 
             bool drawSmallTicks = true; // TODO
 
-            float length = rangeEnd - rangeStart;
-            for (float t = offsetSmall; t <= length; t += smallTickInterval)
+            float t = offsetSmall;
+            for (int i = 0; i < numVisibleTicks; i++)
             {
-                Debug.Log(t + " - " + length + " - " + width);
-
                 float distanceToLargeTick = MathEx.CeilToInt(t / largeTickInterval) * largeTickInterval - t;
                 if (MathEx.ApproxEquals(distanceToLargeTick, 0.0f))
                 {
-                    int xPos = (int)((t/length)*width);
+                    int xPos = (int)((t/rangeLength)* drawableWidth) + PADDING;
 
                     Vector2I start = new Vector2I(xPos, height - largeTickHeight);
                     Vector2I end = new Vector2I(xPos, height);
 
-                    canvas.DrawLine(start, end, Color.DarkGray);
+                    canvas.DrawLine(start, end, Color.LightGray);
 
                     TimeSpan intervalSpan = TimeSpan.FromSeconds(largeTickInterval);
                     TimeSpan timeSpan = TimeSpan.FromSeconds(rangeStart + t);
@@ -104,20 +106,21 @@ namespace BansheeEditor
                     else
                         timeString = timeSpan.ToString(@"ss\:fff");
 
-                    Vector2I textBounds = GUIUtility.CalculateTextBounds(timeString, Builtin.DefaultFont, 
+                    Vector2I textBounds = GUIUtility.CalculateTextBounds(timeString, EditorBuiltin.DefaultFont, 
                         EditorStyles.DefaultFontSize);
 
                     Vector2I textPosition = new Vector2I();
-                    textPosition.x = -textBounds.x/2;
+                    textPosition.x = xPos - textBounds.x/2;
+                    textPosition.y = TEXT_PADDING;
 
-                    //canvas.DrawText(timeString, textPosition, Builtin.DefaultFont, Color.DarkGray, 
-                    //    EditorStyles.DefaultFontSize);
+                    canvas.DrawText(timeString, textPosition, EditorBuiltin.DefaultFont, Color.LightGray, 
+                        EditorStyles.DefaultFontSize);
                 }
                 else
                 {
                     if (drawSmallTicks)
                     {
-                        int xPos = (int)((t / length) * width);
+                        int xPos = (int)((t / rangeLength) * drawableWidth) + PADDING;
 
                         Vector2I start = new Vector2I(xPos, height - smallTickHeight);
                         Vector2I end = new Vector2I(xPos, height);
@@ -125,6 +128,8 @@ namespace BansheeEditor
                         canvas.DrawLine(start, end, Color.LightGray);
                     }
                 }
+
+                t += smallTickInterval;
             }
         }
     }

+ 20 - 1
Source/MBansheeEditor/Windows/AnimationWindow.cs

@@ -14,6 +14,9 @@ namespace BansheeEditor
     internal class AnimationWindow : EditorWindow
     {
         private GUITimeline timeline;
+        private GUIFloatField startField;
+        private GUIFloatField endField;
+        private GUIIntField fpsField;
 
         /// <summary>
         /// Opens the animation window.
@@ -32,7 +35,23 @@ namespace BansheeEditor
 
         private void OnInitialize()
         {
-            timeline = new GUITimeline(GUI, 300, 40);
+            startField = new GUIFloatField(new LocEdString("Start"), 50);
+            endField = new GUIFloatField(new LocEdString("End"), 50);
+            fpsField = new GUIIntField(new LocEdString("FPS"), 50);
+
+            endField.Value = 60.0f;
+            fpsField.Value = 1;
+
+            startField.OnChanged += x => timeline.SetRange(x, endField.Value);
+            endField.OnChanged += x => timeline.SetRange(startField.Value, x);
+            fpsField.OnChanged += x => timeline.SetFPS(x);
+
+            GUILayout buttonLayout = GUI.AddLayoutX();
+            buttonLayout.AddElement(startField);
+            buttonLayout.AddElement(endField);
+            buttonLayout.AddElement(fpsField);
+
+            timeline = new GUITimeline(GUI, 300, 20);
         }
 
         private void OnEditorUpdate()

+ 8 - 0
Source/MBansheeEngine/Serialization/SerializableField.cs

@@ -44,6 +44,14 @@ namespace BansheeEngine
             get { return type; }
         }
 
+        /// <summary>
+        /// Returns the actual type of the object contained in the field.
+        /// </summary>
+        public Type InternalType
+        {
+            get { return internalType; }
+        }
+
         /// <summary>
         /// Returns the name of the field.
         /// </summary>

+ 2 - 0
Source/SBansheeEditor/Include/BsScriptEditorBuiltin.h

@@ -35,6 +35,8 @@ namespace BansheeEngine
 		static MonoObject* internal_GetInspectorWindowIcon(InspectorWindowIcon icon);
 		static MonoObject* internal_GetSceneWindowIcon(SceneWindowIcon icon);
 		static MonoObject* internal_GetLogIcon(LogMessageIcon icon, int size, bool dark);
+
+		static MonoObject* internal_GetDefaultFont();
 	};
 
 	/** @} */

+ 13 - 0
Source/SBansheeEditor/Source/BsScriptEditorBuiltin.cpp

@@ -7,6 +7,8 @@
 #include "BsMonoUtil.h"
 #include "BsScriptSpriteTexture.h"
 #include "BsScriptGUIContentImages.h"
+#include "BsScriptResourceManager.h"
+#include "BsScriptFont.h"
 
 namespace BansheeEngine
 {
@@ -25,6 +27,7 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_GetInspectorWindowIcon", &ScriptEditorBuiltin::internal_GetInspectorWindowIcon);
 		metaData.scriptClass->addInternalCall("Internal_GetSceneWindowIcon", &ScriptEditorBuiltin::internal_GetSceneWindowIcon);
 		metaData.scriptClass->addInternalCall("Internal_GetLogIcon", &ScriptEditorBuiltin::internal_GetLogIcon);
+		metaData.scriptClass->addInternalCall("Internal_GetDefaultFont", &ScriptEditorBuiltin::internal_GetDefaultFont);
 	}
 
 	MonoObject* ScriptEditorBuiltin::internal_getLibraryItemIcon(ProjectIcon icon, int size)
@@ -89,4 +92,14 @@ namespace BansheeEngine
 
 		return ScriptSpriteTexture::toManaged(tex);
 	}
+	
+	MonoObject* ScriptEditorBuiltin::internal_GetDefaultFont()
+	{
+		HFont font = BuiltinEditorResources::instance().getDefaultFont();
+
+		ScriptFont* scriptFont;
+		ScriptResourceManager::instance().getScriptResource(font, &scriptFont, true);
+
+		return scriptFont->getManagedInstance();
+	}
 }