Files
ShrlAlgoToolkit/WPFDark/Controls/BiaFlagBox.cs
ShrlAlgo 4d35cadb56 更新
2025-07-11 09:20:23 +08:00

771 lines
23 KiB
C#

using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using WPFDark.Internals;
namespace WPFDark.Controls
{
public class BiaFlagBox : FrameworkElement
{
#region Flag0
public bool Flag0
{
get => _Flag0;
set
{
if (value != _Flag0)
SetValue(Flag0Property, value);
}
}
private bool _Flag0;
public static readonly DependencyProperty Flag0Property =
DependencyProperty.Register(
nameof(Flag0),
typeof(bool),
typeof(BiaFlagBox),
new FrameworkPropertyMetadata(
false,
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
(s, e) =>
{
var self = (BiaFlagBox) s;
self._Flag0 = (bool) e.NewValue;
}));
#endregion
#region Flag1
public bool Flag1
{
get => _Flag1;
set
{
if (value != _Flag1)
SetValue(Flag1Property, value);
}
}
private bool _Flag1;
public static readonly DependencyProperty Flag1Property =
DependencyProperty.Register(
nameof(Flag1),
typeof(bool),
typeof(BiaFlagBox),
new FrameworkPropertyMetadata(
false,
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
(s, e) =>
{
var self = (BiaFlagBox) s;
self._Flag1 = (bool) e.NewValue;
}));
#endregion
#region Flag2
public bool Flag2
{
get => _Flag2;
set
{
if (value != _Flag2)
SetValue(Flag2Property, value);
}
}
private bool _Flag2;
public static readonly DependencyProperty Flag2Property =
DependencyProperty.Register(
nameof(Flag2),
typeof(bool),
typeof(BiaFlagBox),
new FrameworkPropertyMetadata(
false,
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
(s, e) =>
{
var self = (BiaFlagBox) s;
self._Flag2 = (bool) e.NewValue;
}));
#endregion
#region Flag3
public bool Flag3
{
get => _Flag3;
set
{
if (value != _Flag3)
SetValue(Flag3Property, value);
}
}
private bool _Flag3;
public static readonly DependencyProperty Flag3Property =
DependencyProperty.Register(
nameof(Flag3),
typeof(bool),
typeof(BiaFlagBox),
new FrameworkPropertyMetadata(
false,
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
(s, e) =>
{
var self = (BiaFlagBox) s;
self._Flag3 = (bool) e.NewValue;
}));
#endregion
#region Flag4
public bool Flag4
{
get => _Flag4;
set
{
if (value != _Flag4)
SetValue(Flag4Property, value);
}
}
private bool _Flag4;
public static readonly DependencyProperty Flag4Property =
DependencyProperty.Register(
nameof(Flag4),
typeof(bool),
typeof(BiaFlagBox),
new FrameworkPropertyMetadata(
false,
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
(s, e) =>
{
var self = (BiaFlagBox) s;
self._Flag4 = (bool) e.NewValue;
}));
#endregion
#region Flag5
public bool Flag5
{
get => _Flag5;
set
{
if (value != _Flag5)
SetValue(Flag5Property, value);
}
}
private bool _Flag5;
public static readonly DependencyProperty Flag5Property =
DependencyProperty.Register(
nameof(Flag5),
typeof(bool),
typeof(BiaFlagBox),
new FrameworkPropertyMetadata(
false,
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
(s, e) =>
{
var self = (BiaFlagBox) s;
self._Flag5 = (bool) e.NewValue;
}));
#endregion
#region Flag6
public bool Flag6
{
get => _Flag6;
set
{
if (value != _Flag6)
SetValue(Flag6Property, value);
}
}
private bool _Flag6;
public static readonly DependencyProperty Flag6Property =
DependencyProperty.Register(
nameof(Flag6),
typeof(bool),
typeof(BiaFlagBox),
new FrameworkPropertyMetadata(
false,
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
(s, e) =>
{
var self = (BiaFlagBox) s;
self._Flag6 = (bool) e.NewValue;
}));
#endregion
#region Flag7
public bool Flag7
{
get => _Flag7;
set
{
if (value != _Flag7)
SetValue(Flag7Property, value);
}
}
private bool _Flag7;
public static readonly DependencyProperty Flag7Property =
DependencyProperty.Register(
nameof(Flag7),
typeof(bool),
typeof(BiaFlagBox),
new FrameworkPropertyMetadata(
false,
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
(s, e) =>
{
var self = (BiaFlagBox) s;
self._Flag7 = (bool) e.NewValue;
}));
#endregion
private uint AllFlags
{
get
{
uint f = 0;
if (Flag0) f |= 1 << 0;
if (Flag1) f |= 1 << 1;
if (Flag2) f |= 1 << 2;
if (Flag3) f |= 1 << 3;
if (Flag4) f |= 1 << 4;
if (Flag5) f |= 1 << 5;
if (Flag6) f |= 1 << 6;
if (Flag7) f |= 1 << 7;
return f;
}
set
{
Flag0 = (value & (1 << 0)) != 0;
Flag1 = (value & (1 << 1)) != 0;
Flag2 = (value & (1 << 2)) != 0;
Flag3 = (value & (1 << 3)) != 0;
Flag4 = (value & (1 << 4)) != 0;
Flag5 = (value & (1 << 5)) != 0;
Flag6 = (value & (1 << 6)) != 0;
Flag7 = (value & (1 << 7)) != 0;
}
}
#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(BiaFlagBox),
new PropertyMetadata(
default(ICommand),
(s, e) =>
{
var self = (BiaFlagBox) 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(BiaFlagBox),
new PropertyMetadata(
default(ICommand),
(s, e) =>
{
var self = (BiaFlagBox) s;
self._EndContinuousEditingCommand = (ICommand) e.NewValue;
}));
#endregion
#region StartedBatchEditingCommand
public ICommand? StartedBatchEditingCommand
{
get => _StartedBatchEditingCommand;
set
{
if (value != _StartedBatchEditingCommand)
SetValue(StartedBatchEditingCommandProperty, value);
}
}
private ICommand? _StartedBatchEditingCommand;
public static readonly DependencyProperty StartedBatchEditingCommandProperty =
DependencyProperty.Register(
nameof(StartedBatchEditingCommand),
typeof(ICommand),
typeof(BiaFlagBox),
new PropertyMetadata(
default,
(s, e) =>
{
var self = (BiaFlagBox) s;
self._StartedBatchEditingCommand = (ICommand) e.NewValue;
}));
#endregion
#region EndBatchEditingCommand
public ICommand? EndBatchEditingCommand
{
get => _EndBatchEditingCommand;
set
{
if (value != _EndBatchEditingCommand)
SetValue(EndBatchEditingCommandProperty, value);
}
}
private ICommand? _EndBatchEditingCommand;
public static readonly DependencyProperty EndBatchEditingCommandProperty =
DependencyProperty.Register(
nameof(EndBatchEditingCommand),
typeof(ICommand),
typeof(BiaFlagBox),
new PropertyMetadata(
default,
(s, e) =>
{
var self = (BiaFlagBox) s;
self._EndBatchEditingCommand = (ICommand) e.NewValue;
}));
#endregion
private bool _isPressed;
private bool IsCheckedButton(int index)
{
return index switch
{
0 => Flag0,
1 => Flag1,
2 => Flag2,
3 => Flag3,
4 => Flag4,
5 => Flag5,
6 => Flag6,
7 => Flag7,
_ => throw new NotImplementedException()
};
}
private void SetIsCheckedButton(int index, bool i)
{
switch (index)
{
case 0:
Flag0 = i;
return;
case 1:
Flag1 = i;
return;
case 2:
Flag2 = i;
return;
case 3:
Flag3 = i;
return;
case 4:
Flag4 = i;
return;
case 5:
Flag5 = i;
return;
case 6:
Flag6 = i;
return;
case 7:
Flag7 = i;
return;
}
throw new NotImplementedException();
}
private bool IsMouseOverButton(int index)
=> (_isMouseOverButton & (1 << index)) != 0;
private void SetIsMouseOverButton(int index, bool i)
{
if (i)
_isMouseOverButton |= (1u << index);
else
_isMouseOverButton &= ~(1u << index);
InvalidateVisual();
}
private void ResetIsMouseOverButton()
{
_isMouseOverButton = 0;
InvalidateVisual();
}
private bool IsPressedButton(int index)
=> (_isPressedButton & (1 << index)) != 0;
private void SetIsPressedButton(int index, bool i)
{
if (i)
_isPressedButton |= (1u << index);
else
_isPressedButton &= ~(1u << index);
InvalidateVisual();
}
private void ResetIsPressedButton()
{
_isPressedButton = 0;
InvalidateVisual();
}
private uint _isMouseOverButton;
private uint _isPressedButton;
static BiaFlagBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(BiaFlagBox),
new FrameworkPropertyMetadata(typeof(BiaFlagBox)));
}
protected override void OnRender(DrawingContext dc)
{
if (ActualWidth <= 1 ||
ActualHeight <= 1)
return;
var rounder = new LayoutRounder(this);
// 背景
{
dc.PushClip(Caches.GetClipGeom(rounder, RenderSize.Width, RenderSize.Height, Constants.BasicCornerRadiusPrim, false));
var index = 0;
var isEnabled = IsEnabled;
for (var row = 0; row != RowCount; ++row)
{
for (var column = 0; column != ColumnCount; ++column, ++index)
{
var x = column * ButtonWidth;
var y = row * ButtonHeight;
var isChecked = IsCheckedButton(index);
var isMouseOver = IsMouseOverButton(index);
var isPressed = IsPressedButton(index);
DrawButton(rounder, dc, x, y, isEnabled, isChecked, isMouseOver, isPressed);
}
}
dc.Pop();
}
var borderPen = rounder.GetBorderPen(new ByteColor(0xFF, 0x2D, 0x2D, 0x30));
// 境界線
{
{
var x = rounder.RoundLayoutValue(RenderSize.Width);
var y = rounder.RoundLayoutValue(RenderSize.Height * 0.5 + FrameworkElementExtensions.BorderHalfWidth);
dc.DrawLine(borderPen, new Point(0, y), new Point(x, y));
}
{
var y = rounder.RoundLayoutValue(RenderSize.Height + FrameworkElementExtensions.BorderHalfWidth);
for (var column = 1; column != ColumnCount; ++column)
{
var x = rounder.RoundLayoutValue(column * ButtonWidth + FrameworkElementExtensions.BorderHalfWidth);
dc.DrawLine(borderPen, new Point(x, 0), new Point(x, y));
}
}
}
}
private static void DrawButton(in LayoutRounder rounder, DrawingContext dc, double x, double y, bool isEnabled, bool isChecked, bool isMouseOver, bool isPressed)
{
dc.DrawRectangle(
SelectBrush(isEnabled, isChecked, isMouseOver, isPressed),
null,
new Rect(
rounder.RoundLayoutValue(x),
rounder.RoundLayoutValue(y),
rounder.RoundLayoutValue(ButtonWidth),
rounder.RoundLayoutValue(ButtonHeight)));
}
private static Brush SelectBrush(bool isEnabled, bool isChecked, bool isMouseOver, bool isPressed)
{
if (isEnabled == false)
{
return isChecked
? _toggleButtonBackgroundBrushKeyIsCheckedIsDisabled
: _buttonInactiveBackgroundBrushKey;
}
if (isPressed)
{
return isChecked
? _toggleButtonBackgroundBrushKeyIsCheckedIsMouseOver
: _buttonPressedBackgroundBrushKey;
}
if (isMouseOver)
{
return isChecked
? _toggleButtonBackgroundBrushKeyIsCheckedIsMouseOver
: _buttonActiveBackgroundBrushKey;
}
return isChecked
? _toggleButtonBackgroundBrushKeyIsChecked
: _buttonBackgroundBrushKey;
}
#region Brush
private static readonly Brush _buttonInactiveBackgroundBrushKey =
(Brush) ThemeManager.Current.TryFindResource("ButtonInactiveBackgroundBrushKey");
private static readonly Brush _toggleButtonBackgroundBrushKeyIsCheckedIsDisabled =
(Brush) ThemeManager.Current.TryFindResource("ToggleButtonBackgroundBrushKey.IsChecked.IsDisabled");
private static readonly Brush _toggleButtonBackgroundBrushKeyIsCheckedIsMouseOver =
(Brush) ThemeManager.Current.TryFindResource("ToggleButtonBackgroundBrushKey.IsChecked.IsMouseOver");
private static readonly Brush _toggleButtonBackgroundBrushKeyIsChecked =
(Brush) ThemeManager.Current.TryFindResource("ToggleButtonBackgroundBrushKey.IsChecked");
private static readonly Brush _buttonPressedBackgroundBrushKey =
(Brush) ThemeManager.Current.TryFindResource("ButtonPressedBackgroundBrushKey");
private static readonly Brush _buttonActiveBackgroundBrushKey =
(Brush) ThemeManager.Current.TryFindResource("ButtonActiveBackgroundBrushKey");
private static readonly Brush _buttonBackgroundBrushKey =
(Brush) ThemeManager.Current.TryFindResource("ButtonBackgroundBrushKey");
#endregion
private bool _isContinuousEdited;
private uint _ContinuousEditingStartValue;
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
_isPressed = IsInMouse(e);
_ContinuousEditingStartValue = AllFlags;
_isContinuousEdited = true;
StartedContinuousEditingCommand?.ExecuteIfCan(null);
CaptureMouse();
UpdateState(e, true);
e.Handled = true;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
UpdateState(e, false);
e.Handled = true;
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
if (_isPressed == false)
return;
if (IsMouseCaptured)
ReleaseMouseCapture();
_isPressed = false;
UpdateState(e, false);
if (_isContinuousEdited)
{
if (EndContinuousEditingCommand != null)
{
if (EndContinuousEditingCommand.CanExecute(null))
{
var changedValue = AllFlags;
AllFlags = _ContinuousEditingStartValue;
EndContinuousEditingCommand.Execute(null);
StartedBatchEditingCommand?.Execute(null);
AllFlags = changedValue;
EndBatchEditingCommand?.Execute(null);
}
}
_isContinuousEdited = false;
}
if (IsInMouse(e) == false)
return;
e.Handled = true;
}
protected override void OnMouseLeave(MouseEventArgs e)
{
ResetIsMouseOverButton();
}
private bool _continueIsSelected;
private void UpdateState(MouseEventArgs e, bool isMouseDown)
{
var mousePos = e.GetPosition(this);
var x = (int) (mousePos.X / ButtonWidth);
var y = (int) (mousePos.Y / ButtonHeight);
ResetIsMouseOverButton();
ResetIsPressedButton();
if (x < 0 || x >= ColumnCount ||
y < 0 || y >= RowCount)
return;
var index = y * ColumnCount + x;
// IsChecked を作る
if (_isPressed)
{
if (KeyboardHelper.IsPressShift)
{
if (isMouseDown)
_continueIsSelected = !IsCheckedButton(index);
SetIsCheckedButton(index, _continueIsSelected);
}
else
{
for (var i = 0; i != ButtonCount; ++i)
SetIsCheckedButton(i, i == index);
}
}
// IsMouseOver を作る
SetIsMouseOverButton(index, true);
// IsPressed を作る
if (_isPressed)
SetIsPressedButton(index, true);
}
private bool IsInMouse(MouseEventArgs e)
{
var pos = e.GetPosition(this);
return this.IsInActualSize(pos);
}
private const double ButtonWidth = 16.0;
private const double ButtonHeight = 16.0;
private const int ColumnCount = 4;
private const int RowCount = 2;
private const int ButtonCount = ColumnCount * RowCount;
protected override Size MeasureOverride(Size constraint)
{
// todo:DPI変更時に再描画が行われないため明示的に指示している。要調査。
InvalidateVisual();
return new Size(ColumnCount * ButtonWidth, RowCount * ButtonHeight);
}
protected override Size ArrangeOverride(Size arrangeSize)
{
return new Size(ColumnCount * ButtonWidth, RowCount * ButtonHeight);
}
}
}