using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Input; using System.Windows.Media; using WPFDark.Internals; namespace WPFDark.Controls { public class BiaColorBar : FrameworkElement { #region Value public double Value { get => _Value; set { if (NumberHelper.AreClose(value, _Value) == false) SetValue(ValueProperty, value); } } private double _Value; public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(nameof(Value), typeof(double), typeof(BiaColorBar), new FrameworkPropertyMetadata( 0.0, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender, (s, e) => { var self = (BiaColorBar) s; self._Value = (double) e.NewValue; })); #endregion #region Color0 public ByteColor Color0 { get => _Color0; set { if (value != _Color0) SetValue(Color0Property, value); } } private ByteColor _Color0 = ByteColor.Black; public static readonly DependencyProperty Color0Property = DependencyProperty.Register(nameof(Color0), typeof(ByteColor), typeof(BiaColorBar), new FrameworkPropertyMetadata( Boxes.ByteColorBlack, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender, (s, e) => { var self = (BiaColorBar) s; self._Color0 = (ByteColor) e.NewValue; self._isRequestUpdateBackgroundBrush = true; })); #endregion #region Color1 public ByteColor Color1 { get => _Color1; set { if (value != _Color1) SetValue(Color1Property, value); } } private ByteColor _Color1 = ByteColor.White; public static readonly DependencyProperty Color1Property = DependencyProperty.Register(nameof(Color1), typeof(ByteColor), typeof(BiaColorBar), new FrameworkPropertyMetadata( Boxes.ByteColorWhite, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender, (s, e) => { var self = (BiaColorBar) s; self._Color1 = (ByteColor) e.NewValue; self._isRequestUpdateBackgroundBrush = true; })); #endregion #region BorderColor public ByteColor BorderColor { get => _BorderColor; set { if (value != _BorderColor) SetValue(BorderColorProperty, value); } } private ByteColor _BorderColor = ByteColor.Red; public static readonly DependencyProperty BorderColorProperty = DependencyProperty.Register(nameof(BorderColor), typeof(ByteColor), typeof(BiaColorBar), new FrameworkPropertyMetadata( Boxes.ByteColorRed, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender, (s, e) => { var self = (BiaColorBar) s; self._BorderColor = (ByteColor) e.NewValue; })); #endregion #region IsInverseValue public bool IsInverseValue { get => _IsInverseValue; set { if (value != _IsInverseValue) SetValue(IsInverseValueProperty, value); } } private bool _IsInverseValue; public static readonly DependencyProperty IsInverseValueProperty = DependencyProperty.Register(nameof(IsInverseValue), typeof(bool), typeof(BiaColorBar), new FrameworkPropertyMetadata( false, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender, (s, e) => { var self = (BiaColorBar) s; self._IsInverseValue = (bool) e.NewValue; })); #endregion #region IsReadOnly public bool IsReadOnly { get => _IsReadOnly; set { if (value != _IsReadOnly) SetValue(IsReadOnlyProperty, value); } } private bool _IsReadOnly; public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register(nameof(IsReadOnly), typeof(bool), typeof(BiaColorBar), new FrameworkPropertyMetadata( false, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender, (s, e) => { var self = (BiaColorBar) s; self._IsReadOnly = (bool) e.NewValue; })); #endregion #region StartedContinuousEditingCommand public ICommand? StartedContinuousEditingCommand { get => _StartedContinuousEditingCommand; set { if (value != _StartedContinuousEditingCommand) SetValue(StartedContinuousEditingCommandProperty, value); } } private ICommand? _StartedContinuousEditingCommand; public static readonly DependencyProperty StartedContinuousEditingCommandProperty = DependencyProperty.Register( nameof(StartedContinuousEditingCommand), typeof(ICommand), typeof(BiaColorBar), new PropertyMetadata( default(ICommand), (s, e) => { var self = (BiaColorBar) s; self._StartedContinuousEditingCommand = (ICommand) e.NewValue; })); #endregion #region EndContinuousEditingCommand public ICommand? EndContinuousEditingCommand { get => _EndContinuousEditingCommand; set { if (value != _EndContinuousEditingCommand) SetValue(EndContinuousEditingCommandProperty, value); } } private ICommand? _EndContinuousEditingCommand; public static readonly DependencyProperty EndContinuousEditingCommandProperty = DependencyProperty.Register( nameof(EndContinuousEditingCommand), typeof(ICommand), typeof(BiaColorBar), new PropertyMetadata( default(ICommand), (s, e) => { var self = (BiaColorBar) s; self._EndContinuousEditingCommand = (ICommand) e.NewValue; })); #endregion private Brush? _backgroundBrush; private bool _isRequestUpdateBackgroundBrush = true; // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable private readonly PropertyChangeNotifier _isEnabledChangeNotifier; static BiaColorBar() { DefaultStyleKeyProperty.OverrideMetadata(typeof(BiaColorBar), new FrameworkPropertyMetadata(typeof(BiaColorBar))); } public BiaColorBar() { RenderOptions.SetEdgeMode(this, EdgeMode.Aliased); _isEnabledChangeNotifier = new PropertyChangeNotifier(this, IsEnabledProperty); _isEnabledChangeNotifier.ValueChanged += (_, __) => { _isRequestUpdateBackgroundBrush = true; InvalidateVisual(); }; } protected override void OnRender(DrawingContext dc) { if (ActualWidth <= 1 || ActualHeight <= 1) return; var rounder = new LayoutRounder(this); VisualEdgeMode = EdgeMode.Unspecified; if (_isRequestUpdateBackgroundBrush) { _isRequestUpdateBackgroundBrush = false; UpdateBackgroundBrush(); } var rect = rounder.RoundRenderRectangle(true); dc.DrawRectangle(_backgroundBrush, rounder.GetBorderPen(BorderColor), rect); // Cursor this.DrawPointCursor(rounder, dc, MakeCursorRenderPos(rounder), IsEnabled, IsReadOnly); } private ImmutableVec2_double MakeCursorRenderPos(in LayoutRounder rounder) { var bw = rounder.RoundLayoutValue(FrameworkElementExtensions.BorderWidth); var h = rounder.RoundLayoutValue(ActualHeight - bw * 2); var y = NumberHelper.Clamp01(Value) * h; if (IsInverseValue) y = h - y; y += bw; return new ImmutableVec2_double(rounder.RoundLayoutValue(ActualWidth / 2), rounder.RoundLayoutValue(y)); } private static Brush? _disabledBackgroundBrush; private void UpdateBackgroundBrush() { if (IsEnabled) { _backgroundBrush = new LinearGradientBrush(Color1.ToColor(), Color0.ToColor(), 90); _backgroundBrush.Freeze(); } else { if (_disabledBackgroundBrush is null) _disabledBackgroundBrush = (Brush) ThemeManager.Current.TryFindResource("InactiveBackgroundBrushKey"); _backgroundBrush = _disabledBackgroundBrush; } } private void UpdateParams(MouseEventArgs e) { var rounder = new LayoutRounder(this); var pos = e.GetPosition(this); var s = rounder.RoundLayoutValue(1); var y = (pos.Y - s) / (ActualHeight - s * 2); y = NumberHelper.Clamp01(y); Value = IsInverseValue ? 1 - y : y; } private bool _isMouseDown; private bool _isContinuousEdited; private double _ContinuousEditingStartValue; protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { base.OnMouseLeftButtonDown(e); if (IsReadOnly) return; _isMouseDown = true; GuiHelper.HideCursor(); _ContinuousEditingStartValue = Value; _isContinuousEdited = true; StartedContinuousEditingCommand?.ExecuteIfCan(null); UpdateParams(e); CaptureMouse(); this.SetMouseClipping(); e.Handled = true; } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (IsReadOnly) return; if (_isMouseDown == false) return; UpdateParams(e); e.Handled = true; } protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) { base.OnMouseLeftButtonUp(e); if (IsReadOnly) return; if (_isMouseDown == false) return; // マウス位置を補正する { var rounder = new LayoutRounder(this); var cp = MakeCursorRenderPos(rounder); var p = PointToScreen(Unsafe.As(ref cp)); Win32Helper.SetCursorPos((int) p.X, (int) p.Y); } _isMouseDown = false; this.ResetMouseClipping(); GuiHelper.ShowCursor(); ReleaseMouseCapture(); if (_isContinuousEdited) { if (EndContinuousEditingCommand != null) { if (EndContinuousEditingCommand.CanExecute(null)) { var changedValue = Value; Value = _ContinuousEditingStartValue; EndContinuousEditingCommand.Execute(null); Value = changedValue; } } _isContinuousEdited = false; } e.Handled = true; } protected override void OnMouseLeave(MouseEventArgs e) { base.OnMouseLeave(e); if (_isMouseDown) { _isMouseDown = false; ReleaseMouseCapture(); GuiHelper.ShowCursor(); this.ResetMouseClipping(); } e.Handled = true; } } }