return ((ScrollbarStyle)((Scrollbar)bindable).viewStyle)?.TrackPadding;
});
- private static readonly string TrackVisualName = "Track";
- private static readonly string ThumbVisualName = "Thumb";
private ColorVisual trackVisual;
private ColorVisual thumbVisual;
private Animation thumbPositionAnimation;
private Animation thumbSizeAnimation;
private Calculator calculator;
+ private Size containerSize = new Size(0, 0);
+ private float currentPosition;
#endregion Fields
/// <summary>
/// Create a Scrollbar and initialize with properties.
/// </summary>
- /// <param name="contentLength">The total length of the content.</param>
- /// <param name="viewSize">The size of View that contains the content to scroll.</param>
- /// <param name="currentPosition">The start position of the View in content length. This is the View's top position if the scroller is vertical, otherwise, View's left position.</param>
- /// <param name="isHorizontal">Whether the direction of scrolling is horizontal or not. It is vertical if the value is false.</param>
+ /// <param name="contentLength">The length of the scrollable content area.</param>
+ /// <param name="viewportLength">The length of the viewport representing the amount of visible content.</param>
+ /// <param name="currentPosition">The current position of the viewport in scrollable content area. This is the viewport's top position if the scroller is vertical, otherwise, left.</param>
+ /// <param name="isHorizontal">Whether the direction of scrolling is horizontal or not. It is vertical by default.</param>
[EditorBrowsable(EditorBrowsableState.Never)]
- public Scrollbar(float contentLength, Size viewSize, float currentPosition, bool isHorizontal = false) : base(new ScrollbarStyle())
+ public Scrollbar(float contentLength, float viewportLength, float currentPosition, bool isHorizontal = false) : base(new ScrollbarStyle())
{
- Initialize(contentLength, viewSize, currentPosition, isHorizontal);
+ Initialize(contentLength, viewportLength, currentPosition, isHorizontal);
}
/// <summary>
/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
- public override void Initialize(float contentLength, Size viewSize, float currentPosition, bool isHorizontal = false)
+ public override void Initialize(float contentLength, float viewportLength, float currentPosition, bool isHorizontal = false)
{
if (isHorizontal)
{
- calculator = new HorizontalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewSize.Width);
+ calculator = new HorizontalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewportLength, currentPosition);
}
else
{
- calculator = new VerticalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewSize.Height);
+ calculator = new VerticalCalculator(contentLength > 0.0f ? contentLength : 0.0f, viewportLength, currentPosition);
}
- Size = viewSize;
-
thumbPositionAnimation?.Stop();
thumbPositionAnimation = null;
thumbSizeAnimation?.Stop();
thumbSizeAnimation = null;
- CreateTrackVisual();
- CreateThumbVisual(currentPosition);
+ Size trackSize = calculator.CalculateTrackSize(TrackThickness, containerSize, TrackPadding);
+ Vector2 trackPosition = calculator.CalculateTrackPosition(TrackPadding);
+ Size thumbSize = calculator.CalculateThumbSize(ThumbThickness, trackSize);
+ Vector2 thumbPosition = calculator.CalculateThumbPosition(trackSize, thumbSize, TrackPadding);
+
+ if (trackVisual == null)
+ {
+ trackVisual = new ColorVisual
+ {
+ SuppressUpdateVisual = true,
+ Color = TrackColor,
+ SizePolicy = VisualTransformPolicyType.Absolute,
+ Origin = calculator.CalculatorTrackAlign(),
+ AnchorPoint = calculator.CalculatorTrackAlign(),
+ Size = trackSize,
+ Position = trackPosition,
+ };
- AddVisual(TrackVisualName, trackVisual);
- AddVisual(ThumbVisualName, thumbVisual);
+ AddVisual("Track", trackVisual);
+ }
+ else
+ {
+ trackVisual.Size = trackSize;
+ trackVisual.Position = trackPosition;
+ trackVisual.UpdateVisual(true);
+ }
+
+ if (thumbVisual == null)
+ {
+ thumbVisual = new ColorVisual
+ {
+ SuppressUpdateVisual = true,
+ MixColor = ThumbColor,
+ SizePolicy = VisualTransformPolicyType.Absolute,
+ Origin = calculator.CalculatorThumbAlign(),
+ AnchorPoint = calculator.CalculatorThumbAlign(),
+ Opacity = calculator.CalculateThumbVisibility() ? 1.0f : 0.0f,
+ Size = thumbSize,
+ Position = thumbPosition,
+ };
+
+ AddVisual("Thumb", thumbVisual);
+ }
+ else
+ {
+ thumbVisual.Size = thumbSize;
+ thumbVisual.Position = thumbPosition;
+ thumbVisual.UpdateVisual(true);
+ }
}
/// <inheritdoc/>
return;
}
- calculator.Update(contentLength > 0.0f ? contentLength : 0.0f);
+ calculator.contentLength = contentLength > 0.0f ? contentLength : 0.0f;
+ calculator.currentPosition = position;
thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
- thumbVisual.Position = calculator.CalculateThumbScrollPosition(position, trackVisual.Size, thumbVisual.Position, TrackPadding);
+ thumbVisual.Position = calculator.CalculateThumbScrollPosition(trackVisual.Size, thumbVisual.Position, TrackPadding);
thumbVisual.Opacity = calculator.CalculateThumbVisibility() ? 1.0f : 0.0f;
if (durationMs == 0)
[EditorBrowsable(EditorBrowsableState.Never)]
public override void ScrollTo(float position, uint durationMs = 0, AlphaFunction alphaFunction = null)
{
- if (thumbVisual == null)
+ if (calculator == null)
{
return;
}
- thumbVisual.Position = calculator.CalculateThumbScrollPosition(position, trackVisual.Size, thumbVisual.Position, TrackPadding);
+ calculator.currentPosition = position;
+ thumbVisual.Position = calculator.CalculateThumbScrollPosition(trackVisual.Size, thumbVisual.Position, TrackPadding);
if (durationMs == 0)
{
/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
- protected override ViewStyle GetViewStyle()
+ public override void OnRelayout(Vector2 size, RelayoutContainer container)
{
- return new ScrollbarStyle();
- }
+ base.OnRelayout(size, container);
- /// <summary>
- /// Create a track visual.
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- protected virtual void CreateTrackVisual()
- {
- trackVisual = new ColorVisual
- {
- SuppressUpdateVisual = true,
- Color = Color.Black,
- SizePolicy = VisualTransformPolicyType.Absolute,
- Origin = calculator.CalculatorTrackAlign(),
- AnchorPoint = calculator.CalculatorTrackAlign(),
- Size = calculator.CalculateTrackSize(TrackThickness, TrackPadding),
- Position = calculator.CalculateTrackPosition(TrackPadding),
- };
+ if (size.Width == containerSize.Width && size.Height == containerSize.Height)
+ {
+ return;
+ }
+
+ containerSize = new Size(size.Width, size.Height);
+
+ if (calculator == null)
+ {
+ return;
+ }
+
+ trackVisual.Size = calculator.CalculateTrackSize(TrackThickness, containerSize, TrackPadding);
+ trackVisual.Position = calculator.CalculateTrackPosition(TrackPadding);
+ thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
+ thumbVisual.Position = calculator.CalculateThumbPosition(trackVisual.Size, thumbVisual.Size, TrackPadding);
+
+ trackVisual.UpdateVisual(true);
+ thumbVisual.UpdateVisual(true);
}
- /// <summary>
- /// Create a thumb visual.
- /// </summary>
+ /// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
- protected virtual void CreateThumbVisual(float currentPosition)
+ protected override ViewStyle GetViewStyle()
{
- Size thumbSize = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
-
- thumbVisual = new ColorVisual
- {
- SuppressUpdateVisual = true,
- MixColor = ThumbColor,
- SizePolicy = VisualTransformPolicyType.Absolute,
- Origin = calculator.CalculatorThumbAlign(),
- AnchorPoint = calculator.CalculatorThumbAlign(),
- Size = thumbSize,
- Position = calculator.CalculateThumbPosition(currentPosition, trackVisual.Size, thumbSize, TrackPadding),
- Opacity = (calculator.CalculateThumbVisibility() ? 1.0f : 0.0f),
- };
+ return new ScrollbarStyle();
}
/// <summary>
return;
}
- trackVisual.Size = calculator.CalculateTrackSize(thickness, TrackPadding);
+ trackVisual.Size = calculator.CalculateTrackSize(thickness, containerSize, TrackPadding);
trackVisual.UpdateVisual(true);
}
/// <param name="trackPadding">The padding of the track.</param>
protected virtual void UpdateTrackPadding(Extents trackPadding)
{
- if (trackVisual == null || thumbVisual == null)
+ if (calculator == null)
{
return;
}
- trackVisual.Size = calculator.CalculateTrackSize(TrackThickness, trackPadding);
+ trackVisual.Size = calculator.CalculateTrackSize(TrackThickness, containerSize, trackPadding);
trackVisual.Position = calculator.CalculateTrackPosition(trackPadding);
thumbVisual.Size = calculator.CalculateThumbSize(ThumbThickness, trackVisual.Size);
thumbVisual.Position = calculator.CalculateThumbPaddingPosition(trackVisual.Size, thumbVisual.Size, thumbVisual.Position, trackPadding);
private abstract class Calculator
{
- protected float contentLength;
- protected float visibleLength;
+ public float contentLength;
+ public float visibleLength;
+ public float currentPosition;
- public Calculator(float contentLength, float visibleLength)
+ public Calculator(float contentLength, float visibleLength, float currentPosition)
{
this.contentLength = contentLength;
this.visibleLength = visibleLength;
- }
-
- public void Update(float contentLength)
- {
- this.contentLength = contentLength;
+ this.currentPosition = currentPosition;
}
public bool CalculateThumbVisibility()
public abstract Visual.AlignType CalculatorTrackAlign();
public abstract Visual.AlignType CalculatorThumbAlign();
- public abstract Size CalculateTrackSize(float thickness, Extents trackPadding);
+ public abstract Size CalculateTrackSize(float thickness, Size containerSize, Extents trackPadding);
public abstract Vector2 CalculateTrackPosition(Extents trackPadding);
public abstract Size CalculateThumbSize(float thickness, Size trackSize);
- public abstract Vector2 CalculateThumbPosition(float position, Size trackSize, Size thumbSize, Extents trackPadding);
+ public abstract Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, Extents trackPadding);
public abstract Vector2 CalculateThumbPaddingPosition(Size trackSize, Size thumbSize, Vector2 thumbCurrentPosition, Extents trackPadding);
- public abstract Vector2 CalculateThumbScrollPosition(float position, Size trackSize, Vector2 thumbCurrentPosition, Extents trackPadding);
+ public abstract Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbCurrentPosition, Extents trackPadding);
}
private class HorizontalCalculator : Calculator
{
- public HorizontalCalculator(float contentLength, float visibleLength) : base(contentLength, visibleLength)
+ public HorizontalCalculator(float contentLength, float visibleLength, float currentPosition) : base(contentLength, visibleLength, currentPosition)
{
}
return Visual.AlignType.BottomBegin;
}
- public override Size CalculateTrackSize(float thickness, Extents trackPadding)
+ public override Size CalculateTrackSize(float thickness, Size containerSize, Extents trackPadding)
{
- return new Size(visibleLength - trackPadding.Start - trackPadding.End, thickness);
+ return new Size(containerSize.Width - trackPadding.Start - trackPadding.End, thickness);
}
public override Vector2 CalculateTrackPosition(Extents trackPadding)
return new Size(trackSize.Width * visibleLength / contentLength, thickness);
}
- public override Vector2 CalculateThumbPosition(float position, Size trackSize, Size thumbSize, Extents trackPadding)
+ public override Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, Extents trackPadding)
{
float padding = ((trackSize.Height - thumbSize.Height) / 2.0f) + trackPadding.Bottom;
- float pos = Math.Min(Math.Max(position, 0.0f), contentLength - visibleLength);
+ float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
return new Vector2(trackPadding.Start + trackSize.Width * pos / contentLength, -padding);
}
return new Vector2(thumbCurrentPosition.X, -padding);
}
- public override Vector2 CalculateThumbScrollPosition(float position, Size trackSize, Vector2 thumbCurrentPosition, Extents trackPadding)
+ public override Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbCurrentPosition, Extents trackPadding)
{
- float pos = Math.Min(Math.Max(position, 0.0f), contentLength - visibleLength);
+ float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
return new Vector2(trackPadding.Start + trackSize.Width * pos / contentLength, thumbCurrentPosition.Y);
}
}
private class VerticalCalculator : Calculator
{
- public VerticalCalculator(float contentLength, float visibleLength) : base(contentLength, visibleLength)
+ public VerticalCalculator(float contentLength, float visibleLength, float currentPosition) : base(contentLength, visibleLength, currentPosition)
{
}
return Visual.AlignType.TopEnd;
}
- public override Size CalculateTrackSize(float thickness, Extents trackPadding)
+ public override Size CalculateTrackSize(float thickness, Size containerSize, Extents trackPadding)
{
- return new Size(thickness, visibleLength - trackPadding.Top - trackPadding.Bottom);
+ return new Size(thickness, containerSize.Height - trackPadding.Top - trackPadding.Bottom);
}
public override Vector2 CalculateTrackPosition(Extents trackPadding)
return new Size(thickness, trackSize.Height * visibleLength / contentLength);
}
- public override Vector2 CalculateThumbPosition(float position, Size trackSize, Size thumbSize, Extents trackPadding)
+ public override Vector2 CalculateThumbPosition(Size trackSize, Size thumbSize, Extents trackPadding)
{
float padding = ((trackSize.Width - thumbSize.Width) / 2.0f) + trackPadding.End;
- float pos = Math.Min(Math.Max(position, 0.0f), contentLength - visibleLength);
+ float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
return new Vector2(-padding, trackPadding.Top + trackSize.Height * pos / contentLength);
}
return new Vector2(-padding, thumbCurrentPosition.Y);
}
- public override Vector2 CalculateThumbScrollPosition(float position, Size trackSize, Vector2 thumbPosition, Extents trackPadding)
+ public override Vector2 CalculateThumbScrollPosition(Size trackSize, Vector2 thumbPosition, Extents trackPadding)
{
- float pos = Math.Min(Math.Max(position, 0.0f), contentLength - visibleLength);
+ float pos = Math.Min(Math.Max(currentPosition, 0.0f), contentLength - visibleLength);
return new Vector2(thumbPosition.X, trackPadding.Top + trackSize.Height * pos / contentLength);
}
}
private float visibleLength;
private float currentPosition;
private float directionAlpha;
+ private Size containerSize = new Size(0, 0);
private Animation thumbStartAngleAnimation;
private Animation thumbSweepAngleAnimation;
/// <summary>
/// Create a CircularScrollbar and initialize with properties.
/// </summary>
- /// <param name="contentLength">The total length of the content.</param>
- /// <param name="viewSize">The size of View that contains the content to scroll.</param>
- /// <param name="currentPosition">Scrolled position.</param>
- /// <param name="isHorizontal">Whether the direction of scrolling is horizontal or not. It is vertical if the value is false.</param>
+ /// <param name="contentLength">The length of the scrollable content area.</param>
+ /// <param name="viewportLength">The length of the viewport representing the amount of visible content.</param>
+ /// <param name="currentPosition">The current position of the viewport in scrollable content area. This is the viewport's top position if the scroller is vertical, otherwise, left.</param>
+ /// <param name="isHorizontal">Whether the direction of scrolling is horizontal or not. It is vertical by default.</param>
[EditorBrowsable(EditorBrowsableState.Never)]
- public CircularScrollbar(float contentLength, Size viewSize, float currentPosition, bool isHorizontal = false) : base(new CircularScrollbarStyle())
+ public CircularScrollbar(float contentLength, float viewportLength, float currentPosition, bool isHorizontal = false) : base(new CircularScrollbarStyle())
{
- Initialize(contentLength, viewSize, currentPosition, isHorizontal);
+ Initialize(contentLength, viewportLength, currentPosition, isHorizontal);
}
/// <summary>
/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
- public override void Initialize(float contentLength, Size viewSize, float currentPosition, bool isHorizontal = false)
+ public override void Initialize(float contentLength, float viewportLenth, float currentPosition, bool isHorizontal = false)
{
this.contentLength = contentLength > 0.0f ? contentLength : 0.0f;
- this.visibleLength = isHorizontal ? viewSize.Width : viewSize.Height;
+ this.visibleLength = viewportLenth;
this.currentPosition = currentPosition;
this.directionAlpha = isHorizontal ? 270.0f : 0.0f;
- Size = viewSize;
-
thumbStartAngleAnimation?.Stop();
thumbStartAngleAnimation = null;
thumbSweepAngleAnimation?.Stop();
thumbSweepAngleAnimation = null;
- CreateTrackVisual();
- CreateThumbVisual(currentPosition);
- AddVisual("Track", trackVisual);
- AddVisual("Thumb", thumbVisual);
+ float trackSweepAngle = CalculateTrackSweepAngle(TrackSweepAngle);
+ float trackStartAngle = CalculateTrackStartAngle(trackSweepAngle);
+ float thumbSweepAngle = CalculateThumbSweepAngle(TrackSweepAngle);
+ float thumbStartAngle = CalculateThumbStartAngle(currentPosition, trackStartAngle, trackSweepAngle, thumbSweepAngle);
+
+ if (trackVisual == null)
+ {
+ trackVisual = new ArcVisual
+ {
+ SuppressUpdateVisual = true,
+ Thickness = this.Thickness,
+ Cap = ArcVisual.CapType.Round,
+ MixColor = TrackColor,
+ Size = containerSize - new Size(2, 2),
+ SizePolicy = VisualTransformPolicyType.Absolute,
+ SweepAngle = trackSweepAngle,
+ StartAngle = trackStartAngle,
+ };
+
+ AddVisual("Track", trackVisual);
+ }
+ else
+ {
+ trackVisual.SweepAngle = trackSweepAngle;
+ trackVisual.StartAngle = trackStartAngle;
+ trackVisual.UpdateVisual(true);
+ }
+
+ if (thumbVisual == null)
+ {
+ thumbVisual = new ArcVisual
+ {
+ SuppressUpdateVisual = true,
+ Thickness = trackVisual.Thickness,
+ Cap = ArcVisual.CapType.Round,
+ MixColor = ThumbColor,
+ Size = containerSize - new Size(2, 2),
+ SizePolicy = VisualTransformPolicyType.Absolute,
+ SweepAngle = thumbSweepAngle,
+ StartAngle = thumbStartAngle,
+ Opacity = CalculateThumbVisibility() ? 1.0f : 0.0f,
+ };
+
+ AddVisual("Thumb", thumbVisual);
+ }
+ else
+ {
+ thumbVisual.SweepAngle = thumbSweepAngle;
+ thumbVisual.StartAngle = thumbStartAngle;
+ thumbVisual.UpdateVisual(true);
+ }
}
/// <inheritdoc/>
/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
- protected override ViewStyle GetViewStyle()
+ public override void OnRelayout(Vector2 size, RelayoutContainer container)
{
- return new CircularScrollbarStyle();
- }
+ base.OnRelayout(size, container);
- private void CreateTrackVisual()
- {
- float sweepAngle = CalculateTrackSweepAngle(TrackSweepAngle);
+ if (size.Width == containerSize?.Width && size.Height == containerSize.Height)
+ {
+ return;
+ }
- trackVisual = new ArcVisual
+ containerSize = new Size(size.Width, size.Height);
+
+ if (trackVisual == null)
{
- SuppressUpdateVisual = true,
- Thickness = this.Thickness,
- Cap = ArcVisual.CapType.Round,
- MixColor = TrackColor,
- Size = new Size(visibleLength - 2, visibleLength - 2),
- SizePolicy = VisualTransformPolicyType.Absolute,
- SweepAngle = sweepAngle,
- StartAngle = CalculateTrackStartAngle(sweepAngle),
- };
+ return;
+ }
+
+ trackVisual.Size = containerSize - new Size(2, 2);
+ thumbVisual.Size = containerSize - new Size(2, 2);
+
+ trackVisual.UpdateVisual(true);
+ thumbVisual.UpdateVisual(true);
}
- private void CreateThumbVisual(float position)
+ /// <inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected override ViewStyle GetViewStyle()
{
- float sweepAngle = CalculateThumbSweepAngle(TrackSweepAngle);
-
- thumbVisual = new ArcVisual
- {
- SuppressUpdateVisual = true,
- Thickness = trackVisual.Thickness,
- Cap = ArcVisual.CapType.Round,
- MixColor = ThumbColor,
- Size = new Size(visibleLength - 2, visibleLength - 2),
- SizePolicy = VisualTransformPolicyType.Absolute,
- SweepAngle = sweepAngle,
- StartAngle = CalculateThumbStartAngle(position, trackVisual.StartAngle, trackVisual.SweepAngle, sweepAngle),
- Opacity = CalculateThumbVisibility() ? 1.0f : 0.0f,
- };
+ return new CircularScrollbarStyle();
}
private float CalculateTrackStartAngle(float currentTrackSweepAngle)