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 PinnedObjects { get; private set; } = new List(); [JsonIgnore] public List DrawMethodes { get; private set; } = new List(); [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; } = new PaintingObjectLayering(this); public PaintingObjectList PaintingObjects { get; private set; } = new PaintingObjectList(_Parent) { EnableRaisingEvents = false }; [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() { } public PaintingObject(PaintingObjectType @type) { 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(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(), 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 { [JsonIgnore] internal PaintingControl MyParent { get; private set; } internal bool EnableRaisingEvents { get; set; } = true; [JsonIgnore] public PaintingObjectListLayering Layering { get; private set; } = new PaintingObjectListLayering(this); public PaintingObjectList() : this(null) { } public PaintingObjectList(PaintingControl parent) { 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 }