[683] | 1 | using System;
|
---|
[861] | 2 | using System.Collections.Generic;
|
---|
[1244] | 3 | using System.Diagnostics;
|
---|
[928] | 4 | using System.Drawing;
|
---|
| 5 | using System.Windows.Forms;
|
---|
[697] | 6 | using HeuristicLab.Core;
|
---|
[1233] | 7 | using HeuristicLab.Visualization.Legend;
|
---|
[1195] | 8 | using HeuristicLab.Visualization.Options;
|
---|
[683] | 9 |
|
---|
[861] | 10 | namespace HeuristicLab.Visualization {
|
---|
[1187] | 11 | public partial class LineChart : ViewBase {
|
---|
| 12 | internal class LinesShape : WorldShape {}
|
---|
[697] | 13 | private readonly IChartDataRowsModel model;
|
---|
[1240] | 14 | private readonly Canvas canvas;
|
---|
| 15 |
|
---|
[981] | 16 | private int maxDataRowCount;
|
---|
| 17 | private Boolean zoomFullView;
|
---|
| 18 | private double minDataValue;
|
---|
| 19 | private double maxDataValue;
|
---|
[1242] | 20 |
|
---|
[684] | 21 |
|
---|
[1038] | 22 | private readonly TextShape titleShape;
|
---|
| 23 | private readonly LinesShape linesShape;
|
---|
[1049] | 24 | private readonly LegendShape legendShape;
|
---|
[1038] | 25 |
|
---|
[983] | 26 | private readonly XAxis xAxis;
|
---|
[1182] | 27 | private readonly YAxis yAxis;
|
---|
| 28 | private readonly Grid grid;
|
---|
[983] | 29 |
|
---|
[1240] | 30 | private readonly WorldShape berni;
|
---|
| 31 | private readonly RectangleShape mousePointer;
|
---|
| 32 |
|
---|
[697] | 33 | /// <summary>
|
---|
| 34 | /// This constructor shouldn't be called. Only required for the designer.
|
---|
| 35 | /// </summary>
|
---|
[861] | 36 | public LineChart() {
|
---|
[684] | 37 | InitializeComponent();
|
---|
| 38 | }
|
---|
| 39 |
|
---|
[697] | 40 | /// <summary>
|
---|
| 41 | /// Initializes the chart.
|
---|
| 42 | /// </summary>
|
---|
[754] | 43 | /// <param name="model">Referenz to the model, for data</param>
|
---|
[861] | 44 | public LineChart(IChartDataRowsModel model) : this() {
|
---|
[1045] | 45 | if (model == null) {
|
---|
[697] | 46 | throw new NullReferenceException("Model cannot be null.");
|
---|
[1045] | 47 | }
|
---|
[684] | 48 |
|
---|
[1242] | 49 |
|
---|
[1240] | 50 | canvas = canvasUI.Canvas;
|
---|
[983] | 51 |
|
---|
[1182] | 52 | grid = new Grid();
|
---|
[1240] | 53 | canvas.AddShape(grid);
|
---|
[1038] | 54 |
|
---|
[1182] | 55 | linesShape = new LinesShape();
|
---|
[1240] | 56 | canvas.AddShape(linesShape);
|
---|
[1038] | 57 |
|
---|
[1182] | 58 | xAxis = new XAxis();
|
---|
[1240] | 59 | canvas.AddShape(xAxis);
|
---|
[983] | 60 |
|
---|
[1182] | 61 | yAxis = new YAxis();
|
---|
[1240] | 62 | canvas.AddShape(yAxis);
|
---|
[1182] | 63 |
|
---|
| 64 | titleShape = new TextShape(0, 0, model.Title, 15);
|
---|
[1240] | 65 | canvas.AddShape(titleShape);
|
---|
[1038] | 66 |
|
---|
[1242] | 67 | // horizontalLineShape = new HorizontalLineShape(this.maxDataValue, Color.Yellow, 4, DrawingStyle.Solid);
|
---|
| 68 | // root.AddShape(horizontalLineShape);
|
---|
[1195] | 69 |
|
---|
| 70 | legendShape = new LegendShape();
|
---|
[1240] | 71 | canvas.AddShape(legendShape);
|
---|
[1195] | 72 |
|
---|
[1240] | 73 | berni = new WorldShape();
|
---|
| 74 | canvas.AddShape(berni);
|
---|
| 75 |
|
---|
| 76 | mousePointer = new RectangleShape(10, 10, 20, 20, Color.Black);
|
---|
| 77 | berni.AddShape(mousePointer);
|
---|
| 78 |
|
---|
[1187] | 79 | maxDataRowCount = 0;
|
---|
[869] | 80 | this.model = model;
|
---|
[983] | 81 | Item = model;
|
---|
[1038] | 82 |
|
---|
[1240] | 83 | UpdateLayout();
|
---|
| 84 | canvasUI.Resize += delegate { UpdateLayout(); };
|
---|
[1187] | 85 |
|
---|
[981] | 86 | //The whole data rows are shown per default
|
---|
[1187] | 87 | ResetView();
|
---|
[697] | 88 | }
|
---|
[684] | 89 |
|
---|
[1038] | 90 | /// <summary>
|
---|
| 91 | /// Layout management - arranges the inner shapes.
|
---|
| 92 | /// </summary>
|
---|
| 93 | private void UpdateLayout() {
|
---|
| 94 | titleShape.X = 10;
|
---|
[1240] | 95 | titleShape.Y = canvasUI.Height - 10;
|
---|
[1038] | 96 |
|
---|
[1182] | 97 | const int yAxisWidth = 100;
|
---|
| 98 | const int xAxisHeight = 20;
|
---|
[1038] | 99 |
|
---|
[1182] | 100 | linesShape.BoundingBox = new RectangleD(yAxisWidth,
|
---|
| 101 | xAxisHeight,
|
---|
[1240] | 102 | canvasUI.Width,
|
---|
| 103 | canvasUI.Height);
|
---|
[1187] | 104 |
|
---|
[1240] | 105 | berni.BoundingBox = linesShape.BoundingBox;
|
---|
| 106 | berni.ClippingArea = new RectangleD(0, 0, berni.BoundingBox.Width, berni.BoundingBox.Height);
|
---|
| 107 |
|
---|
[1182] | 108 | grid.BoundingBox = linesShape.BoundingBox;
|
---|
| 109 |
|
---|
[1187] | 110 |
|
---|
[1182] | 111 | yAxis.BoundingBox = new RectangleD(0,
|
---|
| 112 | linesShape.BoundingBox.Y1,
|
---|
| 113 | linesShape.BoundingBox.X1,
|
---|
| 114 | linesShape.BoundingBox.Y2);
|
---|
| 115 |
|
---|
[1038] | 116 | xAxis.BoundingBox = new RectangleD(linesShape.BoundingBox.X1,
|
---|
| 117 | 0,
|
---|
| 118 | linesShape.BoundingBox.X2,
|
---|
| 119 | linesShape.BoundingBox.Y1);
|
---|
[1049] | 120 |
|
---|
[1240] | 121 | legendShape.BoundingBox = new RectangleD(10, 10, 110, canvasUI.Height - 50);
|
---|
[1195] | 122 | legendShape.ClippingArea = new RectangleD(0, 0, legendShape.BoundingBox.Width,
|
---|
| 123 | legendShape.BoundingBox.Height);
|
---|
[1038] | 124 | }
|
---|
| 125 |
|
---|
[985] | 126 | public void ResetView() {
|
---|
| 127 | zoomFullView = true;
|
---|
| 128 | ZoomToFullView();
|
---|
[1038] | 129 |
|
---|
[1240] | 130 | canvasUI.Invalidate();
|
---|
[985] | 131 | }
|
---|
| 132 |
|
---|
[1242] | 133 | private void optionsToolStripMenuItem_Click(object sender, EventArgs e) {
|
---|
| 134 | var optionsdlg = new OptionsDialog(this.model);
|
---|
| 135 | optionsdlg.ShowDialog(this);
|
---|
| 136 | }
|
---|
| 137 |
|
---|
| 138 | public void OnDataRowChanged(IDataRow row) {
|
---|
| 139 | foreach (LineShape ls in rowToLineShapes[row]) {
|
---|
| 140 | ls.LSColor = row.Color;
|
---|
| 141 | ls.LSThickness = row.Thickness;
|
---|
| 142 | ls.LSDrawingStyle = row.Style;
|
---|
| 143 | }
|
---|
| 144 | canvasUI.Invalidate();
|
---|
| 145 | }
|
---|
| 146 |
|
---|
[861] | 147 | #region Add-/RemoveItemEvents
|
---|
| 148 |
|
---|
[1242] | 149 | private readonly IDictionary<IDataRow, List<LineShape>> rowToLineShapes =
|
---|
| 150 | new Dictionary<IDataRow, List<LineShape>>();
|
---|
| 151 |
|
---|
[861] | 152 | protected override void AddItemEvents() {
|
---|
| 153 | base.AddItemEvents();
|
---|
| 154 |
|
---|
| 155 | model.DataRowAdded += OnDataRowAdded;
|
---|
| 156 | model.DataRowRemoved += OnDataRowRemoved;
|
---|
| 157 | model.ModelChanged += OnModelChanged;
|
---|
[869] | 158 |
|
---|
[1045] | 159 | foreach (IDataRow row in model.Rows) {
|
---|
[869] | 160 | OnDataRowAdded(row);
|
---|
[1045] | 161 | }
|
---|
[683] | 162 | }
|
---|
[684] | 163 |
|
---|
[861] | 164 | protected override void RemoveItemEvents() {
|
---|
| 165 | base.RemoveItemEvents();
|
---|
| 166 |
|
---|
| 167 | model.DataRowAdded -= OnDataRowAdded;
|
---|
| 168 | model.DataRowRemoved -= OnDataRowRemoved;
|
---|
| 169 | model.ModelChanged -= OnModelChanged;
|
---|
[697] | 170 | }
|
---|
| 171 |
|
---|
[861] | 172 | private void OnDataRowAdded(IDataRow row) {
|
---|
| 173 | row.ValueChanged += OnRowValueChanged;
|
---|
| 174 | row.ValuesChanged += OnRowValuesChanged;
|
---|
[1237] | 175 | row.DataRowChanged += OnDataRowChanged;
|
---|
| 176 |
|
---|
[1045] | 177 | if (row.Count > maxDataRowCount) {
|
---|
[981] | 178 | maxDataRowCount = row.Count;
|
---|
[1242] | 179 | // UpdateSingleValueRows();
|
---|
[1045] | 180 | }
|
---|
[1038] | 181 |
|
---|
[1049] | 182 | legendShape.AddLegendItem(new LegendItem(row.Label, row.Color, row.Thickness));
|
---|
| 183 | legendShape.CreateLegend();
|
---|
[987] | 184 | InitLineShapes(row);
|
---|
[684] | 185 | }
|
---|
[697] | 186 |
|
---|
[1240] | 187 | private void OnDataRowRemoved(IDataRow row) {
|
---|
| 188 | row.ValueChanged -= OnRowValueChanged;
|
---|
| 189 | row.ValuesChanged -= OnRowValuesChanged;
|
---|
| 190 | row.DataRowChanged -= OnDataRowChanged;
|
---|
| 191 | }
|
---|
| 192 |
|
---|
| 193 | #endregion
|
---|
| 194 |
|
---|
[1038] | 195 | private void ZoomToFullView() {
|
---|
[1045] | 196 | if (!zoomFullView) {
|
---|
[1038] | 197 | return;
|
---|
[1045] | 198 | }
|
---|
[1242] | 199 | var newClippingArea = new RectangleD(-0.1,
|
---|
| 200 | minDataValue - ((maxDataValue - minDataValue)*0.05),
|
---|
| 201 | maxDataRowCount - 0.9,
|
---|
| 202 | maxDataValue + ((maxDataValue - minDataValue)*0.05));
|
---|
[987] | 203 |
|
---|
[1038] | 204 | SetLineClippingArea(newClippingArea);
|
---|
[1059] | 205 | historyStack.Push(newClippingArea);
|
---|
[987] | 206 | }
|
---|
| 207 |
|
---|
[1038] | 208 | /// <summary>
|
---|
| 209 | /// Sets the clipping area of the data to display.
|
---|
| 210 | /// </summary>
|
---|
| 211 | /// <param name="clippingArea"></param>
|
---|
| 212 | private void SetLineClippingArea(RectangleD clippingArea) {
|
---|
| 213 | linesShape.ClippingArea = clippingArea;
|
---|
[1187] | 214 |
|
---|
[1182] | 215 | grid.ClippingArea = linesShape.ClippingArea;
|
---|
| 216 |
|
---|
[1242] | 217 | // horizontalLineShape.ClippingArea = linesShape.ClippingArea;
|
---|
[1187] | 218 |
|
---|
[1242] | 219 |
|
---|
[1038] | 220 | xAxis.ClippingArea = new RectangleD(linesShape.ClippingArea.X1,
|
---|
| 221 | xAxis.BoundingBox.Y1,
|
---|
| 222 | linesShape.ClippingArea.X2,
|
---|
| 223 | xAxis.BoundingBox.Y2);
|
---|
[1187] | 224 |
|
---|
[1182] | 225 | yAxis.ClippingArea = new RectangleD(yAxis.BoundingBox.X1,
|
---|
| 226 | linesShape.ClippingArea.Y1,
|
---|
| 227 | yAxis.BoundingBox.X2,
|
---|
| 228 | linesShape.ClippingArea.Y2);
|
---|
[981] | 229 | }
|
---|
| 230 |
|
---|
[987] | 231 | private void InitLineShapes(IDataRow row) {
|
---|
[1242] | 232 | var lineShapes = new List<LineShape>();
|
---|
[1187] | 233 | if (rowToLineShapes.Count == 0) {
|
---|
| 234 | minDataValue = Double.PositiveInfinity;
|
---|
| 235 | maxDataValue = Double.NegativeInfinity;
|
---|
| 236 | }
|
---|
[1242] | 237 | if ((row.Count > 0)) {
|
---|
[1045] | 238 | maxDataValue = Math.Max(row[0], maxDataValue);
|
---|
[983] | 239 | minDataValue = Math.Min(row[0], minDataValue);
|
---|
[981] | 240 | }
|
---|
[1242] | 241 | if ((row.LineType == DataRowType.SingleValue)) {
|
---|
| 242 | if (row.Count > 0) {
|
---|
| 243 | LineShape lineShape = new HorizontalLineShape(0, row[0], double.MaxValue, row[0], row.Color, row.Thickness,
|
---|
| 244 | row.Style);
|
---|
| 245 | lineShapes.Add(lineShape);
|
---|
| 246 | // TODO each DataRow needs its own WorldShape so Y Axes can be zoomed independently.
|
---|
| 247 | linesShape.AddShape(lineShape);
|
---|
| 248 | }
|
---|
[861] | 249 | }
|
---|
[1242] | 250 | else {
|
---|
| 251 | for (int i = 1; i < row.Count; i++) {
|
---|
| 252 | var lineShape = new LineShape(i - 1, row[i - 1], i, row[i], row.Color, row.Thickness, row.Style);
|
---|
| 253 | lineShapes.Add(lineShape);
|
---|
| 254 | // TODO each DataRow needs its own WorldShape so Y Axes can be zoomed independently.
|
---|
| 255 | linesShape.AddShape(lineShape);
|
---|
| 256 | maxDataValue = Math.Max(row[i], maxDataValue);
|
---|
| 257 | minDataValue = Math.Min(row[i], minDataValue);
|
---|
| 258 | }
|
---|
| 259 | }
|
---|
| 260 | //horizontalLineShape.YVal = maxDataValue;
|
---|
[861] | 261 | rowToLineShapes[row] = lineShapes;
|
---|
[981] | 262 | ZoomToFullView();
|
---|
[1038] | 263 |
|
---|
[1240] | 264 | canvasUI.Invalidate();
|
---|
[697] | 265 | }
|
---|
| 266 |
|
---|
[870] | 267 | // TODO use action parameter
|
---|
[869] | 268 | private void OnRowValueChanged(IDataRow row, double value, int index, Action action) {
|
---|
[861] | 269 | List<LineShape> lineShapes = rowToLineShapes[row];
|
---|
[983] | 270 | maxDataValue = Math.Max(value, maxDataValue);
|
---|
| 271 | minDataValue = Math.Min(value, minDataValue);
|
---|
[1242] | 272 | if (row.LineType == DataRowType.SingleValue) {
|
---|
| 273 | if (action == Action.Added) {
|
---|
| 274 | LineShape lineShape = new HorizontalLineShape(0, row[0], double.MaxValue, row[0], row.Color, row.Thickness,
|
---|
| 275 | row.Style);
|
---|
| 276 | lineShapes.Add(lineShape);
|
---|
| 277 | // TODO each DataRow needs its own WorldShape so Y Axes can be zoomed independently.
|
---|
| 278 | linesShape.AddShape(lineShape);
|
---|
| 279 | }
|
---|
| 280 | else {
|
---|
| 281 | // lineShapes[0].X2 = maxDataRowCount;
|
---|
| 282 | lineShapes[0].Y1 = value;
|
---|
| 283 | lineShapes[0].Y2 = value;
|
---|
| 284 | }
|
---|
[1045] | 285 | }
|
---|
[1242] | 286 | else {
|
---|
| 287 | // horizontalLineShape.YVal = maxDataValue;
|
---|
| 288 | if (index > lineShapes.Count + 1) {
|
---|
| 289 | throw new NotImplementedException();
|
---|
| 290 | }
|
---|
[861] | 291 |
|
---|
[1242] | 292 | // new value was added
|
---|
| 293 | if (index > 0 && index == lineShapes.Count + 1) {
|
---|
| 294 | if (maxDataRowCount < row.Count) {
|
---|
| 295 | maxDataRowCount = row.Count;
|
---|
| 296 | // UpdateSingleValueRows();
|
---|
| 297 | }
|
---|
| 298 | var lineShape = new LineShape(index - 1, row[index - 1], index, row[index], row.Color, row.Thickness,
|
---|
| 299 | row.Style);
|
---|
| 300 | lineShapes.Add(lineShape);
|
---|
| 301 | // TODO each DataRow needs its own WorldShape so Y Axes can be zoomed independently.
|
---|
| 302 | linesShape.AddShape(lineShape);
|
---|
[1045] | 303 | }
|
---|
[861] | 304 |
|
---|
[1242] | 305 | // not the first value
|
---|
| 306 | if (index > 0) {
|
---|
| 307 | lineShapes[index - 1].Y2 = value;
|
---|
| 308 | }
|
---|
| 309 |
|
---|
| 310 | // not the last value
|
---|
| 311 | if (index > 0 && index < row.Count - 1) {
|
---|
| 312 | lineShapes[index].Y1 = value;
|
---|
| 313 | }
|
---|
[1045] | 314 | }
|
---|
[861] | 315 |
|
---|
[981] | 316 | ZoomToFullView();
|
---|
[1240] | 317 | canvasUI.Invalidate();
|
---|
[697] | 318 | }
|
---|
| 319 |
|
---|
[1240] | 320 | // TODO remove (see ticket #501)
|
---|
[1187] | 321 | public IList<IDataRow> GetRows() {
|
---|
| 322 | return model.Rows;
|
---|
| 323 | }
|
---|
| 324 |
|
---|
| 325 |
|
---|
[870] | 326 | // TODO use action parameter
|
---|
[869] | 327 | private void OnRowValuesChanged(IDataRow row, double[] values, int index, Action action) {
|
---|
[1045] | 328 | foreach (double value in values) {
|
---|
[869] | 329 | OnRowValueChanged(row, value, index++, action);
|
---|
[1045] | 330 | }
|
---|
[861] | 331 | }
|
---|
[761] | 332 |
|
---|
[1182] | 333 | private void OnModelChanged() {
|
---|
| 334 | titleShape.Text = model.Title;
|
---|
[697] | 335 |
|
---|
[1240] | 336 | canvasUI.Invalidate();
|
---|
[1182] | 337 | }
|
---|
| 338 |
|
---|
[1242] | 339 |
|
---|
[697] | 340 | #region Begin-/EndUpdate
|
---|
| 341 |
|
---|
[1242] | 342 | private int beginUpdateCount;
|
---|
[697] | 343 |
|
---|
[861] | 344 | public void BeginUpdate() {
|
---|
[697] | 345 | beginUpdateCount++;
|
---|
| 346 | }
|
---|
| 347 |
|
---|
[861] | 348 | public void EndUpdate() {
|
---|
[1045] | 349 | if (beginUpdateCount == 0) {
|
---|
[697] | 350 | throw new InvalidOperationException("Too many EndUpdates.");
|
---|
[1045] | 351 | }
|
---|
[697] | 352 |
|
---|
| 353 | beginUpdateCount--;
|
---|
| 354 |
|
---|
[1045] | 355 | if (beginUpdateCount == 0) {
|
---|
[1240] | 356 | canvasUI.Invalidate();
|
---|
[1045] | 357 | }
|
---|
[697] | 358 | }
|
---|
| 359 |
|
---|
| 360 | #endregion
|
---|
[928] | 361 |
|
---|
[1059] | 362 | #region Zooming / Panning
|
---|
| 363 |
|
---|
| 364 | private readonly Stack<RectangleD> historyStack = new Stack<RectangleD>();
|
---|
[1045] | 365 | private RectangleShape rectangleShape;
|
---|
[928] | 366 |
|
---|
[1059] | 367 | private void canvasUI1_KeyDown(object sender, KeyEventArgs e) {
|
---|
[1187] | 368 | if (e.KeyCode == Keys.Back && historyStack.Count > 1) {
|
---|
[1059] | 369 | historyStack.Pop();
|
---|
| 370 |
|
---|
| 371 | RectangleD clippingArea = historyStack.Peek();
|
---|
[1187] | 372 |
|
---|
[1059] | 373 | SetNewClippingArea(clippingArea);
|
---|
[1240] | 374 | canvasUI.Invalidate();
|
---|
[1059] | 375 | }
|
---|
| 376 | }
|
---|
| 377 |
|
---|
[928] | 378 | private void canvasUI1_MouseDown(object sender, MouseEventArgs e) {
|
---|
[1058] | 379 | Focus();
|
---|
[1237] | 380 | if (e.Button == MouseButtons.Right) {
|
---|
[1242] | 381 | contextMenuStrip1.Show(PointToScreen(e.Location));
|
---|
[984] | 382 | }
|
---|
[1187] | 383 | else {
|
---|
| 384 | if (ModifierKeys == Keys.Control) {
|
---|
| 385 | CreateZoomListener(e);
|
---|
| 386 | }
|
---|
| 387 | else {
|
---|
| 388 | CreatePanListener(e);
|
---|
| 389 | }
|
---|
| 390 | }
|
---|
[928] | 391 | }
|
---|
| 392 |
|
---|
[1244] | 393 | private Point prevMousePosition = Point.Empty;
|
---|
| 394 |
|
---|
[1240] | 395 | private void canvas_MouseMove(object sender, MouseEventArgs e) {
|
---|
[1244] | 396 | if (prevMousePosition != e.Location) {
|
---|
| 397 | prevMousePosition = e.Location;
|
---|
[1240] | 398 |
|
---|
[1244] | 399 | double x = Transform.ToWorldX(e.X, berni.Viewport, berni.ClippingArea);
|
---|
| 400 | double y = Transform.ToWorldY(e.Y, berni.Viewport, berni.ClippingArea);
|
---|
| 401 |
|
---|
| 402 | mousePointer.Rectangle = new RectangleD(x - 1, y - 1, x + 1, y + 1);
|
---|
| 403 | canvasUI.Invalidate();
|
---|
| 404 | }
|
---|
[1240] | 405 | }
|
---|
| 406 |
|
---|
[1058] | 407 | private void canvasUI1_MouseWheel(object sender, MouseEventArgs e) {
|
---|
| 408 | if (ModifierKeys == Keys.Control) {
|
---|
| 409 | double zoomFactor = (e.Delta > 0) ? 0.9 : 1.1;
|
---|
| 410 |
|
---|
| 411 | RectangleD clippingArea = ZoomListener.ZoomClippingArea(linesShape.ClippingArea, zoomFactor);
|
---|
| 412 |
|
---|
| 413 | SetLineClippingArea(clippingArea);
|
---|
[1240] | 414 | canvasUI.Invalidate();
|
---|
[1058] | 415 | }
|
---|
| 416 | }
|
---|
| 417 |
|
---|
[1045] | 418 | private void CreateZoomListener(MouseEventArgs e) {
|
---|
[1242] | 419 | var zoomListener = new ZoomListener(e.Location);
|
---|
[1045] | 420 | zoomListener.DrawRectangle += DrawRectangle;
|
---|
| 421 | zoomListener.OnMouseUp += OnZoom_MouseUp;
|
---|
[928] | 422 |
|
---|
[1240] | 423 | canvasUI.MouseEventListener = zoomListener;
|
---|
[928] | 424 |
|
---|
[1045] | 425 | rectangleShape = new RectangleShape(e.X, e.Y, e.X, e.Y, Color.Blue);
|
---|
| 426 | rectangleShape.Opacity = 50;
|
---|
[928] | 427 |
|
---|
[1045] | 428 | linesShape.AddShape(rectangleShape);
|
---|
[928] | 429 | }
|
---|
[984] | 430 |
|
---|
[1045] | 431 | private void OnZoom_MouseUp(object sender, MouseEventArgs e) {
|
---|
[1240] | 432 | canvasUI.MouseEventListener = null;
|
---|
[984] | 433 |
|
---|
[1059] | 434 | RectangleD clippingArea = rectangleShape.Rectangle;
|
---|
| 435 |
|
---|
| 436 | SetLineClippingArea(clippingArea);
|
---|
| 437 | historyStack.Push(clippingArea);
|
---|
| 438 |
|
---|
[1038] | 439 | linesShape.RemoveShape(rectangleShape);
|
---|
[984] | 440 |
|
---|
[1045] | 441 | zoomFullView = false; //user wants to zoom => no full view
|
---|
[984] | 442 |
|
---|
[1240] | 443 | canvasUI.Invalidate();
|
---|
[984] | 444 | }
|
---|
| 445 |
|
---|
[1045] | 446 | private void DrawRectangle(Rectangle rectangle) {
|
---|
[1240] | 447 | rectangleShape.Rectangle = Transform.ToWorld(rectangle, canvasUI.ClientRectangle, linesShape.ClippingArea);
|
---|
| 448 | canvasUI.Invalidate();
|
---|
[1045] | 449 | }
|
---|
[984] | 450 |
|
---|
[1045] | 451 | private void CreatePanListener(MouseEventArgs e) {
|
---|
[1240] | 452 | PanListener panListener = new PanListener(canvasUI.ClientRectangle, linesShape.ClippingArea, e.Location);
|
---|
[984] | 453 |
|
---|
[1045] | 454 | panListener.SetNewClippingArea += SetNewClippingArea;
|
---|
[1059] | 455 | panListener.OnMouseUp += delegate {
|
---|
[1187] | 456 | historyStack.Push(linesShape.ClippingArea);
|
---|
[1240] | 457 | canvasUI.MouseEventListener = null;
|
---|
[1187] | 458 | };
|
---|
[984] | 459 |
|
---|
[1240] | 460 | canvasUI.MouseEventListener = panListener;
|
---|
[1045] | 461 | }
|
---|
[984] | 462 |
|
---|
[1045] | 463 | private void SetNewClippingArea(RectangleD newClippingArea) {
|
---|
| 464 | SetLineClippingArea(newClippingArea);
|
---|
| 465 |
|
---|
| 466 | zoomFullView = false;
|
---|
[1240] | 467 | canvasUI.Invalidate();
|
---|
[984] | 468 | }
|
---|
[1059] | 469 |
|
---|
| 470 | #endregion
|
---|
[1187] | 471 |
|
---|
[1242] | 472 |
|
---|
[684] | 473 | }
|
---|
[1237] | 474 | }
|
---|