#region Imports using DPumpHydr.WinFrmUI.RLT.Controls; using DPumpHydr.WinFrmUI.RLT.Enum.Metro; using DPumpHydr.WinFrmUI.RLT.Extension.Metro; using DPumpHydr.WinFrmUI.RLT.Interface.Metro; using DPumpHydr.WinFrmUI.RLT.Manager; using DPumpHydr.WinFrmUI.RLT.Native; using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Runtime.InteropServices; using System.Windows.Forms; using static DPumpHydr.WinFrmUI.RLT.Native.User32; #endregion namespace DPumpHydr.WinFrmUI.RLT.Forms { #region MetroForm [ToolboxItem(false)] [ToolboxBitmap(typeof(MetroForm), "Bitmaps.Form.bmp")] [DesignerCategory("Form")] [DefaultEvent("Load")] [DesignTimeVisible(false)] [ComVisible(true)] [InitializationEvent("Load")] public class MetroForm : Form, IMetroForm { #region Constructor protected MetroForm() { SetStyle ( ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ContainerControl | ControlStyles.SupportsTransparentBackColor, true ); UpdateStyles(); _mth = new Methods(); _utl = new Utilites(); _user32 = new User32(); Padding = new Padding(12, 70, 12, 12); FormBorderStyle = FormBorderStyle.None; _backgroundImageTransparency = 0.90f; base.Font = MetroFonts.SemiLight(13); DropShadowEffect = true; _showLeftRect = true; _showHeader = false; AllowResize = true; ApplyTheme(); } #endregion Constructor #region Draw Control protected override void OnPaint(PaintEventArgs e) { e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; e.Graphics.InterpolationMode = InterpolationMode.High; e.Graphics.CompositingQuality = CompositingQuality.HighQuality; using (SolidBrush b = new(BackgroundColor)) { e.Graphics.FillRectangle(b, new Rectangle(0, 0, Width, Height)); if (BackgroundImage != null) { _mth.DrawImageWithTransparency(e.Graphics, BackgroundImageTransparency, BackgroundImage, ClientRectangle); } } if (ShowBorder) { using Pen p = new(BorderColor, BorderThickness); e.Graphics.DrawRectangle(p, new Rectangle(0, 0, Width - 1, Height - 1)); } if (ShowLeftRect) { using LinearGradientBrush b = new(new Rectangle(0, 25, SmallRectThickness, 35), SmallLineColor1, SmallLineColor2, 90); using SolidBrush textBrush = new(TextColor); e.Graphics.FillRectangle(b, new Rectangle(0, 40, SmallRectThickness, 35)); e.Graphics.DrawString(Text, Font, textBrush, new Point(SmallRectThickness + 10, 46)); } else { if (ShowHeader) { using SolidBrush b = new(HeaderColor); e.Graphics.FillRectangle(b, new Rectangle(1, 1, Width - 1, HeaderHeight)); } SolidBrush textBrush = new(TextColor); if (ShowTitle) { switch (TextAlign) { case TextAlign.Left: using (StringFormat stringFormat = new() { LineAlignment = StringAlignment.Center }) { e.Graphics.DrawString(Text, Font, textBrush, new Rectangle(20, 0, Width, HeaderHeight), stringFormat); } break; case TextAlign.Center: using (StringFormat stringFormat = new() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }) { e.Graphics.DrawString(Text, Font, textBrush, new Rectangle(20, 0, Width - 21, HeaderHeight), stringFormat); } break; case TextAlign.Right: using (StringFormat stringFormat = new() { Alignment = StringAlignment.Far, LineAlignment = StringAlignment.Center }) { e.Graphics.DrawString(Text, Font, textBrush, new Rectangle(20, 0, Width - 26, HeaderHeight), stringFormat); } break; default: throw new ArgumentOutOfRangeException(); } } textBrush.Dispose(); } } #endregion Draw Control #region Properties [Category("Metro"), Description("Gets or sets the form backcolor.")] public Color BackgroundColor { get => _backgroundColor; set { _backgroundColor = value; Refresh(); } } [Category("Metro"), Description("Gets or sets the form forecolor.")] public override Color ForeColor { get; set; } [Category("Metro"), Description("Gets or sets the form bordercolor.")] public Color BorderColor { get => _borderColor; set { _borderColor = value; Refresh(); } } [Category("Metro"), Description("Gets or sets the form textcolor.")] public Color TextColor { get => _textColor; set { _textColor = value; Refresh(); } } [Category("Metro"), Description("Gets or sets the form small line color 1.")] public Color SmallLineColor1 { get => _smallLineColor1; set { _smallLineColor1 = value; Refresh(); } } [Category("Metro"), Description("Gets or sets the form small line color 2.")] public Color SmallLineColor2 { get => _smallLineColor2; set { _smallLineColor2 = value; Refresh(); } } [Category("Metro"), Description("Gets or sets the header color.")] public Color HeaderColor { get => _headerColor; set { _headerColor = value; Refresh(); } } [Category("Metro")] [Description("Gets or sets the width of the small rectangle on top left of the window.")] public int SmallRectThickness { get => _smallRectThickness; set { _smallRectThickness = value; Refresh(); } } [Category("Metro"), Description("Gets or sets whether the border be shown."), DefaultValue(true)] public bool ShowBorder { get => _showBorder; set { _showBorder = value; Refresh(); } } [Category("Metro")] [Description("Gets or sets the border thickness.")] public float BorderThickness { get => _borderThickness; set { _borderThickness = value; Refresh(); } } [DefaultValue(FormBorderStyle.None)] [Browsable(false)] private new FormBorderStyle FormBorderStyle { set { if (!System.Enum.IsDefined(typeof(FormBorderStyle), value)) { throw new InvalidEnumArgumentException(nameof(value), (int)value, typeof(FormBorderStyle)); } base.FormBorderStyle = FormBorderStyle.None; } } [Category("WindowStyle")] [Browsable(false)] [DefaultValue(false)] [Description("FormMaximizeBox")] public new bool MaximizeBox => false; [Category("WindowStyle")] [Browsable(false)] [DefaultValue(false)] [Description("FormMinimizeBox")] public new bool MinimizeBox { get => false; set => value = false; } [Category("Metro"), Description("Gets or sets whether the title be shown.")] public bool ShowTitle { get => _showTitle; set { _showTitle = value; Refresh(); } } [Category("Metro"), Description("Gets or sets the title alignment.")] public TextAlign TextAlign { get => _textAlign; set { _textAlign = value; Refresh(); } } [Category("Metro"), Description("Gets or sets whether show the header.")] public bool ShowHeader { get => _showHeader; set { _showHeader = value; if (value) { ShowLeftRect = false; Padding = new Padding(2, HeaderHeight + 30, 2, 2); Text = Text.ToUpper(); TextColor = Color.White; ShowTitle = true; foreach (Control c in Controls) { if (c.GetType() != typeof(MetroControlBox)) { continue; } c.BringToFront(); c.Location = new(Width - 12, 11); } } else { Padding = new Padding(12, 90, 12, 12); ShowTitle = false; } Invalidate(); } } [Category("Metro"), Description("Gets or sets whether the small rectangle on top left of the window be shown.")] public bool ShowLeftRect { get => _showLeftRect; set { _showLeftRect = value; if (value) { ShowHeader = false; } Invalidate(); } } [Category("Metro"), Description("Gets or sets whether the form can be move or not."), DefaultValue(true)] public bool Moveable { get => _movable; set { _movable = value; Refresh(); } } [Category("Metro"), Description("Gets or sets whether the form use animation.")] public bool UseSlideAnimation { get => _useSlideAnimation; set { _useSlideAnimation = value; Refresh(); } } [Browsable(false)] public new Padding Padding { get => base.Padding; set => base.Padding = value; } [Category("Metro"), Description("Gets or sets the backgroundimage transparency.")] public float BackgroundImageTransparency { get => _backgroundImageTransparency; set { if (value > 1) { throw new Exception("The Value must be between 0-1."); } _backgroundImageTransparency = value; Invalidate(); } } [Category("Metro"), Description("Gets or sets the header height.")] public int HeaderHeight { get => _headerHeight; set { _headerHeight = value; Refresh(); } } [Category("Metro"), Description("Gets or sets the background image displayed in the control.")] public override Image BackgroundImage { get => base.BackgroundImage; set => base.BackgroundImage = value; } [Category("Metro"), Description("Gets or sets whether the drop shadow effect apply on form.")] public bool DropShadowEffect { get => _dropShadowEffect; set { _dropShadowEffect = value; Refresh(); } } [Category("Metro"), Description("Gets or sets whether the user be able to resize the form or not.")] public bool AllowResize { get => _allowResize; set { _allowResize = value; Refresh(); } } #endregion Properties #region Methods private void ResizeForm(ref Message message) { if (!AllowResize) { return; } int x = (int)(message.LParam.ToInt64() & 65535); int y = (int)((message.LParam.ToInt64() & -65536) >> 0x10); Point point = PointToClient(new Point(x, y)); #region From Corners if (point.Y >= Height - 0x10) { if (point.X >= Width - 0x10) { message.Result = (IntPtr)(IsMirrored ? 0x10 : 0x11); return; } if (point.X <= 0x10) { message.Result = (IntPtr)(IsMirrored ? 0x11 : 0x10); return; } } else if (point.Y <= 0x10) { if (point.X <= 0x10) { message.Result = (IntPtr)(IsMirrored ? 0xe : 0xd); return; } if (point.X >= Width - 0x10) { message.Result = (IntPtr)(IsMirrored ? 0xd : 0xe); return; } } #endregion #region From Sides if (point.Y <= 0x10) { message.Result = (IntPtr)0xc; return; } if (point.Y >= Height - 0x10) { message.Result = (IntPtr)0xf; return; } if (point.X <= 0x10) { message.Result = (IntPtr)0xa; return; } if (point.X >= Width - 0x10) { message.Result = (IntPtr)0xb; } #endregion } #endregion Methods #region Interfaces [Category("Metro"), Description("Gets or sets the style associated with the control."), DefaultValue(Style.Light)] public Style Style { get => StyleManager?.Style ?? _style; set { _style = value; switch (value) { case Style.Light: ApplyTheme(); break; case Style.Dark: ApplyTheme(Style.Dark); break; case Style.Custom: ApplyTheme(Style.Custom); break; default: throw new ArgumentOutOfRangeException(nameof(value), value, null); } Invalidate(); } } [Category("Metro"), Description("Gets or sets the Style Manager associated with the control.")] public MetroStyleManager StyleManager { get => _styleManager; set { _styleManager = value; Invalidate(); } } [Category("Metro"), Description("Gets or sets the The Author name associated with the theme.")] public string ThemeAuthor { get; set; } [Category("Metro"), Description("Gets or sets the The Theme name associated with the theme.")] public string ThemeName { get; set; } private User32 User32 => _user32; private User32 _user32 { get; } #endregion Interfaces #region Global Vars private readonly Utilites _utl; private readonly Methods _mth; #endregion Global Vars #region Internal Vars private Style _style; private MetroStyleManager _styleManager; private bool _showLeftRect; private bool _showHeader; private float _backgroundImageTransparency; private Color _backgroundColor; private Color _borderColor; private Color _textColor; private Color _smallLineColor1; private Color _smallLineColor2; private Color _headerColor; private int _smallRectThickness = 10; private bool _showBorder; private float _borderThickness = 1; private bool _showTitle = true; private TextAlign _textAlign = TextAlign.Left; private bool _movable = true; private bool _useSlideAnimation; private int _headerHeight = 40; private bool _dropShadowEffect; private bool _allowResize; #endregion Internal Vars #region ApplyTheme internal void ApplyTheme(Style style = Style.Light) { switch (style) { case Style.Light: ForeColor = Color.Gray; BackgroundColor = Color.White; BorderColor = Color.FromArgb(65, 177, 225); TextColor = ShowHeader ? Color.White : Color.Gray; SmallLineColor1 = Color.FromArgb(65, 177, 225); SmallLineColor2 = Color.FromArgb(65, 177, 225); HeaderColor = Color.FromArgb(65, 177, 225); ThemeAuthor = "Taiizor"; ThemeName = "MetroLight"; UpdateProperties(); break; case Style.Dark: ForeColor = Color.White; BackgroundColor = Color.FromArgb(30, 30, 30); BorderColor = Color.FromArgb(65, 177, 225); SmallLineColor1 = Color.FromArgb(65, 177, 225); SmallLineColor2 = Color.FromArgb(65, 177, 225); HeaderColor = Color.FromArgb(65, 177, 225); TextColor = ShowHeader ? Color.Gray : Color.White; ThemeAuthor = "Taiizor"; ThemeName = "MetroDark"; UpdateProperties(); break; case Style.Custom: if (StyleManager != null) { foreach (System.Collections.Generic.KeyValuePair varkey in StyleManager.FormDictionary) { if (!string.Equals(varkey.Key, null, StringComparison.Ordinal) && varkey.Key != null) { if (varkey.Key == "ForeColor") { ForeColor = _utl.HexColor((string)varkey.Value); } else if (varkey.Key == "BackColor") { BackgroundColor = _utl.HexColor((string)varkey.Value); } else if (varkey.Key == "BorderColor") { BorderColor = _utl.HexColor((string)varkey.Value); } else if (varkey.Key == "TextColor") { TextColor = _utl.HexColor((string)varkey.Value); } else if (varkey.Key == "SmallLineColor1") { SmallLineColor1 = _utl.HexColor((string)varkey.Value); } else if (varkey.Key == "SmallLineColor2") { SmallLineColor2 = _utl.HexColor((string)varkey.Value); } else if (varkey.Key == "SmallRectThickness") { SmallRectThickness = int.Parse(varkey.Value.ToString()); } else if (varkey.Key == "HeaderColor") { HeaderColor = _utl.HexColor((string)varkey.Value); } } else { throw new Exception("FormDictionary is empty"); } } } UpdateProperties(); break; } } private void UpdateProperties() { Invalidate(); } #endregion Theme Changing #region Events protected override void WndProc(ref Message message) { base.WndProc(ref message); if ((message.Msg != _WM_NCHITTEST) | !Moveable) { return; } if ((int)message.Result == _HTCLIENT) { message.Result = new IntPtr(_HTCAPTION); } ResizeForm(ref message); } protected override void OnHandleCreated(EventArgs e) { AutoScaleMode = AutoScaleMode.None; base.OnHandleCreated(e); } protected override CreateParams CreateParams { get { if (!DropShadowEffect) { return base.CreateParams; } CreateParams cp = base.CreateParams; cp.ClassStyle |= _CS_DROPSHADOW; return cp; } } protected override void OnLoad(EventArgs e) { base.OnLoad(e); // https://www.codeproject.com/Articles/30255/C-Fade-Form-Effect-With-the-AnimateWindow-API-Func AnimateWindow(Handle, 800, AnimateWindowFlags.AW_ACTIVATE | (UseSlideAnimation ? AnimateWindowFlags.AW_HOR_POSITIVE | AnimateWindowFlags.AW_SLIDE : AnimateWindowFlags.AW_BLEND)); } protected override void OnClosing(CancelEventArgs e) { base.OnClosing(e); // https://www.codeproject.com/Articles/30255/C-Fade-Form-Effect-With-the-AnimateWindow-API-Func if (e.Cancel == false) { AnimateWindow(Handle, 800, User32.AW_HIDE | (UseSlideAnimation ? AnimateWindowFlags.AW_HOR_NEGATIVE | AnimateWindowFlags.AW_SLIDE : AnimateWindowFlags.AW_BLEND)); } } #endregion } #endregion }