using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Reflection;
using System.Runtime.Serialization;
using System.Windows.Forms;
namespace CraftSynth.ImageEditor
{
///
/// List of graphic objects
///
[Serializable]
public class GraphicsList: IDisposable
{
private ArrayList graphicsList;
private bool _isDirty;
public bool Dirty
{
get
{
if (_isDirty == false)
{
foreach (DrawObject o in graphicsList)
{
if (o.Dirty)
{
_isDirty = true;
break;
}
}
}
return _isDirty;
}
set
{
foreach (DrawObject o in graphicsList)
o.Dirty = false;
_isDirty = false;
}
}
///
/// Returns IEnumerable object which may be used for enumeration
/// of selected objects.
///
/// Note: returning IEnumerable breaks CLS-compliance
/// (assembly CLSCompliant = true is removed from AssemblyInfo.cs).
/// To make this program CLS-compliant, replace
/// IEnumerable with IEnumerable. This requires
/// casting to object at runtime.
///
///
public IEnumerable Selection
{
get
{
foreach (DrawObject o in graphicsList)
{
if (o.Selected)
{
yield return o;
}
}
}
}
private const string entryCount = "ObjectCount";
private const string entryType = "ObjectType";
public GraphicsList()
{
graphicsList = new ArrayList();
}
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
// Flag: Has Dispose already been called?
bool _disposed = false;
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
// Free any managed objects here.
//
if (this.graphicsList != null)
{
for (int i = 0; i < this.graphicsList.Count; i++)
{
if (this.graphicsList[i] != null)
{
((DrawObject) this.graphicsList[i]).Dispose();
}
}
}
}
// Free any unmanaged objects here.
//
this._disposed = true;
}
}
~GraphicsList()
{
this.Dispose(false);
}
///
/// Load the GraphicsList from data pulled from disk
///
/// Data from disk
/// Layer number to be loaded
public void LoadFromStream(SerializationInfo info, int orderNumber)
{
graphicsList = new ArrayList();
// Get number of DrawObjects in this GraphicsList
int numberObjects = info.GetInt32(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}",
entryCount, orderNumber));
for (int i = 0; i < numberObjects; i++)
{
string typeName;
typeName = info.GetString(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}",
entryType, i));
object drawObject;
drawObject = Assembly.GetExecutingAssembly().CreateInstance(
typeName);
// Let the Draw Object load itself
((DrawObject)drawObject).LoadFromStream(info, orderNumber, i);
graphicsList.Add(drawObject);
}
}
///
/// Save GraphicsList to the stream
///
/// Stream to place the GraphicsList into
/// Layer Number the List is on
public void SaveToStream(SerializationInfo info, int orderNumber)
{
// First store the number of DrawObjects in the list
info.AddValue(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}",
entryCount, orderNumber),
graphicsList.Count);
// Next save each individual object
int i = 0;
foreach (DrawObject o in graphicsList)
{
info.AddValue(
String.Format(CultureInfo.InvariantCulture,
"{0}{1}",
entryType, i),
o.GetType().FullName);
// Let each object save itself
o.SaveToStream(info, orderNumber, i);
i++;
}
}
///
/// Draw all the visible objects in the List
///
/// Graphics to draw on
public void Draw(Graphics g)
{
int numberObjects = graphicsList.Count;
// Enumerate list in reverse order
// to get first object on the top
//graphicsList.Sort();
for (int i = numberObjects - 1; i >= 0; i--)
{
DrawObject o;
o = (DrawObject)graphicsList[i];
// Only draw objects that are visible
if (o.IntersectsWith(Rectangle.Round(g.ClipBounds)))
o.Draw(g);
if (o.Selected)
o.DrawTracker(g);
}
}
///
/// Clear all objects in the list
///
///
/// true if at least one object is deleted
///
public bool Clear()
{
bool result = (graphicsList.Count > 0);
if (graphicsList.Count > 0)
{
for (int i = graphicsList.Count - 1; i >= 0; i--)
{
if (graphicsList[i] != null)
{
((DrawObject) graphicsList[i]).Dispose();
}
graphicsList.RemoveAt(i);
}
}
// Set dirty flag based on result. Result is true only if at least one item was cleared and since the list is empty, there can be nothing dirty.
if (result)
_isDirty = false;
return result;
}
///
/// Count and this [nIndex] allow to read all graphics objects
/// from GraphicsList in the loop.
///
public int Count
{
get { return graphicsList.Count; }
}
///
/// Allow accessing Draw Objects by index
///
/// 0-based index to retrieve
/// Selected DrawObject
public DrawObject this[int index]
{
get
{
if (index < 0 ||
index >= graphicsList.Count)
return null;
return (DrawObject)graphicsList[index];
}
}
///
/// SelectedCount and GetSelectedObject allow to read
/// selected objects in the loop
///
public int SelectionCount
{
get
{
int n = 0;
foreach (DrawObject o in graphicsList)
{
if (o.Selected)
n++;
}
return n;
}
}
public DrawObject GetSelectedObject(int index)
{
int n = -1;
foreach (DrawObject o in graphicsList)
{
if (o.Selected)
{
n++;
if (n == index)
return o;
}
}
return null;
}
public void Add(DrawObject obj)
{
graphicsList.Sort();
foreach (DrawObject o in graphicsList)
o.ZOrder++;
graphicsList.Insert(0, obj);
}
public void AddAsInitialGraphic(DrawObject obj)
{
graphicsList.Add(obj);
}
///
/// Thanks to Member 3272353 for this fix to object ordering problem.
///
///
public void Append(DrawObject obj)
{
graphicsList.Add(obj);
}
public void SelectInRectangle(Rectangle rectangle)
{
UnselectAll();
foreach (DrawObject o in graphicsList)
{
if (o.IntersectsWith(rectangle))
o.Selected = true;
}
}
public void UnselectAll()
{
foreach (DrawObject o in graphicsList)
{
o.Selected = false;
}
}
public void SelectAll()
{
foreach (DrawObject o in graphicsList)
{
o.Selected = true;
}
}
///
/// Delete selected items
///
///
/// true if at least one object is deleted
///
public bool DeleteSelection()
{
bool result = false;
int n = graphicsList.Count;
for (int i = n - 1; i >= 0; i--)
{
if (((DrawObject)graphicsList[i]).Selected)
{
graphicsList.RemoveAt(i);
result = true;
}
}
if (result)
_isDirty = true;
return result;
}
///
/// Delete last added object from the list
/// (used for Undo operation).
///
public void DeleteLastAddedObject()
{
if (graphicsList.Count > 0)
{
graphicsList.RemoveAt(0);
}
}
///
/// Replace object in specified place.
/// Used for Undo.
///
public void Replace(int index, DrawObject obj)
{
if (index >= 0 &&
index < graphicsList.Count)
{
graphicsList.RemoveAt(index);
graphicsList.Insert(index, obj);
}
}
///
/// Remove object by index.
/// Used for Undo.
///
public void RemoveAt(int index)
{
graphicsList.RemoveAt(index);
}
///
/// Move selected items to front (beginning of the list)
///
///
/// true if at least one object is moved
///
public bool MoveSelectionToFront()
{
int n;
int i;
ArrayList tempList;
tempList = new ArrayList();
n = graphicsList.Count;
// Read source list in reverse order, add every selected item
// to temporary list and remove it from source list
for (i = n - 1; i >= 0; i--)
{
if (((DrawObject)graphicsList[i]).Selected)
{
tempList.Add(graphicsList[i]);
graphicsList.RemoveAt(i);
}
}
// Read temporary list in direct order and insert every item
// to the beginning of the source list
n = tempList.Count;
for (i = 0; i < n; i++)
{
graphicsList.Insert(0, tempList[i]);
}
if (n > 0)
_isDirty = true;
return (n > 0);
}
///
/// Move selected items to back (end of the list)
///
///
/// true if at least one object is moved
///
public bool MoveSelectionToBack()
{
int n;
int i;
ArrayList tempList;
tempList = new ArrayList();
n = graphicsList.Count;
// Read source list in reverse order, add every selected item
// to temporary list and remove it from source list
for (i = n - 1; i >= 0; i--)
{
if (((DrawObject)graphicsList[i]).Selected)
{
tempList.Add(graphicsList[i]);
graphicsList.RemoveAt(i);
}
}
// Read temporary list in reverse order and add every item
// to the end of the source list
n = tempList.Count;
for (i = n - 1; i >= 0; i--)
{
graphicsList.Add(tempList[i]);
}
if (n > 0)
_isDirty = true;
return (n > 0);
}
///
/// Get properties from selected objects and fill GraphicsProperties instance
///
///
private GraphicsProperties GetProperties()
{
GraphicsProperties properties = new GraphicsProperties();
//int n = SelectionCount;
//if (n < 1)
// return properties;
//DrawObject o = GetSelectedObject(0);
//int firstColor = o.Color.ToArgb();
//int firstPenWidth = o.PenWidth;
//bool allColorsAreEqual = true;
//bool allWidthAreEqual = true;
//for (int i = 1; i < n; i++)
//{
// if (GetSelectedObject(i).Color.ToArgb() != firstColor)
// allColorsAreEqual = false;
// if (GetSelectedObject(i).PenWidth != firstPenWidth)
// allWidthAreEqual = false;
//}
//if (allColorsAreEqual)
//{
// properties.ColorDefined = true;
// properties.Color = Color.FromArgb(firstColor);
//}
//if (allWidthAreEqual)
//{
// properties.PenWidthDefined = true;
// properties.PenWidth = firstPenWidth;
//}
return properties;
}
///
/// Apply properties for all selected objects
///
private void ApplyProperties()
{
//foreach (DrawObject o in graphicsList)
//{
// if (o.Selected)
// {
// if (properties.ColorDefined)
// {
// o.Color = properties.Color;
// DrawObject.LastUsedColor = properties.Color;
// }
// if (properties.PenWidthDefined)
// {
// o.PenWidth = properties.PenWidth;
// DrawObject.LastUsedPenWidth = properties.PenWidth;
// }
// }
//}
}
///
/// Show Properties dialog. Return true if list is changed
///
///
///
public bool ShowPropertiesDialog(IWin32Window parent)
{
if (SelectionCount < 1)
return false;
GraphicsProperties properties = GetProperties();
PropertiesDialog dlg = new PropertiesDialog();
dlg.Properties = properties;
if (dlg.ShowDialog(parent) !=
DialogResult.OK)
return false;
ApplyProperties();
return true;
}
}
}