The code of the Rectangle graphic object
//------------------------------------------------------------------------------ // // Графический объект Rectangle. Copyright (c) 2020 Ilya Smirnov. All rights reserved. // //------------------------------------------------------------------------------ using System; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.Serialization; using System.Windows; using System.Windows.Media; using TigerTrade.Chart.Base; using TigerTrade.Chart.Base.Enums; using TigerTrade.Chart.Objects.Common; using TigerTrade.Dx; using TigerTrade.Dx.Enums; namespace TigerTrade.Chart.Objects.Custom { [DataContract(Name = "RectangleObject", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Objects.Custom")] [ChartObject("X_Rectangle", "Прямоугольник", 2, Type = typeof(RectangleObject))] public sealed class RectangleObject : ObjectBase { private bool _drawBorder; [DataMember(Name = "DrawBorder")] [Category("Граница"), DisplayName("Граница")] public bool DrawBorder { get => _drawBorder; set { if (value == _drawBorder) { return; } _drawBorder = value; OnPropertyChanged(); } } private XBrush _lineBrush; private XPen _linePen; private XColor _lineColor; [DataMember(Name = "LineColor")] [Category("Граница"), DisplayName("Цвет линии")] public XColor LineColor { get => _lineColor; set { if (value == _lineColor) { return; } _lineColor = value; _lineBrush = new XBrush(_lineColor); _linePen = new XPen(_lineBrush, LineWidth, LineStyle); OnPropertyChanged(); } } private int _lineWidth; [DataMember(Name = "LineWidth")] [Category("Граница"), DisplayName("Толщина линии")] public int LineWidth { get => _lineWidth; set { value = Math.Max(1, Math.Min(10, value)); if (value == _lineWidth) { return; } _lineWidth = value; _linePen = new XPen(_lineBrush, _lineWidth, LineStyle); OnPropertyChanged(); } } private XDashStyle _lineStyle; [DataMember(Name = "LineStyle")] [Category("Граница"), DisplayName("Стиль линии")] public XDashStyle LineStyle { get => _lineStyle; set { if (value == _lineStyle) { return; } _lineStyle = value; _linePen = new XPen(_lineBrush, LineWidth, _lineStyle); OnPropertyChanged(); } } private bool _drawBack; [DataMember(Name = "DrawBack")] [Category("Фон"), DisplayName("Фон")] public bool DrawBack { get => _drawBack; set { if (value == _drawBack) { return; } _drawBack = value; OnPropertyChanged(); } } private XBrush _backBrush; private XColor _backColor; [DataMember(Name = "BackColor")] [Category("Фон"), DisplayName("Цвет фона")] public XColor BackColor { get => _backColor; set { if (value == _backColor) { return; } _backColor = value; _backBrush = new XBrush(_backColor); OnPropertyChanged(); } } protected override int PenWidth => LineWidth; private bool _isObjectInArea; public class RectangleInfo { public Point ControlPoint1; public Point ControlPoint2; public Point ExtraPoint1; public Point ExtraPoint2; public Rect Rectangle; } private RectangleInfo _rectInfo; public RectangleObject() { DrawBorder = true; LineColor = Colors.Black; LineWidth = 1; LineStyle = XDashStyle.Solid; DrawBack = true; BackColor = Color.FromArgb(30, 0, 0, 0); } protected override void Prepare() { var point1 = ToPoint(ControlPoints[0]); var point2 = ToPoint(ControlPoints[1]); var ep1 = ToPoint(ExtraPoints[0]); var ep2 = ToPoint(ExtraPoints[1]); var w = Canvas.ColumnWidth / 2.0; var h = Canvas.StepHeight / 2.0; var extendHeight = Canvas.StockType == ChartStockType.Clusters; if (point1.X > point2.X) { point1.X += w; point2.X -= w; } else { point1.X -= w; point2.X += w; } if (extendHeight) { if (point1.Y > point2.Y) { point1.Y += h; point2.Y -= h; } else { point1.Y -= h; point2.Y += h; } } if (ep1.X > ep2.X) { ep1.X += w; ep2.X -= w; } else { ep1.X -= w; ep2.X += w; } if (extendHeight) { if (ep1.Y > ep2.Y) { ep1.Y += h; ep2.Y -= h; } else { ep1.Y -= h; ep2.Y += h; } } _rectInfo = new RectangleInfo { ControlPoint1 = point1, ControlPoint2 = point2, ExtraPoint1 = ep1, ExtraPoint2 = ep2, Rectangle = new Rect(point1, point2) }; _isObjectInArea = Canvas.Rect.IntersectsWith(_rectInfo.Rectangle); } protected override void Draw(DxVisualQueue visual, ref List<ObjectLabelInfo> labels) { if (DrawBack) { visual.FillRectangle(_backBrush, _rectInfo.Rectangle); } if (DrawBorder) { visual.DrawRectangle(_linePen, _rectInfo.Rectangle); } } public override void DrawControlPoints(DxVisualQueue visual) { if (_rectInfo == null) { return; } DrawControlPoint(visual, _rectInfo.ControlPoint1); DrawControlPoint(visual, _rectInfo.ControlPoint2); DrawControlPoint(visual, _rectInfo.ExtraPoint1); DrawControlPoint(visual, _rectInfo.ExtraPoint2); } public override int GetControlPoint(int x, int y) { if (Canvas == null || _rectInfo == null) { return -1; } var points = new[] { _rectInfo.ControlPoint1, _rectInfo.ControlPoint2 }; for (var i = 0; i < points.Length; i++) { var distX = points[i].X - x; var distY = points[i].Y - y; if (distX * distX + distY * distY < 9.0 + PenWidth / 2.0) { return i; } } return -1; } public override int GetExtraPoint(int x, int y) { if (Canvas == null || _rectInfo == null) { return -1; } var points = new[] { _rectInfo.ExtraPoint1, _rectInfo.ExtraPoint2 }; for (var i = 0; i < points.Length; i++) { var distX = points[i].X - x; var distY = points[i].Y - y; if (distX * distX + distY * distY < 9.0 + PenWidth / 2.0) { return i; } } return -1; } protected override bool IsObjectInArea() { return _isObjectInArea; } protected override bool InObject(int x, int y) { if (_rectInfo == null) { return false; } return _rectInfo.Rectangle != Rect.Empty && _rectInfo.Rectangle.Contains(x, y); } protected override int GetMinDist(int x, int y) { var rect = _rectInfo.Rectangle; var dx = Math.Min(rect.X + rect.Width - x, x - rect.X); var dy = Math.Min(rect.Y + rect.Height - y, y - rect.Y); var result = Math.Min(dx, dy); return result > 0 ? (int)result : -1; } public override ObjectPoint[] ExtraPoints { get { var cp1 = ControlPoints[0]; var cp2 = ControlPoints[1]; var ep1 = new ObjectPoint(cp2.X, cp1.Y); var ep2 = new ObjectPoint(cp1.X, cp2.Y); var extraPoints = new[] { ep1, ep2 }; return extraPoints; } } public override void ExtraPointChanged(int index, ObjectPoint op) { switch (index) { case 0: ControlPoints[1].X = op.X; ControlPoints[0].Y = op.Y; break; case 1: ControlPoints[0].X = op.X; ControlPoints[1].Y = op.Y; break; } } public override void ApplyTheme(IChartTheme theme) { base.ApplyTheme(theme); LineColor = theme.ChartObjectLineColor; BackColor = theme.ChartObjectFillColor; } public override void CopyTemplate(ObjectBase objectBase, bool style) { if (objectBase is RectangleObject obj) { DrawBorder = obj.DrawBorder; LineColor = obj.LineColor; LineWidth = obj.LineWidth; LineStyle = obj.LineStyle; DrawBack = obj.DrawBack; BackColor = obj.BackColor; } base.CopyTemplate(objectBase, style); } } }