Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Visualization/HeuristicLab.Visualization/3.3/ChartControl.cs @ 13716

Last change on this file since 13716 was 13716, checked in by bburlacu, 8 years ago

#1265: Added option to select the SmoothingMode in the ChartControl. Introduced a LabeledPrimitive which encapsulates a RectangularPrimitiveBase primitive and supports drawing a text label on top of it.
Introduced a set of useful methods in the PrimitiveUtil class for calculating intersection points between linear and rectangular primitives (useful for connecting shapes together).

File size: 14.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.ComponentModel;
25using System.Drawing;
26using System.Drawing.Drawing2D;
27using System.Drawing.Imaging;
28using System.Linq;
29using System.Windows.Forms;
30
31namespace HeuristicLab.Visualization {
32  public partial class ChartControl : UserControl {
33    protected Bitmap Picture;
34    protected bool RenderingRequired;
35    protected Dictionary<Type, ChartMode> Modes = new Dictionary<Type, ChartMode>();
36
37    protected bool SuppressEvents { get; set; }
38    private bool SuppressRender { get; set; }
39
40    public bool ShowToolBar {
41      get { return !splitContainer.Panel1Collapsed; }
42      set { splitContainer.Panel1Collapsed = !value; }
43    }
44
45    private IChart chart;
46    public IChart Chart {
47      get { return chart; }
48      protected set {
49        if (chart != null) DeregisterChartEvents(chart);
50        chart = value;
51        chart.Enabled = Enabled;
52        pictureBox.Enabled = Enabled;
53        if (chart != null) RegisterChartEvents(chart);
54      }
55    }
56
57    private ChartMode mode;
58    private ChartMode defaultMode;
59    public ChartMode Mode {
60      get { return mode; }
61      set {
62        if (mode == value) return;
63        mode = value;
64        if (defaultMode == null) defaultMode = mode;
65        if (mode == null) mode = defaultMode;
66        SetModeButtonCheckedState();
67        SetModeMenuItemCheckedState();
68        SetPictureBoxCursor(GetPictureBoxCursor());
69        OnModeChanged();
70        if (chart != null) {
71          GenerateImage();
72        }
73      }
74    }
75
76    public SmoothingMode SmoothingMode { get; set; } = SmoothingMode.None;
77
78    public bool ScaleOnResize { get; set; }
79
80    public bool IsRenderingPaused { get { return SuppressRender; } }
81
82    public ChartControl() : this(null) { }
83    public ChartControl(IChart defaultChart) {
84      InitializeComponent();
85      ScaleOnResize = true;
86      Chart = defaultChart ?? new Chart(0, 0, Width, Height);
87    }
88
89    public void AddChartModes(params ChartMode[] chartModes) {
90      foreach (var chartMode in chartModes)
91        Modes.Add(chartMode.GetType(), chartMode);
92
93      ReloadModeToolBar();
94      ReloadModeContextMenu();
95    }
96
97    public void SuspendRendering() {
98      SuppressRender = true;
99    }
100
101    public void ResumeRendering() {
102      SuppressRender = false;
103      if (Chart != null) GenerateImage();
104    }
105
106    public void RefreshPicture() {
107      pictureBox.Refresh();
108    }
109
110    public void UpdatePicture() {
111      pictureBox.Update();
112    }
113
114    public Graphics CreatePictureGraphics() {
115      return pictureBox.CreateGraphics();
116    }
117
118    protected virtual void ReloadModeToolBar() {
119      splitContainer.Panel1.Controls.Clear();
120
121      var chartModes = Modes.Values.ToList();
122      for (int i = 0; i < chartModes.Count; i++) {
123        var chartMode = chartModes[i];
124        var rb = CreateChartModeRadioButton(chartMode);
125        rb.Location = new Point(3, 3 + i * (rb.Height + rb.Margin.Vertical));
126        rb.TabIndex = i;
127        toolTip.SetToolTip(rb, chartMode.ToolTipText);
128        splitContainer.Panel1.Controls.Add(rb);
129      }
130
131      SetModeButtonCheckedState();
132    }
133
134    protected virtual void ReloadModeContextMenu() {
135      modeToolStripMenuItem.DropDownItems.Clear();
136
137      foreach (var chartMode in Modes.Values) {
138        var mi = CreateChartModeMenuItem(chartMode);
139        modeToolStripMenuItem.DropDownItems.Add(mi);
140      }
141
142      SetModeMenuItemCheckedState();
143    }
144
145    protected virtual void SetModeButtonCheckedState() {
146      foreach (var rb in splitContainer.Panel1.Controls.OfType<RadioButton>())
147        rb.Checked = rb.Tag == Mode;
148    }
149
150    protected virtual void SetModeMenuItemCheckedState() {
151      foreach (var mi in modeToolStripMenuItem.DropDownItems.OfType<ToolStripMenuItem>())
152        mi.Checked = mi.Tag == Mode;
153    }
154
155    protected virtual void SetPictureBoxCursor(Cursor cursor) {
156      if (pictureBox.Cursor != cursor) pictureBox.Cursor = cursor;
157    }
158
159    protected virtual Cursor GetPictureBoxCursor() {
160      return mode != null ? mode.Cursor : null;
161    }
162
163    protected virtual void RegisterChartEvents(IChart chart) {
164      chart.RedrawRequired += ChartOnUpdateRequired;
165    }
166
167    protected virtual void DeregisterChartEvents(IChart chart) {
168      chart.RedrawRequired -= ChartOnUpdateRequired;
169    }
170
171    protected virtual void ChartOnUpdateRequired(object sender, EventArgs e) {
172      if (SuppressRender) return;
173      GenerateImage();
174    }
175
176    #region PictureBox Events
177    protected virtual void PictureBoxOnSizeChanged(object sender, EventArgs e) {
178      if (Chart == null) return;
179      if (ScaleOnResize) {
180        if ((pictureBox.Width > 0) && (pictureBox.Height > 0) && (Chart != null)) {
181          var point = Chart.TransformPixelToWorld(new Point(pictureBox.Width, Chart.SizeInPixels.Height - pictureBox.Height));
182          var diff = Chart.UpperRight - point;
183          Chart.SetPosition(new PointD(Chart.LowerLeft.X + (diff.DX / 2.0), Chart.LowerLeft.Y + (diff.DY / 2.0)),
184            new PointD(Chart.UpperRight.X - (diff.DX / 2.0), Chart.UpperRight.Y - (diff.DY / 2.0)));
185        }
186      }
187      GenerateImage();
188    }
189
190    protected virtual void PictureBoxOnVisibleChanged(object sender, EventArgs e) {
191      if (pictureBox.Visible && RenderingRequired) GenerateImage();
192    }
193
194    protected virtual void PictureBoxOnMouseClick(object sender, MouseEventArgs e) {
195      if (mode != null)
196        mode.HandleOnMouseClick(sender, e);
197    }
198
199    protected virtual void PictureBoxOnMouseDoubleClick(object sender, MouseEventArgs e) {
200      if (mode != null)
201        mode.HandleOnMouseDoubleClick(sender, e);
202    }
203
204    protected virtual void OnKeyDown(object sender, KeyEventArgs e) {
205      if (mode != null)
206        mode.HandleOnKeyDown(sender, e);
207    }
208
209    protected virtual void OnKeyUp(object sender, KeyEventArgs e) {
210      if (mode != null)
211        mode.HandleOnKeyUp(sender, e);
212    }
213
214    protected virtual void PictureBoxOnMouseWheel(object sender, MouseEventArgs e) {
215      if (mode != null)
216        mode.HandleOnMouseWheel(sender, e);
217    }
218
219    protected virtual void PictureBoxOnMouseDown(object sender, MouseEventArgs e) {
220      if (mode != null)
221        mode.HandleOnMouseDown(sender, e);
222    }
223
224    protected virtual void PictureBoxOnMouseUp(object sender, MouseEventArgs e) {
225      if (mode != null)
226        mode.HandleOnMouseUp(sender, e);
227
228      if (Chart == null) return;
229
230      if (e.Button == MouseButtons.Right) {
231        propertiesToolStripMenuItem.Enabled = Chart.Group.SelectedPrimitives.Count() == 1;
232        oneLayerUpToolStripMenuItem.Enabled = Chart.Group.SelectedPrimitives.Count() == 1;
233        oneLayerDownToolStripMenuItem.Enabled = Chart.Group.SelectedPrimitives.Count() == 1;
234        intoForegroundToolStripMenuItem.Enabled = Chart.Group.SelectedPrimitives.Count() == 1;
235        intoBackgroundToolStripMenuItem.Enabled = Chart.Group.SelectedPrimitives.Count() == 1;
236      }
237    }
238
239    protected virtual void PictureBoxOnMouseMove(object sender, MouseEventArgs e) {
240      if (InvokeRequired) {
241        Invoke((Action<object, MouseEventArgs>)PictureBoxOnMouseMove, sender, e);
242      } else {
243        var toolTipText = Chart.GetToolTipText(e.Location);
244        if (toolTip.GetToolTip(pictureBox) != toolTipText) toolTip.SetToolTip(pictureBox, toolTipText);
245
246        if (mode != null)
247          mode.HandleOnMouseMove(sender, e);
248
249        SetPictureBoxCursor(GetPictureBoxCursor());
250      }
251    }
252
253    protected virtual void PictureBoxOnMouseEnter(object sender, EventArgs e) {
254      if (InvokeRequired) {
255        Invoke((Action<object, MouseEventArgs>)PictureBoxOnMouseEnter, sender, e);
256        return;
257      }
258      if (!Focused) pictureBox.Focus();
259
260      if (mode != null)
261        mode.HandleOnMouseEnter(sender, e);
262    }
263
264    protected virtual void PictureBoxOnMouseLeave(object sender, EventArgs e) {
265      if (mode != null)
266        mode.HandleOnMouseLeave(sender, e);
267    }
268
269    protected virtual void PictureBoxOnClick(object sender, EventArgs e) {
270      if (InvokeRequired) {
271        Invoke((Action<object, MouseEventArgs>)PictureBoxOnClick, sender, e);
272        return;
273      }
274      if (!Focused) pictureBox.Focus();
275
276      if (mode != null)
277        mode.HandleOnClick(sender, e);
278    }
279    #endregion
280
281    protected virtual void PictureBoxContextMenuStripOnOpening(object sender, CancelEventArgs e) { }
282
283    protected virtual void oneLayerUpToolStripMenuItem_Click(object sender, EventArgs e) {
284      if (Chart == null) return;
285      if (Chart.Group.SelectedPrimitives.Count() == 1) {
286        Chart.OneLayerUp(Chart.Group.SelectedPrimitives.First());
287      }
288    }
289    protected virtual void oneLayerDownToolStripMenuItem_Click(object sender, EventArgs e) {
290      if (Chart == null) return;
291      if (Chart.Group.SelectedPrimitives.Count() == 1) {
292        Chart.OneLayerDown(Chart.Group.SelectedPrimitives.First());
293      }
294    }
295    protected virtual void intoForegroundToolStripMenuItem_Click(object sender, EventArgs e) {
296      if (Chart == null) return;
297      if (Chart.Group.SelectedPrimitives.Count() == 1) {
298        Chart.IntoForeground(Chart.Group.SelectedPrimitives.First());
299      }
300    }
301    protected virtual void intoBackgroundToolStripMenuItem_Click(object sender, EventArgs e) {
302      if (Chart == null) return;
303      if (Chart.Group.SelectedPrimitives.Count() == 1) {
304        Chart.IntoBackground(Chart.Group.SelectedPrimitives.First());
305      }
306    }
307    protected virtual void propertiesToolStripMenuItem_Click(object sender, EventArgs e) {
308      if (Chart == null) return;
309      if (Chart.Group.SelectedPrimitives.Count() == 1) {
310        using (var dialog = new PropertiesDialog(Chart.Group.SelectedPrimitives.First())) {
311          dialog.ShowDialog(this);
312        }
313      }
314    }
315    protected virtual void saveImageToolStripMenuItem_Click(object sender, EventArgs e) {
316      if (Picture == null) return;
317
318      if (saveFileDialog.ShowDialog() == DialogResult.OK) {
319        var format = ImageFormat.Bmp;
320        var filename = saveFileDialog.FileName.ToLower();
321        if (filename.EndsWith("emf")) {
322          using (var g1 = Graphics.FromImage(Picture)) {
323            var rectangle = new System.Drawing.Rectangle(0, 0, Picture.Width, Picture.Height);
324            using (var metafile = new Metafile(filename, g1.GetHdc(), rectangle, MetafileFrameUnit.Pixel, EmfType.EmfPlusDual))
325            using (var g2 = Graphics.FromImage(metafile))
326              Chart.Render(g2, pictureBox.Width, pictureBox.Height);
327          }
328        } else {
329          using (var graphics = Graphics.FromImage(Picture))
330            Chart.Render(graphics, Picture.Width, Picture.Height);
331
332          if (filename.EndsWith("jpg")) {
333            format = ImageFormat.Jpeg;
334          } else if (filename.EndsWith("gif")) {
335            format = ImageFormat.Gif;
336          } else if (filename.EndsWith("png")) {
337            format = ImageFormat.Png;
338          } else if (filename.EndsWith("tif")) {
339            format = ImageFormat.Tiff;
340          }
341
342          Picture.Save(saveFileDialog.FileName, format);
343        }
344      }
345    }
346
347    protected virtual void GenerateImage() {
348      if (InvokeRequired) {
349        Invoke((Action)GenerateImage);
350        return;
351      }
352      if (!Visible) {
353        RenderingRequired = true;
354      } else {
355        if ((pictureBox.Width == 0) || (pictureBox.Height == 0)) {
356          pictureBox.Image = pictureBox.ErrorImage;
357          if (Picture != null) Picture.Dispose();
358          Picture = null;
359        } else {
360          if (Picture != null) Picture.Dispose();
361          Picture = new Bitmap(pictureBox.Width, pictureBox.Height);
362          using (var graphics = Graphics.FromImage(Picture)) {
363            graphics.SmoothingMode = SmoothingMode;
364            graphics.SetClip(new System.Drawing.Rectangle(0, 0, pictureBox.Width, pictureBox.Height));
365            Chart.Render(graphics, pictureBox.Width, pictureBox.Height);
366          }
367        }
368        pictureBox.Image = Picture;
369        RenderingRequired = false;
370      }
371    }
372
373    public event EventHandler ModeChanged;
374    protected void OnModeChanged() {
375      var handler = ModeChanged;
376      if (handler != null) handler(this, EventArgs.Empty);
377    }
378
379    private void ChartControl_Load(object sender, EventArgs e) {
380      if (!SuppressRender) GenerateImage();
381    }
382
383    #region Helpers
384    private RadioButton CreateChartModeRadioButton(ChartMode chartMode) {
385      var rb = new RadioButton {
386        Appearance = Appearance.Button,
387        Image = chartMode.Image,
388        Size = new Size(24, 24),
389        TabStop = true,
390        Tag = chartMode,
391        UseVisualStyleBackColor = true
392      };
393
394      rb.CheckedChanged += (sender, args) => { if (rb.Checked) chartMode.Select(); };
395
396      return rb;
397    }
398
399    private ToolStripMenuItem CreateChartModeMenuItem(ChartMode chartMode) {
400      var mi = new ToolStripMenuItem(chartMode.Text) {
401        CheckOnClick = true,
402        Image = chartMode.Image,
403        Tag = chartMode
404      };
405
406      mi.CheckedChanged += (sender, args) => { if (mi.Checked) chartMode.Select(); };
407
408      return mi;
409    }
410    #endregion
411  }
412}
Note: See TracBrowser for help on using the repository browser.