298 lines
10 KiB
C#
298 lines
10 KiB
C#
using System.Windows;
|
|||
|
|
using System.Windows.Input;
|
||
|
|
using System.Windows.Media;
|
||
|
|
using System.Windows.Shapes;
|
||
|
|
|
||
|
|
using PCL.Core.App.Localization;
|
||
|
|
namespace PCL;
|
||
|
|
|
||
|
|
public partial class MySlider
|
||
|
|
{
|
||
|
|
public delegate void ChangeEventHandler(object sender, bool user);
|
||
|
|
|
||
|
|
public delegate void PreviewChangeEventHandler(object sender, ModBase.RouteEventArgs e);
|
||
|
|
|
||
|
|
// 自定义属性
|
||
|
|
|
||
|
|
private int _Value;
|
||
|
|
private bool changeByKey;
|
||
|
|
|
||
|
|
// 拖动
|
||
|
|
|
||
|
|
public Delegate getHintText;
|
||
|
|
|
||
|
|
// 基础
|
||
|
|
|
||
|
|
public int Uuid = ModBase.GetUuid();
|
||
|
|
|
||
|
|
public MySlider()
|
||
|
|
{
|
||
|
|
InitializeComponent();
|
||
|
|
SizeChanged += RefreshWidth;
|
||
|
|
MouseLeftButtonDown += DragStart;
|
||
|
|
IsEnabledChanged += (_, _) => RefreshColor();
|
||
|
|
MouseEnter += (_, _) => RefreshColor();
|
||
|
|
MouseLeave += (_, _) => RefreshColor();
|
||
|
|
MouseEnter += (_, _) => MySlider_MouseEnter();
|
||
|
|
KeyDown += MySlider_KeyDown;
|
||
|
|
}
|
||
|
|
|
||
|
|
public int MaxValue
|
||
|
|
{
|
||
|
|
get => field;
|
||
|
|
set
|
||
|
|
{
|
||
|
|
if (value == field)
|
||
|
|
return;
|
||
|
|
field = value;
|
||
|
|
RefreshWidth(null, null);
|
||
|
|
}
|
||
|
|
} = 100;
|
||
|
|
|
||
|
|
public int Value
|
||
|
|
{
|
||
|
|
get => _Value;
|
||
|
|
set
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
value = (int)Math.Round(ModBase.MathClamp(value, 0d, MaxValue));
|
||
|
|
if (_Value == value)
|
||
|
|
return;
|
||
|
|
|
||
|
|
// 触发 Preview 事件,修改新值
|
||
|
|
var oldValue = _Value;
|
||
|
|
_Value = value;
|
||
|
|
if (ModAnimation.AniControlEnabled == 0)
|
||
|
|
{
|
||
|
|
var e = new ModBase.RouteEventArgs();
|
||
|
|
PreviewChange?.Invoke(this, e);
|
||
|
|
if (e.handled)
|
||
|
|
{
|
||
|
|
_Value = oldValue;
|
||
|
|
DragStop();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (IsLoaded && ModAnimation.AniControlEnabled == 0)
|
||
|
|
{
|
||
|
|
if (ActualWidth < ShapeDot.Width)
|
||
|
|
return;
|
||
|
|
var newWidth = _Value / (double)MaxValue * (ActualWidth - ShapeDot.Width);
|
||
|
|
var deltaProcess =
|
||
|
|
Math.Abs(LineFore.Width / (ActualWidth - ShapeDot.Width) - _Value / (double)MaxValue);
|
||
|
|
var time = (1d - Math.Pow(1d - deltaProcess, 3d)) * 300d + (changeByKey ? 100 : 0);
|
||
|
|
ModAnimation.AniStart(
|
||
|
|
new[]
|
||
|
|
{
|
||
|
|
ModAnimation.AaWidth(LineFore,
|
||
|
|
Math.Max(0d, newWidth + (newWidth < 0.5d ? 0d : 0.5d)) - LineFore.Width,
|
||
|
|
(int)Math.Round(time),
|
||
|
|
ease: time > 50d
|
||
|
|
? new ModAnimation.AniEaseOutFluent()
|
||
|
|
: new ModAnimation.AniEaseLinear()),
|
||
|
|
ModAnimation.AaWidth(LineBack,
|
||
|
|
Math.Max(0d,
|
||
|
|
ActualWidth - ShapeDot.Width - newWidth +
|
||
|
|
(ActualWidth - ShapeDot.Width - newWidth < 0.5d ? 0d : 0.5d)) - LineBack.Width,
|
||
|
|
(int)Math.Round(time),
|
||
|
|
ease: time > 50d
|
||
|
|
? new ModAnimation.AniEaseOutFluent()
|
||
|
|
: new ModAnimation.AniEaseLinear()),
|
||
|
|
ModAnimation.AaX(ShapeDot, newWidth - ShapeDot.Margin.Left, (int)Math.Round(time),
|
||
|
|
ease: time > 50d
|
||
|
|
? new ModAnimation.AniEaseOutFluent()
|
||
|
|
: new ModAnimation.AniEaseLinear())
|
||
|
|
}, "MySlider Progress " + Uuid);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
RefreshWidth(null, null);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (ModAnimation.AniControlEnabled == 0)
|
||
|
|
Change?.Invoke(this, false);
|
||
|
|
}
|
||
|
|
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
ModBase.Log(
|
||
|
|
ex,
|
||
|
|
"滑动条进度改变出错",
|
||
|
|
ModBase.LogLevel.Hint,
|
||
|
|
userSummary: Lang.Text("Application.Control.Error.OperationFailed"));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 按键改变
|
||
|
|
|
||
|
|
public uint ValueByKey { get; set; } = 1U;
|
||
|
|
public event ChangeEventHandler? Change;
|
||
|
|
public event PreviewChangeEventHandler? PreviewChange;
|
||
|
|
|
||
|
|
private void RefreshWidth(object sender, SizeChangedEventArgs? e)
|
||
|
|
{
|
||
|
|
if (e is not null)
|
||
|
|
PanMain.Width = e.NewSize.Width;
|
||
|
|
ModAnimation.AniStop("MySlider Progress " + Uuid);
|
||
|
|
var newWidth = _Value / (double)MaxValue * (ActualWidth - ShapeDot.Width);
|
||
|
|
LineFore.Width = Math.Max(0d, newWidth + (newWidth < 0.5d ? 0d : 0.5d));
|
||
|
|
LineBack.Width = Math.Max(0d,
|
||
|
|
ActualWidth - ShapeDot.Width - newWidth + (ActualWidth - ShapeDot.Width - newWidth < 0.5d ? 0d : 0.5d));
|
||
|
|
ModBase.SetLeft(ShapeDot, newWidth);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void DragStart(object sender, MouseButtonEventArgs e)
|
||
|
|
{
|
||
|
|
CaptureMouse();
|
||
|
|
MouseMove += OnDragMouseMove;
|
||
|
|
e.Handled = true; // 防止 ScrollViewer 失焦问题
|
||
|
|
ModMain.dragControl = this;
|
||
|
|
RefreshColor();
|
||
|
|
ModMain.frmMain.DragDoing();
|
||
|
|
ModAnimation.AniStart(
|
||
|
|
ModAnimation.AaScaleTransform(ShapeDot, 1.3d - ((ScaleTransform)ShapeDot.RenderTransform).ScaleX, 40,
|
||
|
|
ease: new ModAnimation.AniEaseOutFluent()), "MySlider Scale " + Uuid);
|
||
|
|
RefreshPopup();
|
||
|
|
ModAnimation.AniStop("MySlider KeyPopup " + Uuid);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void DragDoing()
|
||
|
|
{
|
||
|
|
var percent =
|
||
|
|
ModBase.MathClamp((Mouse.GetPosition(PanMain).X - ShapeDot.Width / 2d) / (ActualWidth - ShapeDot.Width), 0d,
|
||
|
|
1d);
|
||
|
|
var newValue = (int)Math.Round(percent * MaxValue);
|
||
|
|
if (newValue != Value) Value = newValue;
|
||
|
|
RefreshPopup();
|
||
|
|
}
|
||
|
|
|
||
|
|
private void OnDragMouseMove(object sender, MouseEventArgs e)
|
||
|
|
{
|
||
|
|
DragDoing();
|
||
|
|
}
|
||
|
|
|
||
|
|
public void DragStop()
|
||
|
|
{
|
||
|
|
MouseMove -= OnDragMouseMove;
|
||
|
|
if (IsMouseCaptured) ReleaseMouseCapture();
|
||
|
|
RefreshColor();
|
||
|
|
ModAnimation.AniStart(
|
||
|
|
ModAnimation.AaScaleTransform(ShapeDot, 1d - ((ScaleTransform)ShapeDot.RenderTransform).ScaleX, 200,
|
||
|
|
ease: new ModAnimation.AniEaseOutFluent()), "MySlider Scale " + Uuid);
|
||
|
|
Popup.IsOpen = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void RefreshPopup()
|
||
|
|
{
|
||
|
|
if (getHintText is null)
|
||
|
|
return;
|
||
|
|
Popup.IsOpen = true;
|
||
|
|
TextHint.Text = getHintText.DynamicInvoke(Value)?.ToString() ?? "";
|
||
|
|
var typeface = new Typeface(TextHint.FontFamily, TextHint.FontStyle, TextHint.FontWeight, TextHint.FontStretch);
|
||
|
|
var formattedText = new FormattedText(TextHint.Text, Thread.CurrentThread.CurrentCulture,
|
||
|
|
TextHint.FlowDirection, typeface, TextHint.FontSize, TextHint.Foreground, ModBase.dpi);
|
||
|
|
TextHint.Width = formattedText.Width; // 使用手动测量的宽度修复 #1057
|
||
|
|
}
|
||
|
|
|
||
|
|
// 指向动画
|
||
|
|
|
||
|
|
private void RefreshColor()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
// 判断当前颜色
|
||
|
|
string foregroundName;
|
||
|
|
string dotFillName;
|
||
|
|
int animationTime;
|
||
|
|
if (IsEnabled)
|
||
|
|
{
|
||
|
|
if (ModMain.dragControl is not null && ModMain.dragControl.Equals(this) || IsMouseOver)
|
||
|
|
{
|
||
|
|
foregroundName = "ColorBrush3";
|
||
|
|
dotFillName = "ColorBrush3";
|
||
|
|
animationTime = 40;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
foregroundName = "ColorBrushBg0";
|
||
|
|
dotFillName = "ColorBrushBg0";
|
||
|
|
animationTime = 100;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
foregroundName = "ColorBrushGray5";
|
||
|
|
dotFillName = "ColorBrushGray5";
|
||
|
|
animationTime = 200;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 触发颜色动画
|
||
|
|
if (IsLoaded && ModAnimation.AniControlEnabled == 0) // 防止默认属性变更触发动画
|
||
|
|
{
|
||
|
|
// 有动画
|
||
|
|
ModAnimation.AniStart(
|
||
|
|
new[]
|
||
|
|
{
|
||
|
|
ModAnimation.AaColor(this, BorderBrushProperty, foregroundName, animationTime),
|
||
|
|
ModAnimation.AaColor(ShapeDot, Shape.FillProperty, dotFillName, animationTime)
|
||
|
|
}, "MySlider Color " + Uuid);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// 无动画
|
||
|
|
ModAnimation.AniStop("MySlider Color " + Uuid);
|
||
|
|
SetResourceReference(BorderBrushProperty, foregroundName);
|
||
|
|
ShapeDot.SetResourceReference(Shape.FillProperty, dotFillName);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
ModBase.Log(ex, "滑动条颜色改变出错");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void MySlider_MouseEnter()
|
||
|
|
{
|
||
|
|
Focus(); // 确保按键能改变值
|
||
|
|
}
|
||
|
|
|
||
|
|
private void MySlider_KeyDown(object sender, KeyEventArgs e)
|
||
|
|
{
|
||
|
|
// 拒绝一边拖动一边用按键改变
|
||
|
|
if (ReferenceEquals(this, ModMain.dragControl))
|
||
|
|
return;
|
||
|
|
// 改变值
|
||
|
|
if (e.Key == Key.Left)
|
||
|
|
{
|
||
|
|
changeByKey = true;
|
||
|
|
Value = (int)(Value - ValueByKey);
|
||
|
|
changeByKey = false;
|
||
|
|
e.Handled = true;
|
||
|
|
}
|
||
|
|
else if (e.Key == Key.Right)
|
||
|
|
{
|
||
|
|
changeByKey = true;
|
||
|
|
Value = (int)(Value + ValueByKey);
|
||
|
|
changeByKey = false;
|
||
|
|
e.Handled = true;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 更新 Popup
|
||
|
|
if (getHintText is not null)
|
||
|
|
{
|
||
|
|
RefreshPopup();
|
||
|
|
ModAnimation.AniStop("MySlider KeyPopup " + Uuid);
|
||
|
|
ModAnimation.AniStart(
|
||
|
|
ModAnimation.AaCode(() => Popup.IsOpen = false, (int)Math.Round(700d * ModAnimation.aniSpeed)),
|
||
|
|
"MySlider KeyPopup " + Uuid);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|