using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.Runtime.Serialization;
using System.Windows.Forms;
namespace CraftSynth.ImageEditor
{
///
/// Base class for all draw objects
///
[Serializable]
public abstract class DrawObject : IComparable, IDisposable
{
#region Members
// Object properties
private bool selected;
private Color color;
private Color fillColor;
private bool filled;
private int penWidth;
private Pen drawpen;
private Brush drawBrush;
private DrawingPens.PenType _penType;
private LineCap _endCap;
private FillBrushes.BrushType _brushType;
private string tipText;
// Last used property values (may be kept in the Registry)
private static Color lastUsedColor = Color.Black;
private static int lastUsedPenWidth = 1;
// Entry names for serialization
private const string entryColor = "Color";
private const string entryPenWidth = "PenWidth";
private const string entryPen = "DrawPen";
private const string entryBrush = "DrawBrush";
private const string entryFillColor = "FillColor";
private const string entryFilled = "Filled";
private const string entryZOrder = "ZOrder";
private const string entryRotation = "Rotation";
private const string entryTipText = "TipText";
private bool dirty;
private int _id;
private int _zOrder;
private int _rotation = 0;
private Point _center;
private bool _disposed;
#endregion Members
#region Properties
///
/// Center of the object being drawn.
///
public Point Center
{
get { return _center; }
set { _center = value; }
}
///
/// Rotation of the object in degrees. Negative is Left, Positive is Right.
///
public int Rotation
{
get { return _rotation; }
set
{
if (value > 360)
_rotation = value - 360;
else if (value < -360)
_rotation = value + 360;
else
_rotation = value;
}
}
///
/// ZOrder is the order the objects will be drawn in - lower the ZOrder, the closer the to top the object is.
///
public int ZOrder
{
get { return _zOrder; }
set { _zOrder = value; }
}
///
/// Object ID used for Undo Redo functions
///
public int ID
{
get { return _id; }
set { _id = value; }
}
///
/// Set to true whenever the object changes
///
public bool Dirty
{
get { return dirty; }
set { dirty = value; }
}
///
/// Draw object filled?
///
public bool Filled
{
get { return filled; }
set { filled = value; }
}
///
/// Selection flag
///
public bool Selected
{
get { return selected; }
set { selected = value; }
}
///
/// Fill Color
///
public Color FillColor
{
get { return fillColor; }
set { fillColor = value; }
}
///
/// Border (line) Color
///
public Color Color
{
get { return color; }
set { color = value; }
}
///
/// Pen width
///
public int PenWidth
{
get { return penWidth; }
set { penWidth = value; }
}
public FillBrushes.BrushType BrushType
{
get { return _brushType; }
set { _brushType = value; }
}
///
/// Brush used to paint object
///
public Brush DrawBrush
{
get { return drawBrush; }
set { drawBrush = value; }
}
public DrawingPens.PenType PenType
{
get { return _penType; }
set { _penType = value; }
}
public LineCap EndCap
{
get { return _endCap; }
set { _endCap = value; }
}
///
/// Pen used to draw object
///
public Pen DrawPen
{
get { return drawpen; }
set { drawpen = value; }
}
///
/// Number of handles
///
public virtual int HandleCount
{
get { return 0; }
}
///
/// Number of Connection Points
///
public virtual int ConnectionCount
{
get { return 0; }
}
///
/// Last used color
///
public static Color LastUsedColor
{
get { return lastUsedColor; }
set { lastUsedColor = value; }
}
///
/// Last used pen width
///
public static int LastUsedPenWidth
{
get { return lastUsedPenWidth; }
set { lastUsedPenWidth = value; }
}
///
/// Text to display when mouse is over an object
///
public string TipText
{
get { return tipText; }
set { tipText = value; }
}
#endregion Properties
#region Constructor
protected DrawObject()
{
// ReSharper disable DoNotCallOverridableMethodsInConstructor
ID = GetHashCode();
// ReSharper restore DoNotCallOverridableMethodsInConstructor
}
#endregion
#region Virtual Functions
///
/// Clone this instance.
///
public abstract DrawObject Clone();
///
/// Draw object
///
/// Graphics object will be drawn on
public virtual void Draw(Graphics g)
{
}
#region Selection handle methods
///
/// Get handle point by 1-based number
///
/// 1-based handle number to return
/// Point where handle is located, if found
public virtual Point GetHandle(int handleNumber)
{
return new Point(0, 0);
}
///
/// Get handle rectangle by 1-based number
///
///
/// Rectangle structure to draw the handle
public virtual Rectangle GetHandleRectangle(int handleNumber)
{
Point point = GetHandle(handleNumber);
// Take into account width of pen
return new Rectangle(point.X - (penWidth + 3), point.Y - (penWidth + 3), 7 + penWidth, 7 + penWidth);
}
///
/// Draw tracker for selected object
///
/// Graphics to draw on
public virtual void DrawTracker(Graphics g)
{
if (!Selected)
return;
SolidBrush brush = new SolidBrush(Color.Black);
for (int i = 1; i <= HandleCount; i++)
{
g.FillRectangle(brush, GetHandleRectangle(i));
}
brush.Dispose();
}
#endregion Selection handle methods
#region Connection Point methods
///
/// Get connection point by 0-based number
///
/// 0-based connection number to return
/// Point where connection is located, if found
public virtual Point GetConnection(int connectionNumber)
{
return new Point(0, 0);
}
///
/// Get connectionPoint rectangle that defines the ellipse for the requested connection
///
/// 0-based connection number
/// Rectangle structure to draw the connection
public virtual Rectangle GetConnectionEllipse(int connectionNumber)
{
Point p = GetConnection(connectionNumber);
// Take into account width of pen
return new Rectangle(p.X - (penWidth + 3), p.Y - (penWidth + 3), 7 + penWidth, 7 + penWidth);
}
public virtual void DrawConnection(Graphics g, int connectionNumber)
{
SolidBrush b = new SolidBrush(System.Drawing.Color.Red);
Pen p = new Pen(System.Drawing.Color.Red, -1.0f);
g.DrawEllipse(p, GetConnectionEllipse(connectionNumber));
g.FillEllipse(b, GetConnectionEllipse(connectionNumber));
p.Dispose();
b.Dispose();
}
///
/// Draws the ellipse for the connection handles on the object
///
/// Graphics to draw on
public virtual void DrawConnections(Graphics g)
{
if (!Selected)
return;
SolidBrush b = new SolidBrush(System.Drawing.Color.White);
Pen p = new Pen(System.Drawing.Color.Black, -1.0f);
for (int i = 0; i < ConnectionCount; i++)
{
g.DrawEllipse(p, GetConnectionEllipse(i));
g.FillEllipse(b, GetConnectionEllipse(i));
}
p.Dispose();
b.Dispose();
}
#endregion Connection Point methods
///
/// Hit test to determine if object is hit.
///
/// Point to test
/// (-1) no hit
/// (0) hit anywhere
/// (1 to n) handle number
public virtual int HitTest(Point point)
{
return -1;
}
///
/// Test whether point is inside of the object
///
/// Point to test
/// true if in object, false if not
protected virtual bool PointInObject(Point point)
{
return false;
}
public abstract Rectangle GetBounds(Graphics g);
///
/// Get cursor for the handle
///
/// handle number to return cursor for
/// Cursor object
public virtual Cursor GetHandleCursor(int handleNumber)
{
return Cursors.Default;
}
///
/// Test whether object intersects with rectangle
///
/// Rectangle structure to test
/// true if intersect, false if not
public virtual bool IntersectsWith(Rectangle rectangle)
{
return false;
}
///
/// Move object
///
/// Distance along X-axis: (+)=Right, (-)=Left
/// Distance along Y axis: (+)=Down, (-)=Up
public virtual void Move(int deltaX, int deltaY)
{
}
///
/// Move handle to the point
///
/// Point to Move Handle to
/// Handle number to move
public virtual void MoveHandleTo(Point point, int handleNumber)
{
}
///
/// Dump (for debugging)
///
public virtual void Dump()
{
Trace.WriteLine("");
Trace.WriteLine(GetType().Name);
Trace.WriteLine("Selected = " + selected.ToString(CultureInfo.InvariantCulture));
}
///
/// Normalize object.
/// Call this function in the end of object resizing.
///
public virtual void Normalize()
{
}
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
// Free any managed objects here.
//
if (this.drawpen != null)
{
this.drawpen.Dispose();
}
if (this.drawBrush != null)
{
this.drawBrush.Dispose();
}
}
// Free any unmanaged objects here.
//
this._disposed = true;
}
}
~DrawObject()
{
this.Dispose(false);
}
#region Save / Load methods
///
/// Save object to serialization stream
///
/// The data being written to disk
/// Index of the Layer being saved
/// Index of the object on the Layer
public virtual void SaveToStream(SerializationInfo info, int orderNumber, int objectIndex)
{
info.AddValue(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryColor, orderNumber, objectIndex),
Color.ToArgb());
info.AddValue(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryPenWidth, orderNumber, objectIndex),
PenWidth);
info.AddValue(
string.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryPen, orderNumber, objectIndex),
PenType);
info.AddValue(
string.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryBrush, orderNumber, objectIndex),
BrushType);
info.AddValue(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryFillColor, orderNumber, objectIndex),
FillColor.ToArgb());
info.AddValue(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryFilled, orderNumber, objectIndex),
Filled);
info.AddValue(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryZOrder, orderNumber, objectIndex),
ZOrder);
info.AddValue(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryRotation, orderNumber, objectIndex),
Rotation);
info.AddValue(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryTipText, orderNumber, objectIndex),
tipText);
}
///
/// Load object from serialization stream
///
/// Data from disk to parse into an object
/// Index of the layer object resides on
/// Index of the object on the layer
public virtual void LoadFromStream(SerializationInfo info, int orderNumber, int objectData)
{
int n = info.GetInt32(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryColor, orderNumber, objectData));
Color = Color.FromArgb(n);
PenWidth = info.GetInt32(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryPenWidth, orderNumber, objectData));
PenType = (DrawingPens.PenType)info.GetValue(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryPen, orderNumber, objectData),
typeof(DrawingPens.PenType));
BrushType = (FillBrushes.BrushType)info.GetValue(
string.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryBrush, orderNumber, objectData),
typeof(FillBrushes.BrushType));
n = info.GetInt32(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryFillColor, orderNumber, objectData));
FillColor = Color.FromArgb(n);
Filled = info.GetBoolean(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryFilled, orderNumber, objectData));
ZOrder = info.GetInt32(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryZOrder, orderNumber, objectData));
Rotation = info.GetInt32(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryRotation, orderNumber, objectData));
tipText = info.GetString(String.Format(CultureInfo.InvariantCulture,
"{0}{1}-{2}",
entryTipText, orderNumber, objectData));
// Set the Pen and the Brush, if defined
//if (PenType != DrawingPens.PenType.Generic)
// DrawPen = DrawingPens.SetCurrentPen(PenType);
if (BrushType != FillBrushes.BrushType.NoBrush)
DrawBrush = FillBrushes.SetCurrentBrush(BrushType);
}
#endregion Save/Load methods
#endregion Virtual Functions
#region Other functions
///
/// Initialization
///
protected void Initialize()
{
}
// private
///
/// Copy fields from this instance to cloned instance drawObject.
/// Called from Clone functions of derived classes.
///
/// Object being cloned
protected void FillDrawObjectFields(DrawObject drawObject)
{
drawObject.selected = selected;
drawObject.color = color;
drawObject.penWidth = penWidth;
drawObject._endCap = _endCap;
drawObject.ID = ID;
drawObject._brushType = _brushType;
drawObject._penType = _penType;
drawObject.drawBrush = drawBrush;
drawObject.drawpen = drawpen;
drawObject.filled = filled;
drawObject.fillColor = fillColor;
drawObject._rotation = _rotation;
drawObject._center = _center;
drawObject.tipText = tipText;
}
#endregion Other functions
#region IComparable Members
///
/// Returns (-1), (0), (+1) to represent the relative Z-order of the object being compared with this object
///
/// DrawObject that is compared to this object
/// (-1) if the object is less (further back) than this object.
/// (0) if the object is equal to this object (same level graphically).
/// (1) if the object is greater (closer to the front) than this object.
public int CompareTo(object obj)
{
DrawObject d = obj as DrawObject;
int x = 0;
if (d != null)
if (d.ZOrder == ZOrder)
x = 0;
else if (d.ZOrder > ZOrder)
x = -1;
else
x = 1;
return x;
}
#endregion IComparable Members
}
}