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 } }