context: /**
   * MetroFramework - Modern UI for WinForms
   * 
   * The MIT License (MIT)
   * Copyright (c) 2011 Sven Walter, http://github.com/viperneo
   * 
   * Permission is hereby granted, free of charge, to any person obtaining a copy of 
   * this software and associated documentation files (the "Software"), to deal in the 
   * Software without restriction, including without limitation the rights to use, copy, 
   * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
   * and to permit persons to whom the Software is furnished to do so, subject to the 
   * following conditions:
   * 
   * The above copyright notice and this permission notice shall be included in 
   * all copies or substantial portions of the Software.
   * 
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
   * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
   * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
   * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
   * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
   * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   */
  using System;
  using System.Diagnostics;
  using System.Drawing;
  using System.Drawing.Drawing2D;
  using System.Drawing.Imaging;
  using System.ComponentModel;
  using System.Collections.Generic;
  using System.Reflection;
  using System.Security;
  using System.Windows.Forms;
  
  using MetroFramework.Components;
  using MetroFramework.Drawing;
  using MetroFramework.Interfaces;
  using MetroFramework.Native;
  
  namespace MetroFramework.Forms
  {
      #region Enums
  
      public enum MetroFormTextAlign
      {
          Left,
          Center,
          Right
      }
  
      public enum MetroFormShadowType
      {
          None,
          Flat,
          DropShadow,
          SystemShadow,
          AeroShadow
      }
  
      public enum MetroFormBorderStyle
      {
          None,
          FixedSingle
      }
  
      #endregion
  
      public class MetroForm : Form, IMetroForm, IDisposable
      {
          #region Interface
  
          private MetroColorStyle metroStyle = MetroColorStyle.Blue;
          [Category(MetroDefaults.PropertyCategory.Appearance)]
          public MetroColorStyle Style
          {
              get
              {
                  if (StyleManager != null)
                      return StyleManager.Style;
  
                  return metroStyle;
              }
              set { metroStyle = value; }
          }
  
          private MetroThemeStyle metroTheme = MetroThemeStyle.Light;
  
          [Category(MetroDefaults.PropertyCategory.Appearance)]
          public MetroThemeStyle Theme
          {
              get
              {
                  if (StyleManager != null)
                      return StyleManager.Theme;
  
                  return metroTheme;
              }
              set { metroTheme = value; }
          }
  
          private MetroStyleManager metroStyleManager = null;
          [Browsable(false)]
          public MetroStyleManager StyleManager
          {
              get { return metroStyleManager; }
              set { metroStyleManager = value; }
          }
  
          #endregion
  
          #region Fields
  
          private MetroFormTextAlign textAlign = MetroFormTextAlign.Left;
          [Browsable(true)]
          [Category(MetroDefaults.PropertyCategory.Appearance)]
          public MetroFormTextAlign TextAlign
          {
              get { return textAlign; }
              set { textAlign = value; }
          }
  
          [Browsable(false)]
          public override Color BackColor
          {
              get { return MetroPaint.BackColor.Form(Theme); }
          }
  
          private MetroFormBorderStyle formBorderStyle = MetroFormBorderStyle.None;
          [DefaultValue(MetroFormBorderStyle.None)]
          [Browsable(true)]
          [Category(MetroDefaults.PropertyCategory.Appearance)]
          public MetroFormBorderStyle BorderStyle
          {
              get { return formBorderStyle; }
              set { formBorderStyle = value; }
          }
  
          private bool isMovable = true;
          [Category(MetroDefaults.PropertyCategory.Appearance)]
          public bool Movable
          {
              get { return isMovable; }
              set { isMovable = value; }
          }
  
          public new Padding Padding
          {
              get { return base.Padding; }
              set
              {
                  value.Top = Math.Max(value.Top, DisplayHeader ? 60 : 30);
                  base.Padding = value;
              }
          }
  
          protected override Padding DefaultPadding
          {
              get { return new Padding(20, DisplayHeader ? 60 : 20, 20, 20); }
          }
  
          private bool displayHeader = true;
          [Category(MetroDefaults.PropertyCategory.Appearance)]
          [DefaultValue(true)]
          public bool DisplayHeader
          {
              get { return displayHeader; }
              set 
              {
                  if (value != displayHeader)
                  {
                      Padding p = base.Padding;
                      p.Top += value ? 30 : -30;
                      base.Padding = p;
                  }
                  displayHeader = value;
              }
          }
  
          private bool isResizable = true;
          [Category(MetroDefaults.PropertyCategory.Appearance)]
          public bool Resizable
          {
              get { return isResizable; }
              set { isResizable = value; }
          }
  
  				//private MetroFormShadowType shadowType = MetroFormShadowType.Flat;
  				private MetroFormShadowType shadowType = MetroFormShadowType.AeroShadow;
          [Category(MetroDefaults.PropertyCategory.Appearance)]
          //[DefaultValue(MetroFormShadowType.Flat)]
  				[DefaultValue(MetroFormShadowType.AeroShadow)]
  				public MetroFormShadowType ShadowType
          {
              get { return IsMdiChild ? MetroFormShadowType.None : shadowType; }
              set { shadowType = value; }
          }
  
          [Browsable(false)]
          public new FormBorderStyle FormBorderStyle
          {
              get { return base.FormBorderStyle; }
              set { base.FormBorderStyle = value; }
          }
  
          public new Form MdiParent
          {
              get { return base.MdiParent; }
              set
              {
                  if (value != null)
                  {
                      RemoveShadow();
                      shadowType = MetroFormShadowType.None;
                  }
  
                  base.MdiParent = value;
              }
          }
  
          private const int borderWidth = 5;
  
          #endregion
  
          #region Constructor
  
          public MetroForm()
          {
              SetStyle(ControlStyles.AllPaintingInWmPaint |
                       ControlStyles.OptimizedDoubleBuffer |
                       ControlStyles.ResizeRedraw |
                       ControlStyles.UserPaint, true);
  
              FormBorderStyle = FormBorderStyle.None;
              Name = "MetroForm";
              StartPosition = FormStartPosition.CenterScreen;
          }
  
  				private bool _disposing;
  
          protected override void Dispose(bool disposing)
          {
  						if (disposing && !_disposing)
              {
  							_disposing = true;
                 RemoveShadow();
              }
  
              base.Dispose(disposing);
  
  						_disposing = false;
          }
  
          #endregion
  
          #region Paint Methods
  
          protected override void OnPaint(PaintEventArgs e)
          {
              Color backColor = MetroPaint.BackColor.Form(Theme);
              Color foreColor = MetroPaint.ForeColor.Title(Theme);
  
              e.Graphics.Clear(backColor);
  
              using (SolidBrush b = MetroPaint.GetStyleBrush(Style))
              {
                  Rectangle topRect = new Rectangle(0, 0, Width, borderWidth);
                  e.Graphics.FillRectangle(b, topRect);
              }
  
              if (BorderStyle != MetroFormBorderStyle.None)
              {
                  Color c = MetroPaint.BorderColor.Form(Theme);
  
                  using (Pen pen = new Pen(c))
                  {
                      e.Graphics.DrawLines(pen, new[]
                          {
                              new Point(0, borderWidth),
                              new Point(0, Height - 1),
                              new Point(Width - 1, Height - 1),
                              new Point(Width - 1, borderWidth)
                          });
                  }
              }
  
              if (displayHeader)
              {
                  Rectangle bounds = new Rectangle(20, 20, ClientRectangle.Width - 2 * 20, 40);
                  TextFormatFlags flags = TextFormatFlags.EndEllipsis | GetTextFormatFlags();
                  TextRenderer.DrawText(e.Graphics, Text, MetroFonts.Title, bounds, foreColor, flags);
              }
  
              if (Resizable && (SizeGripStyle == SizeGripStyle.Auto || SizeGripStyle == SizeGripStyle.Show))
              {
                  using (SolidBrush b = new SolidBrush(MetroPaint.ForeColor.Button.Disabled(Theme)))
                  {
                      Size resizeHandleSize = new Size(2, 2);
                      e.Graphics.FillRectangles(b, new Rectangle[] {
                          new Rectangle(new Point(ClientRectangle.Width-6,ClientRectangle.Height-6), resizeHandleSize),
                          new Rectangle(new Point(ClientRectangle.Width-10,ClientRectangle.Height-10), resizeHandleSize),
                          new Rectangle(new Point(ClientRectangle.Width-10,ClientRectangle.Height-6), resizeHandleSize),
                          new Rectangle(new Point(ClientRectangle.Width-6,ClientRectangle.Height-10), resizeHandleSize),
                          new Rectangle(new Point(ClientRectangle.Width-14,ClientRectangle.Height-6), resizeHandleSize),
                          new Rectangle(new Point(ClientRectangle.Width-6,ClientRectangle.Height-14), resizeHandleSize)
                      });
                  }
              }
          }
  
          private TextFormatFlags GetTextFormatFlags()
          {
              switch (TextAlign)
              {
                  case MetroFormTextAlign.Left: return TextFormatFlags.Left;
                  case MetroFormTextAlign.Center: return TextFormatFlags.HorizontalCenter;
                  case MetroFormTextAlign.Right: return TextFormatFlags.Right;
              }
  
              throw new InvalidOperationException();
          }
  
          #endregion
  
          #region Management Methods
  
          protected override void OnClosing(CancelEventArgs e)
          {
              if (!(this is MetroTaskWindow))
                  MetroTaskWindow.ForceClose();
  
              base.OnClosing(e);
          }
  
          protected override void OnClosed(EventArgs e)
          {
              RemoveShadow();
  
              base.OnClosed(e);
          }
  
          [SecuritySafeCritical]
          public bool FocusMe()
          {
              return WinApi.SetForegroundWindow(Handle);
          }
  
          protected override void OnLoad(EventArgs e)
          {
              base.OnLoad(e);
  
              if (DesignMode) return;
  
              switch (StartPosition)
              {
                  case FormStartPosition.CenterParent:
                      CenterToParent();
                      break;
                  case FormStartPosition.CenterScreen:
                      if (IsMdiChild)
                      {
                          CenterToParent(); 
                      }
                      else 
                      {
                          CenterToScreen();
                      }
                      break;
              }
  
              RemoveCloseButton();
          
              if (ControlBox)
              {
                  AddWindowButton(WindowButtons.Close);
  
                  if (MaximizeBox)
                      AddWindowButton(WindowButtons.Maximize);
  
                  if (MinimizeBox)
                      AddWindowButton(WindowButtons.Minimize);
  
                  UpdateWindowButtonPosition();
              }
  
              CreateShadow();
          }
  
          protected override void OnActivated(EventArgs e)
          {
              base.OnActivated(e);
  
              if (DesignMode) return;
          }
  
          protected override void OnEnabledChanged(EventArgs e)
          {
              base.OnEnabledChanged(e);
  
              Invalidate();
          }
  
          protected override void OnResizeEnd(EventArgs e)
          {
              base.OnResizeEnd(e);
              UpdateWindowButtonPosition();
          }
  
          protected override void WndProc(ref Message m)
          {
              if (DesignMode)
              {
                  base.WndProc(ref m);
                  return;
              }
  
              switch (m.Msg)
              {
                  case (int)WinApi.Messages.WM_SYSCOMMAND:
                      int sc = m.WParam.ToInt32() & 0xFFF0;
                      switch (sc)
                      {
                          case (int)WinApi.Messages.SC_MOVE: 
                              if (!Movable) return; 
                              break;
                          case (int)WinApi.Messages.SC_MAXIMIZE: 
                              break;
                          case (int)WinApi.Messages.SC_RESTORE:
                              break;
                      }
                      break;
  
                  case (int)WinApi.Messages.WM_NCLBUTTONDBLCLK:
                  case (int)WinApi.Messages.WM_LBUTTONDBLCLK:
                      if (!MaximizeBox) return;
                      break;
  
                  case (int)WinApi.Messages.WM_NCHITTEST:
                      WinApi.HitTest ht = HitTestNCA(m.HWnd, m.WParam, m.LParam);
                      if (ht != WinApi.HitTest.HTCLIENT)
                      {
                          m.Result = (IntPtr)ht;
                          return;
                      }
                      break;
  
                  case (int)WinApi.Messages.WM_DWMCOMPOSITIONCHANGED:
                      break;
              }
  
              base.WndProc(ref m);
  
              switch (m.Msg)
              {
                  case (int)WinApi.Messages.WM_GETMINMAXINFO:
                      OnGetMinMaxInfo(m.HWnd, m.LParam);
                      break;
              }
          }
  
          [SecuritySafeCritical]
          private unsafe void OnGetMinMaxInfo(IntPtr hwnd, IntPtr lParam)
          {
              WinApi.MINMAXINFO* pmmi = (WinApi.MINMAXINFO*)lParam;
  
              Screen s = Screen.FromHandle(hwnd);
              pmmi->ptMaxSize.x = s.WorkingArea.Width;
              pmmi->ptMaxSize.y = s.WorkingArea.Height;
              pmmi->ptMaxPosition.x = Math.Abs(s.WorkingArea.Left - s.Bounds.Left);
              pmmi->ptMaxPosition.y = Math.Abs(s.WorkingArea.Top - s.Bounds.Top);
  
              //if (MinimumSize.Width > 0) pmmi->ptMinTrackSize.x = MinimumSize.Width;
              //if (MinimumSize.Height > 0) pmmi->ptMinTrackSize.y = MinimumSize.Height;
              //if (MaximumSize.Width > 0) pmmi->ptMaxTrackSize.x = MaximumSize.Width;
              //if (MaximumSize.Height > 0) pmmi->ptMaxTrackSize.y = MaximumSize.Height;
          }
  
          private WinApi.HitTest HitTestNCA(IntPtr hwnd, IntPtr wparam, IntPtr lparam)
          {
              //Point vPoint = PointToClient(new Point((int)lparam & 0xFFFF, (int)lparam >> 16 & 0xFFFF));
              //Point vPoint = PointToClient(new Point((Int16)lparam, (Int16)((int)lparam >> 16)));
              Point vPoint = new Point((Int16)lparam, (Int16)((int)lparam >> 16));
              int vPadding = Math.Max(Padding.Right, Padding.Bottom);
  
              if (Resizable)
              {
                  if (RectangleToScreen(new Rectangle(ClientRectangle.Width - vPadding, ClientRectangle.Height - vPadding, vPadding, vPadding)).Contains(vPoint))
                      return WinApi.HitTest.HTBOTTOMRIGHT;
              }
  
            if (RectangleToScreen(new Rectangle(borderWidth, borderWidth, ClientRectangle.Width - 2 * borderWidth, 50)).Contains(vPoint))
                  return WinApi.HitTest.HTCAPTION;
  
              return WinApi.HitTest.HTCLIENT;
          }
  
          protected override void OnMouseDown(MouseEventArgs e)
          {
              base.OnMouseDown(e);
  
              if (e.Button == MouseButtons.Left && Movable)
              {
                  if (WindowState == FormWindowState.Maximized) return;
                  if (Width - borderWidth > e.Location.X && e.Location.X > borderWidth && e.Location.Y > borderWidth)
                  {
                      MoveControl();                    
                  }
              }
              
          }
  
          [SecuritySafeCritical]
          private void MoveControl()
          {
              WinApi.ReleaseCapture();
              WinApi.SendMessage(Handle, (int)WinApi.Messages.WM_NCLBUTTONDOWN, (int)WinApi.HitTest.HTCAPTION, 0);
          }
  
          #endregion
  
          #region Window Buttons
  
          private enum WindowButtons
          {
              Minimize,
              Maximize,
              Close
          }
  
          private Dictionary<WindowButtons, MetroFormButton> windowButtonList;
  
          private void AddWindowButton(WindowButtons button)
          {
              if (windowButtonList == null)
                  windowButtonList = new Dictionary<WindowButtons, MetroFormButton>();
  
              if (windowButtonList.ContainsKey(button))
                  return;
  
              MetroFormButton newButton = new MetroFormButton();
  
              if (button == WindowButtons.Close)
              {
                  newButton.Text = "r";
              }
              else if (button == WindowButtons.Minimize)
              {
                  newButton.Text = "0";
              }
              else if (button == WindowButtons.Maximize)
              {
                  if (WindowState == FormWindowState.Normal)
                      newButton.Text = "1";
                  else
                      newButton.Text = "2";
              }
  
              newButton.Style = Style;
              newButton.Theme = Theme;
              newButton.Tag = button;
              newButton.Size = new Size(25, 20);
              newButton.Anchor = AnchorStyles.Top | AnchorStyles.Right;
  						newButton.TabStop = false;
              newButton.Click += WindowButton_Click;
              Controls.Add(newButton);
  
              windowButtonList.Add(button, newButton);
          }
  
          private void WindowButton_Click(object sender, EventArgs e)
          {
              var btn = sender as MetroFormButton;
              if (btn != null)
              {
                  var btnFlag = (WindowButtons)btn.Tag;
                  if (btnFlag == WindowButtons.Close)
                  {
                      Close();
                  }
                  else if (btnFlag == WindowButtons.Minimize)
                  {
                      WindowState = FormWindowState.Minimized;
                  }
                  else if (btnFlag == WindowButtons.Maximize)
                  {
                      if (WindowState == FormWindowState.Normal)
                      {
                          WindowState = FormWindowState.Maximized;
                          btn.Text = "2";
                      }
                      else
                      {
                          WindowState = FormWindowState.Normal;
                          btn.Text = "1";
                      }
                  }
              }
          }
  
          private void UpdateWindowButtonPosition()
          {
              if (!ControlBox) return;
  
              Dictionary<int, WindowButtons> priorityOrder = new Dictionary<int, WindowButtons>(3) { {0, WindowButtons.Close}, {1, WindowButtons.Maximize}, {2, WindowButtons.Minimize} };
  
              Point firstButtonLocation = new Point(ClientRectangle.Width - borderWidth - 25, borderWidth);
              int lastDrawedButtonPosition = firstButtonLocation.X - 25;
  
              MetroFormButton firstButton = null;
  
              if (windowButtonList.Count == 1)
              {
                  foreach (KeyValuePair<WindowButtons, MetroFormButton> button in windowButtonList)
                  {
                      button.Value.Location = firstButtonLocation;
                  }
              }
              else
              {
                  foreach (KeyValuePair<int, WindowButtons> button in priorityOrder)
                  {
                      bool buttonExists = windowButtonList.ContainsKey(button.Value);
  
                      if (firstButton == null && buttonExists)
                      {
                          firstButton = windowButtonList[button.Value];
                          firstButton.Location = firstButtonLocation;
                          continue;
                      }
  
                      if (firstButton == null || !buttonExists) continue;
  
                      windowButtonList[button.Value].Location = new Point(lastDrawedButtonPosition, borderWidth);
                      lastDrawedButtonPosition = lastDrawedButtonPosition - 25;
                  }
              }
  
              Refresh();
          }
  
          private class MetroFormButton : Button, IMetroControl
          {
              #region Interface
  
              [Category(MetroDefaults.PropertyCategory.Appearance)]
              public event EventHandler<MetroPaintEventArgs> CustomPaintBackground;
              protected virtual void OnCustomPaintBackground(MetroPaintEventArgs e)
              {
                  if (GetStyle(ControlStyles.UserPaint) && CustomPaintBackground != null)
                  {
                      CustomPaintBackground(this, e);
                  }
              }
  
              [Category(MetroDefaults.PropertyCategory.Appearance)]
              public event EventHandler<MetroPaintEventArgs> CustomPaint;
              protected virtual void OnCustomPaint(MetroPaintEventArgs e)
              {
                  if (GetStyle(ControlStyles.UserPaint) && CustomPaint != null)
                  {
                      CustomPaint(this, e);
                  }
              }
  
              [Category(MetroDefaults.PropertyCategory.Appearance)]
              public event EventHandler<MetroPaintEventArgs> CustomPaintForeground;
              protected virtual void OnCustomPaintForeground(MetroPaintEventArgs e)
              {
                  if (GetStyle(ControlStyles.UserPaint) && CustomPaintForeground != null)
                  {
                      CustomPaintForeground(this, e);
                  }
              }
  
              private MetroColorStyle metroStyle = MetroColorStyle.Default;
              [Category(MetroDefaults.PropertyCategory.Appearance)]
              [DefaultValue(MetroColorStyle.Default)]
              public MetroColorStyle Style
              {
                  get
                  {
                      if (DesignMode || metroStyle != MetroColorStyle.Default)
                      {
                          return metroStyle;
                      }
  
                      if (StyleManager != null && metroStyle == MetroColorStyle.Default)
                      {
                          return StyleManager.Style;
                      }
                      if (StyleManager == null && metroStyle == MetroColorStyle.Default)
                      {
                          return MetroDefaults.Style;
                      }
  
                      return metroStyle;
                  }
                  set { metroStyle = value; }
              }
  
              private MetroThemeStyle metroTheme = MetroThemeStyle.Default;
              [Category(MetroDefaults.PropertyCategory.Appearance)]
              [DefaultValue(MetroThemeStyle.Default)]
              public MetroThemeStyle Theme
              {
                  get
                  {
                      if (DesignMode || metroTheme != MetroThemeStyle.Default)
                      {
                          return metroTheme;
                      }
  
                      if (StyleManager != null && metroTheme == MetroThemeStyle.Default)
                      {
                          return StyleManager.Theme;
                      }
                      if (StyleManager == null && metroTheme == MetroThemeStyle.Default)
                      {
                          return MetroDefaults.Theme;
                      }
  
                      return metroTheme;
                  }
                  set { metroTheme = value; }
              }
  
              private MetroStyleManager metroStyleManager = null;
              [Browsable(false)]
              [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
              public MetroStyleManager StyleManager
              {
                  get { return metroStyleManager; }
                  set { metroStyleManager = value; }
              }
  
              private bool useCustomBackColor = false;
              [DefaultValue(false)]
              [Category(MetroDefaults.PropertyCategory.Appearance)]
              public bool UseCustomBackColor
              {
                  get { return useCustomBackColor; }
                  set { useCustomBackColor = value; }
              }
  
              private bool useCustomForeColor = false;
              [DefaultValue(false)]
              [Category(MetroDefaults.PropertyCategory.Appearance)]
              public bool UseCustomForeColor
              {
                  get { return useCustomForeColor; }
                  set { useCustomForeColor = value; }
              }
  
              private bool useStyleColors = false;
              [DefaultValue(false)]
              [Category(MetroDefaults.PropertyCategory.Appearance)]
              public bool UseStyleColors
              {
                  get { return useStyleColors; }
  
gt:                 set { useStyleColors = value; }