Files
Pilz/Pilz.UI/PaintingControl/PaintingObject.cs
2024-06-10 13:15:24 +02:00

829 lines
21 KiB
C#

using Microsoft.VisualBasic.CompilerServices;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
namespace Pilz.UI;
[Serializable]
public class PaintingObject : ICloneable, IPaintingObjectContainer
{
private PaintingObjectResizing resizeEngine = null;
private bool _Selected = false;
private PaintingControl _Parent = null;
public Color FillColor { get; set; } = Color.Blue;
public Color OutlineColor { get; set; } = Color.DarkBlue;
public float OutlineThicknes { get; set; } = 1f;
public DashStyle OutlineDashStyle { get; set; } = DashStyle.Solid;
public LineCapProps LineStartCap { get; set; } = null;
public LineCapProps LineEndCap { get; set; } = null;
[JsonProperty]
private string _Text = "";
public TextPosition TextPosition { get; set; } = TextPosition.FullCenter;
public StringAlignment VerticalTextAlignment { get; set; } = StringAlignment.Center;
public StringAlignment HorizontalTextAlignment { get; set; } = StringAlignment.Center;
public Font TextFont { get; set; } = new Font(FontFamily.GenericSansSerif, 8.25f);
public Color TextColor { get; set; } = Color.Black;
[JsonProperty]
private PointF _Location = new PointF(50f, 50f);
[JsonProperty]
private SizeF _Size = new SizeF(50f, 80f);
public bool EnableFill { get; set; } = true;
public bool EnableOutline { get; set; } = true;
public Color SelectionColor { get; set; } = Color.CornflowerBlue;
public DashStyle SelectionDashStyle { get; set; } = DashStyle.Dot;
[JsonProperty]
private bool _EnableSelection = true;
public Image Image { get; set; } = null;
[JsonIgnore]
public Image BufferedImage { get; set; } = null;
public ImageSizeMode ImageSizeMode { get; set; }
public PaintingObjectImageProperties ImageProperties { get; set; } = new PaintingObjectImageProperties();
[JsonIgnore]
public object Tag { get; set; } = null;
public string Name { get; set; } = "";
public List<PaintingObject> PinnedObjects { get; private set; } = new List<PaintingObject>();
[JsonIgnore]
public List<DelegateDrawPaintingObjectMethode> DrawMethodes { get; private set; } = new List<DelegateDrawPaintingObjectMethode>();
[JsonIgnore]
public DelegateDrawPaintingObjectMethode DrawSelectionMethode { get; private set; } = DefaultDrawMethodes.DrawSelection;
public Cursor Cursor { get; set; } = Cursors.Default;
public bool HardcodedSize { get; set; } = false;
public bool HardcodedLocation { get; set; } = false;
[JsonProperty]
private bool _Visible = true;
[JsonProperty]
private bool _AutoAlignToGrid = false;
public bool MouseTransparency { get; set; } = false;
public PaintingObjectLayering Layering { get; private set; }
public PaintingObjectList PaintingObjects { get; private set; }
[JsonIgnore]
public ulong ErrorsAtDrawing { get; private set; } = 0UL;
public event MouseClickEventHandler MouseClick;
public delegate void MouseClickEventHandler(PaintingObject sender, MouseEventArgs e);
public event MouseDownEventHandler MouseDown;
public delegate void MouseDownEventHandler(PaintingObject sender, MouseEventArgs e);
public event MouseUpEventHandler MouseUp;
public delegate void MouseUpEventHandler(PaintingObject sender, MouseEventArgs e);
public event MouseMoveEventHandler MouseMove;
public delegate void MouseMoveEventHandler(PaintingObject sender, MouseEventArgs e);
public event SelectedChangedEventHandler SelectedChanged;
public delegate void SelectedChangedEventHandler(PaintingObject sender, EventArgs e);
public event PaintEventHandler Paint;
public delegate void PaintEventHandler(PaintingObject sender, PaintEventArgs e);
public event ParentChangedEventHandler ParentChanged;
public delegate void ParentChangedEventHandler(PaintingObject sender, EventArgs e);
public event VisibleChangedEventHandler VisibleChanged;
public delegate void VisibleChangedEventHandler(PaintingObject sender, EventArgs e);
public event MovedEventHandler Moved;
public delegate void MovedEventHandler(PaintingObject sender, EventArgs e);
public event MovingEventHandler Moving;
public delegate void MovingEventHandler(PaintingObject sender, EventArgs e);
public event MovingBeforePositionUpdatedEventHandler MovingBeforePositionUpdated;
public delegate void MovingBeforePositionUpdatedEventHandler(PaintingObject sender, CancelEventArgs e);
public PaintingObject()
{
Layering = new(this);
PaintingObjects = new PaintingObjectList(_Parent) { EnableRaisingEvents = false };
}
public PaintingObject(PaintingObjectType @type) : this()
{
Type = type;
}
public PaintingObject(PaintingObjectType @type, DelegateDrawPaintingObjectMethode[] drawMethodes) : this(type)
{
DrawMethodes.AddRange(drawMethodes);
}
internal void RaiseMouseClick(MouseEventArgs e)
{
MouseClick?.Invoke(this, e);
}
internal void RaiseMouseDown(MouseEventArgs e)
{
MouseDown?.Invoke(this, e);
}
internal void RaiseMouseUp(MouseEventArgs e)
{
MouseUp?.Invoke(this, e);
}
internal void RaiseMouseMove(MouseEventArgs e)
{
MouseMove?.Invoke(this, e);
}
private void RaisePaint(PaintEventArgs e)
{
Paint?.Invoke(this, e);
}
internal void RaiseMoved(EventArgs e)
{
Moved?.Invoke(this, e);
}
internal void RaiseMoving(EventArgs e)
{
Moving?.Invoke(this, e);
}
internal void RaiseMovingBeforePositionUpdated(EventArgs e)
{
MovingBeforePositionUpdated?.Invoke(this, (CancelEventArgs)e);
}
public PaintingObjectType Type
{
get
{
var tt = PaintingObjectType.Custom;
foreach (DelegateDrawPaintingObjectMethode d in DrawMethodes)
{
if (ReferenceEquals(d.Method.DeclaringType, typeof(DefaultDrawMethodes)))
{
switch (d.Method.Name ?? "")
{
case "DrawPicture":
{
tt = tt | PaintingObjectType.Picture;
break;
}
case "DrawText":
{
tt = tt | PaintingObjectType.Text;
break;
}
case "DrawRectangle":
{
tt = tt | PaintingObjectType.Rectangle;
break;
}
case "DrawEllipse":
{
tt = tt | PaintingObjectType.Elipse;
break;
}
case "DrawTriangle":
{
tt = tt | PaintingObjectType.Triangle;
break;
}
case "DrawLine":
{
tt = tt | PaintingObjectType.Line;
break;
}
}
}
}
return tt;
}
set
{
DrawMethodes.Clear();
if ((value & PaintingObjectType.Picture) == PaintingObjectType.Picture)
DrawMethodes.Add(DefaultDrawMethodes.DrawPicture);
if ((value & PaintingObjectType.Rectangle) == PaintingObjectType.Rectangle)
DrawMethodes.Add(DefaultDrawMethodes.DrawRectangle);
if ((value & PaintingObjectType.Elipse) == PaintingObjectType.Elipse)
DrawMethodes.Add(DefaultDrawMethodes.DrawEllipse);
if ((value & PaintingObjectType.Triangle) == PaintingObjectType.Triangle)
DrawMethodes.Add(DefaultDrawMethodes.DrawTriangle);
if ((value & PaintingObjectType.Line) == PaintingObjectType.Line)
DrawMethodes.Add(DefaultDrawMethodes.DrawLine);
if ((value & PaintingObjectType.Text) == PaintingObjectType.Text)
DrawMethodes.Add(DefaultDrawMethodes.DrawText);
}
}
[JsonIgnore]
public PointF Location
{
get
{
if (Parent is not null)
return new PointF(_Location.X * Parent.ZoomFactor.Width, _Location.Y * Parent.ZoomFactor.Height);
else
{
return _Location;
}
}
set
{
if (Parent is not null)
_Location = new PointF(value.X / Parent.ZoomFactor.Width, value.Y / Parent.ZoomFactor.Height);
else
{
_Location = value;
}
}
}
[JsonIgnore]
public PointF LocationDirect
{
get
{
return _Location;
}
set
{
_Location = value;
}
}
[JsonIgnore]
public SizeF Size
{
get
{
if (Parent is not null)
return new SizeF(_Size.Width * Parent.ZoomFactor.Width, _Size.Height * Parent.ZoomFactor.Height);
else
{
return _Size;
}
}
set
{
if (Parent is not null)
_Size = new SizeF(value.Width / Parent.ZoomFactor.Width, value.Height / Parent.ZoomFactor.Height);
else
{
_Size = value;
}
ResetImageBuffer();
}
}
[JsonIgnore]
public SizeF SizeDirect
{
get
{
return _Size;
}
set
{
_Size = value;
ResetImageBuffer();
}
}
[JsonIgnore]
public bool AutoAlignToGrid
{
get
{
return _AutoAlignToGrid;
}
set
{
_AutoAlignToGrid = value;
if (value)
ArrangeToGrid();
}
}
[JsonIgnore]
public bool IsResizing
{
get
{
if (resizeEngine is null)
return false;
else
{
return (bool)resizeEngine?.IsResizing;
}
}
}
[JsonIgnore]
public PaintingControl Parent
{
get
{
return _Parent;
}
set
{
bool re = !ReferenceEquals(value, _Parent);
_Parent = value;
if (re)
ParentChanged?.Invoke(this, new EventArgs());
}
}
[JsonIgnore]
public bool Visible
{
get
{
return _Visible;
}
set
{
if (value != _Visible)
{
_Visible = value;
if (!value && !_EnableSelection)
EnableResize = false;
VisibleChanged?.Invoke(this, new EventArgs());
}
}
}
[JsonIgnore]
public bool Selected
{
get
{
return _Selected;
}
set
{
SetSelection(value, true);
}
}
[JsonIgnore]
public bool SelectedDirect
{
get
{
return Selected;
}
set
{
SetSelection(value, false);
}
}
private void SetSelection(bool value, bool raiseEventOnParent)
{
if (EnableSelection)
{
if (_Selected != value)
{
_Selected = value;
SelectedChanged?.Invoke(this, new EventArgs());
if (raiseEventOnParent)
Parent.RaiseSelectionChanged();
}
}
else
{
_Selected = false;
}
}
[JsonIgnore]
public float Width
{
get
{
return Size.Width;
}
set
{
Size = new SizeF(value, Size.Height);
}
}
[JsonIgnore]
public float Height
{
get
{
return Size.Height;
}
set
{
Size = new SizeF(Size.Width, value);
}
}
[JsonIgnore]
public float X
{
get
{
return Location.X;
}
set
{
Location = new PointF(value, Location.Y);
}
}
[JsonIgnore]
public float Y
{
get
{
return Location.Y;
}
set
{
Location = new PointF(Location.X, value);
}
}
[JsonIgnore]
public string Text
{
get
{
return _Text;
}
set
{
_Text = value;
}
}
[JsonIgnore]
public RectangleF Rectangle
{
get
{
return new RectangleF(Location, Size);
}
set
{
Location = value.Location;
Size = value.Size;
}
}
[JsonIgnore]
public bool EnableSelection
{
get
{
return _EnableSelection;
}
set
{
_EnableSelection = value;
if (!value && !_Visible)
EnableResize = false;
if (!value)
Selected = false;
}
}
[JsonIgnore]
public Rectangle RectangleExtended
{
get
{
return new Rectangle((int)Math.Round(X - 12f), (int)Math.Round(Y - 12f), (int)Math.Round(Width + 12f + 12f), (int)Math.Round(Height + 12f + 12f));
}
set
{
X = value.X + 12;
Y = value.Y + 12;
Width = value.Width - 12 - 12;
Height = value.Height - 12 - 12;
}
}
public void FitSizeToText()
{
if (Parent is null)
throw new Exception("You have to put that PaintingObject to a PaintingControl before.");
var g = Parent.CreateGraphics();
var newSize = g.MeasureString(Text, TextFont);
SizeDirect = newSize + new SizeF(1f, 0f);
}
public void SetBounds(int x, int y, int width, int height)
{
Location = new Point(x, y);
Size = new Size(width, height);
}
[JsonIgnore]
public int Left
{
get
{
return (int)Math.Round(X);
}
set
{
X = value;
}
}
[JsonIgnore]
public int Top
{
get
{
return (int)Math.Round(Y);
}
set
{
Y = value;
}
}
[JsonIgnore]
public int Right
{
get
{
return (int)Math.Round(X + Width);
}
set
{
X = value - Width;
}
}
[JsonIgnore]
public int Bottom
{
get
{
return (int)Math.Round(Y + Height);
}
set
{
Y = value - Height;
}
}
[JsonProperty(nameof(Tag))]
public string TagString
{
get
{
if (Tag is string)
return Conversions.ToString(Tag);
else
{
return string.Empty;
}
}
set
{
Tag = value;
}
}
public bool EnableResize
{
get
{
if (resizeEngine is null)
return false;
else
{
return resizeEngine.Enabled;
}
}
set
{
if (resizeEngine is null && value)
resizeEngine = new PaintingObjectResizing(this);
else if (resizeEngine is not null)
{
resizeEngine.Enabled = value;
}
}
}
public void Remove()
{
Parent?.PaintingObjects.Remove(this);
}
public void AutoArrangeToGrid()
{
if (((Parent?.GridEnabled) is var arg1 && !arg1.HasValue || arg1.Value) && AutoAlignToGrid && arg1.HasValue)
ArrangeToGrid();
}
public void ArrangeToGrid()
{
if (Parent is not null)
{
Parent.ArrangeToGrid(this, true);
if (!Parent.StopDrawing)
Parent.Refresh();
}
}
public void Draw(PaintEventArgs e)
{
Draw(e, e.ClipRectangle.Location);
}
public void Draw(PaintEventArgs e, PointF offset)
{
Draw(e.Graphics, offset);
if (Visible)
RaisePaint(e);
}
public void Draw(Graphics g, PointF offset)
{
if (Visible)
{
var poevargs = new PaintingObjectPaintEventArgs(this, g, offset);
foreach (DelegateDrawPaintingObjectMethode dm in DrawMethodes)
{
try
{
dm?.Invoke(poevargs);
}
catch (Exception ex)
{
ErrorsAtDrawing = (ulong)Math.Round(ErrorsAtDrawing + 1m);
}
}
if (Selected && DrawSelectionMethode is not null)
DrawSelectionMethode?.Invoke(poevargs);
}
}
public object Clone()
{
return Clone(true);
}
public object Clone(bool includePinnedObject)
{
var obj = new PaintingObject();
var metype = GetType();
string[] blackField = new[] { nameof(PinnedObjects), nameof(resizeEngine), nameof(_Parent), nameof(BufferedImage), nameof(ImageProperties) };
void copyFields(object source, object dest, string[] blackFields, Type t)
{
var fields = new List<FieldInfo>(t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase | BindingFlags.Instance));
foreach (FieldInfo @field in fields)
{
if (!blackFields.Contains(@field.Name))
@field.SetValue(dest, @field.GetValue(source));
}
};
copyFields(this, obj, blackField, metype);
copyFields(ImageProperties, obj.ImageProperties, Array.Empty<string>(), ImageProperties.GetType());
if (includePinnedObject)
obj.PinnedObjects.AddRange(PinnedObjects);
obj.EnableResize = EnableResize;
return obj;
}
[Obsolete("Use Layering.BringToTop() instead!")]
public void BringToFront()
{
Layering.BringToTop();
}
[Obsolete("Use Layering.SendToBack() instead!")]
public void SendToBack()
{
Layering.SendToBack();
}
public void ResetImageBuffer()
{
BufferedImage = null;
}
}
public class PaintingObjectList : List<PaintingObject>
{
[JsonIgnore]
internal PaintingControl MyParent { get; private set; }
internal bool EnableRaisingEvents { get; set; } = true;
[JsonIgnore]
public PaintingObjectListLayering Layering { get; private set; }
public PaintingObjectList() : this(null)
{
}
public PaintingObjectList(PaintingControl parent)
{
Layering = new(this);
MyParent = parent;
}
public new void Add(PaintingObject item)
{
item.Parent = MyParent;
base.Add(item);
item.AutoArrangeToGrid();
if (EnableRaisingEvents)
MyParent?.RaisePaintingObjectAdded(new PaintingObjectEventArgs(new[] { item }));
}
public void AddRange(PaintingObject[] items)
{
foreach (PaintingObject item in items)
item.Parent = MyParent;
base.AddRange(items);
foreach (PaintingObject item in items)
item.AutoArrangeToGrid();
if (EnableRaisingEvents)
MyParent?.RaisePaintingObjectAdded(new PaintingObjectEventArgs(items));
}
public new void Insert(int index, PaintingObject item)
{
item.Parent = MyParent;
base.Insert(index, item);
MyParent?.AutoArrangeToGrid();
if (EnableRaisingEvents)
MyParent?.RaisePaintingObjectAdded(new PaintingObjectEventArgs(new[] { item }));
}
public new void Remove(PaintingObject item)
{
item.Parent = null;
base.Remove(item);
if (EnableRaisingEvents)
MyParent?.RaisePaintingObjectRemoved(new PaintingObjectEventArgs(new[] { item }));
}
public new void RemoveAt(int index)
{
this[index].Parent = null;
var item = this[index];
base.RemoveAt(index);
if (EnableRaisingEvents)
MyParent?.RaisePaintingObjectRemoved(new PaintingObjectEventArgs(new[] { item }));
}
}
public enum PaintingObjectType
{
Custom = 0,
Text = 1,
Picture = 2,
Line = 4,
Triangle = 8,
Rectangle = 16,
Elipse = 32
}
public enum ImageSizeMode
{
Fit,
Zoom,
Original
}
public enum TextPosition
{
HLeft = 0x1,
HRight = 0x2,
HCenter = 0x4,
VUp = 0x10,
VDown = 0x20,
VCenter = 0x40,
FullCenter = HCenter | VCenter
}