using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using Core.Common.Controls.Charting.Series;
using Core.Common.Controls.Charting.Properties;
using Steema.TeeChart;
using Steema.TeeChart.Drawing;
using Steema.TeeChart.Styles;
using Steema.TeeChart.Tools;
namespace Core.Common.Controls.Charting.Tools
{
///
/// Describes the possible values of the property.
///
public enum NearestPointStyles
{
///
/// No shape is drawn.
///
None,
///
/// Shape is a circle.
///
Circle,
///
/// Shape is a rectangle.
///
Rectangle,
///
/// Shape is a diamond.
///
Diamond
};
public class SelectPoint
{
internal SelectPoint(Steema.TeeChart.Styles.Series series, int pointIndex)
{
Series = series;
PointIndex = pointIndex;
}
///
/// The index of the point in the datasource.
///
public int PointIndex { get; private set; }
internal Steema.TeeChart.Styles.Series Series { get; private set; }
}
///
/// Interactive selection of points of a specific series on the chart.
///
public class SelectPointTool : ChartViewSeriesToolBase
{
public event EventHandler SelectedChartPointsChanged;
private readonly ICollection selectedPoints = new HashSet();
private readonly bool dragging = false;
private readonly int Point = -1;
private readonly Steema.TeeChart.Styles.PointerStyles selectedPointerStyle = Steema.TeeChart.Styles.PointerStyles.Diamond;
private bool drawLine = true;
private bool fullRepaint = true;
private Point mouseLocation;
private Color selectedPointerColor = SystemColors.Highlight;
private int size = 10;
private NearestPointStyles style = NearestPointStyles.Circle;
internal SelectPointTool(Steema.TeeChart.Chart c) : base(c)
{
Pen.Style = DashStyle.Dot;
Pen.Color = Color.White;
HandleDelete = true;
}
///
/// Gets descriptive text.
///
public override string Description
{
get
{
return Texts.NearestTool;
}
}
///
/// Gets detailed descriptive text.
///
public override string Summary
{
get
{
return Texts.NearestPointSummary;
}
}
///
/// Draws a temporary line from the mouse coordinates to the nearest point.
///
public bool DrawLine
{
get
{
return drawLine;
}
set
{
SetBooleanProperty(ref drawLine, value);
}
}
///
/// Allows the whole Parent Chart to repainted when true.
///
public bool FullRepaint
{
get
{
return fullRepaint;
}
set
{
SetBooleanProperty(ref fullRepaint, value);
}
}
///
/// Determines whether the selectTool should delete point when DEL is pressed
///
public bool HandleDelete { get; set; }
///
/// Color of the point selected in the chart
///
public Color SelectedPointerColor
{
get
{
return selectedPointerColor;
}
set
{
selectedPointerColor = value;
}
}
///
/// Defines the Size of the NearestTool shape.
///
public int Size
{
get
{
return size;
}
set
{
SetIntegerProperty(ref size, value);
}
}
///
/// Sets the shape of the NearestTool.
///
public NearestPointStyles Style
{
get
{
return style;
}
set
{
if (style != value)
{
style = value;
Invalidate();
}
}
}
public Cursor Cursor { get; set; }
///
/// Add point a pointIndex for series to selectedPoints
///
///
///
public void AddPointAtIndexToSelection(IChartSeries series, int pointIndex)
{
var teeChartSeries = ((ChartSeries)series).series;
SelectChartPoint(teeChartSeries, pointIndex);
}
public void ClearSelection()
{
selectedPoints.Clear();
FireSelectedChartPointsChangedEvent();
SelectedPointIndex = -1;
}
protected override void OnCustomSeriesGetPointerStyle(CustomPoint series, GetPointerStyleEventArgs e)
{
if (e.ValueIndex == selectedPointIndex)
{
e.Color = selectedPointerColor;
e.Style = selectedPointerStyle;
}
}
protected override void Assign(Tool t)
{
base.Assign(t);
SelectPointTool tmp = t as SelectPointTool;
tmp.Brush = Brush.Clone() as ChartBrush;
tmp.DrawLine = DrawLine;
tmp.FullRepaint = FullRepaint;
tmp.Pen = Pen.Clone() as ChartPen;
tmp.Style = Style;
}
protected override void ChartEvent(EventArgs e)
{
base.ChartEvent(e);
if (e is AfterDrawEventArgs)
{
PaintHint();
}
}
protected override void KeyEvent(KeyEventArgs e)
{
base.KeyEvent(e);
if (HandleDelete && (e.KeyCode == Keys.Delete) && (selectedPointIndex != -1) && (null != iSeries))
{
// try to delete point from datasource
DataTable dataTable = iSeries.DataSource as DataTable;
if (dataTable != null)
{
dataTable.Rows[selectedPointIndex].Delete();
}
else
{
throw new NotImplementedException(Resources.KeyEvent_Deletion_not_implemented_for_this_type_of_datasource);
}
//// delete selected point from the series
//Series.Delete(selectedPointIndex);
//selectedPointIndex = -1;
//// todo make sure event is fired, either from tool or series object.
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
ClearSelection();
AddClickedPoint(e.X, e.Y);
Invalidate();
}
protected override void OnMouseMove(MouseEventArgs e, ref Cursor c)
{
Point P = new Point(e.X, e.Y);
if (!dragging)
{
Steema.TeeChart.Styles.Series s = ClickedSeries(P);
if (s != null)
{
int abovePoint = s.Clicked(P);
if (abovePoint > -1)
{
c = Cursor ?? Cursors.Cross;
//new Cursor(Assembly.GetExecutingAssembly().GetManifestResourceStream("Steema.TeeChart.Cursors.moveTracker.cur"));
}
Chart.CancelMouse = true;
}
else
{
c = Cursors.Default;
}
}
}
///
/// Element Pen characteristics.
///
private ChartPen Pen
{
get
{
if (pPen == null)
{
pPen = new ChartPen(Chart, Color.Blue);
}
return pPen;
}
set
{
pPen = value;
}
}
///
/// Element Brush characteristics.
///
private ChartBrush Brush
{
get
{
return bBrush ?? (bBrush = new ChartBrush(Chart, Color.HotPink, false));
}
set
{
bBrush = value;
}
}
private void SelectChartPoint(Steema.TeeChart.Styles.Series teeChartSeries, int pointIndex)
{
if (!selectedPoints.Any(p => p.Series == teeChartSeries && p.PointIndex == pointIndex))
{
var selectPoint = new SelectPoint(teeChartSeries, pointIndex);
selectedPoints.Add(selectPoint);
FireSelectedChartPointsChangedEvent();
}
}
private void FireSelectedChartPointsChangedEvent()
{
if (SelectedChartPointsChanged != null)
{
SelectedChartPointsChanged(this, EventArgs.Empty);
}
}
private void PaintHint()
{
if (selectedPoints.Count > 0)
{
var brush = new SolidBrush(selectedPointerColor);
Graphics3D g = Chart.Graphics3D;
foreach (var point in selectedPoints)
{
//the points might have been deleted (multi threading crap)
if (point.PointIndex > point.Series.XValues.Count - 1)
{
return;
}
//no selection, don't draw
if (point.PointIndex < 0)
{
continue;
}
int x = point.Series.CalcXPos(point.PointIndex);
int y = point.Series.CalcYPos(point.PointIndex);
// Local copy to prevent compiler warning CS1690 (https://msdn.microsoft.com/en-us/library/x524dkh4.aspx)
var chartRect = Chart.ChartRect;
if (!chartRect.Contains(x, y)) //outside chart area
{
continue;
}
g.Pen = Pen;
g.Brush = Brush;
g.FillRectangle(brush, (int)(x - size * 0.5), (int)(y - size * 0.5), size, size);
/*
g.Rectangle(new Rectangle(2, 2, totalWidth - 1, totaHeight - 1));
g.FillRectangle(brush, new Rectangle(2, 2, width, height));
g.Rectangle(pen, new Rectangle(2, 2, width - 1, height - 1));
g.FillRectangle(brush, new Rectangle(totalWidth - width + 2, 2, width, height));
g.Rectangle(pen, new Rectangle(totalWidth - width + 2, 2, width - 1, height - 1));
g.FillRectangle(brush, new Rectangle(totalWidth - width + 2, totaHeight - height + 2, width, height));
g.Rectangle(pen, new Rectangle(totalWidth - width + 2, totaHeight - height + 2, width - 1, height - 1));
g.FillRectangle(brush, new Rectangle(2, totaHeight - height + 2, width, height));
g.Rectangle(pen, new Rectangle(2, totaHeight - height + 2, width - 1, height - 1));
*/
}
brush.Dispose();
//g.Dispose();
}
if ((iSeries != null) && (Point != -1))
{
Graphics3D g = Chart.Graphics3D;
g.Pen = Pen;
int x = iSeries.CalcXPos(Point);
int y = iSeries.CalcYPos(Point);
if (style != NearestPointStyles.None)
{
g.Brush = Brush;
Rectangle r = Rectangle.FromLTRB(x - size, y - size, x + size, y + size);
switch (style)
{
case NearestPointStyles.Circle:
if (Chart.Aspect.View3D)
{
g.Ellipse(r, iSeries.StartZ);
}
else
{
g.Ellipse(r);
}
break;
case NearestPointStyles.Rectangle:
{
if (Chart.Aspect.View3D)
{
g.Rectangle(r, iSeries.StartZ);
}
else
{
g.Rectangle(r);
}
}
break;
case NearestPointStyles.Diamond:
{
Point[] P = new Point[4];
P[0] = new Point(x, y - size);
P[1] = new Point(x + size, y);
P[2] = new Point(x, y + size);
P[3] = new Point(x - size, y);
g.Polygon(iSeries.StartZ, P);
}
break;
}
}
if (drawLine)
{
g.Pen.Style = DashStyle.Solid;
g.MoveTo(mouseLocation);
g.LineTo(x, y);
}
}
}
private void AddClickedPoint(int x, int y)
{
mouseLocation = new Point(x, y);
//don't remove this..otherwise firstlastvisibleindex will be -1 so the selecttool doesn't work
if (iSeries != null)
{
//// iSeries.CalcFirstLastVisibleIndex is changed from public to internal and we do not want to modify TeeChart
MethodInfo calcFirstLastVisibleIndex = iSeries.GetType().GetMethod("CalcFirstLastVisibleIndex", BindingFlags.NonPublic | BindingFlags.Instance);
calcFirstLastVisibleIndex.Invoke(iSeries, new object[]
{});
}
var clickedSeries = ClickedSeries(mouseLocation);
if (clickedSeries != null)
{
LastSelectedSeries = clickedSeries;
SelectedPointIndex = TeeChartHelper.GetNearestPoint(clickedSeries, mouseLocation, 4);
if (SelectedPointIndex > -1)
{
SelectChartPoint(clickedSeries, SelectedPointIndex);
}
}
}
}
}