#region License Information
/* HeuristicLab
* Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Windows.Forms;
namespace HeuristicLab.Visualization {
public partial class ChartControl : UserControl {
protected Bitmap Picture;
protected bool RenderingRequired;
protected Dictionary Modes = new Dictionary();
protected Stack ModeStack = new Stack();
protected List Shortcuts = new List();
protected ChartMode.Shortcut ActiveShortcut;
protected bool SuppressEvents { get; set; }
private bool SuppressRender { get; set; }
public bool ShowToolBar {
get { return !splitContainer.Panel1Collapsed; }
set { splitContainer.Panel1Collapsed = !value; }
}
private IChart chart;
public IChart Chart {
get { return chart; }
protected set {
if (chart != null) DeregisterChartEvents(chart);
chart = value;
chart.Enabled = Enabled;
pictureBox.Enabled = Enabled;
if (chart != null) RegisterChartEvents(chart);
}
}
private ChartMode mode;
private ChartMode defaultMode;
public ChartMode Mode {
get { return mode; }
set {
if (mode == value) return;
mode = value;
if (defaultMode == null) defaultMode = mode;
if (mode == null) mode = defaultMode;
SetModeButtonCheckedState();
SetModeMenuItemCheckedState();
SetPictureBoxCursor(GetPictureBoxCursor());
OnModeChanged();
if (chart != null) {
GenerateImage();
}
}
}
public SmoothingMode SmoothingMode { get; set; }
public bool ScaleOnResize { get; set; }
public bool IsRenderingPaused { get { return SuppressRender; } }
public ChartControl() : this(null) { }
public ChartControl(IChart defaultChart) {
InitializeComponent();
ScaleOnResize = true;
Chart = defaultChart ?? new Chart(0, 0, Width, Height);
}
public void AddChartModes(params ChartMode[] chartModes) {
foreach (var chartMode in chartModes) {
Modes.Add(chartMode.GetType(), chartMode);
foreach (var shortcut in chartMode.Shortcuts)
Shortcuts.Add(shortcut);
}
ReloadModeToolBar();
ReloadModeContextMenu();
}
public void SetTempChartMode(ChartMode chartMode) {
if (Mode == chartMode) return;
ModeStack.Push(mode);
Mode = chartMode;
}
public void ResetTempChartMode() {
if (ModeStack.Any())
Mode = ModeStack.Pop();
}
public void SuspendRendering() {
SuppressRender = true;
}
public void ResumeRendering() {
SuppressRender = false;
if (Chart != null) GenerateImage();
}
public void RefreshPicture() {
pictureBox.Refresh();
}
public void UpdatePicture() {
pictureBox.Update();
}
public Graphics CreatePictureGraphics() {
return pictureBox.CreateGraphics();
}
public System.Drawing.Rectangle GetPictureBounds() {
return pictureBox.Bounds;
}
protected virtual void ReloadModeToolBar() {
splitContainer.Panel1.Controls.Clear();
var chartModes = Modes.Values.ToList();
for (int i = 0; i < chartModes.Count; i++) {
var chartMode = chartModes[i];
var rb = CreateChartModeRadioButton(chartMode);
rb.Location = new Point(3, 3 + i * (rb.Height + rb.Margin.Vertical));
rb.TabIndex = i;
toolTip.SetToolTip(rb, chartMode.ToolTipText);
splitContainer.Panel1.Controls.Add(rb);
}
SetModeButtonCheckedState();
}
protected virtual void ReloadModeContextMenu() {
modeToolStripMenuItem.DropDownItems.Clear();
foreach (var chartMode in Modes.Values) {
var mi = CreateChartModeMenuItem(chartMode);
modeToolStripMenuItem.DropDownItems.Add(mi);
}
SetModeMenuItemCheckedState();
}
protected virtual void SetModeButtonCheckedState() {
foreach (var rb in splitContainer.Panel1.Controls.OfType())
rb.Checked = rb.Tag == Mode;
}
protected virtual void SetModeMenuItemCheckedState() {
foreach (var mi in modeToolStripMenuItem.DropDownItems.OfType())
mi.Checked = mi.Tag == Mode;
}
protected virtual void SetPictureBoxCursor(Cursor cursor) {
if (pictureBox.Cursor != cursor) pictureBox.Cursor = cursor;
}
protected virtual Cursor GetPictureBoxCursor() {
return mode != null ? mode.Cursor : null;
}
protected virtual void RegisterChartEvents(IChart chart) {
chart.RedrawRequired += ChartOnUpdateRequired;
}
protected virtual void DeregisterChartEvents(IChart chart) {
chart.RedrawRequired -= ChartOnUpdateRequired;
}
protected virtual void ChartOnUpdateRequired(object sender, EventArgs e) {
if (SuppressRender) return;
GenerateImage();
}
#region PictureBox Events
protected virtual void PictureBoxOnSizeChanged(object sender, EventArgs e) {
if (Chart == null) return;
if (ScaleOnResize) {
if ((pictureBox.Width > 0) && (pictureBox.Height > 0) && (Chart != null)) {
var point = Chart.TransformPixelToWorld(new Point(pictureBox.Width, Chart.SizeInPixels.Height - pictureBox.Height));
var diff = Chart.UpperRight - point;
Chart.SetPosition(new PointD(Chart.LowerLeft.X, Chart.LowerLeft.Y),
new PointD(Chart.UpperRight.X - diff.DX, Chart.UpperRight.Y - diff.DY));
}
}
GenerateImage();
}
protected virtual void PictureBoxOnVisibleChanged(object sender, EventArgs e) {
if (pictureBox.Visible && RenderingRequired) GenerateImage();
}
protected virtual void PictureBoxOnMouseClick(object sender, MouseEventArgs e) {
if (mode != null)
mode.HandleOnMouseClick(sender, e);
}
protected virtual void PictureBoxOnMouseDoubleClick(object sender, MouseEventArgs e) {
if (mode != null)
mode.HandleOnMouseDoubleClick(sender, e);
}
protected virtual void OnKeyDown(object sender, KeyEventArgs e) {
if (mode != null) {
mode.HandleOnKeyDown(sender, e);
if (e.Handled || ActiveShortcut != null) return;
foreach (var shortcut in Shortcuts) {
if (e.KeyCode == shortcut.Key && e.Modifiers == shortcut.Modifiers) {
ActiveShortcut = shortcut;
var downAction = shortcut.DownAction;
if (downAction != null) downAction();
e.Handled = true;
break;
}
}
}
}
protected virtual void OnKeyUp(object sender, KeyEventArgs e) {
if (mode != null) {
mode.HandleOnKeyUp(sender, e);
if (e.Handled || ActiveShortcut == null) return;
var modifiers = new List(from key in Enum.GetValues(typeof(Keys)).Cast()
where e.Modifiers.HasFlag(key)
select key);
if (ActiveShortcut.Key == e.KeyCode || ActiveShortcut.GetModifiers().Except(modifiers).Any()) {
var upAction = ActiveShortcut.UpAction;
if (upAction != null) upAction();
ActiveShortcut = null;
e.Handled = true;
}
}
}
protected virtual void PictureBoxOnMouseWheel(object sender, MouseEventArgs e) {
if (mode != null)
mode.HandleOnMouseWheel(sender, e);
}
protected virtual void PictureBoxOnMouseDown(object sender, MouseEventArgs e) {
if (mode != null)
mode.HandleOnMouseDown(sender, e);
}
protected virtual void PictureBoxOnMouseUp(object sender, MouseEventArgs e) {
if (mode != null)
mode.HandleOnMouseUp(sender, e);
if (Chart == null) return;
if (e.Button == MouseButtons.Right) {
propertiesToolStripMenuItem.Enabled = Chart.Group.SelectedPrimitives.Count() == 1;
oneLayerUpToolStripMenuItem.Enabled = Chart.Group.SelectedPrimitives.Count() == 1;
oneLayerDownToolStripMenuItem.Enabled = Chart.Group.SelectedPrimitives.Count() == 1;
intoForegroundToolStripMenuItem.Enabled = Chart.Group.SelectedPrimitives.Count() == 1;
intoBackgroundToolStripMenuItem.Enabled = Chart.Group.SelectedPrimitives.Count() == 1;
}
}
protected virtual void PictureBoxOnMouseMove(object sender, MouseEventArgs e) {
if (InvokeRequired) {
Invoke((Action