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