Pilz.UI: convert to C#

This commit is contained in:
2024-06-10 12:29:56 +02:00
parent b9be604f0d
commit 5c6f0c8bfc
32 changed files with 3950 additions and 166 deletions

252
Pilz.UI/DisplayHelp.cs Normal file
View File

@@ -0,0 +1,252 @@
using System.Drawing;
using System.Drawing.Drawing2D;
namespace Pilz.UI;
public class DisplayHelp
{
public static void FillRectangle(Graphics g, Rectangle bounds, Color color1)
{
FillRectangle(g, bounds, color1, Color.Empty, 90);
}
public static void FillRectangle(Graphics g, Rectangle bounds, Color color1, Color color2)
{
FillRectangle(g, bounds, color1, color2, 90);
}
public static void FillRectangle(Graphics g, Rectangle r, Color color1, Color color2, int gradientAngle)
{
if (r.Width == 0 || r.Height == 0)
return;
if (color2.IsEmpty)
{
if (!color1.IsEmpty)
{
var sm = g.SmoothingMode;
g.SmoothingMode = SmoothingMode.None;
using var brush = new SolidBrush(color1);
g.FillRectangle(brush, r);
g.SmoothingMode = sm;
}
}
else
{
using var brush = CreateLinearGradientBrush(r, color1, color2, gradientAngle);
g.FillRectangle(brush, r);
}
}
public static void FillRectangle(Graphics g, Rectangle r, Color color1, Color color2, int gradientAngle, float[] factors, float[] positions)
{
if (r.Width == 0 || r.Height == 0)
return;
if (color2.IsEmpty)
{
if (!color1.IsEmpty)
{
var sm = g.SmoothingMode;
g.SmoothingMode = SmoothingMode.None;
using var brush = new SolidBrush(color1);
g.FillRectangle(brush, r);
g.SmoothingMode = sm;
}
}
else
{
using var brush = CreateLinearGradientBrush(r, color1, color2, gradientAngle);
var blend = new Blend(factors.Length);
blend.Factors = factors;
blend.Positions = positions;
brush.Blend = blend;
g.FillRectangle(brush, r);
}
}
public static void FillRoundedRectangle(Graphics g, Rectangle bounds, int cornerSize, Color color1, Color color2, int gradientAngle)
{
if (color2.IsEmpty)
{
if (!color1.IsEmpty)
{
using var brush = new SolidBrush(color1);
FillRoundedRectangle(g, brush, bounds, cornerSize);
}
}
else
{
using var brush = CreateLinearGradientBrush(bounds, color1, color2, gradientAngle);
FillRoundedRectangle(g, brush, bounds, cornerSize);
}
}
public static void FillRoundedRectangle(Graphics g, Rectangle bounds, int cornerSize, Color color1, Color color2)
{
FillRoundedRectangle(g, bounds, cornerSize, color1, color2, 90);
}
public static void FillRoundedRectangle(Graphics g, Rectangle bounds, int cornerSize, Color color1)
{
using var brush = new SolidBrush(color1);
FillRoundedRectangle(g, brush, bounds, cornerSize);
}
public static void FillRoundedRectangle(Graphics g, Brush brush, Rectangle bounds, int cornerSize)
{
if (cornerSize <= 0)
{
var sm = g.SmoothingMode;
g.SmoothingMode = SmoothingMode.None;
g.FillRectangle(brush, bounds);
g.SmoothingMode = sm;
}
else
{
bounds.Width -= 1;
bounds.Height -= 1;
using var path = GetRoundedRectanglePath(bounds, cornerSize);
g.FillPath(brush, path);
}
}
public static void DrawRectangle(Graphics g, Color color, int x, int y, int width, int height)
{
using var pen = new Pen(color, 1f);
DrawRectangle(g, pen, x, y, width, height);
}
public static void DrawRectangle(Graphics g, Color color, Rectangle r)
{
DrawRectangle(g, color, r.X, r.Y, r.Width, r.Height);
}
public static void DrawRectangle(Graphics g, Pen pen, int x, int y, int width, int height)
{
width -= 1;
height -= 1;
g.DrawRectangle(pen, x, y, width, height);
}
public static void DrawRoundedRectangle(Graphics g, Color color, Rectangle bounds, int cornerSize)
{
if (color.IsEmpty)
return;
using var pen = new Pen(color);
DrawRoundedRectangle(g, pen, bounds.X, bounds.Y, bounds.Width, bounds.Height, cornerSize);
}
public static void DrawRoundedRectangle(Graphics g, Pen pen, int x, int y, int width, int height, int cornerSize)
{
DrawRoundedRectangle(g, pen, null, x, y, width, height, cornerSize);
}
public static void DrawRoundedRectangle(Graphics g, Pen pen, Brush fill, int x, int y, int width, int height, int cornerSize)
{
width -= 1;
height -= 1;
var r = new Rectangle(x, y, width, height);
using var path = GetRoundedRectanglePath(r, cornerSize);
if (fill is not null)
g.FillPath(fill, path);
g.DrawPath(pen, path);
}
public static GraphicsPath GetRoundedRectanglePath(Rectangle r, int cornerSize)
{
var path = new GraphicsPath();
if (cornerSize == 0)
path.AddRectangle(r);
else
{
AddCornerArc(path, r, cornerSize, eCornerArc.TopLeft);
AddCornerArc(path, r, cornerSize, eCornerArc.TopRight);
AddCornerArc(path, r, cornerSize, eCornerArc.BottomRight);
AddCornerArc(path, r, cornerSize, eCornerArc.BottomLeft);
path.CloseAllFigures();
}
return path;
}
public static LinearGradientBrush CreateLinearGradientBrush(Rectangle r, Color color1, Color color2, float gradientAngle)
{
if (r.Width <= 0)
r.Width = 1;
if (r.Height <= 0)
r.Height = 1;
return new LinearGradientBrush(new Rectangle(r.X, r.Y - 1, r.Width, r.Height + 1), color1, color2, gradientAngle);
}
public static void AddCornerArc(GraphicsPath path, Rectangle bounds, int cornerDiameter, eCornerArc corner)
{
if (cornerDiameter > 0)
{
var a = GetCornerArc(bounds, cornerDiameter, corner);
path.AddArc(a.X, a.Y, a.Width, a.Height, a.StartAngle, a.SweepAngle);
}
else if (corner == eCornerArc.TopLeft)
path.AddLine(bounds.X, bounds.Y + 2, bounds.X, bounds.Y);
else if (corner == eCornerArc.BottomLeft)
path.AddLine(bounds.X + 2, bounds.Bottom, bounds.X, bounds.Bottom);
else if (corner == eCornerArc.TopRight)
path.AddLine(bounds.Right - 2, bounds.Y, bounds.Right, bounds.Y);
else if (corner == eCornerArc.BottomRight)
path.AddLine(bounds.Right, bounds.Bottom - 2, bounds.Right, bounds.Bottom);
}
internal static ArcData GetCornerArc(Rectangle bounds, int cornerDiameter, eCornerArc corner)
{
if (cornerDiameter == 0)
cornerDiameter = 1;
int diameter = cornerDiameter * 2;
return corner switch
{
eCornerArc.TopLeft => new ArcData(bounds.X, bounds.Y, diameter, diameter, 180f, 90f),
eCornerArc.TopRight => new ArcData(bounds.Right - diameter, bounds.Y, diameter, diameter, 270f, 90f),
eCornerArc.BottomLeft => new ArcData(bounds.X, bounds.Bottom - diameter, diameter, diameter, 90f, 90f),
_ => new ArcData(bounds.Right - diameter, bounds.Bottom - diameter, diameter, diameter, 0f, 90f),
};
}
public enum eCornerArc
{
TopLeft,
TopRight,
BottomLeft,
BottomRight
}
internal struct ArcData
{
public int X;
public int Y;
public int Width;
public int Height;
public float StartAngle;
public float SweepAngle;
public ArcData(int x, int y, int width, int height, float startAngle, float sweepAngle)
{
X = x;
Y = y;
Width = width;
Height = height;
StartAngle = startAngle;
SweepAngle = sweepAngle;
}
}
}

13
Pilz.UI/Extensions.cs Normal file
View File

@@ -0,0 +1,13 @@
using System.Drawing;
namespace Pilz.UI;
public static class Extensions
{
public static Image? ToIcon(this Image image)
{
if (image is Bitmap bmp)
return Icon.FromHandle(bmp.GetHicon());
return null;
}
}

14
Pilz.UI/Extensions.vb Normal file
View File

@@ -0,0 +1,14 @@
Imports System.Drawing
Imports System.Runtime.CompilerServices
Public Module Extensions
<Extension>
Public Function ToIcon(image As Image)
If TypeOf image Is Bitmap Then
Return Icon.FromHandle(CType(image, Bitmap).GetHicon)
End If
Return Nothing
End Function
End Module

View File

@@ -0,0 +1,19 @@
using System.Diagnostics;
using System.Windows.Forms;
namespace Pilz.UI;
public static class HelpfulFunctions
{
public static void Sleep(int milliseconds)
{
var stopw = new Stopwatch();
stopw.Start();
while (stopw.ElapsedMilliseconds < milliseconds)
Application.DoEvents();
stopw.Stop();
}
}

323
Pilz.UI/HighlightPanel.cs Normal file
View File

@@ -0,0 +1,323 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace Pilz.UI;
internal class HighlightPanel : Control
{
private Dictionary<Control, eHighlightColor> _Highlights = null;
private List<HighlightRegion> _HighlightRegions = new List<HighlightRegion>();
public HighlightPanel(Dictionary<Control, eHighlightColor> highlights)
{
_Highlights = highlights;
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.Opaque, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.Selectable, false);
}
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
foreach (HighlightRegion highlightRegion in _HighlightRegions)
{
Color[] colors = GetHighlightColors(highlightRegion.HighlightColor);
var r = highlightRegion.Bounds;
var back = highlightRegion.BackColor;
r.Inflate(1, 1);
DisplayHelp.FillRectangle(g, r, back);
r.Inflate(-1, -1);
DisplayHelp.FillRoundedRectangle(g, r, 2, colors[0]);
r.Inflate(-2, -2);
DisplayHelp.DrawRectangle(g, colors[2], r);
r.Inflate(1, 1);
DisplayHelp.DrawRoundedRectangle(g, colors[1], r, 2);
}
base.OnPaint(e);
}
private Color[] GetHighlightColors(eHighlightColor color)
{
Color[] colors = new Color[3];
if (color == eHighlightColor.Blue)
{
colors[0] = GetColor(172, 0x6A9CD4);
colors[1] = GetColor(0x6A9CD4);
colors[2] = GetColor(0x5D7EA4);
}
else if (color == eHighlightColor.Orange)
{
colors[0] = GetColor(172, 0xFF9C00);
colors[1] = GetColor(0xFF9C00);
colors[2] = GetColor(0xCC6600);
}
else if (color == eHighlightColor.Green)
{
colors[0] = GetColor(172, 0x71B171);
colors[1] = GetColor(0x71B171);
colors[2] = GetColor(0x339933);
}
else if (color == eHighlightColor.Custom)
{
if (_CustomHighlightColors is null || _CustomHighlightColors.Length < 3)
{
colors[0] = Color.Red;
colors[1] = Color.Red;
colors[2] = Color.Red;
}
else
{
colors[0] = _CustomHighlightColors[0];
colors[1] = _CustomHighlightColors[1];
colors[2] = _CustomHighlightColors[2];
}
}
else
{
colors[0] = GetColor(172, 0xC63030);
colors[1] = GetColor(0xC63030);
colors[2] = GetColor(0x990000);
}
return colors;
}
protected override void OnVisibleChanged(EventArgs e)
{
if (Visible && !_UpdatingRegion)
UpdateRegion();
base.OnVisibleChanged(e);
}
protected override void OnHandleCreated(EventArgs e)
{
if (!_RegionInitialized)
UpdateRegion();
base.OnHandleCreated(e);
}
private bool _RegionInitialized = false;
private bool _UpdatingRegion = false;
internal void UpdateRegion()
{
if (_UpdatingRegion || !IsHandleCreated)
return;
try
{
_UpdatingRegion = true;
Region = null;
_HighlightRegions.Clear();
if (_Highlights is null)
return;
if (_Highlights.Count == 0 && _FocusHighlightControl is null)
{
Visible = false;
return;
}
bool processFocusControl = true;
Region region = null;
foreach (KeyValuePair<Control, eHighlightColor> item in _Highlights)
{
if (item.Value == eHighlightColor.None || !GetIsVisible(item.Key))
continue;
if (ReferenceEquals(item.Key, _FocusHighlightControl))
processFocusControl = false;
var r = GetControlRect(item.Key);
if (r.IsEmpty)
continue;
r.Inflate(2, 2);
_HighlightRegions.Add(new HighlightRegion(r, GetBackColor(item.Key.Parent), item.Value));
if (region is null)
region = new Region(r);
else
{
region.Union(r);
}
r.Inflate(-3, -3);
region.Exclude(r);
}
if (processFocusControl && _FocusHighlightControl is not null && _FocusHighlightControl.Visible)
{
var r = GetControlRect(_FocusHighlightControl);
if (!r.IsEmpty)
{
r.Inflate(2, 2);
_HighlightRegions.Add(new HighlightRegion(r, GetBackColor(_FocusHighlightControl.Parent), _FocusHighlightColor));
if (region is null)
region = new Region(r);
else
{
region.Union(r);
}
r.Inflate(-3, -3);
region.Exclude(r);
}
}
Region = region;
if (region is null)
Visible = false;
else if (!Visible)
{
Visible = true;
BringToFront();
}
Invalidate();
}
finally
{
_UpdatingRegion = false;
_RegionInitialized = true;
}
}
private static Color GetColor(int rgb)
{
if (rgb == -1)
return Color.Empty;
else
{
return Color.FromArgb((rgb & 0xFF0000) >> 16, (rgb & 0xFF00) >> 8, rgb & 0xFF);
}
}
private static Color GetColor(int alpha, int rgb)
{
if (rgb == -1)
return Color.Empty;
else
{
return Color.FromArgb(alpha, (rgb & 0xFF0000) >> 16, (rgb & 0xFF00) >> 8, rgb & 0xFF);
}
}
private bool GetIsVisible(Control control)
{
if (!control.Visible)
return false;
if (control.Parent is null || !control.IsHandleCreated)
return control.Visible;
var rect = new Pilz.Win32.Native.RECT();
Pilz.Win32.Native.User32.GetWindowRect(control.Handle, ref rect);
var pp = control.Parent.PointToClient(new Point(rect.Left + 3, rect.Top + 3));
var handle = Pilz.Win32.Native.User32.ChildWindowFromPointEx(control.Parent.Handle, new Pilz.Win32.Native.POINT(pp.X, pp.Y), (uint)Pilz.Win32.Native.WindowFromPointFlags.CWP_SKIPINVISIBLE);
if (handle == nint.Zero)
return control.Visible;
var c = Control.FromHandle(handle);
if (c is not null && !ReferenceEquals(c, control) && !ReferenceEquals(c, this) && !ReferenceEquals(c, control.Parent))
return false;
return control.Visible;
}
private Color GetBackColor(Control control)
{
var backColor = control.BackColor;
if (backColor.IsEmpty || backColor == Color.Transparent)
backColor = SystemColors.Control;
else if (backColor.A < 255)
{
backColor = Color.FromArgb(255, backColor);
}
return backColor;
}
protected override void OnResize(EventArgs e)
{
UpdateRegion();
base.OnResize(e);
}
private Rectangle GetControlRect(Control c)
{
if (!c.IsHandleCreated)
return Rectangle.Empty;
var rect = default(Pilz.Win32.Native.RECT);
Pilz.Win32.Native.User32.GetWindowRect(c.Handle, ref rect);
var p = this.PointToClient(rect.Location);
return new Rectangle(p, rect.Size);
}
private struct HighlightRegion
{
public Rectangle Bounds;
public Color BackColor;
public eHighlightColor HighlightColor;
public HighlightRegion(Rectangle bounds, Color backColor, eHighlightColor highlightColor)
{
Bounds = bounds;
BackColor = backColor;
HighlightColor = highlightColor;
}
}
private Control _FocusHighlightControl;
public Control FocusHighlightControl
{
get
{
return _FocusHighlightControl;
}
set
{
_FocusHighlightControl = value;
}
}
private eHighlightColor _FocusHighlightColor = eHighlightColor.Blue;
public eHighlightColor FocusHighlightColor
{
get
{
return _FocusHighlightColor;
}
set
{
_FocusHighlightColor = value;
}
}
private Color[] _CustomHighlightColors = null;
public Color[] CustomHighlightColors
{
get
{
return _CustomHighlightColors;
}
set
{
_CustomHighlightColors = value;
}
}
}

510
Pilz.UI/Highlighter.cs Normal file
View File

@@ -0,0 +1,510 @@
using Microsoft.VisualBasic.CompilerServices;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
// Nicht gemergte Änderung aus Projekt "Pilz.UI (net8.0-windows)"
// Vor:
// Imports System.Windows.Forms
// Imports System.Drawing
// Nach:
// Imports System.Drawing
// Imports System.Windows.Forms
using System.Windows.Forms;
namespace Pilz.UI;
public class Highlighter : Component
{
private Dictionary<Control, eHighlightColor> _Highlights = new Dictionary<Control, eHighlightColor>();
private Dictionary<Control, bool> _HighlightOnFocus = new Dictionary<Control, bool>();
protected override void Dispose(bool disposing)
{
if (_ContainerControl is not null)
{
_ContainerControl.SizeChanged -= ContainerControlSizeChanged;
_ContainerControl.HandleCreated -= ContainerControlHandleCreated;
}
if (_HighlightPanel is not null && _HighlightPanel.Parent is null && !_HighlightPanel.IsDisposed)
{
_HighlightPanel.Dispose();
_HighlightPanel = null;
}
else
{
_HighlightPanel = null;
}
base.Dispose(disposing);
}
[DefaultValue(false)]
[Localizable(true)]
[Description("Indicates whether control is highlighted when it receives input focus.")]
public bool GetHighlightOnFocus(Control c)
{
if (_HighlightOnFocus.ContainsKey(c))
return _HighlightOnFocus[c];
return false;
}
public void SetHighlightOnFocus(Control c, bool highlight)
{
if (c is null)
throw new NullReferenceException();
if (_HighlightOnFocus.ContainsKey(c))
{
if (!highlight)
RemoveHighlightOnFocus(_HighlightOnFocus, c);
return;
}
if (highlight)
AddHighlightOnFocus(_HighlightOnFocus, c);
}
private void AddHighlightOnFocus(Dictionary<Control, bool> highlightOnFocus, Control c)
{
c.Enter += ControlHighlightEnter;
c.Leave += ControlHighlightLeave;
c.VisibleChanged += ControlHighlightVisibleChanged;
highlightOnFocus.Add(c, true);
}
private void ControlHighlightVisibleChanged(object sender, EventArgs e)
{
if (_HighlightPanel is not null && Conversions.ToBoolean(Operators.ConditionalCompareObjectEqual(_HighlightPanel.FocusHighlightControl, sender, false)))
UpdateHighlighterRegion();
}
private void ControlHighlightLeave(object sender, EventArgs e)
{
if (_HighlightPanel is not null)
_HighlightPanel.FocusHighlightControl = null;
UpdateHighlighterRegion();
}
private void ControlHighlightEnter(object sender, EventArgs e)
{
if (_HighlightPanel is not null)
{
if (!_HighlightPanel.Visible)
_HighlightPanel.Visible = true;
_HighlightPanel.BringToFront();
_HighlightPanel.FocusHighlightControl = (Control)sender;
}
UpdateHighlighterRegion();
}
private void RemoveHighlightOnFocus(Dictionary<Control, bool> highlightOnFocus, Control c)
{
c.Enter -= ControlHighlightEnter;
c.Leave -= ControlHighlightLeave;
c.VisibleChanged -= ControlHighlightVisibleChanged;
highlightOnFocus.Remove(c);
}
[DefaultValue(eHighlightColor.None)]
[Localizable(true)]
[Description("Indicates the highlight color that is applied to the control.")]
public eHighlightColor GetHighlightColor(Control c)
{
if (_Highlights.ContainsKey(c))
return _Highlights[c];
return eHighlightColor.None;
}
public void SetHighlightColor(Control c, eHighlightColor highlightColor)
{
if (_Highlights.ContainsKey(c))
{
if (highlightColor == eHighlightColor.None)
RemoveHighlight(_Highlights, c);
else
{
var color = _Highlights[c];
RemoveHighlight(_Highlights, c);
AddHighlight(_Highlights, c, highlightColor);
}
}
else if (highlightColor != eHighlightColor.None)
{
AddHighlight(_Highlights, c, highlightColor);
}
}
private Dictionary<TabControl, int> _TabControl2 = new Dictionary<TabControl, int>();
private Dictionary<Panel, int> _ParentPanel = new Dictionary<Panel, int>();
private void AddHighlight(Dictionary<Control, eHighlightColor> highlights, Control c, eHighlightColor highlightColor)
{
highlights.Add(c, highlightColor);
c.LocationChanged += new EventHandler(ControlLocationChanged);
c.SizeChanged += new EventHandler(ControlSizeChanged);
c.VisibleChanged += new EventHandler(ControlVisibleChanged);
if (_HighlightPanel is not null)
{
if (!_HighlightPanel.Visible)
_HighlightPanel.Visible = true;
_HighlightPanel.BringToFront();
}
if (c.Parent is null)
c.ParentChanged += ControlParentChanged;
else
{
AddTabControlHandlers(c);
}
UpdateHighlighterRegion();
}
private void ControlParentChanged(object sender, EventArgs e)
{
Control c = (Control)sender;
c.ParentChanged -= ControlParentChanged;
AddTabControlHandlers(c);
}
private void AddTabControlHandlers(Control c)
{
TabControl tab2 = GetParentControl(c, typeof(TabControl)) as TabControl;
if (tab2 is not null)
{
if (_TabControl2.ContainsKey(tab2))
_TabControl2[tab2] = _TabControl2[tab2] + 1;
else
{
_TabControl2.Add(tab2, 1);
tab2.SelectedIndexChanged += WinFormsTabSelectedIndexChanged;
}
}
else
{
Panel parentPanel = GetParentControl(c, typeof(Panel)) as Panel;
if (parentPanel is not null)
{
if (_ParentPanel.ContainsKey(parentPanel))
_ParentPanel[parentPanel] = _ParentPanel[parentPanel] + 1;
else
{
_ParentPanel.Add(parentPanel, 1);
parentPanel.Resize += ParentPanelResized;
parentPanel.LocationChanged += ParentPanelLocationChanged;
}
}
}
}
private void ParentPanelLocationChanged(object sender, EventArgs e)
{
UpdateHighlights();
}
private void ParentPanelResized(object sender, EventArgs e)
{
UpdateHighlights();
}
private void WinFormsTabSelectedIndexChanged(object sender, EventArgs e)
{
UpdateHighlighterRegion();
}
private Control GetParentControl(Control c, Type parentType)
{
var parent = c.Parent;
while (parent is not null)
{
if (parentType.IsAssignableFrom(parent.GetType()))
return parent;
parent = parent.Parent;
}
return null;
}
private void ControlVisibleChanged(object sender, EventArgs e)
{
UpdateHighlighterRegion();
}
private void ControlSizeChanged(object sender, EventArgs e)
{
UpdateHighlighterRegion();
}
private void ControlLocationChanged(object sender, EventArgs e)
{
UpdateHighlighterRegion();
}
private void UpdateHighlighterRegion()
{
if (_HighlightPanel is not null)
_HighlightPanel.UpdateRegion();
}
public void UpdateHighlights()
{
UpdateHighlighterRegion();
}
private void RemoveHighlight(Dictionary<Control, eHighlightColor> highlights, Control c)
{
highlights.Remove(c);
c.LocationChanged -= new EventHandler(ControlLocationChanged);
c.SizeChanged -= new EventHandler(ControlSizeChanged);
c.VisibleChanged -= new EventHandler(ControlVisibleChanged);
TabControl tab2 = GetParentControl(c, typeof(TabControl)) as TabControl;
if (tab2 is not null)
{
if (_TabControl2.ContainsKey(tab2))
{
if (_TabControl2[tab2] == 1)
{
_TabControl2.Remove(tab2);
tab2.SelectedIndexChanged -= WinFormsTabSelectedIndexChanged;
}
else
{
_TabControl2[tab2] = _TabControl2[tab2] - 1;
}
}
}
else
{
Panel parentPanel = GetParentControl(c, typeof(Panel)) as Panel;
if (parentPanel is not null)
{
if (_ParentPanel.ContainsKey(parentPanel))
{
if (_ParentPanel[parentPanel] == 1)
{
_ParentPanel.Remove(parentPanel);
parentPanel.LocationChanged -= ParentPanelLocationChanged;
parentPanel.SizeChanged -= ParentPanelResized;
}
else
{
_ParentPanel[parentPanel] = _ParentPanel[parentPanel] - 1;
}
}
}
}
UpdateHighlighterRegion();
}
internal Dictionary<Control, eHighlightColor> Highlights
{
get
{
return _Highlights;
}
}
private eHighlightColor _FocusHighlightColor = eHighlightColor.Blue;
[DefaultValue(eHighlightColor.Blue)]
[Category("Appearance")]
[Description("Indicates the highlight focus color.")]
[Localizable(true)]
public eHighlightColor FocusHighlightColor
{
get
{
return _FocusHighlightColor;
}
set
{
_FocusHighlightColor = value;
if (_HighlightPanel is not null)
{
_HighlightPanel.FocusHighlightColor = value;
UpdateHighlighterRegion();
}
}
}
private HighlightPanel _HighlightPanel = null;
private Control _ContainerControl = null;
[Description("Indicates container control highlighter is bound to. Should be set to parent form.")]
[Category("Behavior")]
public Control ContainerControl
{
get
{
return _ContainerControl;
}
set
{
if (DesignMode)
{
_ContainerControl = value;
return;
}
if (!ReferenceEquals(_ContainerControl, value))
{
if (_ContainerControl is not null)
{
_ContainerControl.SizeChanged -= ContainerControlSizeChanged;
_ContainerControl.HandleCreated -= ContainerControlHandleCreated;
if (_HighlightPanel is not null && ReferenceEquals(_HighlightPanel.Parent, _ContainerControl))
_ContainerControl.Controls.Remove(_HighlightPanel);
}
_ContainerControl = value;
if (_ContainerControl is not null)
{
if (_HighlightPanel is null)
{
_HighlightPanel = new HighlightPanel(_Highlights);
_HighlightPanel.FocusHighlightColor = _FocusHighlightColor;
_HighlightPanel.Margin = new Padding(0);
_HighlightPanel.Padding = new Padding(0);
_HighlightPanel.CustomHighlightColors = _CustomHighlightColors;
_HighlightPanel.Visible = false;
}
_ContainerControl.SizeChanged += ContainerControlSizeChanged;
_ContainerControl.HandleCreated += ContainerControlHandleCreated;
_ContainerControl.Controls.Add(_HighlightPanel);
UpdateHighlightPanelBounds();
}
}
}
}
private void ContainerControlHandleCreated(object sender, EventArgs e)
{
if (_Highlights.Count > 0 && _HighlightPanel is not null && !_HighlightPanel.Visible)
_HighlightPanel.Visible = true;
}
private void UpdateHighlightPanelBounds()
{
var bounds = new Rectangle(0, 0, _ContainerControl.ClientRectangle.Width, _ContainerControl.ClientRectangle.Height);
if (_HighlightPanel is not null)
{
if (_HighlightPanel.Parent is Form)
{
Form form = _HighlightPanel.Parent as Form;
if (form.AutoSize)
{
bounds.X += form.Padding.Left;
bounds.Y += form.Padding.Top;
bounds.Width -= form.Padding.Horizontal;
bounds.Height -= form.Padding.Vertical;
}
}
if (_HighlightPanel.Bounds.Equals(bounds))
_HighlightPanel.UpdateRegion();
else
{
_HighlightPanel.Bounds = bounds;
}
_HighlightPanel.BringToFront();
}
}
private Timer _DelayTimer = null;
private void ContainerControlSizeChanged(object sender, EventArgs e)
{
Form form = sender as Form;
if (form is not null)
{
if (_DelayTimer is null)
{
_DelayTimer = new Timer();
_DelayTimer.Interval = 100;
_DelayTimer.Tick += new EventHandler(DelayTimerTick);
_DelayTimer.Start();
}
return;
}
UpdateHighlightPanelBounds();
}
private void DelayTimerTick(object sender, EventArgs e)
{
var timer = _DelayTimer;
_DelayTimer = null;
timer.Tick -= new EventHandler(DelayTimerTick);
timer.Stop();
timer.Dispose();
UpdateHighlightPanelBounds();
}
private Color[] _CustomHighlightColors = null;
[Category("Appearance")]
[Description("Array of colors used to render custom highlight color. Control expects 3 colors in array to be specified which define the highlight border.")]
public Color[] CustomHighlightColors
{
get
{
return _CustomHighlightColors;
}
set
{
_CustomHighlightColors = value;
if (_HighlightPanel is not null)
{
_HighlightPanel.CustomHighlightColors = _CustomHighlightColors;
_HighlightPanel.Invalidate();
}
}
}
}
public enum eHighlightColor
{
None,
Red,
Blue,
Green,
Orange,
Custom
}

View File

@@ -1,13 +0,0 @@
'------------------------------------------------------------------------------
' <auto-generated>
' Dieser Code wurde von einem Tool generiert.
' Laufzeitversion:4.0.30319.42000
'
' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
' der Code erneut generiert wird.
' </auto-generated>
'------------------------------------------------------------------------------
Option Strict On
Option Explicit On

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MySubMain>false</MySubMain>
<SingleInstance>false</SingleInstance>
<ShutdownMode>0</ShutdownMode>
<EnableVisualStyles>true</EnableVisualStyles>
<AuthenticationMode>0</AuthenticationMode>
<ApplicationType>1</ApplicationType>
<SaveMySettingsOnExit>true</SaveMySettingsOnExit>
</MyApplicationData>

View File

@@ -1,63 +0,0 @@
'------------------------------------------------------------------------------
' <auto-generated>
' Dieser Code wurde von einem Tool generiert.
' Laufzeitversion:4.0.30319.42000
'
' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
' der Code erneut generiert wird.
' </auto-generated>
'------------------------------------------------------------------------------
Option Strict On
Option Explicit On
Imports System
Namespace My.Resources
'Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
'-Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
'Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
'mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
'''<summary>
''' Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
'''</summary>
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0"), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
Friend Module Resources
Private resourceMan As Global.System.Resources.ResourceManager
Private resourceCulture As Global.System.Globalization.CultureInfo
'''<summary>
''' Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
'''</summary>
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
Get
If Object.ReferenceEquals(resourceMan, Nothing) Then
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("Pilz.UI.Resources", GetType(Resources).Assembly)
resourceMan = temp
End If
Return resourceMan
End Get
End Property
'''<summary>
''' Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
''' Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
'''</summary>
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Friend Property Culture() As Global.System.Globalization.CultureInfo
Get
Return resourceCulture
End Get
Set
resourceCulture = value
End Set
End Property
End Module
End Namespace

View File

@@ -1,73 +0,0 @@
'------------------------------------------------------------------------------
' <auto-generated>
' Dieser Code wurde von einem Tool generiert.
' Laufzeitversion:4.0.30319.42000
'
' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
' der Code erneut generiert wird.
' </auto-generated>
'------------------------------------------------------------------------------
Option Strict On
Option Explicit On
Namespace My
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0"), _
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Partial Friend NotInheritable Class MySettings
Inherits Global.System.Configuration.ApplicationSettingsBase
Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings()),MySettings)
#Region "Automatische My.Settings-Speicherfunktion"
#If _MyType = "WindowsForms" Then
Private Shared addedHandler As Boolean
Private Shared addedHandlerLockObject As New Object
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Private Shared Sub AutoSaveSettings(sender As Global.System.Object, e As Global.System.EventArgs)
If My.Application.SaveMySettingsOnExit Then
My.Settings.Save()
End If
End Sub
#End If
#End Region
Public Shared ReadOnly Property [Default]() As MySettings
Get
#If _MyType = "WindowsForms" Then
If Not addedHandler Then
SyncLock addedHandlerLockObject
If Not addedHandler Then
AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
addedHandler = True
End If
End SyncLock
End If
#End If
Return defaultInstance
End Get
End Property
End Class
End Namespace
Namespace My
<Global.Microsoft.VisualBasic.HideModuleNameAttribute(), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _
Friend Module MySettingsProperty
<Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")> _
Friend ReadOnly Property Settings() As Global.Pilz.UI.My.MySettings
Get
Return Global.Pilz.UI.My.MySettings.Default
End Get
End Property
End Module
End Namespace

View File

@@ -1,7 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" UseMySettingsClassName="true">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -0,0 +1,18 @@
using System.Drawing;
using System.Drawing.Drawing2D;
namespace Pilz.UI;
public class ArrowLineCapProps : LineCapProps
{
public Size Size { get; set; } = new Size(10, 10);
public bool IsFilles { get; set; } = true;
internal override LineCapConfigurationArgs Configure()
{
var cap = new AdjustableArrowCap(Size.Width, Size.Height, IsFilles);
return new LineCapConfigurationArgs(cap);
}
}

View File

@@ -0,0 +1,284 @@
using Pilz.Drawing;
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace Pilz.UI;
/// <summary>
/// Contains static methods that are used for the standart PaintingObject Types.
/// </summary>
public class DefaultDrawMethodes
{
public static void DrawText(PaintingObjectPaintEventArgs e)
{
var obj = e.PaintingObject;
var b = new SolidBrush(obj.TextColor);
var p = new PointF();
var rect = new Rectangle((int)Math.Round(e.X), (int)Math.Round(e.Y), (int)Math.Round(obj.Width), (int)Math.Round(obj.Height));
var f = StringFormat.GenericDefault;
f.Alignment = obj.HorizontalTextAlignment;
f.LineAlignment = obj.VerticalTextAlignment;
float zoomFactor;
if (obj.Parent is null)
zoomFactor = 1.0f;
else
{
zoomFactor = obj.Parent.ZoomFactor.Width;
}
e.Graphics.DrawString(obj.Text, new Font(obj.TextFont.FontFamily, obj.TextFont.Size * zoomFactor, obj.TextFont.Style), b, rect, f);
}
private static object _DrawPicture_newSyncObj = new object();
public static void DrawPicture(PaintingObjectPaintEventArgs e)
{
var obj = e.PaintingObject;
Image objImg;
Size objImgSize;
RectangleF result;
Bitmap image;
SizeF zoomf;
bool hasNoParent = e.PaintingObject.Parent is null;
object syncObj;
if (hasNoParent)
{
zoomf = new SizeF(1f, 1f);
syncObj = _DrawPicture_newSyncObj;
}
else
{
zoomf = e.PaintingObject.Parent.ZoomFactor;
syncObj = e.PaintingObject.Parent;
}
lock (syncObj)
{
if (obj?.Image is null)
return;
objImg = obj.Image;
objImgSize = objImg.Size;
}
image = (Bitmap)obj.BufferedImage;
result = CalculateImageResolution(obj, objImgSize, zoomf);
if (obj.ImageProperties.Rotate == 90 || obj.ImageProperties.Rotate == 270)
result = CalculateImageResolution(obj, new SizeF(objImgSize.Height, objImgSize.Width), zoomf);
if (image is null)
{
bool needRescaleImageBecauseRot = false;
image = DrawToNewImage((Bitmap)objImg, result.Size);
switch (obj.ImageProperties.Rotate)
{
case 90:
{
image.RotateFlip(RotateFlipType.Rotate90FlipNone);
needRescaleImageBecauseRot = true;
break;
}
case 180:
{
image.RotateFlip(RotateFlipType.Rotate180FlipNone);
break;
}
case 270:
{
image.RotateFlip(RotateFlipType.Rotate270FlipNone);
needRescaleImageBecauseRot = true;
break;
}
}
if (obj.ImageProperties.FlipX)
image.RotateFlip(RotateFlipType.RotateNoneFlipX);
if (obj.ImageProperties.FlipY)
image.RotateFlip(RotateFlipType.RotateNoneFlipY);
if (needRescaleImageBecauseRot)
{
result = CalculateImageResolution(obj, new SizeF(objImgSize.Height, objImgSize.Width), zoomf);
image = DrawToNewImage(image, result.Size);
}
obj.BufferedImage = image;
}
if (image is not null)
{
lock (syncObj)
e.Graphics.DrawImageUnscaled(image, new Rectangle(new Point((int)Math.Round(obj.Location.X + result.Location.X - e.Offset.X), (int)Math.Round(obj.Location.Y + result.Location.Y - e.Offset.Y)), result.Size.ToSize()));
}
}
private static Bitmap DrawToNewImage(Bitmap image, SizeF newSize)
{
var bmp = new Bitmap((int)Math.Round(newSize.Width < 0f ? newSize.Width * -1 : newSize.Width), (int)Math.Round(newSize.Height < 0f ? newSize.Height * -1 : newSize.Height));
var gimage = Graphics.FromImage(bmp);
gimage.SmoothingMode = SmoothingMode.HighQuality;
gimage.PixelOffsetMode = PixelOffsetMode.HighQuality;
gimage.PageUnit = GraphicsUnit.Pixel;
gimage.InterpolationMode = InterpolationMode.HighQualityBicubic;
gimage.DrawImage(image, new RectangleF(PointF.Empty, newSize));
gimage.Dispose();
return bmp;
}
public static void DrawLine(PaintingObjectPaintEventArgs e)
{
var obj = e.PaintingObject;
var p2 = new Pen(obj.OutlineColor, obj.OutlineThicknes) { DashStyle = obj.OutlineDashStyle };
if (obj.LineEndCap is not null)
{
var args = obj.LineEndCap.Configure();
p2.StartCap = args.LineCap;
p2.CustomStartCap = args.CustomLineCap;
}
if (obj.LineStartCap is not null)
{
var args = obj.LineStartCap.Configure();
p2.EndCap = args.LineCap;
p2.CustomEndCap = args.CustomLineCap;
}
p2.Alignment = PenAlignment.Center;
var no = new PointF(e.X, e.Y);
e.Graphics.DrawLine(p2, no, no + obj.Size);
}
private static RectangleF CalculateImageResolution(PaintingObject obj, SizeF imageSize, SizeF zoom)
{
var result = new RectangleF();
var objrect = new RectangleF(obj.Location, obj.Size);
var size = new SizeF(imageSize.Width * zoom.Width, imageSize.Height * zoom.Height);
var clientRectangle = objrect;
float val = clientRectangle.Width / size.Width;
clientRectangle = objrect;
float num = Math.Min(val, clientRectangle.Height / size.Height);
result.Width = (int)Math.Round(Math.Truncate((double)(size.Width * num)));
result.Height = (int)Math.Round(Math.Truncate((double)(size.Height * num)));
clientRectangle = objrect;
result.X = (long)Math.Round(clientRectangle.Width - result.Width) / 2L;
clientRectangle = objrect;
result.Y = (long)Math.Round(clientRectangle.Height - result.Height) / 2L;
return result;
}
public static void DrawTriangle(PaintingObjectPaintEventArgs e)
{
var obj = e.PaintingObject;
var p1 = new Point((int)Math.Round(obj.Size.Width / 2f + e.X), (int)Math.Round(e.Y));
var p2 = new Point((int)Math.Round(e.X), (int)Math.Round(e.Y + obj.Size.Height));
var p3 = new Point((int)Math.Round(e.X + obj.Size.Width), (int)Math.Round(e.Y + obj.Size.Height));
if (obj.EnableFill)
{
var b = new SolidBrush(obj.FillColor);
e.Graphics.FillPolygon(b, new[] { p1, p2, p3 });
}
if (obj.EnableOutline)
{
float lw = obj.OutlineThicknes;
var p = new Pen(obj.OutlineColor, obj.OutlineThicknes) { DashStyle = obj.OutlineDashStyle, Alignment = PenAlignment.Inset };
e.Graphics.DrawPolygon(p, new[] { p1, p2, p3 });
}
}
public static void DrawRectangle(PaintingObjectPaintEventArgs e)
{
var obj = e.PaintingObject;
float hol = obj.OutlineThicknes / 2f;
if (obj.EnableFill)
{
var b = new SolidBrush(obj.FillColor);
var rect = obj.EnableOutline ? new Rectangle((int)Math.Round(e.X + hol), (int)Math.Round(e.Y + hol), (int)Math.Round(obj.Size.Width - hol * 2f), (int)Math.Round(obj.Size.Height - hol * 2f)) : new Rectangle((int)Math.Round(e.X), (int)Math.Round(e.Y), (int)Math.Round(obj.Size.Width), (int)Math.Round(obj.Size.Height));
e.Graphics.FillRectangle(b, rect);
}
if (obj.EnableOutline)
{
var p = new Pen(obj.OutlineColor, obj.OutlineThicknes) { DashStyle = obj.OutlineDashStyle, Alignment = PenAlignment.Inset };
var rect = new Rectangle((int)Math.Round(e.X), (int)Math.Round(e.Y), (int)Math.Round(obj.Size.Width), (int)Math.Round(obj.Size.Height));
e.Graphics.DrawRectangle(p, rect);
}
}
public static void DrawEllipse(PaintingObjectPaintEventArgs e)
{
var obj = e.PaintingObject;
if (obj.EnableFill)
{
var b = new SolidBrush(obj.FillColor);
var rect = new Rectangle((int)Math.Round(e.X), (int)Math.Round(e.Y), (int)Math.Round(obj.Size.Width), (int)Math.Round(obj.Size.Height));
e.Graphics.FillEllipse(b, rect);
}
if (obj.EnableOutline)
{
var p = new Pen(obj.OutlineColor, obj.OutlineThicknes) { DashStyle = obj.OutlineDashStyle, Alignment = PenAlignment.Inset };
var rect = new Rectangle((int)Math.Round(e.X), (int)Math.Round(e.Y), (int)Math.Round(obj.Size.Width), (int)Math.Round(obj.Size.Height));
e.Graphics.DrawEllipse(p, rect);
}
}
public static void DrawSelection(PaintingObjectPaintEventArgs e)
{
var obj = e.PaintingObject;
float lw = 2.5f;
float hlw = lw / 2f;
float hlwphol = hlw; // + hol
float hlwpholm2 = hlwphol * 2f;
var p = new Pen(Color.CornflowerBlue, lw) { DashStyle = obj.SelectionDashStyle, Alignment = PenAlignment.Outset };
var rect = new Rectangle((int)Math.Round(e.X - hlwphol), (int)Math.Round(e.Y - hlwphol), (int)Math.Round(obj.Size.Width + hlwpholm2), (int)Math.Round(obj.Size.Height + hlwpholm2));
e.Graphics.DrawRectangle(p, rect);
}
public static void DrawGrid(PaintEventArgs e, PaintingControl pc, PointF offset)
{
var p = new Pen(pc.GridColor, 0.5f);
int curX = (int)Math.Round(pc.GridChunkSize.Width * pc.ZoomFactor.Width - offset.X);
while (curX < pc.Width)
{
e.Graphics.DrawLine(p, curX, -offset.Y, curX, pc.Height);
curX = (int)Math.Round(curX + pc.GridChunkSize.Width * pc.ZoomFactor.Width);
}
int curY = (int)Math.Round(pc.GridChunkSize.Height * pc.ZoomFactor.Height - offset.Y);
while (curY < pc.Height)
{
e.Graphics.DrawLine(p, -offset.X, curY, pc.Width, curY);
curY = (int)Math.Round(curY + pc.GridChunkSize.Height * pc.ZoomFactor.Height);
}
}
public static void DrawAreaSelection(PaintEventArgs e, PaintingControl pc, PointF startMousePos, PointF lastMousePos)
{
var rectToDraw = HelpfulDrawingFunctions.GetRectangle(startMousePos, lastMousePos);
var p = new Pen(pc.AreaSelectionColor);
p.DashStyle = startMousePos.X >= lastMousePos.X ? DashStyle.DashDot : DashStyle.Solid;
p.Width = 3f;
e.Graphics.DrawRectangle(p, rectToDraw.X, rectToDraw.Y, rectToDraw.Width, rectToDraw.Height);
}
}

View File

@@ -0,0 +1,17 @@
using System.Drawing.Drawing2D;
namespace Pilz.UI;
public class DefaultLineCapProps : LineCapProps
{
public LineCap LineCap { get; set; } = LineCap.Flat;
public CustomLineCap CustomLineCap { get; set; } = null;
internal override LineCapConfigurationArgs Configure()
{
return new LineCapConfigurationArgs(LineCap, CustomLineCap);
}
}

View File

@@ -0,0 +1,8 @@
using System;
namespace Pilz.UI;
public class PaintingObjectEventArgs(PaintingObject[] paintingObjects) : EventArgs
{
public PaintingObject[] PaintingObjects { get; private set; } = paintingObjects;
}

View File

@@ -0,0 +1,53 @@
using System;
using System.Drawing;
namespace Pilz.UI;
public class PaintingObjectPaintEventArgs(PaintingObject obj, Graphics g, PointF offset) : EventArgs
{
/// <summary>
/// The Painting Object to draw.
/// </summary>
/// <returns></returns>
public PaintingObject PaintingObject { get; } = obj;
/// <summary>
/// The current offset of the page on the screen.
/// </summary>
/// <returns></returns>
public PointF Offset { get; } = offset;
/// <summary>
/// The Grpahics from the parent PaintingControl.
/// </summary>
/// <returns></returns>
public Graphics Graphics { get; } = g;
/// <summary>
/// The position of the PaintingObject on Screen.
/// </summary>
/// <returns></returns>
public PointF Location => new(X, Y);
/// <summary>
/// The X position of the PaintingObject on Screen.
/// </summary>
/// <returns></returns>
public float X => PaintingObject.X - Offset.X;
/// <summary>
/// The Y position of the PaintingObject on Screen.
/// </summary>
/// <returns></returns>
public float Y => PaintingObject.Y - Offset.Y;
/// <summary>
/// The rectangle of the PaintingObject on Screen.
/// </summary>
/// <returns></returns>
public RectangleF Rectangle => new RectangleF(X, Y, PaintingObject.Width, PaintingObject.Height);
public PaintingObjectPaintEventArgs(PaintingObject obj, Graphics g) : this(obj, g, obj.Parent.Offset)
{
}
}

View File

@@ -0,0 +1,7 @@
namespace Pilz.UI;
public interface IPaintingObjectContainer
{
}

View File

@@ -0,0 +1,9 @@
namespace Pilz.UI;
public class PaintingObjectImageProperties
{
public bool FlipY { get; set; } = false;
public bool FlipX { get; set; } = false;
public ushort Rotate { get; set; } = 0;
}

View File

@@ -0,0 +1,26 @@
using System.Drawing.Drawing2D;
namespace Pilz.UI;
public class LineCapConfigurationArgs
{
public LineCap LineCap { get; private set; }
public CustomLineCap CustomLineCap { get; private set; }
public LineCapConfigurationArgs(LineCap lineCap) : this(lineCap, null)
{
}
public LineCapConfigurationArgs(CustomLineCap customLineCap) : this(default, customLineCap)
{
}
public LineCapConfigurationArgs(LineCap lineCap, CustomLineCap customLineCap)
{
LineCap = lineCap;
CustomLineCap = customLineCap;
}
}

View File

@@ -0,0 +1,9 @@
namespace Pilz.UI;
public abstract class LineCapProps
{
internal abstract LineCapConfigurationArgs Configure();
}

View File

@@ -0,0 +1,785 @@
using Microsoft.VisualBasic.CompilerServices;
using Pilz.Drawing;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;
namespace Pilz.UI;
public class PaintingControl : UserControl, IPaintingObjectContainer
{
private PaintingObject curObjMouseDown = null;
private Color bgColor = Color.White;
private Point startMousePos = default;
private Point lastMousePos = default;
private int lastHashCode = 0;
private Point calcOffset_MouseOnTab = Point.Empty;
private bool calcOffset_IsActive = false;
private PointF calcOffset_LastOffset = PointF.Empty;
private new Color ForeColor { get; set; }
private new Font Font { get; set; }
private new string Text { get; set; }
public PointF Offset { get; set; } = PointF.Empty;
public PaintingObjectList PaintingObjects { get; private set; } = new PaintingObjectList(this);
public bool VisibleForMouseEvents { get; set; } = true;
public bool AutoAreaSelection { get; set; } = true;
public bool AutoSingleSelection { get; set; } = true;
public bool AutoMultiselection { get; set; } = true;
public bool AutoRemoveSelection { get; set; } = true;
public DashStyle AreaSelectionDashStyle { get; set; } = DashStyle.DashDot;
public Color AreaSelectionColor { get; set; } = Color.CornflowerBlue;
public bool AutoMoveObjects { get; set; } = true;
private bool _IsAreaSelecting = false;
public bool IsMovingObjects { get; private set; } = false;
public bool GridEnabled { get; set; } = true;
public bool GridVisible { get; set; } = false;
public Size GridChunkSize { get; set; } = new Size(20, 20);
public Color GridColor { get; set; } = Color.LightGray;
public DelegateDrawPaintingControlGridMethode DrawGridMethode { get; set; } = DefaultDrawMethodes.DrawGrid;
public DelegateDrawPaintingControlAreaSelectionMethode DrawAreaSelectionMethode { get; set; } = DefaultDrawMethodes.DrawAreaSelection;
private SizeF _ZoomFactor = new SizeF(1f, 1f);
private int _stopDrawing = -1;
private Image bufferedImg = null;
private bool pressedShift = false;
private bool pressedControl = false;
private bool pressedAlt = false;
private Dictionary<PaintingObject, PointF> savedPos = new Dictionary<PaintingObject, PointF>();
public event SelectionChangedEventHandler SelectionChanged;
public delegate void SelectionChangedEventHandler(object sender, PaintingObjectEventArgs e);
public event PaintingObjectAddedEventHandler PaintingObjectAdded;
public delegate void PaintingObjectAddedEventHandler(object sender, PaintingObjectEventArgs e);
public event PaintingObjectRemovedEventHandler PaintingObjectRemoved;
public delegate void PaintingObjectRemovedEventHandler(object sender, PaintingObjectEventArgs e);
public event AfterScrollingDoneEventHandler AfterScrollingDone;
public delegate void AfterScrollingDoneEventHandler(object sender, EventArgs e);
public event ZoomFactorChangedEventHandler ZoomFactorChanged;
public delegate void ZoomFactorChangedEventHandler(object sender, EventArgs e);
public PaintingObject[] SelectedObjects
{
get
{
var objs = new List<PaintingObject>();
foreach (PaintingObject obj in PaintingObjects)
{
if (obj.Selected)
objs.Add(obj);
}
return objs.ToArray();
}
}
public bool IsLayoutSuspended
{
get
{
return Conversions.ToInteger(GetType().GetField("layoutSuspendCount", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(this)) != 0;
}
}
public bool StopDrawing
{
get
{
return _stopDrawing > -1;
}
}
public override Color BackColor
{
get
{
return bgColor;
}
set
{
bgColor = value;
base.BackColor = value;
// If value <> Color.Transparent Then
// MyBase.BackColor = value
// End If
}
}
public bool IsAreaSelecting
{
get
{
return _IsAreaSelecting && startMousePos != lastMousePos;
}
}
public SizeF ZoomFactor
{
get
{
return _ZoomFactor;
}
set
{
if (_ZoomFactor != value)
{
_ZoomFactor = value;
ResetAllBufferedImages();
ZoomFactorChanged?.Invoke(this, new EventArgs());
}
}
}
public PaintingControl()
{
PaintingObjectResizing.CheckEnabled += PaintingObjectResizing_CheckEnabled;
DoubleBuffered = true;
KeyDown += CheckKeyDown;
KeyUp += CheckKeyDown;
MouseClick += CheckMouseClick;
MouseDown += CheckMouseDown;
MouseUp += CheckMouseUp;
MouseMove += CheckMouseMove;
PaintingObjectAdded += PaintingControl_PaintingObjectAdded;
PaintingObjectRemoved += PaintingControl_PaintingObjectAdded;
MouseWheel += CheckMouseWheel;
}
~PaintingControl()
{
PaintingObjectResizing.CheckEnabled -= PaintingObjectResizing_CheckEnabled;
}
private void PaintingObjectResizing_CheckEnabled(PaintingObjectResizing sender, ref bool enabled)
{
if (PaintingObjects.Contains(sender.PaintingObject) && pressedAlt)
enabled = false;
}
private void ResetAllBufferedImages()
{
foreach (PaintingObject ob in PaintingObjects)
ob.ResetImageBuffer();
Refresh();
}
protected void CheckKeyDown(object sender, KeyEventArgs e)
{
pressedShift = e.Shift;
pressedControl = e.Control;
pressedAlt = e.Alt;
}
internal RectangleF AreaSelectionRectangle
{
get
{
return HelpfulDrawingFunctions.GetRectangle(startMousePos, lastMousePos);
}
}
protected void CheckMouseClick(object sender, MouseEventArgs e)
{
foreach (PaintingObject obj in GetObjects(new Point((int)Math.Round(e.X + Offset.X), (int)Math.Round(e.Y + Offset.Y))))
{
if (!obj.MouseTransparency)
obj.RaiseMouseClick(GetMouseEventArgs(e, obj));
}
}
protected void CheckMouseDown(object sender, MouseEventArgs e)
{
lastMousePos = new Point((int)Math.Round(e.X + Offset.X), (int)Math.Round(e.Y + Offset.Y));
curObjMouseDown = GetObjects(lastMousePos).Where(n => !n.MouseTransparency).LastOrDefault();
curObjMouseDown?.RaiseMouseDown(GetMouseEventArgs(e, curObjMouseDown));
if (curObjMouseDown is null || !curObjMouseDown.Selected || pressedControl)
{
bool hasMovedObjects = false;
if (IsMovingObjects)
{
foreach (PaintingObject obj in GetSelectedObjects())
{
if (HelpfulDrawingFunctions.IsPointInRectangle(lastMousePos, obj.Rectangle))
{
hasMovedObjects = true;
break;
}
}
}
if (!hasMovedObjects && !_IsAreaSelecting)
{
var selChanged = new List<PaintingObject>();
if (AutoRemoveSelection && !pressedControl)
{
foreach (PaintingObject obj in PaintingObjects)
{
if (obj.Selected)
{
obj.SelectedDirect = false;
if (!selChanged.Contains(obj))
selChanged.Add(obj);
}
}
}
if (AutoSingleSelection && curObjMouseDown is not null)
{
var objtosel = curObjMouseDown;
if (objtosel.EnableSelection)
{
objtosel.SelectedDirect = !objtosel.Selected;
if (!selChanged.Contains(objtosel))
selChanged.Add(objtosel);
else
{
selChanged.Remove(objtosel);
}
}
}
SelectionChanged?.Invoke(this, new PaintingObjectEventArgs(selChanged.ToArray()));
}
}
if (pressedAlt)
{
calcOffset_MouseOnTab = new Point(e.X, e.Y);
calcOffset_LastOffset = Offset;
calcOffset_IsActive = true;
Cursor = Cursors.Arrow;
}
else
{
switch (e.Button)
{
case MouseButtons.Left:
{
savedPos.Clear();
if (AutoMoveObjects)
SaveObjectPositions(e, GetSelectedObjects());
if (savedPos.Count > 0)
IsMovingObjects = true;
else if (AutoAreaSelection)
{
startMousePos = new Point((int)Math.Round(e.X + Offset.X), (int)Math.Round(e.Y + Offset.Y));
lastMousePos = startMousePos; // New Point(e.X - Offset.X, e.Y - Offset.Y)
_IsAreaSelecting = true;
}
break;
}
}
}
}
public void RaiseSelectionChanged()
{
SelectionChanged?.Invoke(this, new PaintingObjectEventArgs(SelectedObjects));
}
protected void CheckMouseUp(object sender, MouseEventArgs e)
{
if (_IsAreaSelecting)
_IsAreaSelecting = false;
if (IsMovingObjects)
{
IsMovingObjects = false;
foreach (PaintingObject obj in GetSelectedObjects())
obj.RaiseMoved(new EventArgs());
AutoArrangeToGrid();
}
if (curObjMouseDown is not null)
{
if (!curObjMouseDown.MouseTransparency)
curObjMouseDown.RaiseMouseUp(GetMouseEventArgs(e, curObjMouseDown));
curObjMouseDown = null;
}
if (calcOffset_IsActive)
{
calcOffset_IsActive = false;
Cursor = Cursors.Default;
CalcNewOffset(e.Location);
AfterScrollingDone?.Invoke(this, new EventArgs());
}
}
protected void CheckMouseMove(object sender, MouseEventArgs e)
{
if (_IsAreaSelecting || IsMovingObjects)
lastMousePos = new Point((int)Math.Round(e.X + Offset.X), (int)Math.Round(e.Y + Offset.Y));
if (_IsAreaSelecting)
SelectControlsInArea();
if (IsMovingObjects)
UpdateObjectPositions(e);
foreach (PaintingObject obj in GetObjects(new Point((int)Math.Round(e.X + Offset.X), (int)Math.Round(e.Y + Offset.Y))))
{
if (!obj.MouseTransparency)
obj.RaiseMouseMove(GetMouseEventArgs(e, obj));
}
var topObj = GetObject(new Point((int)Math.Round(e.X + Offset.X), (int)Math.Round(e.Y + Offset.Y)), true);
if (topObj is not null)
Cursor = topObj.Cursor;
else if (calcOffset_IsActive)
{
Cursor = Cursors.Arrow;
}
else
{
Cursor = Cursors.Default;
}
if (calcOffset_IsActive)
{
if (pressedAlt)
CalcNewOffset(e.Location);
else
{
calcOffset_IsActive = false;
}
}
Refresh();
}
private void CalcNewOffset(Point newMousePos)
{
Offset = new PointF(calcOffset_LastOffset.X - (newMousePos.X - calcOffset_MouseOnTab.X), calcOffset_LastOffset.Y - (newMousePos.Y - calcOffset_MouseOnTab.Y));
if (Offset.X < 0f)
Offset = new PointF(0f, Offset.Y);
if (Offset.Y < 0f)
Offset = new PointF(Offset.X, 0f);
}
private PaintingObject[] GetSelectedObjects()
{
var objs = new List<PaintingObject>();
foreach (PaintingObject obj in PaintingObjects)
{
if (obj.Selected)
objs.Add(obj);
}
return objs.ToArray();
}
private void SaveObjectPositions(MouseEventArgs e, IList objs)
{
foreach (PaintingObject obj in objs)
{
if (!obj.HardcodedLocation && !savedPos.ContainsKey(obj))
{
savedPos.Add(obj, new PointF(e.X - obj.Location.X + Offset.X, e.Y - obj.Location.Y + Offset.Y));
SaveObjectPositions(e, obj.PinnedObjects);
}
}
}
private void UpdateObjectPositions(MouseEventArgs e)
{
UpdateObjectPositions(e, GetSelectedObjects());
}
private void UpdateObjectPositions(MouseEventArgs e, IList<PaintingObject> objs, List<PaintingObject> movedObjs = null)
{
if (IsResizingObjs(objs))
return;
if (movedObjs is null)
movedObjs = new List<PaintingObject>();
SuspendDrawing();
foreach (PaintingObject obj in objs)
{
var sp = savedPos[obj];
if (!movedObjs.Contains(obj))
{
if (UpdateObjectPosition(e, obj, sp))
movedObjs.Add(obj);
}
if (obj.PinnedObjects.Count > 0)
{
UpdateObjectPositions(e, obj.PinnedObjects, movedObjs);
movedObjs.AddRange(obj.PinnedObjects.ToArray());
}
}
ResumeDrawing(false);
}
private bool UpdateObjectPosition(MouseEventArgs e, PaintingObject obj, PointF sp)
{
bool moved = false;
var cancel = new CancelEventArgs(false);
obj.RaiseMovingBeforePositionUpdated(cancel);
if (!cancel.Cancel)
{
obj.Location = new Point((int)Math.Round(e.X - sp.X + Offset.X), (int)Math.Round(e.Y - sp.Y + Offset.Y));
obj.RaiseMoving(new EventArgs());
moved = true;
}
return moved;
}
private bool IsResizingObjs(IList<PaintingObject> objs)
{
foreach (PaintingObject obj in objs)
{
if (obj.IsResizing)
return true;
}
return false;
}
private MouseEventArgs GetMouseEventArgs(MouseEventArgs e, PaintingObject obj)
{
return new MouseEventArgs(e.Button, e.Clicks, (int)Math.Round(e.X - obj.X + Offset.X), (int)Math.Round(e.Y - obj.Y + Offset.Y), e.Delta);
}
public PaintingObject GetObject(PointF p, bool UseExtRect = false)
{
PaintingObject val = null;
for (int i = PaintingObjects.Count - 1; i >= 0; i -= 1)
{
var obj = PaintingObjects[i];
if (val is null)
{
if (UseExtRect)
{
if (HelpfulDrawingFunctions.IsPointInRectangle(p, obj.RectangleExtended))
val = obj;
}
else if (HelpfulDrawingFunctions.IsPointInRectangle(p, obj.Rectangle))
{
val = obj;
}
}
}
return val;
}
public PaintingObject[] GetObjects(Point p)
{
var objs = new List<PaintingObject>();
foreach (PaintingObject obj in PaintingObjects)
{
if (HelpfulDrawingFunctions.IsPointInRectangle(p, obj.RectangleExtended))
objs.Add(obj);
}
return objs.ToArray();
}
public PaintingObject[] GetObjects(Point startPoint, Point endPoint)
{
return GetObjects(new Rectangle(startPoint, (Size)(endPoint - (Size)startPoint)));
}
public PaintingObject[] GetObjects(Rectangle rect)
{
var objs = new List<PaintingObject>();
foreach (PaintingObject obj in PaintingObjects)
{
var objRect = obj.Rectangle;
if (HelpfulDrawingFunctions.IsPointInRectangle(objRect.Location, rect) || HelpfulDrawingFunctions.IsPointInRectangle(objRect.Location + objRect.Size, rect) || HelpfulDrawingFunctions.IsPointInRectangle(new PointF(objRect.Left, objRect.Bottom), rect) || HelpfulDrawingFunctions.IsPointInRectangle(new PointF(objRect.Right, objRect.Top), rect))
objs.Add(obj);
}
return objs.ToArray();
}
protected override CreateParams CreateParams
{
get
{
var cp = base.CreateParams;
// If EnableRealTransparency Then
// cp.ExStyle = cp.ExStyle Or &H20 'WS_EX_TRANSPARENT
// End If
return cp;
}
}
/// <summary>
/// Sorg dafür, dass Events durch dieses Control durchdringen zum Parnet-Control.
/// </summary>
/// <param name="m"></param>
protected override void WndProc(ref Message m)
{
const int WM_NCHITTEST = 0x84;
const int HTTRANSPARENT = -1;
if (!VisibleForMouseEvents && m.Msg == WM_NCHITTEST)
m.Result = HTTRANSPARENT;
else
{
base.WndProc(ref m);
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// Stop Drawing directly to the parent
SuspendLayout();
// Draw Background
// If Not EnableRealTransparency Then
base.OnPaintBackground(e);
// End If
}
protected override void OnPaint(PaintEventArgs e)
{
// Draw PaintingObjects stuff
if (StopDrawing)
e.Graphics.DrawImage(bufferedImg, Point.Empty);
else
{
{
var withBlock = e.Graphics;
withBlock.SmoothingMode = SmoothingMode.HighQuality;
withBlock.PixelOffsetMode = PixelOffsetMode.HighQuality;
withBlock.PageUnit = GraphicsUnit.Pixel;
withBlock.InterpolationMode = InterpolationMode.HighQualityBicubic;
}
if (GridVisible)
DrawGridMethode?.Invoke(e, this, Offset);
var baserect = new RectangleF(Offset, Size);
foreach (PaintingObject obj in PaintingObjects)
{
if (obj.Visible && HelpfulDrawingFunctions.OverlapsTwoRectangles(obj.Rectangle, baserect))
obj.Draw(e, Offset);
}
if (_IsAreaSelecting)
DrawAreaSelectionMethode?.Invoke(e, this, new PointF(startMousePos.X - Offset.X, startMousePos.Y - Offset.Y), new PointF(lastMousePos.X - Offset.X, lastMousePos.Y - Offset.Y));
}
// Do default Drawing Methode
base.OnPaint(e);
// Start Drawing directly to the Form
ResumeLayout(false);
}
public new Graphics CreateGraphics()
{
return base.CreateGraphics();
}
public void PaintFullView(Graphics g)
{
foreach (PaintingObject obj in PaintingObjects)
{
if (obj.Visible)
obj.Draw(g, PointF.Empty);
}
}
private SizeF CalcTextSize(PaintingObject obj)
{
return CalcTextSize(obj, Parent.CreateGraphics());
}
private SizeF CalcTextSize(PaintingObject obj, Graphics g)
{
return g.MeasureString(obj.Text, obj.TextFont, (int)Math.Round(obj.Width));
}
private void SelectControlsInArea()
{
var rect = HelpfulDrawingFunctions.GetRectangle(startMousePos, lastMousePos);
foreach (PaintingObject obj in PaintingObjects)
obj.Selected = startMousePos.X >= lastMousePos.X ? HelpfulDrawingFunctions.OverlapsTwoRectangles(obj.Rectangle, rect) : HelpfulDrawingFunctions.RectangleContainsRectangle(rect, obj.Rectangle);
}
public void ArrangeToGrid(PaintingObject obj, bool snapPinnedObjects)
{
if (snapPinnedObjects || !IsPinnedObject(obj))
{
var zoomedGridChunkSize = new SizeF(GridChunkSize.Width * ZoomFactor.Width, GridChunkSize.Height * ZoomFactor.Height);
int modTop = (int)Math.Round(obj.Y % zoomedGridChunkSize.Height);
int modLeft = (int)Math.Round(obj.X % zoomedGridChunkSize.Width);
int halfHeight = (int)Math.Round(zoomedGridChunkSize.Height / 2f);
int halfWidth = (int)Math.Round(zoomedGridChunkSize.Width / 2f);
void zoomLocation(PaintingObject obj2)
{
if (modTop > halfHeight)
obj2.Y += zoomedGridChunkSize.Height - modTop;
else
{
obj2.Y -= modTop;
}
if (modLeft > halfWidth)
obj2.X += zoomedGridChunkSize.Width - modLeft;
else
{
obj2.X -= modLeft;
}
};
zoomLocation(obj);
foreach (PaintingObject pinned in obj.PinnedObjects)
zoomLocation(pinned);
int modH = (int)Math.Round(obj.Height % zoomedGridChunkSize.Height);
int modW = (int)Math.Round(obj.Width % zoomedGridChunkSize.Width);
void zoomSize(PaintingObject obj2) { if (obj2.EnableResize && !obj2.HardcodedSize) { if (modH > halfHeight) obj2.Height += zoomedGridChunkSize.Height - modH; else { obj2.Height -= modH; } if (modW > halfWidth) obj2.Width += zoomedGridChunkSize.Width - modW; else { obj2.Width -= modW; } } };
zoomSize(obj);
foreach (PaintingObject pinned in obj.PinnedObjects)
zoomSize(pinned);
}
}
public bool IsPinnedObject(PaintingObject o)
{
foreach (PaintingObject obj in PaintingObjects)
{
if (obj.PinnedObjects.Contains(o))
return true;
}
return false;
}
public void AutoArrangeToGrid()
{
if (GridEnabled)
{
foreach (PaintingObject obj in GetSelectedObjects())
{
if (obj.AutoAlignToGrid)
ArrangeToGrid(obj, false);
}
if (!StopDrawing)
Refresh();
}
}
public SizeF GetFullSize()
{
return GetFullSize(PaintingObjects);
}
public static SizeF GetFullSize(IEnumerable<PaintingObject> objects)
{
float curX = 0f;
float curY = 0f;
foreach (PaintingObject po in objects)
{
float myX = po.X + po.Width;
if (curX < myX)
curX = myX;
float myY = po.Y + po.Height;
if (curY < myY)
curY = myY;
}
return new SizeF(curX + 20f, curY + 20f);
}
internal void RaisePaintingObjectAdded(PaintingObjectEventArgs args)
{
PaintingObjectAdded?.Invoke(this, args);
}
internal void RaisePaintingObjectRemoved(PaintingObjectEventArgs args)
{
PaintingObjectRemoved?.Invoke(this, args);
}
private void PaintingControl_PaintingObjectAdded(object sender, PaintingObjectEventArgs e)
{
// CalculateScrollValues()
}
private void CheckMouseWheel(object sender, MouseEventArgs e)
{
if (pressedAlt)
{
float val = (float)(e.Delta / 120d / 10d);
ZoomFactor = new SizeF((float)Math.Max((double)(ZoomFactor.Width + val), 0.25d), (float)Math.Max((double)(ZoomFactor.Height + val), 0.25d));
Refresh();
}
else
{
// ...
}
}
public void SuspendDrawing()
{
if (_stopDrawing < 0)
// bufferedImg = New Bitmap(Width, Height)
// DrawToBitmap(bufferedImg, New Rectangle(0, 0, bufferedImg.Width, bufferedImg.Height))
Utils.DrawingControl.SuspendDrawing(this);
_stopDrawing += 1;
}
public void ResumeDrawing()
{
ResumeDrawing(true);
}
public void ResumeDrawing(bool executeRefresh)
{
if (_stopDrawing >= 0)
_stopDrawing -= 1;
if (_stopDrawing == -1)
// bufferedImg.Dispose()
// bufferedImg = Nothing
// If executeRefresh Then Refresh()
Utils.DrawingControl.ResumeDrawing(this, executeRefresh);
}
}

View File

@@ -0,0 +1,11 @@
using System.Drawing;
using System.Windows.Forms;
namespace Pilz.UI;
public delegate void DelegateDrawPaintingObjectMethode(PaintingObjectPaintEventArgs e);
public delegate void DelegateDrawPaintingControlGridMethode(PaintEventArgs e, PaintingControl pc, PointF offset);
public delegate void DelegateDrawPaintingControlAreaSelectionMethode(PaintEventArgs e, PaintingControl pc, PointF startMousePos, PointF lastMousePos);

View File

@@ -0,0 +1,826 @@
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; } = 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<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; } = 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
}

View File

@@ -0,0 +1,7 @@
namespace Pilz.UI;
public class PaintingObjectJsonSerializer
{
}

View File

@@ -0,0 +1,112 @@
using Newtonsoft.Json;
namespace Pilz.UI;
public class PaintingObjectLayering
{
// <JsonProperty(NameOf(PaintingObject))>
private readonly PaintingObject _PaintingObject;
[JsonIgnore]
public PaintingObject PaintingObject
{
get
{
return _PaintingObject;
}
}
/// <summary>
/// Get the current object list from the painting object.
/// </summary>
/// <returns>Returns the current object list from the painting object.</returns>
[JsonIgnore]
public PaintingObjectList ObjectList
{
get
{
return PaintingObject.Parent.PaintingObjects;
}
}
/// <summary>
/// Create a new instance of object layer managing.
/// </summary>
/// <param name="obj"></param>
public PaintingObjectLayering(PaintingObject obj)
{
_PaintingObject = obj;
}
/// <summary>
/// Moves the object by the given number of indicies.
/// </summary>
/// <param name="count">The number how many objects it should be moved.</param>
public void MoveObject(int count)
{
int oldIndex = ObjectList.IndexOf(PaintingObject);
int newIndex = oldIndex + count;
MoveObjectTo(newIndex);
}
/// <summary>
/// Moves the object to the new index.
/// </summary>
/// <param name="newIndex"></param>
public void MoveObjectTo(int newIndex)
{
var list = ObjectList;
// Check & make index valid
if (newIndex >= ObjectList.Count)
newIndex = ObjectList.Count - 1;
else if (newIndex < 0)
{
newIndex = 0;
}
// Remove object
list.Remove(PaintingObject);
// Insert object at new index
list.Insert(newIndex, PaintingObject);
// Order all objects again
list.Layering.OrderAll();
}
/// <summary>
/// Moves the object to the front.
/// </summary>
public void BringToTop()
{
MoveObjectTo(ObjectList.Count - 1);
}
/// <summary>
/// Moves the object to the back.
/// </summary>
public void SendToBack()
{
MoveObjectTo(0);
}
/// <summary>
/// Moves the object fordward by one
/// </summary>
public void OneToTop()
{
MoveObject(+1);
}
/// <summary>
/// Moves the object backward by one
/// </summary>
public void OneToBack()
{
MoveObject(-1);
}
}

View File

@@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
namespace Pilz.UI;
public class PaintingObjectListLayering
{
public PaintingObjectList ObjectList { get; private set; }
public Dictionary<int, Func<PaintingObject, bool>> Conditions { get; private set; } = new Dictionary<int, Func<PaintingObject, bool>>();
/// <summary>
/// Get the order function will checkout the conditions.
/// </summary>
/// <returns>Returns true, if conditions are aviable, otherwise false.</returns>
public bool EnableConditions
{
get
{
return Conditions.Any();
}
}
/// <summary>
/// Create a new instance of object list layer managing.
/// </summary>
/// <param name="list"></param>
public PaintingObjectListLayering(PaintingObjectList list)
{
ObjectList = list;
}
/// <summary>
/// Order all objects using the conditions. If no conditions are setted, this method will do nothing.
/// </summary>
public void OrderAll()
{
if (EnableConditions)
OrderAllPrivate();
}
private void OrderAllPrivate()
{
var list = ObjectList;
var listOld = list.ToList();
var toRemove = new List<PaintingObject>();
// Disable raising events
ObjectList.EnableRaisingEvents = false;
// Clear list
list.Clear();
// Add ordered
foreach (var kvp in Conditions.OrderBy(n => n.Key))
{
var func = kvp.Value;
foreach (PaintingObject obj in listOld)
{
if (func(obj))
{
// Add to list
list.Add(obj);
// Add to remove
toRemove.Add(obj);
}
}
// Remove remembered objects
foreach (PaintingObject obj in toRemove)
listOld.Remove(obj);
toRemove.Clear();
}
// Enable raising events
ObjectList.EnableRaisingEvents = true;
// Refresh
ObjectList.MyParent?.Refresh();
}
}

View File

@@ -0,0 +1,346 @@
using Pilz.Drawing;
using System;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
namespace Pilz.UI;
[Serializable]
internal class PaintingObjectResizing
{
public static event CheckEnabledEventHandler CheckEnabled;
public delegate void CheckEnabledEventHandler(PaintingObjectResizing sender, ref bool enabled);
private PaintingObject _mObj;
private PaintingObject mObj
{
[MethodImpl(MethodImplOptions.Synchronized)]
get
{
return _mObj;
}
[MethodImpl(MethodImplOptions.Synchronized)]
set
{
if (_mObj != null)
{
_mObj.MouseDown -= mControl_MouseDown;
_mObj.MouseUp -= mControl_MouseUp;
_mObj.Paint -= mControl_Paint;
_mObj.SelectedChanged -= mControl_MouseLeave;
_mObj.ParentChanged -= mObj_ParentChanged;
}
_mObj = value;
if (_mObj != null)
{
_mObj.MouseDown += mControl_MouseDown;
_mObj.MouseUp += mControl_MouseUp;
_mObj.Paint += mControl_Paint;
_mObj.SelectedChanged += mControl_MouseLeave;
_mObj.ParentChanged += mObj_ParentChanged;
}
}
}
private Control _mObjParent;
private Control mObjParent
{
[MethodImpl(MethodImplOptions.Synchronized)]
get
{
return _mObjParent;
}
[MethodImpl(MethodImplOptions.Synchronized)]
set
{
_mObjParent = value;
}
}
private Control _mObjControl;
private Control mObjControl
{
[MethodImpl(MethodImplOptions.Synchronized)]
get
{
return _mObjControl;
}
[MethodImpl(MethodImplOptions.Synchronized)]
set
{
if (_mObjControl != null)
{
_mObjControl.MouseMove -= mControl_MouseMove;
_mObjControl.ParentChanged -= mObjParent_ParentChanged;
}
_mObjControl = value;
if (_mObjControl != null)
{
_mObjControl.MouseMove += mControl_MouseMove;
_mObjControl.ParentChanged += mObjParent_ParentChanged;
}
}
}
private bool mMouseDown = false;
private EdgeEnum mEdge = EdgeEnum.None;
private int mWidth = 4;
private int qWidth = 4 * 4;
private Rectangle rect = new Rectangle();
public bool Enabled { get; set; } = true;
public SizeF MinimumSize { get; set; } = new SizeF(15f, 15f);
[Serializable]
private enum EdgeEnum
{
None,
Right,
Left,
Top,
Bottom,
TopLeft,
TopRight,
BottomLeft,
BottomRight
}
public bool IsResizing
{
get
{
return mMouseDown && mEdge != EdgeEnum.None;
}
}
public PaintingObject PaintingObject
{
get
{
return mObj;
}
}
public PaintingObjectResizing(PaintingObject obj)
{
mObjParent = null;
mObjControl = null;
mObj = obj;
mObjControl = mObj.Parent;
}
private bool IsEnabled()
{
bool enabled = Enabled;
CheckEnabled?.Invoke(this, ref enabled);
return enabled;
}
private void mControl_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
mMouseDown = true;
}
private void mControl_MouseUp(object sender, MouseEventArgs e)
{
mMouseDown = false;
if (mObj.Selected)
mObj.AutoArrangeToGrid();
}
private void KeepInRange(ref SizeF size)
{
if (size.Height < MinimumSize.Height || size.Width < MinimumSize.Width)
size = new SizeF(Math.Max(size.Width, MinimumSize.Width), Math.Max(size.Height, MinimumSize.Height));
}
private void mControl_MouseMove(object sender, MouseEventArgs e)
{
if (mMouseDown && mEdge != EdgeEnum.None)
{
int eX = (int)Math.Round(e.X + mObj.Parent.Offset.X);
int eY = (int)Math.Round(e.Y + mObj.Parent.Offset.Y);
switch (mEdge)
{
case EdgeEnum.TopLeft:
{
mObj.SetBounds(eX, eY, (int)Math.Round(mObj.Width + (mObj.Left - eX)), (int)Math.Round(mObj.Height + (mObj.Top - eY)));
break;
}
case EdgeEnum.TopRight:
{
mObj.SetBounds(mObj.Left, eY, eX - mObj.Left, (int)Math.Round(mObj.Height + (mObj.Top - eY)));
break;
}
case EdgeEnum.BottomRight:
{
mObj.SetBounds(mObj.Left, mObj.Top, eX - mObj.Left, eY - mObj.Top);
break;
}
case EdgeEnum.BottomLeft:
{
mObj.SetBounds(eX, mObj.Top, (int)Math.Round(mObj.Width + (mObj.Left - eX)), eY - mObj.Top);
break;
}
case EdgeEnum.Left:
{
mObj.SetBounds(eX, mObj.Top, (int)Math.Round(mObj.Width + (mObj.Left - eX)), (int)Math.Round(mObj.Height));
break;
}
case EdgeEnum.Right:
{
mObj.SetBounds(mObj.Left, mObj.Top, eX - mObj.Left, (int)Math.Round(mObj.Height));
break;
}
case EdgeEnum.Top:
{
mObj.SetBounds(mObj.Left, eY, (int)Math.Round(mObj.Width), (int)Math.Round(mObj.Height + (mObj.Top - eY)));
break;
}
case EdgeEnum.Bottom:
{
mObj.SetBounds(mObj.Left, mObj.Top, (int)Math.Round(mObj.Width), eY - mObj.Top);
break;
}
}
var argsize = mObj.Size;
KeepInRange(ref argsize);
mObj.Size = argsize;
}
else if (!mMouseDown)
{
int eXo = e.X;
int eYo = e.Y;
int realX = (int)Math.Round(eXo + mObj.Parent.Offset.X);
int realY = (int)Math.Round(eYo + mObj.Parent.Offset.Y);
int eXwo = (int)Math.Round(eXo - mObj.X);
int eYwo = (int)Math.Round(eYo - mObj.Y);
int eX = (int)Math.Round(eXwo + mObj.Parent.Offset.X);
int eY = (int)Math.Round(eYwo + mObj.Parent.Offset.Y);
var eLocation = new Point(eX, eY);
RectangleF extRect = mObj.RectangleExtended;
var oldRect = mObj.Rectangle;
var newRect = new RectangleF();
newRect.X = extRect.X - oldRect.X;
newRect.Y = extRect.Y - oldRect.Y;
newRect.Width = (extRect.Width - oldRect.Width) / 2f;
newRect.Height = (extRect.Height - oldRect.Height) / 2f;
bool setToNone = false;
bool isOnTop = ReferenceEquals(mObj.Parent.GetObject(new PointF(realX, realY), true), mObj);
if (IsEnabled() && isOnTop)
{
switch (true)
{
case object _ when HelpfulDrawingFunctions.IsPointInRectangle(eLocation, new Rectangle((int)Math.Round(newRect.X), (int)Math.Round(newRect.Y), (int)Math.Round(newRect.Width), (int)Math.Round(newRect.Height))):
{
mObj.Cursor = Cursors.SizeNWSE;
mEdge = EdgeEnum.TopLeft;
break;
}
case object _ when HelpfulDrawingFunctions.IsPointInRectangle(eLocation, new Rectangle((int)Math.Round(mObj.Width), (int)Math.Round(newRect.Y), (int)Math.Round(newRect.Width), (int)Math.Round(newRect.Height))):
{
mObj.Cursor = Cursors.SizeNESW;
mEdge = EdgeEnum.TopRight;
break;
}
case object _ when HelpfulDrawingFunctions.IsPointInRectangle(eLocation, new Rectangle((int)Math.Round(mObj.Width), (int)Math.Round(mObj.Height), (int)Math.Round(newRect.Width), (int)Math.Round(newRect.Height))):
{
mObj.Cursor = Cursors.SizeNWSE;
mEdge = EdgeEnum.BottomRight;
break;
}
case object _ when HelpfulDrawingFunctions.IsPointInRectangle(eLocation, new Rectangle((int)Math.Round(newRect.X), (int)Math.Round(mObj.Height), (int)Math.Round(newRect.Width), (int)Math.Round(newRect.Height))):
{
mObj.Cursor = Cursors.SizeNESW;
mEdge = EdgeEnum.BottomLeft;
break;
}
case object _ when HelpfulDrawingFunctions.IsPointInRectangle(eLocation, new Rectangle((int)Math.Round(-newRect.Width), 0, (int)Math.Round(newRect.Width), (int)Math.Round(mObj.Height))):
{
mObj.Cursor = Cursors.SizeWE;
mEdge = EdgeEnum.Left;
break;
}
case object _ when HelpfulDrawingFunctions.IsPointInRectangle(eLocation, new Rectangle((int)Math.Round(mObj.Width), 0, (int)Math.Round(newRect.Width), (int)Math.Round(mObj.Height))):
{
mObj.Cursor = Cursors.SizeWE;
mEdge = EdgeEnum.Right;
break;
}
case object _ when HelpfulDrawingFunctions.IsPointInRectangle(eLocation, new Rectangle(0, (int)Math.Round(-newRect.Height), (int)Math.Round(mObj.Width), (int)Math.Round(newRect.Height))):
{
mObj.Cursor = Cursors.SizeNS;
mEdge = EdgeEnum.Top;
break;
}
case object _ when HelpfulDrawingFunctions.IsPointInRectangle(eLocation, new Rectangle(0, (int)Math.Round(mObj.Height), (int)Math.Round(mObj.Width), (int)Math.Round(newRect.Height))):
{
mObj.Cursor = Cursors.SizeNS;
mEdge = EdgeEnum.Bottom;
break;
}
default:
{
setToNone = true;
break;
}
}
}
else
{
setToNone = true;
}
if (setToNone)
{
mObj.Cursor = Cursors.Default;
mEdge = EdgeEnum.None;
}
}
}
private void mControl_Paint(PaintingObject sender, PaintEventArgs e)
{
// e.Graphics.FillRectangle(brush, rect)
}
private void mControl_MouseLeave(PaintingObject sender, EventArgs e)
{
if (!sender.Selected)
mEdge = EdgeEnum.None;
}
private void mObjParent_ParentChanged(object sender, EventArgs e)
{
mObjParent = mObjControl.Parent;
}
private void mObj_ParentChanged(PaintingObject sender, EventArgs e)
{
mObjControl = mObj.Parent;
mObjParent = mObjControl?.Parent;
}
}

85
Pilz.UI/Pilz.UI.csproj Normal file
View File

@@ -0,0 +1,85 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<MyType>Windows</MyType>
<TargetFrameworks>net6.0-windows;net8.0-windows</TargetFrameworks>
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
<DocumentationFile>Pilz.UI.xml</DocumentationFile>
<UseWindowsForms>true</UseWindowsForms>
<DefaultItemExcludes>$(DefaultItemExcludes);$(ProjectDir)**\*.vb</DefaultItemExcludes>
<LangVersion>latest</LangVersion>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DefineConstants>DEBUG</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<RemoveIntegerChecks>true</RemoveIntegerChecks>
</PropertyGroup>
<PropertyGroup>
<OptionExplicit>On</OptionExplicit>
</PropertyGroup>
<PropertyGroup>
<OptionCompare>Binary</OptionCompare>
</PropertyGroup>
<PropertyGroup>
<OptionStrict>Off</OptionStrict>
</PropertyGroup>
<PropertyGroup>
<OptionInfer>On</OptionInfer>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<UseVSHostingProcess>true</UseVSHostingProcess>
<DefineConstants>DEBUG</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>
<RemoveIntegerChecks>true</RemoveIntegerChecks>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup>
<Version>2.0.0</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<Import Include="Microsoft.VisualBasic" />
<Import Include="System" />
<Import Include="System.Collections" />
<Import Include="System.Collections.Generic" />
<Import Include="System.Data" />
<Import Include="System.Diagnostics" />
<Import Include="System.Linq" />
<Import Include="System.Xml.Linq" />
<Import Include="System.Threading.Tasks" />
</ItemGroup>
<ItemGroup>
<Compile Update="PaintingControl\PaintingControl.cs" />
<Compile Update="Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<CustomToolNamespace>Pilz.UI.My.Resources</CustomToolNamespace>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Update="PaintingControl\PaintingControl.resx">
<DependentUpon>PaintingControl.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Pilz.Drawing\Pilz.Drawing.vbproj" />
<ProjectReference Include="..\Pilz.Win32\Pilz.Win32.vbproj" />
</ItemGroup>
</Project>

70
Pilz.UI/Resources.Designer.cs generated Normal file
View File

@@ -0,0 +1,70 @@
// ------------------------------------------------------------------------------
// <auto-generated>
// Dieser Code wurde von einem Tool generiert.
// Laufzeitversion:4.0.30319.42000
//
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
// der Code erneut generiert wird.
// </auto-generated>
// ------------------------------------------------------------------------------
using System.Diagnostics;
using Microsoft.VisualBasic;
namespace Pilz.UI.My.Resources
{
// Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
// -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
// Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
// mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
/// <summary>
/// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[DebuggerNonUserCode()]
[System.Runtime.CompilerServices.CompilerGenerated()]
[HideModuleName()]
internal static class Resources
{
private static System.Resources.ResourceManager resourceMan;
private static System.Globalization.CultureInfo resourceCulture;
/// <summary>
/// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
/// </summary>
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)]
internal static System.Resources.ResourceManager ResourceManager
{
get
{
if (ReferenceEquals(resourceMan, null))
{
var temp = new System.Resources.ResourceManager("Pilz.UI.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
/// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
/// </summary>
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)]
internal static System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View File

@@ -0,0 +1,50 @@
using System.Collections.Generic;
using System.Windows.Forms;
namespace Pilz.UI.Utils;
public static class DrawingControl
{
private const int WM_SETREDRAW = 11;
private readonly static Dictionary<nint, int> dicSuspendCount = new Dictionary<nint, int>();
public static void SuspendDrawing(this Control control)
{
if (!dicSuspendCount.ContainsKey(control.Handle))
dicSuspendCount.Add(control.Handle, 1);
else
{
dicSuspendCount[control.Handle] += 1;
}
if (dicSuspendCount[control.Handle] == 1)
User32Bridge.SendMessage(control.Handle, WM_SETREDRAW, false, 0);
}
public static void ResumeDrawing(this Control control)
{
control.ResumeDrawing(true);
}
public static void ResumeDrawing(this Control control, bool redraw)
{
bool doRedraw = true;
if (dicSuspendCount.ContainsKey(control.Handle))
{
dicSuspendCount[control.Handle] -= 1;
if (dicSuspendCount[control.Handle] >= 1)
doRedraw = false;
}
if (doRedraw)
{
User32Bridge.SendMessage(control.Handle, WM_SETREDRAW, true, 0);
if (redraw)
control.Refresh();
}
}
}

View File

@@ -0,0 +1,9 @@
using System.Runtime.InteropServices;
namespace Pilz.UI;
public static class User32Bridge
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern int SendMessage(nint hWnd, int Msg, bool wParam, int lParam);
}