csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
469 lines
14 KiB
469 lines
14 KiB
using System;
|
|
using System.Linq;
|
|
using Avalonia.Automation;
|
|
using Avalonia.Controls.Primitives;
|
|
using Avalonia.Controls.Templates;
|
|
using Avalonia.Input;
|
|
using Avalonia.Layout;
|
|
using Avalonia.Media;
|
|
using Avalonia.UnitTests;
|
|
using Xunit;
|
|
|
|
namespace Avalonia.Controls.UnitTests.Primitives
|
|
{
|
|
public class ScrollBarTests : ScopedTestBase
|
|
{
|
|
[Fact]
|
|
public void Setting_Value_Should_Update_Track_Value()
|
|
{
|
|
var target = new ScrollBar
|
|
{
|
|
Template = new FuncControlTemplate<ScrollBar>(Template),
|
|
};
|
|
|
|
target.ApplyTemplate();
|
|
var track = (Track)target.GetTemplateDescendants().First(x => x.Name == "track");
|
|
target.Value = 50;
|
|
|
|
Assert.Equal(50, track.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void Setting_Track_Value_Should_Update_Value()
|
|
{
|
|
var target = new ScrollBar
|
|
{
|
|
Template = new FuncControlTemplate<ScrollBar>(Template),
|
|
};
|
|
|
|
target.ApplyTemplate();
|
|
var track = (Track)target.GetTemplateDescendants().First(x => x.Name == "track");
|
|
track.Value = 50;
|
|
|
|
Assert.Equal(50, target.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void Setting_Track_Value_After_Setting_Value_Should_Update_Value()
|
|
{
|
|
var target = new ScrollBar
|
|
{
|
|
Template = new FuncControlTemplate<ScrollBar>(Template),
|
|
};
|
|
|
|
target.ApplyTemplate();
|
|
|
|
var track = (Track)target.GetTemplateDescendants().First(x => x.Name == "track");
|
|
target.Value = 25;
|
|
track.Value = 50;
|
|
|
|
Assert.Equal(50, target.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void Thumb_DragDelta_Event_Should_Raise_Scroll_Event()
|
|
{
|
|
var target = new ScrollBar
|
|
{
|
|
Template = new FuncControlTemplate<ScrollBar>(Template),
|
|
};
|
|
|
|
target.ApplyTemplate();
|
|
|
|
var track = (Track)target.GetTemplateDescendants().First(x => x.Name == "track");
|
|
|
|
var raisedEvent = Assert.Raises<ScrollEventArgs>(
|
|
handler => target.Scroll += handler,
|
|
handler => target.Scroll -= handler,
|
|
() =>
|
|
{
|
|
var ev = new VectorEventArgs
|
|
{
|
|
RoutedEvent = Thumb.DragDeltaEvent,
|
|
Vector = new Vector(0, 0)
|
|
};
|
|
|
|
track.Thumb!.RaiseEvent(ev);
|
|
});
|
|
|
|
Assert.Equal(ScrollEventType.ThumbTrack, raisedEvent.Arguments.ScrollEventType);
|
|
}
|
|
|
|
[Fact]
|
|
public void Thumb_DragComplete_Event_Should_Raise_Scroll_Event()
|
|
{
|
|
var target = new ScrollBar
|
|
{
|
|
Template = new FuncControlTemplate<ScrollBar>(Template),
|
|
};
|
|
|
|
target.ApplyTemplate();
|
|
|
|
var track = (Track)target.GetTemplateDescendants().First(x => x.Name == "track");
|
|
|
|
var raisedEvent = Assert.Raises<ScrollEventArgs>(
|
|
handler => target.Scroll += handler,
|
|
handler => target.Scroll -= handler,
|
|
() =>
|
|
{
|
|
var ev = new VectorEventArgs
|
|
{
|
|
RoutedEvent = Thumb.DragCompletedEvent,
|
|
Vector = new Vector(0, 0)
|
|
};
|
|
|
|
track.Thumb!.RaiseEvent(ev);
|
|
});
|
|
|
|
Assert.Equal(ScrollEventType.EndScroll, raisedEvent.Arguments.ScrollEventType);
|
|
}
|
|
|
|
[Fact]
|
|
public void ScrollBar_Can_AutoHide()
|
|
{
|
|
var target = new ScrollBar();
|
|
|
|
target.Visibility = ScrollBarVisibility.Auto;
|
|
target.ViewportSize = 1;
|
|
target.Maximum = 0;
|
|
|
|
Assert.False(target.IsVisible);
|
|
}
|
|
|
|
[Fact]
|
|
public void ScrollBar_Should_Not_AutoHide_When_ViewportSize_Is_NaN()
|
|
{
|
|
var target = new ScrollBar();
|
|
|
|
target.Visibility = ScrollBarVisibility.Auto;
|
|
target.Minimum = 0;
|
|
target.Maximum = 100;
|
|
target.ViewportSize = double.NaN;
|
|
|
|
Assert.True(target.IsVisible);
|
|
}
|
|
|
|
[Fact]
|
|
public void ScrollBar_Should_Not_AutoHide_When_Visibility_Set_To_Visible()
|
|
{
|
|
var target = new ScrollBar();
|
|
|
|
target.Visibility = ScrollBarVisibility.Visible;
|
|
target.Minimum = 0;
|
|
target.Maximum = 100;
|
|
target.ViewportSize = 100;
|
|
|
|
Assert.True(target.IsVisible);
|
|
}
|
|
|
|
[Fact]
|
|
public void ScrollBar_Should_Hide_When_Visibility_Set_To_Hidden()
|
|
{
|
|
var target = new ScrollBar();
|
|
|
|
target.Visibility = ScrollBarVisibility.Hidden;
|
|
target.Minimum = 0;
|
|
target.Maximum = 100;
|
|
target.ViewportSize = 10;
|
|
|
|
Assert.False(target.IsVisible);
|
|
}
|
|
|
|
private static Control Template(ScrollBar control, INameScope scope)
|
|
{
|
|
return new Border
|
|
{
|
|
Child = new Track
|
|
{
|
|
Name = "track",
|
|
[!Track.MinimumProperty] = control[!RangeBase.MinimumProperty],
|
|
[!Track.MaximumProperty] = control[!RangeBase.MaximumProperty],
|
|
[!!Track.ValueProperty] = control[!!RangeBase.ValueProperty],
|
|
[!Track.ViewportSizeProperty] = control[!ScrollBar.ViewportSizeProperty],
|
|
[!Track.OrientationProperty] = control[!ScrollBar.OrientationProperty],
|
|
Thumb = new Thumb
|
|
{
|
|
Template = new FuncControlTemplate<Thumb>(ThumbTemplate),
|
|
},
|
|
}.RegisterInNameScope(scope),
|
|
};
|
|
}
|
|
|
|
private static Control ThumbTemplate(Thumb control, INameScope scope)
|
|
{
|
|
return new Border
|
|
{
|
|
Background = Brushes.Gray,
|
|
};
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(Orientation.Vertical)]
|
|
[InlineData(Orientation.Horizontal)]
|
|
public void Orientation_Should_Set_Matching_PseudoClass(Orientation orientation)
|
|
{
|
|
var target = new ScrollBar { Orientation = orientation };
|
|
|
|
Assert.Equal(orientation == Orientation.Vertical, target.Classes.Contains(":vertical"));
|
|
Assert.Equal(orientation == Orientation.Horizontal, target.Classes.Contains(":horizontal"));
|
|
}
|
|
|
|
[Fact]
|
|
public void ScrollToHome_Should_Set_Value_To_Minimum()
|
|
{
|
|
var target = CreateScrollBar(minimum: 10, maximum: 100, value: 50);
|
|
|
|
target.ScrollToHome();
|
|
|
|
Assert.Equal(10, target.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void ScrollToEnd_Should_Set_Value_To_Maximum()
|
|
{
|
|
var target = CreateScrollBar(minimum: 0, maximum: 90, value: 50);
|
|
|
|
target.ScrollToEnd();
|
|
|
|
Assert.Equal(90, target.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void PageUp_Should_Decrease_Value_By_LargeChange()
|
|
{
|
|
var target = CreateScrollBar(value: 50, largeChange: 10);
|
|
|
|
target.PageUp();
|
|
|
|
Assert.Equal(40, target.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void PageDown_Should_Increase_Value_By_LargeChange()
|
|
{
|
|
var target = CreateScrollBar(value: 50, largeChange: 10);
|
|
|
|
target.PageDown();
|
|
|
|
Assert.Equal(60, target.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void PageLeft_Should_Decrease_Value_By_LargeChange()
|
|
{
|
|
var target = CreateScrollBar(orientation: Orientation.Horizontal, value: 50, largeChange: 10);
|
|
|
|
target.PageLeft();
|
|
|
|
Assert.Equal(40, target.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void PageRight_Should_Increase_Value_By_LargeChange()
|
|
{
|
|
var target = CreateScrollBar(orientation: Orientation.Horizontal, value: 50, largeChange: 10);
|
|
|
|
target.PageRight();
|
|
|
|
Assert.Equal(60, target.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void LineUp_Should_Decrease_Value_By_SmallChange()
|
|
{
|
|
var target = CreateScrollBar(value: 50, smallChange: 5);
|
|
|
|
target.LineUp();
|
|
|
|
Assert.Equal(45, target.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void LineDown_Should_Increase_Value_By_SmallChange()
|
|
{
|
|
var target = CreateScrollBar(value: 50, smallChange: 5);
|
|
|
|
target.LineDown();
|
|
|
|
Assert.Equal(55, target.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void LineLeft_Should_Decrease_Value_By_SmallChange()
|
|
{
|
|
var target = CreateScrollBar(orientation: Orientation.Horizontal, value: 50, smallChange: 5);
|
|
|
|
target.LineLeft();
|
|
|
|
Assert.Equal(45, target.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void LineRight_Should_Increase_Value_By_SmallChange()
|
|
{
|
|
var target = CreateScrollBar(orientation: Orientation.Horizontal, value: 50, smallChange: 5);
|
|
|
|
target.LineRight();
|
|
|
|
Assert.Equal(55, target.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void Scroll_Methods_Should_Respect_Value_Bounds()
|
|
{
|
|
var target = CreateScrollBar(minimum: 20, maximum: 80, value: 25, smallChange: 10);
|
|
|
|
target.LineUp();
|
|
Assert.Equal(20, target.Value); // Should not go below Minimum
|
|
|
|
target.Value = 75;
|
|
target.LineDown();
|
|
Assert.Equal(80, target.Value); // Should not go above Maximum
|
|
}
|
|
|
|
[Fact]
|
|
public void Scroll_Methods_Should_Raise_Scroll_Event()
|
|
{
|
|
var target = CreateScrollBar(value: 50, smallChange: 5, largeChange: 10);
|
|
var events = new System.Collections.Generic.List<ScrollEventType>();
|
|
target.Scroll += (_, e) => events.Add(e.ScrollEventType);
|
|
|
|
target.LineDown();
|
|
target.PageDown();
|
|
target.ScrollToHome();
|
|
target.ScrollToEnd();
|
|
|
|
Assert.Equal(
|
|
new[]
|
|
{
|
|
ScrollEventType.SmallIncrement,
|
|
ScrollEventType.LargeIncrement,
|
|
ScrollEventType.LargeDecrement,
|
|
ScrollEventType.LargeIncrement,
|
|
},
|
|
events);
|
|
}
|
|
|
|
[Fact]
|
|
public void ScrollHere_Should_Set_Value_Within_Bounds()
|
|
{
|
|
var target = CreateScrollBar(minimum: 0, maximum: 100, value: 0);
|
|
|
|
// No exception even though no pointer position was recorded yet.
|
|
target.ScrollHere();
|
|
|
|
Assert.InRange(target.Value, target.Minimum, target.Maximum);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(PointerType.Touch)]
|
|
[InlineData(PointerType.Pen)]
|
|
public void ContextRequested_Should_Be_Handled_For_Touch_Or_Pen_Input(PointerType pointerType)
|
|
{
|
|
var target = CreateScrollBar();
|
|
|
|
var args = CreateContextRequested(target, pointerType);
|
|
target.RaiseEvent(args);
|
|
|
|
Assert.True(args.Handled);
|
|
}
|
|
|
|
[Fact]
|
|
public void ContextRequested_Should_Not_Be_Handled_For_Mouse_Input()
|
|
{
|
|
var target = CreateScrollBar();
|
|
|
|
var args = CreateContextRequested(target, PointerType.Mouse);
|
|
target.RaiseEvent(args);
|
|
|
|
Assert.False(args.Handled);
|
|
}
|
|
|
|
[Fact]
|
|
public void Focus_KeyInput_Should_Scroll()
|
|
{
|
|
// Vertical scrollbar
|
|
var target = CreateScrollBar(Orientation.Vertical);
|
|
|
|
// Page down and page up
|
|
KeyDown(target, Key.PageDown);
|
|
Assert.Equal(target.LargeChange, target.Value);
|
|
KeyDown(target, Key.PageUp);
|
|
Assert.Equal(0, target.Value);
|
|
|
|
// Small scrolling with arrow keys
|
|
KeyDown(target, Key.Down);
|
|
Assert.Equal(target.SmallChange, target.Value);
|
|
KeyDown(target, Key.Up);
|
|
Assert.Equal(0, target.Value);
|
|
|
|
// Vertical scrollbars shouldn't scroll for left and right keys
|
|
KeyDown(target, Key.Right);
|
|
Assert.Equal(0, target.Value);
|
|
KeyDown(target, Key.Left);
|
|
Assert.Equal(0, target.Value);
|
|
|
|
// Horizontal scrollbar
|
|
target = CreateScrollBar(Orientation.Horizontal);
|
|
|
|
// Small scrolling with arrow keys
|
|
KeyDown(target, Key.Right);
|
|
Assert.Equal(target.SmallChange, target.Value);
|
|
KeyDown(target, Key.Left);
|
|
Assert.Equal(0, target.Value);
|
|
|
|
// Horizontal scrollbars shouldn't scroll for up and down keys
|
|
KeyDown(target, Key.Down);
|
|
Assert.Equal(0, target.Value);
|
|
KeyDown(target, Key.Up);
|
|
Assert.Equal(0, target.Value);
|
|
}
|
|
|
|
private static void KeyDown(IInputElement target, Key key)
|
|
{
|
|
target.RaiseEvent(new KeyEventArgs
|
|
{
|
|
RoutedEvent = InputElement.KeyDownEvent,
|
|
Key = key,
|
|
});
|
|
}
|
|
|
|
private static ContextRequestedEventArgs CreateContextRequested(ScrollBar target, PointerType pointerType)
|
|
{
|
|
var pointer = new Pointer(Pointer.GetNextFreeId(), pointerType, true);
|
|
var pointerArgs = new PointerPressedEventArgs(
|
|
target,
|
|
pointer,
|
|
target,
|
|
default,
|
|
timestamp: 1,
|
|
new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.Other),
|
|
KeyModifiers.None);
|
|
|
|
return new ContextRequestedEventArgs(pointerArgs);
|
|
}
|
|
|
|
private static ScrollBar CreateScrollBar(
|
|
Orientation orientation = Orientation.Vertical,
|
|
double minimum = 0,
|
|
double maximum = 100,
|
|
double value = 0,
|
|
double smallChange = 1,
|
|
double largeChange = 10)
|
|
{
|
|
var target = new ScrollBar
|
|
{
|
|
Orientation = orientation,
|
|
Template = new FuncControlTemplate<ScrollBar>(Template),
|
|
Minimum = minimum,
|
|
Maximum = maximum,
|
|
Value = value,
|
|
SmallChange = smallChange,
|
|
LargeChange = largeChange,
|
|
};
|
|
|
|
target.ApplyTemplate();
|
|
return target;
|
|
}
|
|
}
|
|
}
|
|
|