重构 所有代码结构,减少暴露属性,并为每个方法添加注释

This commit is contained in:
jie65535 2021-01-22 00:15:50 +08:00
parent 877a92d727
commit f50732f708
4 changed files with 859 additions and 401 deletions

View File

@ -1,11 +1,4 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Windows.Forms;
namespace CodeMatrix
@ -49,8 +42,6 @@ namespace CodeMatrix
codeTarget.InputCode(value);
};
Controls.Add(codeMatrix);
Controls.Add(codeQueue);
Controls.AddRange(codeTargets);
@ -59,6 +50,5 @@ namespace CodeMatrix
size.Width += codeQueue.Width;
ClientSize = size;
}
}
}
}

View File

@ -4,45 +4,88 @@ using System.Windows.Forms;
namespace CodeMatrix
{
/// <summary>
/// 表示代码矩阵控件 游戏中的代码矩阵
/// </summary>
/// <seealso cref="System.Windows.Forms.Control" />
internal class UCCodeMatrix : Control
{
public Size CellSize { get; set; }
public int Columns { get; set; }
public int Rows { get; set; }
public byte[,] Matrix { get; set; }
public Point SelectPoint { get; private set; }
public Point CursorPoint { get; private set; }
private Point _HoverPoint;
public Point HoverPoint
{
get => _HoverPoint;
set
{
_HoverPoint = value;
if (HoverPoint.X >= 0)
HoverValueChangedEvent?.Invoke(this, Matrix[HoverPoint.X, HoverPoint.Y]);
else
HoverValueChangedEvent?.Invoke(this, 0);
}
}
public RectangleF CodeMatrixRect { get; private set; }
private static readonly Size MaximumMatrixSize = new Size(10, 10);
private static readonly Size MinimumMatrixSize = new Size(5, 5);
/// <summary>
/// The cell size
/// </summary>
private Size _CellSize;
/// <summary>
/// The code matrix rect
/// </summary>
private RectangleF _CodeMatrixRect;
/// <summary>
/// The columns
/// </summary>
private int _Columns = 5;
/// <summary>
/// The curr dir
/// </summary>
private Directions _currDir;
/// <summary>
/// The cursor point
/// </summary>
private Point _CursorPoint;
/// <summary>
/// The highlight code
/// </summary>
private byte _HighlightCode;
public byte HighlightCode
/// <summary>
/// The hover point
/// </summary>
private Point _HoverPoint;
/// <summary>
/// The is loaded
/// </summary>
private bool _IsLoaded;
/// <summary>
/// The matrix
/// </summary>
private byte[,] _Matrix;
/// <summary>
/// The rows
/// </summary>
private int _Rows = 5;
/// <summary>
/// The select point
/// </summary>
private Point _SelectPoint;
/// <summary>
/// Initializes a new instance of the <see cref="UCCodeMatrix"/> class.
/// </summary>
public UCCodeMatrix()
{
get => _HighlightCode;
set
{
if (_HighlightCode != value)
{
_HighlightCode = value;
Invalidate();
}
}
InitComponent();
}
public event EventHandler<byte> HoverValueChangedEvent;
/// <summary>
/// Occurs when [code selected event].
/// </summary>
public event EventHandler<byte> CodeSelectedEvent;
/// <summary>
/// Occurs when [hover value changed event].
/// </summary>
public event EventHandler<byte> HoverValueChangedEvent;
/// <summary>
/// 方向
/// </summary>
@ -59,153 +102,131 @@ namespace CodeMatrix
Horizontal,
}
private Directions _currDir;
public UCCodeMatrix()
/// <summary>
/// Gets or sets the columns.
/// </summary>
/// <value>
/// The columns.
/// </value>
/// <exception cref="ArgumentOutOfRangeException">Columns - 设置矩阵大小数值不能小于 {MinimumMatrixSize.Width} 或者大于 {MaximumMatrixSize.Width}</exception>
public int Columns
{
InitData();
InitComponent();
get => _Columns;
set
{
if (_Columns != value)
{
if (value < MinimumMatrixSize.Width || value > MaximumMatrixSize.Width)
throw new ArgumentOutOfRangeException("Columns", value, $"设置矩阵大小数值不能小于 {MinimumMatrixSize.Width} 或者大于 {MaximumMatrixSize.Width}");
_Columns = value;
OnCodeMatrixSizeChanged();
}
}
}
private void InitData()
/// <summary>
/// Gets or sets the highlight code.
/// </summary>
/// <value>
/// The highlight code.
/// </value>
public byte HighlightCode
{
get => _HighlightCode;
set
{
if (_HighlightCode != value)
{
_HighlightCode = value;
Invalidate();
}
}
}
/// <summary>
/// Gets or sets the rows.
/// </summary>
/// <value>
/// The rows.
/// </value>
public int Rows
{
get => _Rows;
set
{
if (_Rows != value)
{
if (value < MinimumMatrixSize.Height || value > MaximumMatrixSize.Height)
throw new ArgumentOutOfRangeException("value", value, $"设置矩阵大小数值不能小于 {MinimumMatrixSize.Height} 或者大于 {MaximumMatrixSize.Height}");
_Rows = value;
OnCodeMatrixSizeChanged();
}
}
}
/// <summary>
/// Gets or sets the hover point.
/// </summary>
/// <value>
/// The hover point.
/// </value>
private Point HoverPoint
{
get => _HoverPoint;
set
{
_HoverPoint = value;
if (HoverPoint.X >= 0)
HoverValueChangedEvent?.Invoke(this, _Matrix[HoverPoint.X, HoverPoint.Y]);
else
HoverValueChangedEvent?.Invoke(this, 0);
}
}
/// <summary>
/// Reloads the code matrix.
/// </summary>
public void ReloadCodeMatrix()
{
Rows = 7;
Columns = 7;
_currDir = Directions.Horizontal;
HoverPoint = new Point(-1, -1);
GenerateCodeMatrix();
CalcCodeMatrixRect();
}
private void InitComponent()
protected override void OnMouseClick(MouseEventArgs e)
{
CellSize = Styles.Default.CellSizeA;
MinimumSize = new Size(CellSize.Width * Columns + 100, CellSize.Height * Rows + 10);
Margin = Padding.Empty;
DoubleBuffered = true;
Font = Styles.Default.CodeFontA;
BackColor = Styles.Default.BackColor;
ForeColor = Styles.Default.CodeColor;
}
private bool _IsLoaded;
protected override void OnVisibleChanged(EventArgs e)
{
if (Visible && !_IsLoaded)
{
Load();
_IsLoaded = true;
}
base.OnVisibleChanged(e);
}
private void Load()
{
Matrix = new byte[Columns, Rows];
for (int col = 0; col < Columns; col++)
for (int row = 0; row < Rows; row++)
Matrix[col, row] = Common.Codes[Common.Random.Next(Common.Codes.Length)];
var blockSize = new SizeF(Columns*CellSize.Width, Rows*CellSize.Height);
var blockOffset = new PointF((Width-blockSize.Width)/2, (Height-blockSize.Height)/2);
CodeMatrixRect = new RectangleF(blockOffset, blockSize);
}
//int _paintCount;
protected override void OnPaint(PaintEventArgs e)
{
if (!_IsLoaded) return;
//_paintCount++;
var offset = new PointF(SelectPoint.X*CellSize.Width, SelectPoint.Y*CellSize.Height);
if (_currDir == Directions.Horizontal)
e.Graphics.FillRectangle(Styles.Default.DefaultLineBrush, 0, offset.Y + CodeMatrixRect.Y, Width, CellSize.Height);
else if (_currDir == Directions.Vertical)
e.Graphics.FillRectangle(Styles.Default.DefaultLineBrush, offset.X + CodeMatrixRect.X, 0, CellSize.Width, Height);
if (HoverPoint.X >= 0)
{
Cursor = Cursors.Hand;
if (_currDir == Directions.Horizontal)
{
offset.X = HoverPoint.X * CellSize.Width;
e.Graphics.FillRectangle(Styles.Default.SelectLineBrush, offset.X + CodeMatrixRect.X, 0, CellSize.Width, Height);
}
else if (_currDir == Directions.Vertical)
{
offset.Y = HoverPoint.Y * CellSize.Height;
e.Graphics.FillRectangle(Styles.Default.SelectLineBrush, 0, offset.Y + CodeMatrixRect.Y, Width, CellSize.Height);
}
offset.X += CodeMatrixRect.X;
offset.Y += CodeMatrixRect.Y;
e.Graphics.DrawRectangle(Styles.Default.SelectCellBorderPen, offset.X, offset.Y, CellSize.Width - 1, CellSize.Height - 1);
e.Graphics.DrawRectangle(Styles.Default.SelectCellBorderPen, offset.X + 3, offset.Y + 3, CellSize.Width - 6 - 1, CellSize.Height - 6 - 1);
_SelectPoint = HoverPoint;
_currDir = _currDir == Directions.Horizontal ? Directions.Vertical : Directions.Horizontal;
CodeSelectedEvent?.Invoke(this, _Matrix[_SelectPoint.X, _SelectPoint.Y]);
HoverPoint = _CursorPoint = new Point(-1, -1);
_Matrix[_SelectPoint.X, _SelectPoint.Y] = 0;
Invalidate();
}
else
{
Cursor = Cursors.Default;
}
for (int col = 0; col < Columns; col++)
{
for (int row = 0; row < Rows; row++)
{
var cellOffset = new PointF(col*CellSize.Width, row*CellSize.Height);
//var cellRect = new RectangleF(cellOffset, CellSize);
Brush brush;
string code;
if (Matrix[col, row] == 0)
{
code = "[ ]";
brush = Styles.Default.EmptyCellBrush;
}
else
{
if (HoverPoint.X == col && HoverPoint.Y == row)
brush = Styles.Default.SelectBrush;
else
brush = Styles.Default.CodeBrush;
code = Matrix[col, row].ToString("X2");
}
if (HighlightCode != 0 && HighlightCode == Matrix[col, row])
{
e.Graphics.DrawRectangle(Styles.Default.SelectedCellBorderPen,
CodeMatrixRect.X+cellOffset.X+1,
CodeMatrixRect.Y+cellOffset.Y+1,
CellSize.Width - 3,
CellSize.Height - 3);
}
var codeSize = e.Graphics.MeasureString(code, Font);
var codeOffset = new PointF((CellSize.Width-codeSize.Width)/2, (CellSize.Height-codeSize.Height)/2);
var codePoint = new PointF(codeOffset.X+cellOffset.X+CodeMatrixRect.X, codeOffset.Y+cellOffset.Y+CodeMatrixRect.Y);
e.Graphics.DrawString(code, Font, brush, codePoint);
}
}
e.Graphics.DrawRectangle(Styles.Default.DefaultBorderPen, 0, 0, Width - 1, Height - 1);
//e.Graphics.DrawString(_paintCount.ToString(), Font, Styles.Default.CodeBrush, 0, 0);
base.OnMouseClick(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (CodeMatrixRect.Left <= e.X
&& CodeMatrixRect.Top <= e.Y
&& CodeMatrixRect.Right > e.X
&& CodeMatrixRect.Bottom > e.Y)
if (_CodeMatrixRect.Left <= e.X
&& _CodeMatrixRect.Top <= e.Y
&& _CodeMatrixRect.Right > e.X
&& _CodeMatrixRect.Bottom > e.Y)
{
var offset = new PointF(e.X-CodeMatrixRect.X, e.Y-CodeMatrixRect.Y);
var current = new Point((int)(offset.X / CellSize.Width), (int)(offset.Y / CellSize.Height));
if (CursorPoint != current)
var offset = new PointF(e.X-_CodeMatrixRect.X, e.Y-_CodeMatrixRect.Y);
var current = new Point((int)(offset.X / _CellSize.Width), (int)(offset.Y / _CellSize.Height));
if (_CursorPoint != current)
{
CursorPoint = current;
_CursorPoint = current;
Point hoverPoint;
if (_currDir == Directions.Vertical)
hoverPoint = new Point(SelectPoint.X, CursorPoint.Y);
hoverPoint = new Point(_SelectPoint.X, _CursorPoint.Y);
else
hoverPoint = new Point(CursorPoint.X, SelectPoint.Y);
if (Matrix[hoverPoint.X, hoverPoint.Y] == 0)
hoverPoint = new Point(_CursorPoint.X, _SelectPoint.Y);
if (_Matrix[hoverPoint.X, hoverPoint.Y] == 0)
hoverPoint = new Point(-1, -1);
if (HoverPoint != hoverPoint)
@ -219,25 +240,149 @@ namespace CodeMatrix
{
if (HoverPoint.X >= 0)
{
HoverPoint = CursorPoint = new Point(-1, -1);
HoverPoint = _CursorPoint = new Point(-1, -1);
Invalidate();
}
}
base.OnMouseMove(e);
}
protected override void OnMouseClick(MouseEventArgs e)
protected override void OnPaint(PaintEventArgs e)
{
if (!_IsLoaded) return;
var offset = new PointF(_SelectPoint.X*_CellSize.Width, _SelectPoint.Y*_CellSize.Height);
if (_currDir == Directions.Horizontal)
e.Graphics.FillRectangle(Styles.Default.DefaultLineBrush, 0, offset.Y + _CodeMatrixRect.Y, Width, _CellSize.Height);
else if (_currDir == Directions.Vertical)
e.Graphics.FillRectangle(Styles.Default.DefaultLineBrush, offset.X + _CodeMatrixRect.X, 0, _CellSize.Width, Height);
if (HoverPoint.X >= 0)
{
SelectPoint = HoverPoint;
_currDir = _currDir == Directions.Horizontal ? Directions.Vertical : Directions.Horizontal;
CodeSelectedEvent?.Invoke(this, Matrix[SelectPoint.X, SelectPoint.Y]);
HoverPoint = CursorPoint = new Point(-1, -1);
Matrix[SelectPoint.X, SelectPoint.Y] = 0;
Invalidate();
Cursor = Cursors.Hand;
if (_currDir == Directions.Horizontal)
{
offset.X = HoverPoint.X * _CellSize.Width;
e.Graphics.FillRectangle(Styles.Default.SelectLineBrush, offset.X + _CodeMatrixRect.X, 0, _CellSize.Width, Height);
}
else if (_currDir == Directions.Vertical)
{
offset.Y = HoverPoint.Y * _CellSize.Height;
e.Graphics.FillRectangle(Styles.Default.SelectLineBrush, 0, offset.Y + _CodeMatrixRect.Y, Width, _CellSize.Height);
}
offset.X += _CodeMatrixRect.X;
offset.Y += _CodeMatrixRect.Y;
e.Graphics.DrawRectangle(Styles.Default.SelectCellBorderPen, offset.X, offset.Y, _CellSize.Width - 1, _CellSize.Height - 1);
e.Graphics.DrawRectangle(Styles.Default.SelectCellBorderPen, offset.X + 3, offset.Y + 3, _CellSize.Width - 6 - 1, _CellSize.Height - 6 - 1);
}
base.OnMouseClick(e);
else
{
Cursor = Cursors.Default;
}
for (int col = 0; col < Columns; col++)
{
for (int row = 0; row < Rows; row++)
{
var cellOffset = new PointF(col*_CellSize.Width, row*_CellSize.Height);
//var cellRect = new RectangleF(cellOffset, CellSize);
Brush brush;
string code;
if (_Matrix[col, row] == 0)
{
code = "[ ]";
brush = Styles.Default.EmptyCellBrush;
}
else
{
if (HoverPoint.X == col && HoverPoint.Y == row)
brush = Styles.Default.SelectBrush;
else
brush = Styles.Default.CodeBrush;
code = _Matrix[col, row].ToString("X2");
}
if (HighlightCode != 0 && HighlightCode == _Matrix[col, row])
{
e.Graphics.DrawRectangle(Styles.Default.SelectedCellBorderPen,
_CodeMatrixRect.X + cellOffset.X + 1,
_CodeMatrixRect.Y + cellOffset.Y + 1,
_CellSize.Width - 3,
_CellSize.Height - 3);
}
var codeSize = e.Graphics.MeasureString(code, Font);
var codeOffset = new PointF((_CellSize.Width-codeSize.Width)/2, (_CellSize.Height-codeSize.Height)/2);
var codePoint = new PointF(codeOffset.X+cellOffset.X+_CodeMatrixRect.X, codeOffset.Y+cellOffset.Y+_CodeMatrixRect.Y);
e.Graphics.DrawString(code, Font, brush, codePoint);
}
}
e.Graphics.DrawRectangle(Styles.Default.DefaultBorderPen, 0, 0, Width - 1, Height - 1);
}
protected override void OnVisibleChanged(EventArgs e)
{
if (Visible && !_IsLoaded)
{
OnLoad();
_IsLoaded = true;
}
base.OnVisibleChanged(e);
}
/// <summary>
/// Calculates the code matrix rect.
/// </summary>
private void CalcCodeMatrixRect()
{
var blockSize = new SizeF(Columns*_CellSize.Width, Rows*_CellSize.Height);
var blockOffset = new PointF((Width-blockSize.Width)/2, (Height-blockSize.Height)/2);
_CodeMatrixRect = new RectangleF(blockOffset, blockSize);
}
/// <summary>
/// Generates the code matrix.
/// </summary>
private void GenerateCodeMatrix()
{
_Matrix = new byte[Columns, Rows];
for (int col = 0; col < Columns; col++)
for (int row = 0; row < Rows; row++)
_Matrix[col, row] = Common.Codes[Common.Random.Next(Common.Codes.Length)];
}
/// <summary>
/// Initializes the component.
/// </summary>
private void InitComponent()
{
_CellSize = Styles.Default.CellSizeA;
MinimumSize = new Size(_CellSize.Width * Columns, _CellSize.Height * Rows);
Size = MinimumSize + new Size(100, 10);
Margin = Padding.Empty;
DoubleBuffered = true;
Font = Styles.Default.CodeFontA;
BackColor = Styles.Default.BackColor;
ForeColor = Styles.Default.CodeColor;
}
/// <summary>
/// Called when [code matrix size changed].
/// </summary>
private void OnCodeMatrixSizeChanged()
{
MinimumSize = new Size(_CellSize.Width * Columns, _CellSize.Height * Rows);
if (_IsLoaded)
ReloadCodeMatrix();
}
/// <summary>
/// Called when [load].
/// </summary>
private void OnLoad()
{
ReloadCodeMatrix();
}
}
}

View File

@ -1,87 +1,157 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CodeMatrix
{
class UCCodeQueue : Control
/// <summary>
/// 表示代码队列控件 游戏中的输入缓冲区
/// </summary>
/// <seealso cref="System.Windows.Forms.Control" />
internal class UCCodeQueue : Control
{
public Size CellSize { get; private set; }
public Padding CellMargin { get; set; }
/// <summary>
/// The maximum buffer size
/// </summary>
private const int MaximumBufferSize = 10;
/// <summary>
/// The minimum buffer size
/// </summary>
private const int MinimumBufferSize = 4;
/// <summary>
/// The buffer
/// </summary>
private byte[] _Buffer = new byte[MaximumBufferSize];
/// <summary>
/// The buffer size
/// </summary>
private int _BufferSize = 4;
/// <summary>
/// The cell margin
/// </summary>
private Padding _CellMargin;
/// <summary>
/// The cell size
/// </summary>
private Size _CellSize;
/// <summary>
/// The curr index
/// </summary>
private int _CurrIndex;
/// <summary>
/// The hover code
/// </summary>
private byte _HoverCode;
/// <summary>
/// The is loaded/
/// </summary>
private bool _IsLoaded;
/// <summary>
/// Initializes a new instance of the <see cref="UCCodeQueue"/> class.
/// </summary>
public UCCodeQueue()
{
InitComponent();
}
/// <summary>
/// Gets or sets the size of the buffer.
/// </summary>
/// <value>
/// The size of the buffer.
/// </value>
/// <exception cref="ArgumentOutOfRangeException">BufferSize - 设置缓冲区大小数值不能小于 {MinimumBufferSize} 或者大于 {MaximumBufferSize}</exception>
public int BufferSize
{
get => _BufferSize;
set
{
if (_BufferSize != value)
{
if (value < MinimumBufferSize || value > MaximumBufferSize)
throw new ArgumentOutOfRangeException("BufferSize", value, $"设置缓冲区大小数值不能小于 {MinimumBufferSize} 或者大于 {MaximumBufferSize}");
_BufferSize = value;
OnBufferSizeChanged();
}
}
}
/// <summary>
/// Gets or sets the hover code.
/// </summary>
/// <value>
/// The hover code.
/// </value>
public byte HoverCode
{
get => _HoverCode;
set
{
_HoverCode = value;
Invalidate();
if (_HoverCode != value)
{
_HoverCode = value;
OnHoverCodeChanged();
}
}
}
public int BufferSize { get; set; }
public int CurrIndex { get; private set; }
public byte[] Buffer { get; } = new byte[32];
public UCCodeQueue()
/// <summary>
/// Inputs the code.
/// </summary>
/// <param name="code">The code.</param>
public void InputCode(byte code)
{
InitData();
InitComponent();
if (_CurrIndex < BufferSize)
_Buffer[_CurrIndex++] = code;
}
private void InitData()
/// <summary>
/// Reloads the code queue.
/// </summary>
public void ReloadCodeQueue()
{
BufferSize = 9;
CurrIndex = 0;
_CurrIndex = 0;
HoverCode = 0;
}
private void InitComponent()
{
CellSize = Styles.Default.CellSizeB;
Margin = Padding.Empty;
Padding = new Padding(10);
CellMargin = new Padding(3);
MinimumSize = new Size((CellSize.Width + CellMargin.Horizontal) * BufferSize + Padding.Horizontal,
CellSize.Height + CellMargin.Vertical + Padding.Vertical);
DoubleBuffered = true;
Font = Styles.Default.CodeFontB;
BackColor = Styles.Default.BackColor;
ForeColor = Styles.Default.CodeColor;
Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
var cellOffset = new Rectangle(Padding.Left + CellMargin.Left,
Padding.Top + CellMargin.Top,
CellSize.Width-1,
CellSize.Height-1);
var cellOffsetWidth = CellSize.Width + CellMargin.Horizontal;
for (int i = 0; i < CurrIndex && i < BufferSize; i++)
var cellOffset = new Rectangle(Padding.Left + _CellMargin.Left,
Padding.Top + _CellMargin.Top,
_CellSize.Width-1,
_CellSize.Height-1);
var cellOffsetWidth = _CellSize.Width + _CellMargin.Horizontal;
for (int i = 0; i < _CurrIndex && i < BufferSize; i++)
{
e.Graphics.DrawRectangle(Styles.Default.SelectedCellBorderPen, cellOffset);
var code = Buffer[i].ToString("X2");
var code = _Buffer[i].ToString("X2");
var codeSize = e.Graphics.MeasureString(code, Font);
var codeOffset = new PointF((CellSize.Width-codeSize.Width)/2, (CellSize.Height-codeSize.Height)/2);
var codeOffset = new PointF((_CellSize.Width-codeSize.Width)/2, (_CellSize.Height-codeSize.Height)/2);
var codePoint = new PointF(codeOffset.X+cellOffset.X, codeOffset.Y+cellOffset.Y);
e.Graphics.DrawString(code, Font, Styles.Default.CodeBrush, codePoint);
cellOffset.X += cellOffsetWidth;
}
if (CurrIndex < BufferSize)
if (_CurrIndex < BufferSize)
{
int i = CurrIndex;
int i = _CurrIndex;
if (HoverCode > 0)
{
i++;
e.Graphics.DrawRectangle(Styles.Default.SelectCellBorderPen, cellOffset);
var code = HoverCode.ToString("X2");
var codeSize = e.Graphics.MeasureString(code, Font);
var codeOffset = new PointF((CellSize.Width-codeSize.Width)/2, (CellSize.Height-codeSize.Height)/2);
var codeOffset = new PointF((_CellSize.Width-codeSize.Width)/2, (_CellSize.Height-codeSize.Height)/2);
var codePoint = new PointF(codeOffset.X+cellOffset.X, codeOffset.Y+cellOffset.Y);
e.Graphics.DrawString(code, Font, Styles.Default.SelectBrush, codePoint);
cellOffset.X += cellOffsetWidth;
@ -94,22 +164,63 @@ namespace CodeMatrix
}
}
e.Graphics.DrawRectangle(Styles.Default.DefaultBorderPen, 0, 0, Width - 1, Height - 1);
base.OnPaint(e);
}
public void InputCode(byte code)
protected override void OnVisibleChanged(EventArgs e)
{
if (CurrIndex < BufferSize)
Buffer[CurrIndex++] = code;
if (Visible && !_IsLoaded)
{
OnLoad();
_IsLoaded = true;
}
base.OnVisibleChanged(e);
}
public void ClearBuffer()
/// <summary>
/// Initializes the component.
/// </summary>
private void InitComponent()
{
CurrIndex = 0;
HoverCode = 0;
_CellSize = Styles.Default.CellSizeB;
Margin = Padding.Empty;
Padding = new Padding(10);
_CellMargin = new Padding(3);
MinimumSize = new Size((_CellSize.Width + _CellMargin.Horizontal) * BufferSize + Padding.Horizontal,
_CellSize.Height + _CellMargin.Vertical + Padding.Vertical);
DoubleBuffered = true;
Font = Styles.Default.CodeFontB;
BackColor = Styles.Default.BackColor;
ForeColor = Styles.Default.CodeColor;
}
/// <summary>
/// Called when [buffer size changed].
/// </summary>
private void OnBufferSizeChanged()
{
MinimumSize = new Size((_CellSize.Width + _CellMargin.Horizontal) * BufferSize + Padding.Horizontal,
_CellSize.Height + _CellMargin.Vertical + Padding.Vertical);
ReloadCodeQueue();
}
/// <summary>
/// Called when [hover code changed].
/// </summary>
private void OnHoverCodeChanged()
{
Invalidate();
}
/// <summary>
/// Called when [load].
/// </summary>
private void OnLoad()
{
ReloadCodeQueue();
}
}
}
}

View File

@ -1,18 +1,179 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CodeMatrix
{
/// <summary>
/// 表示代码目标序列控件 游戏中的目标序列
/// </summary>
/// <seealso cref="System.Windows.Forms.Control" />
public class UCCodeTarget : Control
{
public Size CellSize { get; private set; }
public Padding CellMargin { get; set; }
/// <summary>
/// The maximum buffer size
/// </summary>
private const int MaximumBufferSize = 10;
/// <summary>
/// The minimum buffer size
/// </summary>
private const int MinimumBufferSize = 4;
/// <summary>
/// The minimum target length
/// </summary>
private const int MinimumTargetLength = 2;
/// <summary>
/// The KMP next Array
/// </summary>
private readonly int[] _Next = new int[MaximumBufferSize];
/// <summary>
/// The target codes
/// </summary>
private readonly byte[] _TargetCodes = new byte[MaximumBufferSize];
/// <summary>
/// The buffer size
/// </summary>
private int _BufferSize = 4;
/// <summary>
/// The cell margin
/// </summary>
private Padding _CellMargin;
/// <summary>
/// The cell size
/// </summary>
private Size _CellSize;
/// <summary>
/// The curr state
/// </summary>
private State _CurrState;
/// <summary>
/// The hover code
/// </summary>
private byte _HoverCode;
/// <summary>
/// The is loaded
/// </summary>
private bool _IsLoaded;
/// <summary>
/// The offset index
/// </summary>
private int _OffsetIndex;
/// <summary>
/// The target length
/// </summary>
private int _TargetLength = 3;
/// <summary>
/// The hover index
/// </summary>
private int HoverIndex = -1;
/// <summary>
/// Initializes a new instance of the <see cref="UCCodeTarget"/> class.
/// </summary>
public UCCodeTarget()
{
InitComponent();
}
/// <summary>
/// Occurs when [code target state changed event].
/// </summary>
public event EventHandler CodeTargetStateChangedEvent;
/// <summary>
/// Occurs when [hover code event].
/// </summary>
public event EventHandler<byte> HoverCodeEvent;
/// <summary>
/// 状态枚举
/// </summary>
public enum State
{
/// <summary>
/// 输入中
/// </summary>
Input,
/// <summary>
/// 已通过/已安装
/// </summary>
Pass,
/// <summary>
/// 已拒绝
/// </summary>
Reject,
}
/// <summary>
/// Gets or sets the size of the buffer.
/// </summary>
/// <value>
/// The size of the buffer.
/// </value>
/// <exception cref="ArgumentOutOfRangeException">BufferSize - 设置缓冲区大小数值不能小于 {MinimumBufferSize} 或者大于 {MaximumBufferSize}</exception>
public int BufferSize
{
get => _BufferSize;
set
{
if (_BufferSize != value)
{
if (value < MinimumBufferSize || value > MaximumBufferSize)
throw new ArgumentOutOfRangeException("BufferSize", value, $"设置缓冲区大小数值不能小于 {MinimumBufferSize} 或者大于 {MaximumBufferSize}");
_BufferSize = value;
OnBufferSizeChanged();
}
}
}
/// <summary>
/// 获取当前正在输入的下标位置
/// </summary>
/// <value>
/// 当前正在输入的下标位置
/// </value>
public int CurrIndex { get; private set; }
/// <summary>
/// 获取当前序列的输入状态
/// </summary>
/// <value>
/// 当前序列的输入状态
/// </value>
public State CurrState
{
get => _CurrState;
private set
{
if (_CurrState != value)
{
_CurrState = value;
OnTargetStateChanged();
}
}
}
/// <summary>
/// Gets or sets the hover code.
/// </summary>
/// <value>
/// The hover code.
/// </value>
public byte HoverCode
{
get => _HoverCode;
@ -25,173 +186,33 @@ namespace CodeMatrix
}
}
}
public event EventHandler<byte> HoverCodeEvent;
public int BufferSize { get; set; }
public int TargetLength { get; set; }
public int OffsetIndex { get; private set; }
public int CurrIndex { get; private set; }
public byte[] TargetCodes { get; } = new byte[32];
private int[] _Next = new int[32];
public enum State
/// <summary>
/// Gets or sets the length of the target.
/// </summary>
/// <value>
/// The length of the target.
/// </value>
/// <exception cref="ArgumentOutOfRangeException">TargetLength - 设置目标序列长度不能小于 {MinimumTargetLength} 或者大于缓冲区大小</exception>
public int TargetLength
{
Input,
Pass,
Reject,
}
public State CurrState { get; private set; }
public UCCodeTarget()
{
InitData();
InitComponent();
}
private void InitData()
{
BufferSize = 9;
TargetLength = Common.Random.Next(3, 6);
OffsetIndex = 0;
CurrIndex = 0;
HoverCode = 0;
CurrState = State.Input;
for (int i = 0; i < TargetLength; i++)
TargetCodes[i] = Common.Codes[Common.Random.Next(Common.Codes.Length)];
_Next[0] = -1;
_Next[1] = 0;
for (int i = 1, j = 0; i < TargetLength;)
get => _TargetLength;
set
{
if (j == -1 || TargetCodes[i] == TargetCodes[j])
if (_TargetLength != value)
{
i++;
j++;
if (TargetCodes[i] != TargetCodes[j])
_Next[i] = j;
else
_Next[i] = _Next[j];
}
else
{
j = _Next[j];
if (value < MinimumBufferSize || value > BufferSize)
throw new ArgumentOutOfRangeException("TargetLength", value, $"设置目标序列长度不能小于 {MinimumTargetLength} 或者大于缓冲区大小");
_TargetLength = value;
OnTargetLengthChanged();
}
}
}
private void InitComponent()
{
CellSize = Styles.Default.CellSizeB;
Margin = Padding.Empty;
Padding = new Padding(10, 5, 10, 5);
CellMargin = new Padding(3);
MinimumSize = new Size((CellSize.Width + CellMargin.Horizontal) * BufferSize + Padding.Horizontal,
CellSize.Height + CellMargin.Vertical + Padding.Vertical);
DoubleBuffered = true;
Font = Styles.Default.CodeFontB;
BackColor = Styles.Default.BackColor;
ForeColor = Styles.Default.CodeColor;
}
protected override void OnPaint(PaintEventArgs e)
{
if (CurrState == State.Pass)
{
e.Graphics.FillRectangle(Styles.Default.PassBrush, ClientRectangle);
}
else if (CurrState == State.Reject)
{
e.Graphics.FillRectangle(Styles.Default.RejectBrush, ClientRectangle);
}
else
{
var cellOffset = new Rectangle(Padding.Left + CellMargin.Left,
Padding.Top + CellMargin.Top,
CellSize.Width-1,
CellSize.Height-1);
var cellOffsetWidth = CellSize.Width + CellMargin.Horizontal;
cellOffset.X += cellOffsetWidth * OffsetIndex;
int i = 0;
for (; i < CurrIndex && i < TargetLength; i++)
{
DrawCode(e.Graphics, TargetCodes[i], Font, Styles.Default.CodeBrush, cellOffset, Styles.Default.SelectedCellBorderPen);
cellOffset.X += cellOffsetWidth;
}
e.Graphics.FillRectangle(Styles.Default.CurrIndexBrush, cellOffset.X, 0, cellOffset.Width, this.Height);
if (i == CurrIndex && HoverCode == TargetCodes[i])
{
DrawCode(e.Graphics, TargetCodes[CurrIndex], Font, Styles.Default.SelectBrush, cellOffset, Styles.Default.SelectCellBorderPen);
cellOffset.X += cellOffsetWidth;
i++;
}
for (; i < TargetLength; i++)
{
DrawCode(e.Graphics, TargetCodes[i], Font, Styles.Default.ToBeSelectBrush, cellOffset);
cellOffset.X += cellOffsetWidth;
}
}
base.OnPaint(e);
}
private void DrawCode(Graphics g, byte code, Font font, Brush brush, Rectangle cellRect, Pen borderPen = null)
{
if (borderPen != null)
g.DrawRectangle(borderPen, cellRect);
var codeStr = code.ToString("X2");
var codeSize = g.MeasureString(codeStr, font);
var codeOffset = new PointF((CellSize.Width-codeSize.Width)/2, (CellSize.Height-codeSize.Height)/2);
var codePoint = new PointF(codeOffset.X+cellRect.X, codeOffset.Y+cellRect.Y);
g.DrawString(codeStr, font, brush, codePoint);
}
private int HoverIndex = -1;
protected override void OnMouseMove(MouseEventArgs e)
{
if (CurrState == State.Input)
{
int hoverIndex = -1;
//Point currPoint = new Point(e.X - Padding.Left, e.Y - Padding.Top - CellMargin.Top);
//if (currPoint.X >= 0 && currPoint.Y >= 0 && currPoint.Y < CellSize.Height)
//{
// int cellfullwidth = CellSize.Width + CellMargin.Horizontal;
// int index = currPoint.X / cellfullwidth - OffsetIndex;
// int offset = currPoint.X % cellfullwidth;
// if (offset > CellMargin.Left && offset < cellfullwidth - CellMargin.Left)
// {
// if (index >= 0 && index < TargetLength)
// {
// hoverIndex = index;
// }
// }
//}
Point currPoint = new Point(e.X - Padding.Left, e.Y - Padding.Top);
if (currPoint.X >= 0 && currPoint.Y >= 0 && currPoint.Y < CellSize.Height)
{
int cellfullwidth = CellSize.Width + CellMargin.Horizontal;
int index = currPoint.X / cellfullwidth - OffsetIndex;
if (index >= 0 && index < TargetLength)
{
hoverIndex = index;
}
}
if (HoverIndex != hoverIndex)
{
HoverIndex = hoverIndex;
if (HoverIndex >= 0)
HoverCodeEvent?.Invoke(this, TargetCodes[HoverIndex]);
else
HoverCodeEvent?.Invoke(this, 0);
}
}
base.OnMouseMove(e);
}
/// <summary>
/// Inputs the code.
/// </summary>
/// <param name="code">The code.</param>
public void InputCode(byte code)
{
if (CurrState == State.Input)
@ -203,7 +224,7 @@ namespace CodeMatrix
CurrIndex = 0;
break;
}
if (code == TargetCodes[CurrIndex])
if (code == _TargetCodes[CurrIndex])
{
CurrIndex++;
break;
@ -211,22 +232,213 @@ namespace CodeMatrix
else
{
var next = _Next[CurrIndex];
OffsetIndex += CurrIndex - next;
_OffsetIndex += CurrIndex - next;
CurrIndex = next;
}
}
if (OffsetIndex + TargetLength > BufferSize)
if (_OffsetIndex + TargetLength > BufferSize)
CurrState = State.Reject;
else if (CurrIndex == TargetLength)
CurrState = State.Pass;
}
}
public void ClearBuffer()
/// <summary>
/// Reloads the target sequence.
/// </summary>
public void ReloadTargetSequence()
{
_OffsetIndex = 0;
CurrIndex = 0;
HoverCode = 0;
CurrState = State.Input;
GenerateTargetSequence();
Invalidate();
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (CurrState == State.Input)
{
int hoverIndex = -1;
Point currPoint = new Point(e.X - Padding.Left, e.Y - Padding.Top);
if (currPoint.X >= 0 && currPoint.Y >= 0 && currPoint.Y < _CellSize.Height)
{
int cellfullwidth = _CellSize.Width + _CellMargin.Horizontal;
int index = currPoint.X / cellfullwidth - _OffsetIndex;
if (index >= 0 && index < TargetLength)
{
hoverIndex = index;
}
}
if (HoverIndex != hoverIndex)
{
HoverIndex = hoverIndex;
if (HoverIndex >= 0)
HoverCodeEvent?.Invoke(this, _TargetCodes[HoverIndex]);
else
HoverCodeEvent?.Invoke(this, 0);
}
}
base.OnMouseMove(e);
}
protected override void OnPaint(PaintEventArgs e)
{
if (CurrState == State.Pass)
{
e.Graphics.FillRectangle(Styles.Default.PassBrush, ClientRectangle);
e.Graphics.DrawString("已安装", Font, Brushes.Black, 20, 8);
}
else if (CurrState == State.Reject)
{
e.Graphics.FillRectangle(Styles.Default.RejectBrush, ClientRectangle);
e.Graphics.DrawString("失败", Font, Brushes.Black, 20, 8);
}
else
{
var cellOffset = new Rectangle(Padding.Left + _CellMargin.Left,
Padding.Top + _CellMargin.Top,
_CellSize.Width-1,
_CellSize.Height-1);
var cellOffsetWidth = _CellSize.Width + _CellMargin.Horizontal;
cellOffset.X += cellOffsetWidth * _OffsetIndex;
int i = 0;
for (; i < CurrIndex && i < TargetLength; i++)
{
DrawCode(e.Graphics, _TargetCodes[i], Font, Styles.Default.CodeBrush, cellOffset, Styles.Default.SelectedCellBorderPen);
cellOffset.X += cellOffsetWidth;
}
e.Graphics.FillRectangle(Styles.Default.CurrIndexBrush, cellOffset.X, 0, cellOffset.Width, this.Height);
if (i == CurrIndex && HoverCode == _TargetCodes[i])
{
DrawCode(e.Graphics, _TargetCodes[CurrIndex], Font, Styles.Default.SelectBrush, cellOffset, Styles.Default.SelectCellBorderPen);
cellOffset.X += cellOffsetWidth;
i++;
}
for (; i < TargetLength; i++)
{
DrawCode(e.Graphics, _TargetCodes[i], Font, Styles.Default.ToBeSelectBrush, cellOffset);
cellOffset.X += cellOffsetWidth;
}
}
base.OnPaint(e);
}
protected override void OnVisibleChanged(EventArgs e)
{
if (Visible && !_IsLoaded)
{
OnLoad();
_IsLoaded = true;
}
base.OnVisibleChanged(e);
}
/// <summary>
/// Draws the code.
/// </summary>
/// <param name="g">The graphics.</param>
/// <param name="code">The code.</param>
/// <param name="font">The font.</param>
/// <param name="brush">The brush.</param>
/// <param name="cellRect">The cell rect.</param>
/// <param name="borderPen">The border pen.</param>
private void DrawCode(Graphics g, byte code, Font font, Brush brush, Rectangle cellRect, Pen borderPen = null)
{
if (borderPen != null)
g.DrawRectangle(borderPen, cellRect);
var codeStr = code.ToString("X2");
var codeSize = g.MeasureString(codeStr, font);
var codeOffset = new PointF((_CellSize.Width-codeSize.Width)/2, (_CellSize.Height-codeSize.Height)/2);
var codePoint = new PointF(codeOffset.X+cellRect.X, codeOffset.Y+cellRect.Y);
g.DrawString(codeStr, font, brush, codePoint);
}
/// <summary>
/// Generates the target sequence.
/// </summary>
private void GenerateTargetSequence()
{
for (int i = 0; i < TargetLength; i++)
_TargetCodes[i] = Common.Codes[Common.Random.Next(Common.Codes.Length)];
_Next[0] = -1;
_Next[1] = 0;
for (int i = 1, j = 0; i < TargetLength;)
{
if (j == -1 || _TargetCodes[i] == _TargetCodes[j])
{
i++;
j++;
if (_TargetCodes[i] != _TargetCodes[j])
_Next[i] = j;
else
_Next[i] = _Next[j];
}
else
{
j = _Next[j];
}
}
}
/// <summary>
/// Initializes the component.
/// </summary>
private void InitComponent()
{
_CellSize = Styles.Default.CellSizeB;
Margin = Padding.Empty;
Padding = new Padding(10, 5, 10, 5);
_CellMargin = new Padding(3);
MinimumSize = new Size((_CellSize.Width + _CellMargin.Horizontal) * BufferSize + Padding.Horizontal,
_CellSize.Height + _CellMargin.Vertical + Padding.Vertical);
DoubleBuffered = true;
Font = Styles.Default.CodeFontB;
BackColor = Styles.Default.BackColor;
ForeColor = Styles.Default.CodeColor;
}
/// <summary>
/// Called when [buffer size changed].
/// </summary>
private void OnBufferSizeChanged()
{
if (TargetLength > BufferSize)
TargetLength = BufferSize;
else
ReloadTargetSequence();
}
/// <summary>
/// Called when [load].
/// </summary>
private void OnLoad()
{
ReloadTargetSequence();
}
/// <summary>
/// Called when [target length changed].
/// </summary>
private void OnTargetLengthChanged()
{
ReloadTargetSequence();
}
/// <summary>
/// Called when [target state changed].
/// </summary>
private void OnTargetStateChanged()
{
CodeTargetStateChangedEvent?.Invoke(this, EventArgs.Empty);
}
}
}
}