using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using DocToolkit;
namespace CraftSynth.ImageEditor
{
///
/// Working area.
/// Handles mouse input and draws graphics objects.
///
internal partial class DrawArea : UserControl, IDisposable
{
#region Constructor, Dispose
public DrawArea()
{
// create list of Layers, with one default active visible layer
_layers = new Layers();
_layers.CreateNewLayer("Default");
_panning = false;
_panX = 0;
_panY = 0;
this.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.DrawArea_MouseWheel);
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();
//DrawImage o = new DrawImage(0, 0);
//DrawTools.ToolObject.AddNewObject(this, new DrawImage(0, 0));
}
// Public implementation of Dispose pattern callable by consumers.
public new void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
// Flag: Has Dispose already been called?
bool _disposed = false;
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
// Free any managed objects here.
//
if (this._currentBrush != null)
{
this._currentBrush.Dispose();
}
if (this.CurrentPen != null)
{
this._currentPen.Dispose();
}
if (this._layers != null)
{
this._layers.Dispose();
}
if (this.tools != null)
{
foreach (Tool tool in tools)
{
if (tool != null)
{
tool.Dispose();
}
}
}
if (this.undoManager != null)
{
this.undoManager.Dispose();
}
if (components != null)
{
components.Dispose();
}
// Free any unmanaged objects here.
}
this._disposed = true;
}
base.Dispose(disposing);
}
~DrawArea()
{
this.Dispose(false);
}
#endregion Constructor, Dispose
#region Enumerations
public enum DrawToolType
{
Pointer,
Rectangle,
Ellipse,
Line,
PolyLine,
Polygon,
Text,
Image,
Connector,
NumberOfDrawTools
} ;
#endregion Enumerations
#region Members
private float _zoom = 1.0f;
private float _rotation = 0f;
private int _panX = 0;
private int _panY;
private int _originalPanY;
private bool _panning = false;
private Point lastPoint;
private Color _lineColor = Color.Red;
private Color _fillColor = Color.White;
private bool _drawFilled = false;
private int _lineWidth = 5;
private LineCap _endCap = LineCap.Round;
private Pen _currentPen;
private DrawingPens.PenType _penType;
private Brush _currentBrush;
private FillBrushes.BrushType _brushType;
// Define the Layers collection
private Layers _layers;
private DrawToolType activeTool; // active drawing tool
private Tool[] tools; // array of tools
// Information about owner form
private MainForm owner;
private DocManager docManager;
// group selection rectangle
private Rectangle netRectangle;
private bool drawNetRectangle = false;
private MainForm myparent;
public MainForm MyParent
{
get { return myparent; }
set { myparent = value; }
}
private UndoManager undoManager;
#endregion Members
#region Properties
///
/// Allow tools and objects to see the type of brush set
///
public FillBrushes.BrushType BrushType
{
get { return _brushType; }
set { _brushType = value; }
}
public Brush CurrentBrush
{
get { return _currentBrush; }
set { _currentBrush = value; }
}
///
/// Allow tools and objects to see the type of pen set
///
public DrawingPens.PenType PenType
{
get { return _penType; }
set { _penType = value; }
}
///
/// Arrow or Rounded.
///
public LineCap EndCap
{
get { return _endCap; }
set { _endCap = value; }
}
///
/// Current Drawing Pen
///
public Pen CurrentPen
{
get { return _currentPen; }
set { _currentPen = value; }
}
///
/// Current Line Width
///
public int LineWidth
{
get { return _lineWidth; }
set { _lineWidth = value; }
}
///
/// Flag determines if objects will be drawn filled or not
///
public bool DrawFilled
{
get { return _drawFilled; }
set { _drawFilled = value; }
}
///
/// Color to draw filled objects with
///
public Color FillColor
{
get { return _fillColor; }
set { _fillColor = value; }
}
///
/// Color for drawing lines
///
public Color LineColor
{
get { return _lineColor; }
set { _lineColor = value; }
}
///
/// Original Y position - used when panning
///
public int OriginalPanY
{
get { return _originalPanY; }
set { _originalPanY = value; }
}
///
/// Flag is true if panning active
///
public bool Panning
{
get { return _panning; }
set { _panning = value; }
}
///
/// Current pan offset along X-axis
///
public int PanX
{
get { return _panX; }
set { _panX = value; }
}
///
/// Current pan offset along Y-axis
///
public int PanY
{
get { return _panY; }
set { _panY = value; }
}
///
/// Degrees of rotation of the drawing
///
public float Rotation
{
get { return _rotation; }
set { _rotation = value; }
}
///
/// Current Zoom factor
///
public float Zoom
{
get { return _zoom; }
set { _zoom = value; }
}
///
/// Group selection rectangle. Used for drawing.
///
public Rectangle NetRectangle
{
get { return netRectangle; }
set { netRectangle = value; }
}
///
/// Flag is set to true if group selection rectangle should be drawn.
///
public bool DrawNetRectangle
{
get { return drawNetRectangle; }
set { drawNetRectangle = value; }
}
///
/// Reference to the owner form
///
public MainForm Owner
{
get { return owner; }
set { owner = value; }
}
///
/// Reference to DocManager
///
public DocManager DocManager
{
get { return docManager; }
set { docManager = value; }
}
///
/// Active drawing tool.
///
public DrawToolType ActiveTool
{
get { return activeTool; }
set { activeTool = value; }
}
///
/// List of Layers in the drawing
///
public Layers TheLayers
{
get { return _layers; }
set { _layers = value; }
}
///
/// Return True if Undo operation is possible
///
public bool CanUndo
{
get
{
if (undoManager != null)
{
return undoManager.CanUndo;
}
return false;
}
}
///
/// Return True if Redo operation is possible
///
public bool CanRedo
{
get
{
if (undoManager != null)
{
return undoManager.CanRedo;
}
return false;
}
}
public Rectangle GetBounds()
{
int furthestLeft = int.MaxValue;
int furthestTop = int.MaxValue;
int furthestRight = int.MinValue;
int furthestBottom = int.MinValue;
Rectangle rect;
Graphics g = this.CreateGraphics();
if (_layers != null)
{
int lc = _layers.Count;
for (int i = 0; i < lc; i++)
{
// Console.WriteLine(String.Format("Layer {0} is Visible: {1}", i.ToString(), _layers[i].IsVisible.ToString()));
if (_layers[i].IsVisible)
{
if (_layers[i].Graphics != null)
{
for (int ig = 0; ig < _layers[i].Graphics.Count; ig++)
{
rect = _layers[i].Graphics[ig].GetBounds(g);
furthestLeft = Math.Min(furthestLeft, rect.Left);
furthestTop = Math.Min(furthestTop, rect.Left);
furthestRight = Math.Max(furthestRight, rect.Right);
furthestBottom = Math.Max(furthestBottom, rect.Bottom);
}
}
}
}
}
rect = new Rectangle(furthestLeft, furthestTop, Math.Abs(furthestRight-furthestLeft), Math.Abs(furthestBottom-furthestTop));
return rect;
}
internal void ReplaceInitialImage(Image image)
{
((CraftSynth.ImageEditor.DrawImage) (this._layers[0].Graphics[this._layers[0].Graphics.Count - 1])).TheImage = (Bitmap)image;
// this.AddCommandToHistory(new CommandAdd(this.TheLayers[0].Graphics[this._layers[0].Graphics.Count - 1]));
this.Invalidate();
}
internal KeyValuePair? GetInitialImageGraphic()
{
for (int i = this._layers[0].Graphics.Count - 1; i >= 0; i--)
{
if (this._layers[0].Graphics[i] is DrawImage && (this._layers[0].Graphics[i] as DrawImage).IsInitialImage)
{
return new KeyValuePair(i, this._layers[0].Graphics[i] as DrawImage);
}
}
return null;
}
internal void DeselectAll()
{
ActiveTool = DrawToolType.Pointer;
int al = this.TheLayers.ActiveLayerIndex;
this.TheLayers[al].Graphics.UnselectAll();
this.Invalidate();
}
#endregion
#region Event Handlers
///
/// Draw graphic objects and group selection rectangle (optionally)
///
///
///
private void DrawArea_Paint(object sender, PaintEventArgs e)
{
Matrix mx = new Matrix();
mx.Translate(-ClientSize.Width / 2f, -ClientSize.Height / 2f, MatrixOrder.Append);
mx.Rotate(_rotation, MatrixOrder.Append);
mx.Translate(ClientSize.Width / 2f + _panX, ClientSize.Height / 2f + _panY, MatrixOrder.Append);
mx.Scale(_zoom, _zoom, MatrixOrder.Append);
e.Graphics.Transform = mx;
// Determine center of ClientRectangle
Point centerRectangle = new Point();
centerRectangle.X = ClientRectangle.Left + ClientRectangle.Width / 2;
centerRectangle.Y = ClientRectangle.Top + ClientRectangle.Height / 2;
// Get true center point
centerRectangle = BackTrackMouse(centerRectangle);
// Determine offset from current mouse position
SolidBrush brush = new SolidBrush(Color.FromArgb(255, 255, 255));
e.Graphics.FillRectangle(brush,
ClientRectangle);
// Draw objects on each layer, in succession so we get the correct layering. Only draw layers that are visible
if (_layers != null)
{
int lc = _layers.Count;
for (int i = 0; i < lc; i++)
{
Console.WriteLine(String.Format("Layer {0} is Visible: {1}", i.ToString(), _layers[i].IsVisible.ToString()));
if (_layers[i].IsVisible)
{
if (_layers[i].Graphics != null)
_layers[i].Graphics.Draw(e.Graphics);
}
}
}
DrawNetSelection(e.Graphics);
brush.Dispose();
}
///
/// Back Track the Mouse to return accurate coordinates regardless of zoom or pan effects.
/// Courtesy of BobPowell.net
///
/// Point to backtrack
/// Backtracked point
public Point BackTrackMouse(Point p)
{
// Backtrack the mouse...
Point[] pts = new Point[] { p };
Matrix mx = new Matrix();
mx.Translate(-ClientSize.Width / 2f, -ClientSize.Height / 2f, MatrixOrder.Append);
mx.Rotate(_rotation, MatrixOrder.Append);
mx.Translate(ClientSize.Width / 2f + _panX, ClientSize.Height / 2f + _panY, MatrixOrder.Append);
mx.Scale(_zoom, _zoom, MatrixOrder.Append);
mx.Invert();
mx.TransformPoints(pts);
return pts[0];
}
///
/// Mouse down.
/// Left button down event is passed to active tool.
/// Right button down event is handled in this class.
///
///
///
private void DrawArea_MouseDown(object sender, MouseEventArgs e)
{
lastPoint = BackTrackMouse(e.Location);
if (e.Button ==
MouseButtons.Left)
tools[(int)activeTool].OnMouseDown(this, e);
else if (e.Button ==
MouseButtons.Right)
{
if (_panning)
_panning = false;
if (activeTool == DrawToolType.PolyLine || activeTool == DrawToolType.Connector)
tools[(int)activeTool].OnMouseDown(this, e);
ActiveTool = DrawToolType.Pointer;
OnContextMenu(e);
}
}
// else if (e.Button == MouseButtons.Right)
//{
//if (_panning == true)
//_panning = false;
//if (activeTool == DrawToolType.PolyLine)
//tools[(int)activeTool].OnMouseDown(this, e);
//ActiveTool = TETemplateDrawArea.DrawToolType.Pointer;
//}
///
/// Mouse move.
/// Moving without button pressed or with left button pressed
/// is passed to active tool.
///
///
///
private void DrawArea_MouseMove(object sender, MouseEventArgs e)
{
Point curLoc = BackTrackMouse(e.Location);
if (e.Button == MouseButtons.Left ||
e.Button == MouseButtons.None)
if (e.Button == MouseButtons.Left && _panning)
{
if (curLoc.X !=
lastPoint.X)
_panX += curLoc.X - lastPoint.X;
//this.MyParent.ManualScroll(true, -curLoc.X + lastPoint.X);
if (curLoc.Y !=
lastPoint.Y)
_panY += curLoc.Y - lastPoint.Y;
//this.MyParent.ManualScroll(false, -curLoc.Y + lastPoint.Y);
Invalidate();
}
else
tools[(int)activeTool].OnMouseMove(this, e);
else
Cursor = Cursors.Default;
lastPoint = BackTrackMouse(e.Location);
}
///
/// Mouse up event.
/// Left button up event is passed to active tool.
///
///
///
private void DrawArea_MouseUp(object sender, MouseEventArgs e)
{
//lastPoint = BackTrackMouse(e.Location);
if (e.Button == MouseButtons.Left)
{
tools[(int)activeTool].OnMouseUp(this, e);
if (activeTool != DrawToolType.Pointer && activeTool!= DrawToolType.Text && activeTool!= DrawToolType.Image)
{
int al = this.TheLayers.ActiveLayerIndex;
this.AddCommandToHistory(new CommandAdd(this.TheLayers[al].Graphics[0]));
}
if (this.PanX != 0 || this.PanY != 0)
{
this.myparent.ManualScroll(true, -(int)Math.Round(this.PanX*this._zoom));
this.myparent.ManualScroll(false, -(int)Math.Round(this.PanY*this._zoom));
this.PanX = 0;
this.PanY = 0;
this.Invalidate();
this.myparent.pnlDrawArea.Invalidate();
}
this.ActiveTool = DrawArea.DrawToolType.Pointer;//Selected tool is automatically dropped after drawing item
}
}
public void CutObject()
{
MessageBox.Show("Cut (from drawarea)");
}
private void DrawArea_MouseWheel(object sender, MouseEventArgs e)
{
}
#endregion
#region Other Functions
///
/// Initialization
///
/// Reference to the owner form
/// Reference to Document manager
public void Initialize(MainForm owner, DocManager docManager, Image initialImage, string initialImageAsFilePath, byte[] initialImageAsPngBytes)
{
SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
Invalidate();
// Keep reference to owner form
Owner = owner;
DocManager = docManager;
// set default tool
activeTool = DrawToolType.Pointer;
// Create undo manager
undoManager = new UndoManager(_layers);
// create array of drawing tools
tools = new Tool[(int)DrawToolType.NumberOfDrawTools];
tools[(int)DrawToolType.Pointer] = new ToolPointer();
tools[(int)DrawToolType.Rectangle] = new ToolRectangle();
tools[(int)DrawToolType.Ellipse] = new ToolEllipse();
tools[(int)DrawToolType.Line] = new ToolLine();
tools[(int)DrawToolType.PolyLine] = new ToolPolyLine();
tools[(int)DrawToolType.Polygon] = new ToolPolygon();
tools[(int)DrawToolType.Text] = new ToolText();
tools[(int)DrawToolType.Image] = new ToolImage();
tools[(int)DrawToolType.Connector] = new ToolConnector();
LineColor = Color.Red;
FillColor = Color.White;
LineWidth = 5;
LoadInitialImage(initialImage, initialImageAsFilePath, initialImageAsPngBytes, null);
}
public void LoadInitialImage(Image initialImage, string initialImageAsFilePath, byte[] initialImageAsPngBytes, DrawImage paradigm)
{
if (initialImage != null)
{
((ToolImage) tools[(int) DrawToolType.Image]).InsertImage(this, initialImage, true, true, paradigm);
}
if (initialImageAsFilePath != null)
{
((ToolImage) tools[(int) DrawToolType.Image]).InsertImage(this, initialImageAsFilePath, true, true, paradigm);
}
if (initialImageAsPngBytes != null)
{
((ToolImage) tools[(int) DrawToolType.Image]).InsertImage(this, initialImageAsPngBytes, true, true, paradigm);
}
// int al = _layers.ActiveLayerIndex;
//var temp = this.TheLayers[al].Graphics[0];
//this.TheLayers[al].Graphics.RemoveAt(0);
//this.TheLayers[al].Graphics.Add(temp);
this.Invalidate();
}
///
/// Add command to history.
///
public void AddCommandToHistory(Command command)
{
undoManager.AddCommandToHistory(command);
}
///
/// Clear Undo history.
///
public void ClearHistory()
{
undoManager.ClearHistory();
}
///
/// Undo
///
public void Undo()
{
undoManager.Undo();
Refresh();
}
///
/// Redo
///
public void Redo()
{
undoManager.Redo();
Refresh();
}
///
/// Draw group selection rectangle
///
///
public void DrawNetSelection(Graphics g)
{
if (!DrawNetRectangle)
return;
ControlPaint.DrawFocusRectangle(g, NetRectangle, Color.Black, Color.Transparent);
}
///
/// Right-click handler
///
///
private void OnContextMenu(MouseEventArgs e)
{
// Change current selection if necessary
Point point = BackTrackMouse(new Point(e.X, e.Y));
Point menuPoint = new Point(e.X, e.Y);
int al = _layers.ActiveLayerIndex;
int n = _layers[al].Graphics.Count;
DrawObject o = null;
for (int i = 0; i < n; i++)
{
if (_layers[al].Graphics[i].HitTest(point) == 0)
{
o = _layers[al].Graphics[i];
break;
}
}
if (o != null)
{
if (!o.Selected)
_layers[al].Graphics.UnselectAll();
// Select clicked object
o.Selected = true;
}
else
{
_layers[al].Graphics.UnselectAll();
}
Refresh();
Owner.ctxtMenu.Show(this, menuPoint);
}
#endregion
}
}