#region Imports using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; using System.Runtime.InteropServices; using System.Windows.Forms; #endregion namespace DPumpHydr.WinFrmUI.RLT.Util { #region SpaceUtil public abstract class SpaceLibrary : ContainerControl { #region " Initialization " protected Graphics G; protected Bitmap B; public SpaceLibrary() { SetStyle((ControlStyles)139270, true); _ImageSize = Size.Empty; Font = new("Verdana", 8); MeasureBitmap = new(1, 1); MeasureGraphics = Graphics.FromImage(MeasureBitmap); StartPosition = FormStartPosition.CenterScreen; DrawRadialPath = new(); InvalidateCustimization(); } protected sealed override void OnHandleCreated(EventArgs e) { if (DoneCreation) { InitializeMessages(); } InvalidateCustimization(); ColorHook(); if (!(_LockWidth == 0)) { Width = _LockWidth; } if (!(_LockHeight == 0)) { Height = _LockHeight; } if (!_ControlMode) { base.Dock = DockStyle.Fill; } Transparent = _Transparent; if (_Transparent && _BackColor) { BackColor = Color.Transparent; } base.OnHandleCreated(e); } private bool DoneCreation; protected sealed override void OnParentChanged(EventArgs e) { base.OnParentChanged(e); if (Parent == null) { return; } IsParentForm = Parent is Form; if (!_ControlMode) { InitializeMessages(); if (IsParentForm) { ParentForm.FormBorderStyle = _BorderStyle; ParentForm.TransparencyKey = _TransparencyKey; if (!DesignMode) { ParentForm.Shown += FormShown; } } Parent.BackColor = BackColor; } OnCreation(); DoneCreation = true; InvalidateTimer(); } #endregion private void DoAnimation(bool i) { OnAnimation(); if (i) { Invalidate(); } } protected sealed override void OnPaint(PaintEventArgs e) { if (Width == 0 || Height == 0) { return; } if (_Transparent && _ControlMode) { PaintHook(); e.Graphics.DrawImage(B, 0, 0); } else { G = e.Graphics; PaintHook(); } } protected override void OnHandleDestroyed(EventArgs e) { ThemeShareSpace.RemoveAnimationCallback(DoAnimation); base.OnHandleDestroyed(e); } private bool HasShown; private void FormShown(object sender, EventArgs e) { if (_ControlMode || HasShown) { return; } if (_StartPosition is FormStartPosition.CenterParent or FormStartPosition.CenterScreen) { Rectangle SB = Screen.PrimaryScreen.Bounds; Rectangle CB = ParentForm.Bounds; ParentForm.Location = new((SB.Width / 2) - (CB.Width / 2), (SB.Height / 2) - (CB.Height / 2)); } HasShown = true; } #region " Size Handling " private Rectangle Frame; protected sealed override void OnSizeChanged(EventArgs e) { if (Movable && !_ControlMode) { Frame = new(7, 7, Width - 14, _Header - 7); } InvalidateBitmap(); Invalidate(); base.OnSizeChanged(e); } protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) { if (!(_LockWidth == 0)) { width = _LockWidth; } if (!(_LockHeight == 0)) { height = _LockHeight; } base.SetBoundsCore(x, y, width, height, specified); } #endregion #region " State Handling " protected MouseStateSpace State; private void SetState(MouseStateSpace current) { State = current; Invalidate(); } protected override void OnMouseMove(MouseEventArgs e) { if (!(IsParentForm && ParentForm.WindowState == FormWindowState.Maximized)) { if (Sizable && !_ControlMode) { InvalidateMouse(); } } base.OnMouseMove(e); } protected override void OnEnabledChanged(EventArgs e) { if (Enabled) { SetState(MouseStateSpace.None); } else { SetState(MouseStateSpace.Block); } base.OnEnabledChanged(e); } protected override void OnMouseEnter(EventArgs e) { SetState(MouseStateSpace.Over); base.OnMouseEnter(e); } protected override void OnMouseUp(MouseEventArgs e) { SetState(MouseStateSpace.Over); base.OnMouseUp(e); } protected override void OnMouseLeave(EventArgs e) { SetState(MouseStateSpace.None); if (GetChildAtPoint(PointToClient(MousePosition)) != null) { if (Sizable && !_ControlMode) { Cursor = Cursors.Default; Previous = 0; } } base.OnMouseLeave(e); } protected override void OnMouseDown(MouseEventArgs e) { if (e.Button == MouseButtons.Left) { SetState(MouseStateSpace.Down); } if (!((IsParentForm && ParentForm.WindowState == FormWindowState.Maximized) || _ControlMode)) { if (Movable && Frame.Contains(e.Location)) { Capture = false; WM_LMBUTTONDOWN = true; DefWndProc(ref Messages[0]); } else if (Sizable && !(Previous == 0)) { Capture = false; WM_LMBUTTONDOWN = true; DefWndProc(ref Messages[Previous]); } } base.OnMouseDown(e); } private bool WM_LMBUTTONDOWN; protected override void WndProc(ref Message m) { base.WndProc(ref m); if (WM_LMBUTTONDOWN && m.Msg == 513) { WM_LMBUTTONDOWN = false; SetState(MouseStateSpace.Over); if (!SmartBounds) { return; } if (IsParentMdi) { CorrectBounds(new Rectangle(Point.Empty, Parent.Parent.Size)); } else { CorrectBounds(Screen.FromControl(Parent).WorkingArea); } } } private Point GetIndexPoint; private bool B1; private bool B2; private bool B3; private bool B4; private int GetIndex() { GetIndexPoint = PointToClient(MousePosition); B1 = GetIndexPoint.X < 7; B2 = GetIndexPoint.X > Width - 7; B3 = GetIndexPoint.Y < 7; B4 = GetIndexPoint.Y > Height - 7; if (B1 && B3) { return 4; } if (B1 && B4) { return 7; } if (B2 && B3) { return 5; } if (B2 && B4) { return 8; } if (B1) { return 1; } if (B2) { return 2; } if (B3) { return 3; } if (B4) { return 6; } return 0; } private int Current; private int Previous; private void InvalidateMouse() { Current = GetIndex(); if (Current == Previous) { return; } Previous = Current; switch (Previous) { case 0: Cursor = Cursors.Default; break; case 1: case 2: Cursor = Cursors.SizeWE; break; case 3: case 6: Cursor = Cursors.SizeNS; break; case 4: case 8: Cursor = Cursors.SizeNWSE; break; case 5: case 7: Cursor = Cursors.SizeNESW; break; } } private readonly Message[] Messages = new Message[9]; private void InitializeMessages() { Messages[0] = Message.Create(Parent.Handle, 161, new IntPtr(2), IntPtr.Zero); for (int I = 1; I <= 8; I++) { Messages[I] = Message.Create(Parent.Handle, 161, new IntPtr(I + 9), IntPtr.Zero); } } private void CorrectBounds(Rectangle bounds) { if (Parent.Width > bounds.Width) { Parent.Width = bounds.Width; } if (Parent.Height > bounds.Height) { Parent.Height = bounds.Height; } int X = Parent.Location.X; int Y = Parent.Location.Y; if (X < bounds.X) { X = bounds.X; } if (Y < bounds.Y) { Y = bounds.Y; } int Width = bounds.X + bounds.Width; int Height = bounds.Y + bounds.Height; if (X + Parent.Width > Width) { X = Width - Parent.Width; } if (Y + Parent.Height > Height) { Y = Height - Parent.Height; } Parent.Location = new(X, Y); } #endregion #region " Base Properties " public override DockStyle Dock { get => base.Dock; set { if (!_ControlMode) { return; } base.Dock = value; } } private bool _BackColor; [Category("Misc")] public override Color BackColor { get => base.BackColor; set { if (value == base.BackColor) { return; } if (!IsHandleCreated && _ControlMode && value == Color.Transparent) { _BackColor = true; return; } base.BackColor = value; if (Parent != null) { if (!_ControlMode) { Parent.BackColor = value; } ColorHook(); } } } public override Size MinimumSize { get => base.MinimumSize; set { base.MinimumSize = value; if (Parent != null) { Parent.MinimumSize = value; } } } public override Size MaximumSize { get => base.MaximumSize; set { base.MaximumSize = value; if (Parent != null) { Parent.MaximumSize = value; } } } public override string Text { get => base.Text; set { base.Text = value; Invalidate(); } } public override Font Font { get => base.Font; set { base.Font = value; Invalidate(); } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override Color ForeColor { get => Color.Empty; set { } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override Image BackgroundImage { get => null; set { } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override ImageLayout BackgroundImageLayout { get => ImageLayout.None; set { } } #endregion #region " Public Properties " public bool SmartBounds { get; set; } = true; public bool Movable { get; set; } = true; public bool Sizable { get; set; } = true; private Color _TransparencyKey; public Color TransparencyKey { get { if (IsParentForm && !_ControlMode) { return ParentForm.TransparencyKey; } else { return _TransparencyKey; } } set { if (value == _TransparencyKey) { return; } _TransparencyKey = value; if (IsParentForm && !_ControlMode) { ParentForm.TransparencyKey = value; ColorHook(); } } } private FormBorderStyle _BorderStyle; public FormBorderStyle BorderStyle { get { if (IsParentForm && !_ControlMode) { return ParentForm.FormBorderStyle; } else { return _BorderStyle; } } set { _BorderStyle = value; if (IsParentForm && !_ControlMode) { ParentForm.FormBorderStyle = value; if (!(value == FormBorderStyle.None)) { Movable = false; Sizable = false; } } } } private FormStartPosition _StartPosition; public FormStartPosition StartPosition { get { if (IsParentForm && !_ControlMode) { return ParentForm.StartPosition; } else { return _StartPosition; } } set { _StartPosition = value; if (IsParentForm && !_ControlMode) { ParentForm.StartPosition = value; } } } private bool _NoRounding; public bool NoRounding { get => _NoRounding; set { _NoRounding = value; Invalidate(); } } private Image _Image; public Image Image { get => _Image; set { if (value == null) { _ImageSize = Size.Empty; } else { _ImageSize = value.Size; } _Image = value; Invalidate(); } } private readonly Dictionary Items = new(); public BloomSpace[] Colors { get { List T = new(); Dictionary.Enumerator E = Items.GetEnumerator(); while (E.MoveNext()) { T.Add(new BloomSpace(E.Current.Key, E.Current.Value)); } return T.ToArray(); } set { foreach (BloomSpace B in value) { if (Items.ContainsKey(B.Name)) { Items[B.Name] = B.Value; } } InvalidateCustimization(); ColorHook(); Invalidate(); } } private string _Customization; public string Customization { get => _Customization; set { if (value == _Customization) { return; } BloomSpace[] Items = Colors; try { byte[] Data = Convert.FromBase64String(value); for (int I = 0; I <= Items.Length - 1; I++) { Items[I].Value = Color.FromArgb(BitConverter.ToInt32(Data, I * 4)); } } catch { return; } _Customization = value; Colors = Items; ColorHook(); Invalidate(); } } private bool _Transparent; public bool Transparent { get => _Transparent; set { _Transparent = value; if (!(IsHandleCreated || _ControlMode)) { return; } if (!value && !(BackColor.A == 255)) { throw new Exception("Unable to change value to false while a transparent BackColor is in use."); } SetStyle(ControlStyles.Opaque, !value); SetStyle(ControlStyles.SupportsTransparentBackColor, value); InvalidateBitmap(); Invalidate(); } } #endregion #region " Private Properties " private Size _ImageSize; protected Size ImageSize => _ImageSize; protected bool IsParentForm { get; private set; } protected bool IsParentMdi { get { if (Parent == null) { return false; } return Parent.Parent != null; } } private int _LockWidth; protected int LockWidth { get => _LockWidth; set { _LockWidth = value; if (!(LockWidth == 0) && IsHandleCreated) { Width = LockWidth; } } } private int _LockHeight; protected int LockHeight { get => _LockHeight; set { _LockHeight = value; if (!(LockHeight == 0) && IsHandleCreated) { Height = LockHeight; } } } private int _Header = 24; protected int Header { get => _Header; set { _Header = value; if (!_ControlMode) { Frame = new(7, 7, Width - 14, value - 7); Invalidate(); } } } private bool _ControlMode; protected bool ControlMode { get => _ControlMode; set { _ControlMode = value; Transparent = _Transparent; if (_Transparent && _BackColor) { BackColor = Color.Transparent; } InvalidateBitmap(); Invalidate(); } } private bool _IsAnimated; protected bool IsAnimated { get => _IsAnimated; set { _IsAnimated = value; InvalidateTimer(); } } #endregion #region " Property Helpers " protected Pen GetPen(string name) { return new(Items[name]); } protected Pen GetPen(string name, float width) { return new(Items[name], width); } protected SolidBrush GetBrush(string name) { return new SolidBrush(Items[name]); } protected Color GetColor(string name) { return Items[name]; } protected void SetColor(string name, Color value) { if (Items.ContainsKey(name)) { Items[name] = value; } else { Items.Add(name, value); } } protected void SetColor(string name, byte r, byte g, byte b) { SetColor(name, Color.FromArgb(r, g, b)); } protected void SetColor(string name, byte a, byte r, byte g, byte b) { SetColor(name, Color.FromArgb(a, r, g, b)); } protected void SetColor(string name, byte a, Color value) { SetColor(name, Color.FromArgb(a, value)); } private void InvalidateBitmap() { if (_Transparent && _ControlMode) { if (Width == 0 || Height == 0) { return; } B = new(Width, Height, PixelFormat.Format32bppPArgb); G = Graphics.FromImage(B); } else { G = null; B = null; } } private void InvalidateCustimization() { MemoryStream M = new(Items.Count * 4); foreach (BloomSpace B in Colors) { M.Write(BitConverter.GetBytes(B.Value.ToArgb()), 0, 4); } M.Close(); _Customization = Convert.ToBase64String(M.ToArray()); } private void InvalidateTimer() { if (DesignMode || !DoneCreation) { return; } if (_IsAnimated) { ThemeShareSpace.AddAnimationCallback(DoAnimation); } else { ThemeShareSpace.RemoveAnimationCallback(DoAnimation); } } #endregion #region " User Hooks " protected abstract void ColorHook(); protected abstract void PaintHook(); protected virtual void OnCreation() { } protected virtual void OnAnimation() { } #endregion #region " Offset " private Rectangle OffsetReturnRectangle; protected Rectangle Offset(Rectangle r, int amount) { OffsetReturnRectangle = new(r.X + amount, r.Y + amount, r.Width - (amount * 2), r.Height - (amount * 2)); return OffsetReturnRectangle; } private Size OffsetReturnSize; protected Size Offset(Size s, int amount) { OffsetReturnSize = new(s.Width + amount, s.Height + amount); return OffsetReturnSize; } private Point OffsetReturnPoint; protected Point Offset(Point p, int amount) { OffsetReturnPoint = new(p.X + amount, p.Y + amount); return OffsetReturnPoint; } #endregion #region " Center " private Point CenterReturn; protected Point Center(Rectangle p, Rectangle c) { CenterReturn = new((p.Width / 2) - (c.Width / 2) + p.X + c.X, (p.Height / 2) - (c.Height / 2) + p.Y + c.Y); return CenterReturn; } protected Point Center(Rectangle p, Size c) { CenterReturn = new((p.Width / 2) - (c.Width / 2) + p.X, (p.Height / 2) - (c.Height / 2) + p.Y); return CenterReturn; } protected Point Center(Rectangle child) { return Center(Width, Height, child.Width, child.Height); } protected Point Center(Size child) { return Center(Width, Height, child.Width, child.Height); } protected Point Center(int childWidth, int childHeight) { return Center(Width, Height, childWidth, childHeight); } protected Point Center(Size p, Size c) { return Center(p.Width, p.Height, c.Width, c.Height); } protected Point Center(int pWidth, int pHeight, int cWidth, int cHeight) { CenterReturn = new((pWidth / 2) - (cWidth / 2), (pHeight / 2) - (cHeight / 2)); return CenterReturn; } #endregion #region " Measure " private readonly Bitmap MeasureBitmap; private readonly Graphics MeasureGraphics; protected Size Measure() { lock (MeasureGraphics) { return MeasureGraphics.MeasureString(Text, Font, Width).ToSize(); } } protected Size Measure(string text) { lock (MeasureGraphics) { return MeasureGraphics.MeasureString(text, Font, Width).ToSize(); } } #endregion #region " DrawPixel " private SolidBrush DrawPixelBrush; protected void DrawPixel(Color c1, int x, int y) { if (_Transparent) { B.SetPixel(x, y, c1); } else { DrawPixelBrush = new(c1); G.FillRectangle(DrawPixelBrush, x, y, 1, 1); } } #endregion #region " DrawCorners " private SolidBrush DrawCornersBrush; protected void DrawCorners(Color c1, int offset) { DrawCorners(c1, 0, 0, Width, Height, offset); } protected void DrawCorners(Color c1, Rectangle r1, int offset) { DrawCorners(c1, r1.X, r1.Y, r1.Width, r1.Height, offset); } protected void DrawCorners(Color c1, int x, int y, int width, int height, int offset) { DrawCorners(c1, x + offset, y + offset, width - (offset * 2), height - (offset * 2)); } protected void DrawCorners(Color c1) { DrawCorners(c1, 0, 0, Width, Height); } protected void DrawCorners(Color c1, Rectangle r1) { DrawCorners(c1, r1.X, r1.Y, r1.Width, r1.Height); } protected void DrawCorners(Color c1, int x, int y, int width, int height) { if (_NoRounding) { return; } if (_Transparent) { B.SetPixel(x, y, c1); B.SetPixel(x + (width - 1), y, c1); B.SetPixel(x, y + (height - 1), c1); B.SetPixel(x + (width - 1), y + (height - 1), c1); } else { DrawCornersBrush = new(c1); G.FillRectangle(DrawCornersBrush, x, y, 1, 1); G.FillRectangle(DrawCornersBrush, x + (width - 1), y, 1, 1); G.FillRectangle(DrawCornersBrush, x, y + (height - 1), 1, 1); G.FillRectangle(DrawCornersBrush, x + (width - 1), y + (height - 1), 1, 1); } } #endregion #region " DrawBorders " protected void DrawBorders(Pen p1, int offset) { DrawBorders(p1, 0, 0, Width, Height, offset); } protected void DrawBorders(Pen p1, Rectangle r, int offset) { DrawBorders(p1, r.X, r.Y, r.Width, r.Height, offset); } protected void DrawBorders(Pen p1, int x, int y, int width, int height, int offset) { DrawBorders(p1, x + offset, y + offset, width - (offset * 2), height - (offset * 2)); } protected void DrawBorders(Pen p1) { DrawBorders(p1, 0, 0, Width, Height); } protected void DrawBorders(Pen p1, Rectangle r) { DrawBorders(p1, r.X, r.Y, r.Width, r.Height); } protected void DrawBorders(Pen p1, int x, int y, int width, int height) { G.DrawRectangle(p1, x, y, width - 1, height - 1); } #endregion #region " DrawText " private Point DrawTextPoint; private Size DrawTextSize; protected void DrawText(Brush b1, HorizontalAlignment a, int x, int y) { DrawText(b1, Text, a, x, y); } protected void DrawText(Brush b1, string text, HorizontalAlignment a, int x, int y) { if (text.Length == 0) { return; } DrawTextSize = Measure(text); DrawTextPoint = new((Width / 2) - (DrawTextSize.Width / 2), (Header / 2) - (DrawTextSize.Height / 2)); switch (a) { case HorizontalAlignment.Left: G.DrawString(text, Font, b1, x, DrawTextPoint.Y + y); break; case HorizontalAlignment.Center: G.DrawString(text, Font, b1, DrawTextPoint.X + x, DrawTextPoint.Y + y); break; case HorizontalAlignment.Right: G.DrawString(text, Font, b1, Width - DrawTextSize.Width - x, DrawTextPoint.Y + y); break; } } protected void DrawText(Brush b1, Point p1) { if (Text.Length == 0) { return; } G.DrawString(Text, Font, b1, p1); } protected void DrawText(Brush b1, int x, int y) { if (Text.Length == 0) { return; } G.DrawString(Text, Font, b1, x, y); } #endregion #region " DrawImage " private Point DrawImagePoint; protected void DrawImage(HorizontalAlignment a, int x, int y) { DrawImage(_Image, a, x, y); } protected void DrawImage(Image image, HorizontalAlignment a, int x, int y) { if (image == null) { return; } DrawImagePoint = new((Width / 2) - (image.Width / 2), (Header / 2) - (image.Height / 2)); switch (a) { case HorizontalAlignment.Left: G.DrawImage(image, x, DrawImagePoint.Y + y, image.Width, image.Height); break; case HorizontalAlignment.Center: G.DrawImage(image, DrawImagePoint.X + x, DrawImagePoint.Y + y, image.Width, image.Height); break; case HorizontalAlignment.Right: G.DrawImage(image, Width - image.Width - x, DrawImagePoint.Y + y, image.Width, image.Height); break; } } protected void DrawImage(Point p1) { DrawImage(_Image, p1.X, p1.Y); } protected void DrawImage(int x, int y) { DrawImage(_Image, x, y); } protected void DrawImage(Image image, Point p1) { DrawImage(image, p1.X, p1.Y); } protected void DrawImage(Image image, int x, int y) { if (image == null) { return; } G.DrawImage(image, x, y, image.Width, image.Height); } #endregion #region " DrawGradient " private LinearGradientBrush DrawGradientBrush; private Rectangle DrawGradientRectangle; protected void DrawGradient(ColorBlend blend, int x, int y, int width, int height) { DrawGradientRectangle = new(x, y, width, height); DrawGradient(blend, DrawGradientRectangle); } protected void DrawGradient(ColorBlend blend, int x, int y, int width, int height, float angle) { DrawGradientRectangle = new(x, y, width, height); DrawGradient(blend, DrawGradientRectangle, angle); } protected void DrawGradient(ColorBlend blend, Rectangle r) { DrawGradientBrush = new(r, Color.Empty, Color.Empty, 90f) { InterpolationColors = blend }; G.FillRectangle(DrawGradientBrush, r); } protected void DrawGradient(ColorBlend blend, Rectangle r, float angle) { DrawGradientBrush = new(r, Color.Empty, Color.Empty, angle) { InterpolationColors = blend }; G.FillRectangle(DrawGradientBrush, r); } protected void DrawGradient(Color c1, Color c2, int x, int y, int width, int height) { DrawGradientRectangle = new(x, y, width, height); DrawGradient(c1, c2, DrawGradientRectangle); } protected void DrawGradient(Color c1, Color c2, int x, int y, int width, int height, float angle) { DrawGradientRectangle = new(x, y, width, height); DrawGradient(c1, c2, DrawGradientRectangle, angle); } protected void DrawGradient(Color c1, Color c2, Rectangle r) { DrawGradientBrush = new(r, c1, c2, 90f); G.FillRectangle(DrawGradientBrush, r); } protected void DrawGradient(Color c1, Color c2, Rectangle r, float angle) { DrawGradientBrush = new(r, c1, c2, angle); G.FillRectangle(DrawGradientBrush, r); } #endregion #region " DrawRadial " private readonly GraphicsPath DrawRadialPath; private PathGradientBrush DrawRadialBrush1; private LinearGradientBrush DrawRadialBrush2; private Rectangle DrawRadialRectangle; public void DrawRadial(ColorBlend blend, int x, int y, int width, int height) { DrawRadialRectangle = new(x, y, width, height); DrawRadial(blend, DrawRadialRectangle, width / 2, height / 2); } public void DrawRadial(ColorBlend blend, int x, int y, int width, int height, Point center) { DrawRadialRectangle = new(x, y, width, height); DrawRadial(blend, DrawRadialRectangle, center.X, center.Y); } public void DrawRadial(ColorBlend blend, int x, int y, int width, int height, int cx, int cy) { DrawRadialRectangle = new(x, y, width, height); DrawRadial(blend, DrawRadialRectangle, cx, cy); } public void DrawRadial(ColorBlend blend, Rectangle r) { DrawRadial(blend, r, r.Width / 2, r.Height / 2); } public void DrawRadial(ColorBlend blend, Rectangle r, Point center) { DrawRadial(blend, r, center.X, center.Y); } public void DrawRadial(ColorBlend blend, Rectangle r, int cx, int cy) { DrawRadialPath.Reset(); DrawRadialPath.AddEllipse(r.X, r.Y, r.Width - 1, r.Height - 1); DrawRadialBrush1 = new PathGradientBrush(DrawRadialPath) { CenterPoint = new(r.X + cx, r.Y + cy), InterpolationColors = blend }; if (G.SmoothingMode == SmoothingMode.AntiAlias) { G.FillEllipse(DrawRadialBrush1, r.X + 1, r.Y + 1, r.Width - 3, r.Height - 3); } else { G.FillEllipse(DrawRadialBrush1, r); } } protected void DrawRadial(Color c1, Color c2, int x, int y, int width, int height) { DrawRadialRectangle = new(x, y, width, height); DrawRadial(c1, c2, DrawGradientRectangle); } protected void DrawRadial(Color c1, Color c2, int x, int y, int width, int height, float angle) { DrawRadialRectangle = new(x, y, width, height); DrawRadial(c1, c2, DrawGradientRectangle, angle); } protected void DrawRadial(Color c1, Color c2, Rectangle r) { DrawRadialBrush2 = new(r, c1, c2, 90f); G.FillRectangle(DrawGradientBrush, r); } protected void DrawRadial(Color c1, Color c2, Rectangle r, float angle) { DrawRadialBrush2 = new(r, c1, c2, angle); G.FillEllipse(DrawGradientBrush, r); } #endregion #region " CreateRound " private GraphicsPath CreateRoundPath; private Rectangle CreateRoundRectangle; public GraphicsPath CreateRound(int x, int y, int width, int height, int slope) { CreateRoundRectangle = new(x, y, width, height); return CreateRound(CreateRoundRectangle, slope); } public GraphicsPath CreateRound(Rectangle r, int slope) { CreateRoundPath = new(FillMode.Winding); CreateRoundPath.AddArc(r.X, r.Y, slope, slope, 180f, 90f); CreateRoundPath.AddArc(r.Right - slope, r.Y, slope, slope, 270f, 90f); CreateRoundPath.AddArc(r.Right - slope, r.Bottom - slope, slope, slope, 0f, 90f); CreateRoundPath.AddArc(r.X, r.Bottom - slope, slope, slope, 90f, 90f); CreateRoundPath.CloseFigure(); return CreateRoundPath; } #endregion } public abstract class SpaceControl : Control { #region " Initialization " protected Graphics G; protected Bitmap B; public SpaceControl() { SetStyle((ControlStyles)139270, true); _ImageSize = Size.Empty; Font = new("Verdana", 8); MeasureBitmap = new(1, 1); MeasureGraphics = Graphics.FromImage(MeasureBitmap); DrawRadialPath = new(); InvalidateCustimization(); //Remove? } protected sealed override void OnHandleCreated(EventArgs e) { InvalidateCustimization(); ColorHook(); if (!(_LockWidth == 0)) { Width = _LockWidth; } if (!(_LockHeight == 0)) { Height = _LockHeight; } Transparent = _Transparent; if (_Transparent && _BackColor) { BackColor = Color.Transparent; } base.OnHandleCreated(e); } private bool DoneCreation; protected sealed override void OnParentChanged(EventArgs e) { if (Parent != null) { OnCreation(); DoneCreation = true; InvalidateTimer(); } base.OnParentChanged(e); } #endregion private void DoAnimation(bool i) { OnAnimation(); if (i) { Invalidate(); } } protected sealed override void OnPaint(PaintEventArgs e) { if (Width == 0 || Height == 0) { return; } if (_Transparent) { PaintHook(); e.Graphics.DrawImage(B, 0, 0); } else { G = e.Graphics; PaintHook(); } } protected override void OnHandleDestroyed(EventArgs e) { ThemeShareSpace.RemoveAnimationCallback(DoAnimation); base.OnHandleDestroyed(e); } #region " Size Handling " protected sealed override void OnSizeChanged(EventArgs e) { if (_Transparent) { InvalidateBitmap(); } Invalidate(); base.OnSizeChanged(e); } protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) { if (!(_LockWidth == 0)) { width = _LockWidth; } if (!(_LockHeight == 0)) { height = _LockHeight; } base.SetBoundsCore(x, y, width, height, specified); } #endregion #region " State Handling " private bool InPosition; protected override void OnMouseEnter(EventArgs e) { InPosition = true; SetState(MouseStateSpace.Over); base.OnMouseEnter(e); } protected override void OnMouseUp(MouseEventArgs e) { if (InPosition) { SetState(MouseStateSpace.Over); } base.OnMouseUp(e); } protected override void OnMouseDown(MouseEventArgs e) { if (e.Button == MouseButtons.Left) { SetState(MouseStateSpace.Down); } base.OnMouseDown(e); } protected override void OnMouseLeave(EventArgs e) { InPosition = false; SetState(MouseStateSpace.None); base.OnMouseLeave(e); } protected override void OnEnabledChanged(EventArgs e) { if (Enabled) { SetState(MouseStateSpace.None); } else { SetState(MouseStateSpace.Block); } base.OnEnabledChanged(e); } protected MouseStateSpace State; private void SetState(MouseStateSpace current) { State = current; Invalidate(); } #endregion #region " Base Properties " [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override Color ForeColor { get => Color.Empty; set { } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override Image BackgroundImage { get => null; set { } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override ImageLayout BackgroundImageLayout { get => ImageLayout.None; set { } } public override string Text { get => base.Text; set { base.Text = value; Invalidate(); } } public override Font Font { get => base.Font; set { base.Font = value; Invalidate(); } } private bool _BackColor; [Category("Misc")] public override Color BackColor { get => base.BackColor; set { if (!IsHandleCreated && value == Color.Transparent) { _BackColor = true; return; } base.BackColor = value; if (Parent != null) { ColorHook(); } } } #endregion #region " Public Properties " private bool _NoRounding; public bool NoRounding { get => _NoRounding; set { _NoRounding = value; Invalidate(); } } private Image _Image; public Image Image { get => _Image; set { if (value == null) { _ImageSize = Size.Empty; } else { _ImageSize = value.Size; } _Image = value; Invalidate(); } } private bool _Transparent; public bool Transparent { get => _Transparent; set { _Transparent = value; if (!IsHandleCreated) { return; } if (!value && !(BackColor.A == 255)) { throw new Exception("Unable to change value to false while a transparent BackColor is in use."); } SetStyle(ControlStyles.Opaque, !value); SetStyle(ControlStyles.SupportsTransparentBackColor, value); if (value) { InvalidateBitmap(); } else { B = null; } Invalidate(); } } private readonly Dictionary Items = new(); public BloomSpace[] Colors { get { List T = new(); Dictionary.Enumerator E = Items.GetEnumerator(); while (E.MoveNext()) { T.Add(new BloomSpace(E.Current.Key, E.Current.Value)); } return T.ToArray(); } set { foreach (BloomSpace B in value) { if (Items.ContainsKey(B.Name)) { Items[B.Name] = B.Value; } } InvalidateCustimization(); ColorHook(); Invalidate(); } } private string _Customization; public string Customization { get => _Customization; set { if (value == _Customization) { return; } BloomSpace[] Items = Colors; try { byte[] Data = Convert.FromBase64String(value); for (int I = 0; I <= Items.Length - 1; I++) { Items[I].Value = Color.FromArgb(BitConverter.ToInt32(Data, I * 4)); } } catch { return; } _Customization = value; Colors = Items; ColorHook(); Invalidate(); } } #endregion #region " Private Properties " private Size _ImageSize; protected Size ImageSize => _ImageSize; private int _LockWidth; protected int LockWidth { get => _LockWidth; set { _LockWidth = value; if (!(LockWidth == 0) && IsHandleCreated) { Width = LockWidth; } } } private int _LockHeight; protected int LockHeight { get => _LockHeight; set { _LockHeight = value; if (!(LockHeight == 0) && IsHandleCreated) { Height = LockHeight; } } } private bool _IsAnimated; protected bool IsAnimated { get => _IsAnimated; set { _IsAnimated = value; InvalidateTimer(); } } #endregion #region " Property Helpers " protected Pen GetPen(string name) { return new(Items[name]); } protected Pen GetPen(string name, float width) { return new(Items[name], width); } protected SolidBrush GetBrush(string name) { return new SolidBrush(Items[name]); } protected Color GetColor(string name) { return Items[name]; } protected void SetColor(string name, Color value) { if (Items.ContainsKey(name)) { Items[name] = value; } else { Items.Add(name, value); } } protected void SetColor(string name, byte r, byte g, byte b) { SetColor(name, Color.FromArgb(r, g, b)); } protected void SetColor(string name, byte a, byte r, byte g, byte b) { SetColor(name, Color.FromArgb(a, r, g, b)); } protected void SetColor(string name, byte a, Color value) { SetColor(name, Color.FromArgb(a, value)); } private void InvalidateBitmap() { if (Width == 0 || Height == 0) { return; } B = new(Width, Height, PixelFormat.Format32bppPArgb); G = Graphics.FromImage(B); } private void InvalidateCustimization() { MemoryStream M = new(Items.Count * 4); foreach (BloomSpace B in Colors) { M.Write(BitConverter.GetBytes(B.Value.ToArgb()), 0, 4); } M.Close(); _Customization = Convert.ToBase64String(M.ToArray()); } private void InvalidateTimer() { if (DesignMode || !DoneCreation) { return; } if (_IsAnimated) { ThemeShareSpace.AddAnimationCallback(DoAnimation); } else { ThemeShareSpace.RemoveAnimationCallback(DoAnimation); } } #endregion #region " User Hooks " protected abstract void ColorHook(); protected abstract void PaintHook(); protected virtual void OnCreation() { } protected virtual void OnAnimation() { } #endregion #region " Offset " private Rectangle OffsetReturnRectangle; protected Rectangle Offset(Rectangle r, int amount) { OffsetReturnRectangle = new(r.X + amount, r.Y + amount, r.Width - (amount * 2), r.Height - (amount * 2)); return OffsetReturnRectangle; } private Size OffsetReturnSize; protected Size Offset(Size s, int amount) { OffsetReturnSize = new(s.Width + amount, s.Height + amount); return OffsetReturnSize; } private Point OffsetReturnPoint; protected Point Offset(Point p, int amount) { OffsetReturnPoint = new(p.X + amount, p.Y + amount); return OffsetReturnPoint; } #endregion #region " Center " private Point CenterReturn; protected Point Center(Rectangle p, Rectangle c) { CenterReturn = new((p.Width / 2) - (c.Width / 2) + p.X + c.X, (p.Height / 2) - (c.Height / 2) + p.Y + c.Y); return CenterReturn; } protected Point Center(Rectangle p, Size c) { CenterReturn = new((p.Width / 2) - (c.Width / 2) + p.X, (p.Height / 2) - (c.Height / 2) + p.Y); return CenterReturn; } protected Point Center(Rectangle child) { return Center(Width, Height, child.Width, child.Height); } protected Point Center(Size child) { return Center(Width, Height, child.Width, child.Height); } protected Point Center(int childWidth, int childHeight) { return Center(Width, Height, childWidth, childHeight); } protected Point Center(Size p, Size c) { return Center(p.Width, p.Height, c.Width, c.Height); } protected Point Center(int pWidth, int pHeight, int cWidth, int cHeight) { CenterReturn = new((pWidth / 2) - (cWidth / 2), (pHeight / 2) - (cHeight / 2)); return CenterReturn; } #endregion #region " Measure " private readonly Bitmap MeasureBitmap; //TODO: Potential issues during multi-threading. private readonly Graphics MeasureGraphics; protected Size Measure() { return MeasureGraphics.MeasureString(Text, Font, Width).ToSize(); } protected Size Measure(string text) { return MeasureGraphics.MeasureString(text, Font, Width).ToSize(); } #endregion #region " DrawPixel " private SolidBrush DrawPixelBrush; protected void DrawPixel(Color c1, int x, int y) { if (_Transparent) { B.SetPixel(x, y, c1); } else { DrawPixelBrush = new(c1); G.FillRectangle(DrawPixelBrush, x, y, 1, 1); } } #endregion #region " DrawCorners " private SolidBrush DrawCornersBrush; protected void DrawCorners(Color c1, int offset) { DrawCorners(c1, 0, 0, Width, Height, offset); } protected void DrawCorners(Color c1, Rectangle r1, int offset) { DrawCorners(c1, r1.X, r1.Y, r1.Width, r1.Height, offset); } protected void DrawCorners(Color c1, int x, int y, int width, int height, int offset) { DrawCorners(c1, x + offset, y + offset, width - (offset * 2), height - (offset * 2)); } protected void DrawCorners(Color c1) { DrawCorners(c1, 0, 0, Width, Height); } protected void DrawCorners(Color c1, Rectangle r1) { DrawCorners(c1, r1.X, r1.Y, r1.Width, r1.Height); } protected void DrawCorners(Color c1, int x, int y, int width, int height) { if (_NoRounding) { return; } if (_Transparent) { B.SetPixel(x, y, c1); B.SetPixel(x + (width - 1), y, c1); B.SetPixel(x, y + (height - 1), c1); B.SetPixel(x + (width - 1), y + (height - 1), c1); } else { DrawCornersBrush = new(c1); G.FillRectangle(DrawCornersBrush, x, y, 1, 1); G.FillRectangle(DrawCornersBrush, x + (width - 1), y, 1, 1); G.FillRectangle(DrawCornersBrush, x, y + (height - 1), 1, 1); G.FillRectangle(DrawCornersBrush, x + (width - 1), y + (height - 1), 1, 1); } } #endregion #region " DrawBorders " protected void DrawBorders(Pen p1, int offset) { DrawBorders(p1, 0, 0, Width, Height, offset); } protected void DrawBorders(Pen p1, Rectangle r, int offset) { DrawBorders(p1, r.X, r.Y, r.Width, r.Height, offset); } protected void DrawBorders(Pen p1, int x, int y, int width, int height, int offset) { DrawBorders(p1, x + offset, y + offset, width - (offset * 2), height - (offset * 2)); } protected void DrawBorders(Pen p1) { DrawBorders(p1, 0, 0, Width, Height); } protected void DrawBorders(Pen p1, Rectangle r) { DrawBorders(p1, r.X, r.Y, r.Width, r.Height); } protected void DrawBorders(Pen p1, int x, int y, int width, int height) { G.DrawRectangle(p1, x, y, width - 1, height - 1); } #endregion #region " DrawText " private Point DrawTextPoint; private Size DrawTextSize; protected void DrawText(Brush b1, HorizontalAlignment a, int x, int y) { DrawText(b1, Text, a, x, y); } protected void DrawText(Brush b1, string text, HorizontalAlignment a, int x, int y) { if (text.Length == 0) { return; } DrawTextSize = Measure(text); DrawTextPoint = Center(DrawTextSize); switch (a) { case HorizontalAlignment.Left: G.DrawString(text, Font, b1, x, DrawTextPoint.Y + y); break; case HorizontalAlignment.Center: G.DrawString(text, Font, b1, DrawTextPoint.X + x, DrawTextPoint.Y + y); break; case HorizontalAlignment.Right: G.DrawString(text, Font, b1, Width - DrawTextSize.Width - x, DrawTextPoint.Y + y); break; } } protected void DrawText(Brush b1, Point p1) { if (Text.Length == 0) { return; } G.DrawString(Text, Font, b1, p1); } protected void DrawText(Brush b1, int x, int y) { if (Text.Length == 0) { return; } G.DrawString(Text, Font, b1, x, y); } #endregion #region " DrawImage " private Point DrawImagePoint; protected void DrawImage(HorizontalAlignment a, int x, int y) { DrawImage(_Image, a, x, y); } protected void DrawImage(Image image, HorizontalAlignment a, int x, int y) { if (image == null) { return; } DrawImagePoint = Center(image.Size); switch (a) { case HorizontalAlignment.Left: G.DrawImage(image, x, DrawImagePoint.Y + y, image.Width, image.Height); break; case HorizontalAlignment.Center: G.DrawImage(image, DrawImagePoint.X + x, DrawImagePoint.Y + y, image.Width, image.Height); break; case HorizontalAlignment.Right: G.DrawImage(image, Width - image.Width - x, DrawImagePoint.Y + y, image.Width, image.Height); break; } } protected void DrawImage(Point p1) { DrawImage(_Image, p1.X, p1.Y); } protected void DrawImage(int x, int y) { DrawImage(_Image, x, y); } protected void DrawImage(Image image, Point p1) { DrawImage(image, p1.X, p1.Y); } protected void DrawImage(Image image, int x, int y) { if (image == null) { return; } G.DrawImage(image, x, y, image.Width, image.Height); } #endregion #region " DrawGradient " private LinearGradientBrush DrawGradientBrush; private Rectangle DrawGradientRectangle; protected void DrawGradient(ColorBlend blend, int x, int y, int width, int height) { DrawGradientRectangle = new(x, y, width, height); DrawGradient(blend, DrawGradientRectangle); } protected void DrawGradient(ColorBlend blend, int x, int y, int width, int height, float angle) { DrawGradientRectangle = new(x, y, width, height); DrawGradient(blend, DrawGradientRectangle, angle); } protected void DrawGradient(ColorBlend blend, Rectangle r) { DrawGradientBrush = new(r, Color.Empty, Color.Empty, 90f) { InterpolationColors = blend }; G.FillRectangle(DrawGradientBrush, r); } protected void DrawGradient(ColorBlend blend, Rectangle r, float angle) { DrawGradientBrush = new(r, Color.Empty, Color.Empty, angle) { InterpolationColors = blend }; G.FillRectangle(DrawGradientBrush, r); } protected void DrawGradient(Color c1, Color c2, int x, int y, int width, int height) { DrawGradientRectangle = new(x, y, width, height); DrawGradient(c1, c2, DrawGradientRectangle); } protected void DrawGradient(Color c1, Color c2, int x, int y, int width, int height, float angle) { DrawGradientRectangle = new(x, y, width, height); DrawGradient(c1, c2, DrawGradientRectangle, angle); } protected void DrawGradient(Color c1, Color c2, Rectangle r) { DrawGradientBrush = new(r, c1, c2, 90f); G.FillRectangle(DrawGradientBrush, r); } protected void DrawGradient(Color c1, Color c2, Rectangle r, float angle) { DrawGradientBrush = new(r, c1, c2, angle); G.FillRectangle(DrawGradientBrush, r); } #endregion #region " DrawRadial " private readonly GraphicsPath DrawRadialPath; private PathGradientBrush DrawRadialBrush1; private LinearGradientBrush DrawRadialBrush2; private Rectangle DrawRadialRectangle; public void DrawRadial(ColorBlend blend, int x, int y, int width, int height) { DrawRadialRectangle = new(x, y, width, height); DrawRadial(blend, DrawRadialRectangle, width / 2, height / 2); } public void DrawRadial(ColorBlend blend, int x, int y, int width, int height, Point center) { DrawRadialRectangle = new(x, y, width, height); DrawRadial(blend, DrawRadialRectangle, center.X, center.Y); } public void DrawRadial(ColorBlend blend, int x, int y, int width, int height, int cx, int cy) { DrawRadialRectangle = new(x, y, width, height); DrawRadial(blend, DrawRadialRectangle, cx, cy); } public void DrawRadial(ColorBlend blend, Rectangle r) { DrawRadial(blend, r, r.Width / 2, r.Height / 2); } public void DrawRadial(ColorBlend blend, Rectangle r, Point center) { DrawRadial(blend, r, center.X, center.Y); } public void DrawRadial(ColorBlend blend, Rectangle r, int cx, int cy) { DrawRadialPath.Reset(); DrawRadialPath.AddEllipse(r.X, r.Y, r.Width - 1, r.Height - 1); DrawRadialBrush1 = new PathGradientBrush(DrawRadialPath) { CenterPoint = new(r.X + cx, r.Y + cy), InterpolationColors = blend }; if (G.SmoothingMode == SmoothingMode.AntiAlias) { G.FillEllipse(DrawRadialBrush1, r.X + 1, r.Y + 1, r.Width - 3, r.Height - 3); } else { G.FillEllipse(DrawRadialBrush1, r); } } protected void DrawRadial(Color c1, Color c2, int x, int y, int width, int height) { DrawRadialRectangle = new(x, y, width, height); DrawRadial(c1, c2, DrawRadialRectangle); } protected void DrawRadial(Color c1, Color c2, int x, int y, int width, int height, float angle) { DrawRadialRectangle = new(x, y, width, height); DrawRadial(c1, c2, DrawRadialRectangle, angle); } protected void DrawRadial(Color c1, Color c2, Rectangle r) { DrawRadialBrush2 = new(r, c1, c2, 90f); G.FillEllipse(DrawRadialBrush2, r); } protected void DrawRadial(Color c1, Color c2, Rectangle r, float angle) { DrawRadialBrush2 = new(r, c1, c2, angle); G.FillEllipse(DrawRadialBrush2, r); } #endregion #region " CreateRound " private GraphicsPath CreateRoundPath; private Rectangle CreateRoundRectangle; public GraphicsPath CreateRound(int x, int y, int width, int height, int slope) { CreateRoundRectangle = new(x, y, width, height); return CreateRound(CreateRoundRectangle, slope); } public GraphicsPath CreateRound(Rectangle r, int slope) { CreateRoundPath = new(FillMode.Winding); CreateRoundPath.AddArc(r.X, r.Y, slope, slope, 180f, 90f); CreateRoundPath.AddArc(r.Right - slope, r.Y, slope, slope, 270f, 90f); CreateRoundPath.AddArc(r.Right - slope, r.Bottom - slope, slope, slope, 0f, 90f); CreateRoundPath.AddArc(r.X, r.Bottom - slope, slope, slope, 90f, 90f); CreateRoundPath.CloseFigure(); return CreateRoundPath; } #endregion } public static class ThemeShareSpace { #region " Animation " private static int Frames; private static bool Invalidate; public static PrecisionTimerSpace ThemeTimer = new(); //1000 / 50 = 20 FPS private const int FPS = 50; private const int Rate = 10; public delegate void AnimationDelegate(bool invalidate); private static readonly List Callbacks = new(); private static void HandleCallbacks(IntPtr state, bool reserve) { Invalidate = Frames >= FPS; if (Invalidate) { Frames = 0; } lock (Callbacks) { for (int I = 0; I <= Callbacks.Count - 1; I++) { Callbacks[I].Invoke(Invalidate); } } Frames += Rate; } private static void InvalidateThemeTimer() { if (Callbacks.Count == 0) { ThemeTimer.Delete(); } else { ThemeTimer.Create(0, Rate, HandleCallbacks); } } public static void AddAnimationCallback(AnimationDelegate callback) { lock (Callbacks) { if (Callbacks.Contains(callback)) { return; } Callbacks.Add(callback); InvalidateThemeTimer(); } } public static void RemoveAnimationCallback(AnimationDelegate callback) { lock (Callbacks) { if (!Callbacks.Contains(callback)) { return; } Callbacks.Remove(callback); InvalidateThemeTimer(); } } #endregion } public enum MouseStateSpace : byte { None = 0, Over = 1, Down = 2, Block = 3 } public struct BloomSpace { public string _Name; public string Name => _Name; public Color Value { get; set; } public string ValueHex { get => string.Concat("#", Value.R.ToString("X2", null), Value.G.ToString("X2", null), Value.B.ToString("X2", null)); set { try { Value = ColorTranslator.FromHtml(value); } catch { return; } } } public BloomSpace(string name, Color value) { _Name = name; Value = value; } } public class PrecisionTimerSpace : IDisposable { public bool Enabled { get; private set; } private IntPtr Handle; private TimerDelegate TimerCallback; [DllImport("kernel32.dll", EntryPoint = "CreateTimerQueueTimer")] private static extern bool CreateTimerQueueTimer(ref IntPtr handle, IntPtr queue, TimerDelegate callback, IntPtr state, uint dueTime, uint period, uint flags); [DllImport("kernel32.dll", EntryPoint = "DeleteTimerQueueTimer")] private static extern bool DeleteTimerQueueTimer(IntPtr queue, IntPtr handle, IntPtr callback); public delegate void TimerDelegate(IntPtr r1, bool r2); public void Create(uint dueTime, uint period, TimerDelegate callback) { if (Enabled) { return; } TimerCallback = callback; bool Success = CreateTimerQueueTimer(ref Handle, IntPtr.Zero, TimerCallback, IntPtr.Zero, dueTime, period, 0); if (!Success) { ThrowNewException("CreateTimerQueueTimer"); } Enabled = Success; } public void Delete() { if (!Enabled) { return; } bool Success = DeleteTimerQueueTimer(IntPtr.Zero, Handle, IntPtr.Zero); if (!Success && !(Marshal.GetLastWin32Error() == 997)) { ThrowNewException("DeleteTimerQueueTimer"); } Enabled = !Success; } private static void ThrowNewException(string name) { throw new Exception(string.Format("{0} failed. Win32Error: {1}", name, Marshal.GetLastWin32Error())); } void IDisposable.Dispose() { GC.SuppressFinalize(this); Delete(); } } #endregion }