Parcourir la source

GUITimeline display extra ticks beyond visible range to avoid pop-in issues as range changes

BearishSun il y a 9 ans
Parent
commit
d2434ca7dd
1 fichiers modifiés avec 50 ajouts et 37 suppressions
  1. 50 37
      Source/MBansheeEditor/Windows/Animation/GUITimeline.cs

+ 50 - 37
Source/MBansheeEditor/Windows/Animation/GUITimeline.cs

@@ -18,11 +18,16 @@ namespace BansheeEditor
         private const int TEXT_PADDING = 2;
         private const int MIN_TICK_DISTANCE = 25;
 
+        private int maxTextWidth;
+        private int largeTickHeight;
+        private int drawableWidth;
+        private float rangeLength;
+
         private GUICanvas canvas;
         private int width;
         private int height;
-        private float rangeStart = 0.0f;
-        private float rangeEnd = 60.0f;
+        private float rangeStart;
+        private float rangeEnd;
         private int fps = 1;
 
         public GUITimeline(GUILayout layout, int width, int height)
@@ -30,7 +35,11 @@ namespace BansheeEditor
             canvas = new GUICanvas();
             layout.AddElement(canvas);
 
+            maxTextWidth = GUIUtility.CalculateTextBounds("99:999", EditorBuiltin.DefaultFont,
+               EditorStyles.DefaultFontSize).x;
+
             SetSize(width, height);
+            SetRange(0, 60.0f);
         }
 
         public void SetSize(int width, int height)
@@ -41,6 +50,9 @@ namespace BansheeEditor
             canvas.SetWidth(width);
             canvas.SetHeight(height);
 
+            largeTickHeight = (int)(height * LARGE_TICK_HEIGHT_PCT);
+            drawableWidth = Math.Max(0, width - PADDING * 2);
+
             Rebuild();
         }
 
@@ -49,6 +61,8 @@ namespace BansheeEditor
             rangeStart = start;
             rangeEnd = end;
 
+            rangeLength = rangeEnd - rangeStart;
+
             Rebuild();
         }
 
@@ -59,7 +73,7 @@ namespace BansheeEditor
             Rebuild();
         }
 
-        private float CalcTickInterval(float length)
+        private float CalcTickInterval()
         {
             const int OPTIMAL_TICK_COUNT = 10;
             float[] validIntervals =
@@ -79,7 +93,7 @@ namespace BansheeEditor
                 if (validIntervals[i] < timePerFrame)
                     continue;
 
-                float tickCount = length/validIntervals[i];
+                float tickCount = rangeLength/validIntervals[i];
                 float distance = Math.Abs(tickCount - OPTIMAL_TICK_COUNT);
                 if (distance < bestDistance)
                 {
@@ -89,9 +103,7 @@ namespace BansheeEditor
             }
 
             // If the draw area is too narrow, limit amount of ticks displayed so they aren't all clumped together
-            int numTicks = MathEx.FloorToInt(length / validIntervals[bestIntervalIdx]) + 1;
-
-            int drawableWidth = Math.Max(0, width - PADDING * 2);
+            int numTicks = MathEx.FloorToInt(rangeLength / validIntervals[bestIntervalIdx]) + 1;
             int spacePerTick = drawableWidth/numTicks;
 
             float bestInterval;
@@ -102,7 +114,7 @@ namespace BansheeEditor
                 bool foundInterval = false;
                 for (int i = bestIntervalIdx; i < validIntervals.Length; i++)
                 {
-                    float tickCount = length/validIntervals[i];
+                    float tickCount = rangeLength / validIntervals[i];
                     if (tickCount <= maxTickCount)
                     {
                         bestIntervalIdx = i;
@@ -117,7 +129,7 @@ namespace BansheeEditor
                     float currentInterval = validIntervals[validIntervals.Length - 1]*2;
                     while (true)
                     {
-                        float tickCount = length/ currentInterval;
+                        float tickCount = rangeLength / currentInterval;
                         if (tickCount <= maxTickCount)
                         {
                             bestInterval = currentInterval;
@@ -162,27 +174,41 @@ namespace BansheeEditor
                 EditorStyles.DefaultFontSize);
         }
 
+        private int DrawLargeTick(float t, int lastTextPosition, bool displayAsMinutes)
+        {
+            const int TEXT_SPACING = 10;
+
+            int xPos = (int)((t / rangeLength) * drawableWidth) + PADDING;
+
+            // Draw tick
+            Vector2I start = new Vector2I(xPos, height - largeTickHeight);
+            Vector2I end = new Vector2I(xPos, height);
+
+            canvas.DrawLine(start, end, Color.LightGray);
+
+            // Draw text if it fits
+            int diff = xPos - lastTextPosition;
+            if (diff >= (maxTextWidth + TEXT_SPACING))
+            {
+                DrawTime(xPos, rangeStart + t, displayAsMinutes);
+                lastTextPosition = xPos;
+            }
+            return lastTextPosition;
+        }
+
         private void Rebuild()
         {
             canvas.Clear();
 
-            // TODO - Text from invisible ticks should be displayed (otherwise it will just pop in was the tick is shown)
-
             // TODO - Draw small ticks (don't forget to handle offset properly)
             // TODO - Transition between interval sizes more lightly (dynamically change tick height?)
 
-            // Constants
-            const int TEXT_SPACING = 10;
-            int maxTextWidth = GUIUtility.CalculateTextBounds("99:999", EditorBuiltin.DefaultFont, 
-                EditorStyles.DefaultFontSize).x;
-            int largeTickHeight = (int)(height * LARGE_TICK_HEIGHT_PCT);
-            int drawableWidth = Math.Max(0, width - PADDING * 2);
-            float rangeLength = rangeEnd - rangeStart;
-
             // Draw ticks
-            float tickInterval = CalcTickInterval(rangeLength);
-            int numTicks = MathEx.FloorToInt(rangeLength / tickInterval) + 1;
+            float tickInterval = CalcTickInterval();
 
+            // Draw extra ticks outside the visible width so they don't just pop-in/out as range increases/decreases
+            float extraRange = PADDING + maxTextWidth / 2;
+            int numTicks = MathEx.FloorToInt((rangeLength + extraRange) / tickInterval) + 1;
             bool displayAsMinutes = TimeSpan.FromSeconds(tickInterval).Minutes > 0;
 
             float offset = rangeStart % tickInterval - rangeStart;
@@ -190,27 +216,14 @@ namespace BansheeEditor
             int lastTextPosition = -1000;
             for (int i = 0; i < numTicks; i++)
             {
-                int xPos = (int)((t / rangeLength) * drawableWidth) + PADDING;
+                lastTextPosition = DrawLargeTick(t, lastTextPosition, displayAsMinutes);
 
-                // Draw tick
-                Vector2I start = new Vector2I(xPos, height - largeTickHeight);
-                Vector2I end = new Vector2I(xPos, height);
-
-                canvas.DrawLine(start, end, Color.LightGray);
-
-                // Draw text if it fits
-                int diff = xPos - lastTextPosition;
-                if (diff >= (maxTextWidth + TEXT_SPACING))
-                {
-                    DrawTime(xPos, rangeStart + t, displayAsMinutes);
-                    lastTextPosition = xPos;
-                }
-                
                 // Move to next tick
                 t += tickInterval;
-                t = Math.Min(t, rangeLength);
             }
         }
+
+        
     }
 
     /** @} */