Browse Source

Infinite scroll

flabbet 1 year ago
parent
commit
ef3314772b

+ 61 - 2
src/PixiEditor.AvaloniaUI/Views/Animations/Timeline.cs

@@ -7,6 +7,7 @@ using Avalonia.Input;
 using Avalonia.Interactivity;
 using Avalonia.Threading;
 using CommunityToolkit.Mvvm.Input;
+using PixiEditor.AvaloniaUI.Helpers;
 using PixiEditor.AvaloniaUI.ViewModels.Document;
 
 namespace PixiEditor.AvaloniaUI.Views.Animations;
@@ -132,6 +133,8 @@ internal class Timeline : TemplatedControl
     private ScrollViewer? _timelineKeyFramesScroll;
     private ScrollViewer? _timelineHeaderScroll;
     private Control? extendingElement;
+    
+    private Vector clickPos;
 
     static Timeline()
     {
@@ -180,6 +183,9 @@ internal class Timeline : TemplatedControl
         _timelineHeaderScroll = e.NameScope.Find<ScrollViewer>("PART_TimelineHeaderScroll");
 
         _timelineKeyFramesScroll.ScrollChanged += TimelineKeyFramesScrollOnScrollChanged;
+        _contentGrid.PointerPressed += ContentOnPointerPressed;
+        _contentGrid.PointerMoved += ContentOnPointerMoved;
+        _contentGrid.PointerCaptureLost += ContentOnPointerLost;
         
         extendingElement = new Control();
         extendingElement.SetValue(MarginProperty, new Thickness(0, 0, 0, 0));
@@ -193,7 +199,7 @@ internal class Timeline : TemplatedControl
             return;
         }
 
-        ScrollOffset = new Vector(scrollViewer.Offset.X, 0);
+        ScrollOffset = new Vector(scrollViewer.Offset.X, scrollViewer.Offset.Y);
         _timelineSlider.Offset = new Vector(scrollViewer.Offset.X, 0);
         _timelineHeaderScroll!.Offset = new Vector(0, scrollViewer.Offset.Y);
     }
@@ -258,7 +264,7 @@ internal class Timeline : TemplatedControl
         }
         else
         {
-            extendingElement.Margin = new Thickness(0, 0, 0, 0);
+            extendingElement.Margin = new Thickness(_timelineKeyFramesScroll.Viewport.Width, 0, 0, 0);
         }
 
         Dispatcher.UIThread.Post(
@@ -271,6 +277,59 @@ internal class Timeline : TemplatedControl
 
         e.Handled = true;
     }
+    
+    private void ContentOnPointerPressed(object? sender, PointerPressedEventArgs e)
+    {
+        if (e.Source is not Grid content)
+        {
+            return;
+        }
+
+        if (e.GetMouseButton(content) == MouseButton.Middle)
+        {
+            Cursor = new Cursor(StandardCursorType.SizeAll);
+            e.Pointer.Capture(content);
+            clickPos = e.GetPosition(content);
+
+            if (_timelineKeyFramesScroll.ScrollBarMaximum.X == ScrollOffset.X)
+            {
+                extendingElement.Margin = new Thickness(_timelineKeyFramesScroll.Viewport.Width, 0, 0, 0);
+            }
+            
+            e.Handled = true;
+        }
+    }
+    
+    private void ContentOnPointerMoved(object? sender, PointerEventArgs e)
+    {
+        if (e.Source is not Grid content)
+        {
+            return;
+        }
+
+        if (e.GetCurrentPoint(content).Properties.IsMiddleButtonPressed)
+        {
+            double deltaX = clickPos.X - e.GetPosition(content).X;
+            double deltaY = clickPos.Y - e.GetPosition(content).Y;
+            double newOffsetX = ScrollOffset.X + deltaX;
+            double newOffsetY = ScrollOffset.Y + deltaY;
+            newOffsetX = Math.Clamp(newOffsetX, 0, _timelineKeyFramesScroll.ScrollBarMaximum.X);
+            newOffsetY = Math.Clamp(newOffsetY, 0, _timelineKeyFramesScroll.ScrollBarMaximum.Y);
+            ScrollOffset = new Vector(newOffsetX, newOffsetY);
+            
+            extendingElement.Margin += new Thickness(deltaX, 0, 0, 0);
+        }
+    }
+    
+    private void ContentOnPointerLost(object? sender, PointerCaptureLostEventArgs e)
+    {
+        if (e.Source is not Grid content)
+        {
+            return;
+        }
+
+        Cursor = new Cursor(StandardCursorType.Arrow);
+    }
 
     private int MousePosToFrame(PointerEventArgs e, bool round = true)
     {

+ 24 - 11
src/PixiEditor.AvaloniaUI/Views/Animations/TimelineTickBar.cs

@@ -79,10 +79,34 @@ public class TimelineTickBar : Control
         
         int largeStart = visibleMin - (visibleMin % largeTickInterval);
         
+        RenderBigTicks(context, largeStart, visibleMax, largeTickInterval, frameWidth, largeTickPen, height);
+        
+        int smallStart = visibleMin - (visibleMin % smallTickInterval);
+        
+        RenderMinTicks(context, smallStart, visibleMax, smallTickInterval, largeTickInterval, frameWidth, smallTickPen, height);
+    }
+
+    private void RenderMinTicks(DrawingContext context, int smallStart, int visibleMax, int smallTickInterval,
+        int largeTickInterval, double frameWidth, Pen smallTickPen, double height)
+    {
+        for (int i = smallStart; i <= visibleMax; i += smallTickInterval)
+        {
+            if (i % largeTickInterval == 0)
+                continue;
+
+            double x = i * frameWidth - Offset.X + MinLeftOffset;
+            context.DrawLine(smallTickPen, new Point(x, height), new Point(x, height * 0.7f));
+        }
+    }
+
+    private void RenderBigTicks(DrawingContext context, int largeStart, int visibleMax, int largeTickInterval,
+        double frameWidth, Pen largeTickPen, double height)
+    {
         for (int i = largeStart; i <= visibleMax; i += largeTickInterval)
         {
             double x = i * frameWidth - Offset.X + MinLeftOffset;
             context.DrawLine(largeTickPen, new Point(x, height), new Point(x, height * 0.55f));
+            
             var text = new FormattedText(i.ToString(), CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                 Typeface.Default, 12, Fill);
             
@@ -91,16 +115,5 @@ public class TimelineTickBar : Control
             
             context.DrawText(text, textPosition);
         }
-        
-        int smallStart = visibleMin - (visibleMin % smallTickInterval);
-        
-        for (int i = smallStart; i <= visibleMax; i += smallTickInterval)
-        {
-            if (i % largeTickInterval == 0)
-                continue;
-
-            double x = i * frameWidth - Offset.X + MinLeftOffset;
-            context.DrawLine(smallTickPen, new Point(x, height), new Point(x, height * 0.7f));
-        }
     }
 }