check point

This commit is contained in:
meelstorm
2025-07-14 12:03:59 +02:00
commit d3cb790bd9
431 changed files with 44078 additions and 0 deletions

View File

@@ -0,0 +1,250 @@
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;
using MaterialSkin.Animations;
namespace MaterialSkin.Controls
{
public class MaterialCheckBox : CheckBox, IMaterialControl
{
[Browsable(false)]
public int Depth { get; set; }
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
[Browsable(false)]
public MouseState MouseState { get; set; }
[Browsable(false)]
public Point MouseLocation { get; set; }
private bool _ripple;
[Category("Behavior")]
public bool Ripple
{
get { return _ripple; }
set
{
_ripple = value;
AutoSize = AutoSize; //Make AutoSize directly set the bounds.
if (value)
{
Margin = new Padding(0);
}
Invalidate();
}
}
private readonly AnimationManager _animationManager;
private readonly AnimationManager _rippleAnimationManager;
private const int CHECKBOX_SIZE = 18;
private const int CHECKBOX_SIZE_HALF = CHECKBOX_SIZE / 2;
private const int CHECKBOX_INNER_BOX_SIZE = CHECKBOX_SIZE - 4;
private int _boxOffset;
private Rectangle _boxRectangle;
public MaterialCheckBox()
{
_animationManager = new AnimationManager
{
AnimationType = AnimationType.EaseInOut,
Increment = 0.05
};
_rippleAnimationManager = new AnimationManager(false)
{
AnimationType = AnimationType.Linear,
Increment = 0.10,
SecondaryIncrement = 0.08
};
_animationManager.OnAnimationProgress += sender => Invalidate();
_rippleAnimationManager.OnAnimationProgress += sender => Invalidate();
CheckedChanged += (sender, args) =>
{
_animationManager.StartNewAnimation(Checked ? AnimationDirection.In : AnimationDirection.Out);
};
Ripple = true;
MouseLocation = new Point(-1, -1);
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
_boxOffset = Height / 2 - 9;
_boxRectangle = new Rectangle(_boxOffset, _boxOffset, CHECKBOX_SIZE - 1, CHECKBOX_SIZE - 1);
}
public override Size GetPreferredSize(Size proposedSize)
{
var w = _boxOffset + CHECKBOX_SIZE + 2 + (int)CreateGraphics().MeasureString(Text, SkinManager.ROBOTO_MEDIUM_10).Width;
return Ripple ? new Size(w, 30) : new Size(w, 20);
}
private static readonly Point[] CheckmarkLine = { new Point(3, 8), new Point(7, 12), new Point(14, 5) };
private const int TEXT_OFFSET = 22;
protected override void OnPaint(PaintEventArgs pevent)
{
var g = pevent.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.TextRenderingHint = TextRenderingHint.AntiAlias;
// clear the control
g.Clear(Parent.BackColor);
var CHECKBOX_CENTER = _boxOffset + CHECKBOX_SIZE_HALF - 1;
var animationProgress = _animationManager.GetProgress();
var colorAlpha = Enabled ? (int)(animationProgress * 255.0) : SkinManager.GetCheckBoxOffDisabledColor().A;
var backgroundAlpha = Enabled ? (int)(SkinManager.GetCheckboxOffColor().A * (1.0 - animationProgress)) : SkinManager.GetCheckBoxOffDisabledColor().A;
var brush = new SolidBrush(Color.FromArgb(colorAlpha, Enabled ? SkinManager.ColorScheme.AccentColor : SkinManager.GetCheckBoxOffDisabledColor()));
var brush3 = new SolidBrush(Enabled ? SkinManager.ColorScheme.AccentColor : SkinManager.GetCheckBoxOffDisabledColor());
var pen = new Pen(brush.Color);
// draw ripple animation
if (Ripple && _rippleAnimationManager.IsAnimating())
{
for (var i = 0; i < _rippleAnimationManager.GetAnimationCount(); i++)
{
var animationValue = _rippleAnimationManager.GetProgress(i);
var animationSource = new Point(CHECKBOX_CENTER, CHECKBOX_CENTER);
var rippleBrush = new SolidBrush(Color.FromArgb((int)((animationValue * 40)), ((bool)_rippleAnimationManager.GetData(i)[0]) ? Color.Black : brush.Color));
var rippleHeight = (Height % 2 == 0) ? Height - 3 : Height - 2;
var rippleSize = (_rippleAnimationManager.GetDirection(i) == AnimationDirection.InOutIn) ? (int)(rippleHeight * (0.8d + (0.2d * animationValue))) : rippleHeight;
using (var path = DrawHelper.CreateRoundRect(animationSource.X - rippleSize / 2, animationSource.Y - rippleSize / 2, rippleSize, rippleSize, rippleSize / 2))
{
g.FillPath(rippleBrush, path);
}
rippleBrush.Dispose();
}
}
brush3.Dispose();
var checkMarkLineFill = new Rectangle(_boxOffset, _boxOffset, (int)((int)(FontHeight * 1.1) * animationProgress), (int)(FontHeight * 1.1));
using (var checkmarkPath = DrawHelper.CreateRoundRect(_boxOffset, _boxOffset, (int)(FontHeight*1.1), (int)(FontHeight * 1.1), 1f))
{
var brush2 = new SolidBrush(DrawHelper.BlendColor(Parent.BackColor, Enabled ? SkinManager.GetCheckboxOffColor() : SkinManager.GetCheckBoxOffDisabledColor(), backgroundAlpha));
var pen2 = new Pen(brush2.Color);
g.FillPath(brush2, checkmarkPath);
g.DrawPath(pen2, checkmarkPath);
g.FillRectangle(new SolidBrush(Parent.BackColor), _boxOffset + 2, _boxOffset + 2, (int)(FontHeight * 1.1) -4, (int)(FontHeight * 1.1) -4);
g.DrawRectangle(new Pen(Parent.BackColor), _boxOffset + 2, _boxOffset + 2, (int)(FontHeight * 1.1) -4, (int)(FontHeight * 1.1) - 4);
brush2.Dispose();
pen2.Dispose();
if (Enabled)
{
g.FillPath(brush, checkmarkPath);
g.DrawPath(pen, checkmarkPath);
}
else if (Checked)
{
g.SmoothingMode = SmoothingMode.None;
g.FillRectangle(brush, _boxOffset + 2, _boxOffset + 2, CHECKBOX_INNER_BOX_SIZE, CHECKBOX_INNER_BOX_SIZE);
g.SmoothingMode = SmoothingMode.AntiAlias;
}
g.DrawImageUnscaledAndClipped(DrawCheckMarkBitmap(), checkMarkLineFill);
}
// draw checkbox text
SizeF stringSize = g.MeasureString(Text, Font);
g.DrawString(
Text,
Font,
Enabled ? SkinManager.GetPrimaryTextBrush() : SkinManager.GetDisabledOrHintBrush(),
_boxOffset + TEXT_OFFSET, Height / 2 - stringSize.Height / 2);
// dispose used paint objects
pen.Dispose();
brush.Dispose();
}
private Bitmap DrawCheckMarkBitmap()
{
var checkMark = new Bitmap(CHECKBOX_SIZE, CHECKBOX_SIZE);
var g = Graphics.FromImage(checkMark);
// clear everything, transparent
g.Clear(Color.Transparent);
// draw the checkmark lines
using (var pen = new Pen(Parent.BackColor, 2))
{
g.DrawLines(pen, CheckmarkLine);
}
return checkMark;
}
public override bool AutoSize
{
get { return base.AutoSize; }
set
{
base.AutoSize = value;
if (value)
{
Size = new Size(10, 10);
}
}
}
private bool IsMouseInCheckArea()
{
return _boxRectangle.Contains(MouseLocation);
}
protected override void OnCreateControl()
{
base.OnCreateControl();
Font = SkinManager.ROBOTO_MEDIUM_10;
if (DesignMode) return;
MouseState = MouseState.OUT;
MouseEnter += (sender, args) =>
{
MouseState = MouseState.HOVER;
};
MouseLeave += (sender, args) =>
{
MouseLocation = new Point(-1, -1);
MouseState = MouseState.OUT;
};
MouseDown += (sender, args) =>
{
MouseState = MouseState.DOWN;
if (Ripple && args.Button == MouseButtons.Left && IsMouseInCheckArea())
{
_rippleAnimationManager.SecondaryIncrement = 0;
_rippleAnimationManager.StartNewAnimation(AnimationDirection.InOutIn, new object[] { Checked });
}
};
MouseUp += (sender, args) =>
{
MouseState = MouseState.HOVER;
_rippleAnimationManager.SecondaryIncrement = 0.08;
};
MouseMove += (sender, args) =>
{
MouseLocation = args.Location;
Cursor = IsMouseInCheckArea() ? Cursors.Hand : Cursors.Default;
};
}
}
}

View File

@@ -0,0 +1,44 @@
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace MaterialSkin.Controls
{
public partial class MaterialComboBox : ComboBox
{
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
public MaterialComboBox()
{
DrawMode = DrawMode.OwnerDrawFixed;
DrawItem += AdvancedComboBox_DrawItem;
}
void AdvancedComboBox_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index < 0)
return;
ComboBox combo = sender as ComboBox;
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
e.Graphics.FillRectangle(new SolidBrush(SkinManager.ColorScheme.AccentColor),
e.Bounds);
else
e.Graphics.FillRectangle(new SolidBrush(combo.BackColor),
e.Bounds);
e.Graphics.DrawString(combo.Items[e.Index].ToString(), e.Font,
SkinManager.GetRaisedButtonTextBrush((e.State & DrawItemState.Selected) == DrawItemState.Selected),
new Point(e.Bounds.X, e.Bounds.Y));
e.DrawFocusRectangle();
}
}
}

View File

@@ -0,0 +1,195 @@
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;
using MaterialSkin.Animations;
namespace MaterialSkin.Controls
{
public class MaterialContextMenuStrip : ContextMenuStrip, IMaterialControl
{
//Properties for managing the material design properties
[Browsable(false)]
public int Depth { get; set; }
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
[Browsable(false)]
public MouseState MouseState { get; set; }
internal AnimationManager AnimationManager;
internal Point AnimationSource;
public delegate void ItemClickStart(object sender, ToolStripItemClickedEventArgs e);
public event ItemClickStart OnItemClickStart;
public MaterialContextMenuStrip()
{
Renderer = new MaterialToolStripRender();
AnimationManager = new AnimationManager(false)
{
Increment = 0.07,
AnimationType = AnimationType.Linear
};
AnimationManager.OnAnimationProgress += sender => Invalidate();
AnimationManager.OnAnimationFinished += sender => OnItemClicked(_delayesArgs);
BackColor = SkinManager.GetApplicationBackgroundColor();
}
protected override void OnMouseUp(MouseEventArgs mea)
{
base.OnMouseUp(mea);
AnimationSource = mea.Location;
}
private ToolStripItemClickedEventArgs _delayesArgs;
protected override void OnItemClicked(ToolStripItemClickedEventArgs e)
{
if (e.ClickedItem != null && !(e.ClickedItem is ToolStripSeparator))
{
if (e == _delayesArgs)
{
//The event has been fired manualy because the args are the ones we saved for delay
base.OnItemClicked(e);
}
else
{
//Interrupt the default on click, saving the args for the delay which is needed to display the animaton
_delayesArgs = e;
//Fire custom event to trigger actions directly but keep cms open
OnItemClickStart?.Invoke(this, e);
//Start animation
AnimationManager.StartNewAnimation(AnimationDirection.In);
}
}
}
}
public class MaterialToolStripMenuItem : ToolStripMenuItem
{
public MaterialToolStripMenuItem()
{
AutoSize = false;
Size = new Size(120, 30);
}
protected override ToolStripDropDown CreateDefaultDropDown()
{
var baseDropDown = base.CreateDefaultDropDown();
if (DesignMode) return baseDropDown;
var defaultDropDown = new MaterialContextMenuStrip();
defaultDropDown.Items.AddRange(baseDropDown.Items);
return defaultDropDown;
}
}
internal class MaterialToolStripRender : ToolStripProfessionalRenderer, IMaterialControl
{
//Properties for managing the material design properties
public int Depth { get; set; }
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
public MouseState MouseState { get; set; }
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
{
var g = e.Graphics;
g.TextRenderingHint = TextRenderingHint.AntiAlias;
var itemRect = GetItemRect(e.Item);
var textRect = new Rectangle(24, itemRect.Y, itemRect.Width - (24 + 16), itemRect.Height);
g.DrawString(
e.Text,
SkinManager.ROBOTO_MEDIUM_10,
e.Item.Enabled ? SkinManager.GetPrimaryTextBrush() : SkinManager.GetDisabledOrHintBrush(),
textRect,
new StringFormat { LineAlignment = StringAlignment.Center });
}
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
{
var g = e.Graphics;
g.Clear(SkinManager.GetApplicationBackgroundColor());
//Draw background
var itemRect = GetItemRect(e.Item);
g.FillRectangle(e.Item.Selected && e.Item.Enabled ? SkinManager.GetCmsSelectedItemBrush() : new SolidBrush(SkinManager.GetApplicationBackgroundColor()), itemRect);
//Ripple animation
var toolStrip = e.ToolStrip as MaterialContextMenuStrip;
if (toolStrip != null)
{
var animationManager = toolStrip.AnimationManager;
var animationSource = toolStrip.AnimationSource;
if (toolStrip.AnimationManager.IsAnimating() && e.Item.Bounds.Contains(animationSource))
{
for (int i = 0; i < animationManager.GetAnimationCount(); i++)
{
var animationValue = animationManager.GetProgress(i);
var rippleBrush = new SolidBrush(Color.FromArgb((int)(51 - (animationValue * 50)), Color.Black));
var rippleSize = (int)(animationValue * itemRect.Width * 2.5);
g.FillEllipse(rippleBrush, new Rectangle(animationSource.X - rippleSize / 2, itemRect.Y - itemRect.Height, rippleSize, itemRect.Height * 3));
}
}
}
}
protected override void OnRenderImageMargin(ToolStripRenderEventArgs e)
{
//base.OnRenderImageMargin(e);
}
protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e)
{
var g = e.Graphics;
g.FillRectangle(new SolidBrush(SkinManager.GetApplicationBackgroundColor()), e.Item.Bounds);
g.DrawLine(
new Pen(SkinManager.GetDividersColor()),
new Point(e.Item.Bounds.Left, e.Item.Bounds.Height / 2),
new Point(e.Item.Bounds.Right, e.Item.Bounds.Height / 2));
}
protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
{
var g = e.Graphics;
g.DrawRectangle(
new Pen(SkinManager.GetDividersColor()),
new Rectangle(e.AffectedBounds.X, e.AffectedBounds.Y, e.AffectedBounds.Width - 1, e.AffectedBounds.Height - 1));
}
protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e)
{
var g = e.Graphics;
const int ARROW_SIZE = 4;
var arrowMiddle = new Point(e.ArrowRectangle.X + e.ArrowRectangle.Width / 2, e.ArrowRectangle.Y + e.ArrowRectangle.Height / 2);
var arrowBrush = e.Item.Enabled ? SkinManager.GetPrimaryTextBrush() : SkinManager.GetDisabledOrHintBrush();
using (var arrowPath = new GraphicsPath())
{
arrowPath.AddLines(
new[] {
new Point(arrowMiddle.X - ARROW_SIZE, arrowMiddle.Y - ARROW_SIZE),
new Point(arrowMiddle.X, arrowMiddle.Y),
new Point(arrowMiddle.X - ARROW_SIZE, arrowMiddle.Y + ARROW_SIZE) });
arrowPath.CloseFigure();
g.FillPath(arrowBrush, arrowPath);
}
}
private Rectangle GetItemRect(ToolStripItem item)
{
return new Rectangle(0, item.ContentRectangle.Y, item.ContentRectangle.Width + 4, item.ContentRectangle.Height);
}
}
}

View File

@@ -0,0 +1,27 @@
using System.ComponentModel;
using System.Windows.Forms;
namespace MaterialSkin.Controls
{
public sealed class MaterialDivider : Control, IMaterialControl
{
[Browsable(false)]
public int Depth { get; set; }
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
[Browsable(false)]
public MouseState MouseState { get; set; }
public MaterialDivider()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
BackColor = SkinManager.ColorScheme.PrimaryColor;
base.OnPaintBackground(pevent);
}
}
}

View File

@@ -0,0 +1,200 @@
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;
using MaterialSkin.Animations;
namespace MaterialSkin.Controls
{
public class MaterialFlatButton : Button, IMaterialControl
{
[Browsable(false)]
public int Depth { get; set; }
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
[Browsable(false)]
public MouseState MouseState { get; set; }
public bool Primary { get; set; }
private readonly AnimationManager _animationManager;
private readonly AnimationManager _hoverAnimationManager;
private SizeF _textSize;
private Image _icon;
public Image Icon
{
get { return _icon; }
set
{
_icon = value;
if (AutoSize)
Size = GetPreferredSize();
Invalidate();
}
}
public MaterialFlatButton()
{
Primary = false;
_animationManager = new AnimationManager(false)
{
Increment = 0.03,
AnimationType = AnimationType.EaseOut
};
_hoverAnimationManager = new AnimationManager
{
Increment = 0.07,
AnimationType = AnimationType.Linear
};
_hoverAnimationManager.OnAnimationProgress += sender => Invalidate();
_animationManager.OnAnimationProgress += sender => Invalidate();
AutoSizeMode = AutoSizeMode.GrowAndShrink;
Margin = new Padding(4, 6, 4, 6);
Padding = new Padding(0);
}
public override string Text
{
get { return base.Text; }
set
{
base.Text = value;
_textSize = CreateGraphics().MeasureString(value.ToUpper(), SkinManager.ROBOTO_MEDIUM_10);
if (AutoSize)
Size = GetPreferredSize();
Invalidate();
}
}
protected override void OnPaint(PaintEventArgs pevent)
{
var g = pevent.Graphics;
g.TextRenderingHint = TextRenderingHint.AntiAlias;
g.Clear(Parent.BackColor);
//Hover
Color c = SkinManager.GetFlatButtonHoverBackgroundColor();
using (Brush b = new SolidBrush(Color.FromArgb((int)(_hoverAnimationManager.GetProgress() * c.A), c.RemoveAlpha())))
g.FillRectangle(b, ClientRectangle);
//Ripple
if (_animationManager.IsAnimating())
{
g.SmoothingMode = SmoothingMode.AntiAlias;
for (var i = 0; i < _animationManager.GetAnimationCount(); i++)
{
var animationValue = _animationManager.GetProgress(i);
var animationSource = _animationManager.GetSource(i);
using (Brush rippleBrush = new SolidBrush(Color.FromArgb((int)(101 - (animationValue * 100)), Color.Black)))
{
var rippleSize = (int)(animationValue * Width * 2);
g.FillEllipse(rippleBrush, new Rectangle(animationSource.X - rippleSize / 2, animationSource.Y - rippleSize / 2, rippleSize, rippleSize));
}
}
g.SmoothingMode = SmoothingMode.None;
}
//Icon
var iconRect = new Rectangle(8, 6, 24, 24);
if (string.IsNullOrEmpty(Text))
// Center Icon
iconRect.X += 2;
if (Icon != null)
g.DrawImage(Icon, iconRect);
//Text
var textRect = ClientRectangle;
if (Icon != null)
{
//
// Resize and move Text container
//
// First 8: left padding
// 24: icon width
// Second 4: space between Icon and Text
// Third 8: right padding
textRect.Width -= 8 + 24 + 4 + 8;
// First 8: left padding
// 24: icon width
// Second 4: space between Icon and Text
textRect.X += 8 + 24 + 4;
}
g.DrawString(
Text.ToUpper(),
SkinManager.ROBOTO_MEDIUM_10,
Enabled ? (Primary ? SkinManager.ColorScheme.PrimaryBrush : SkinManager.GetPrimaryTextBrush()) : SkinManager.GetFlatButtonDisabledTextBrush(),
textRect,
new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }
);
}
private Size GetPreferredSize()
{
return GetPreferredSize(new Size(0, 0));
}
public override Size GetPreferredSize(Size proposedSize)
{
// Provides extra space for proper padding for content
var extra = 16;
if (Icon != null)
// 24 is for icon size
// 4 is for the space between icon & text
extra += 24 + 4;
return new Size((int)Math.Ceiling(_textSize.Width) + extra, 36);
}
protected override void OnCreateControl()
{
base.OnCreateControl();
if (DesignMode) return;
MouseState = MouseState.OUT;
MouseEnter += (sender, args) =>
{
MouseState = MouseState.HOVER;
_hoverAnimationManager.StartNewAnimation(AnimationDirection.In);
Invalidate();
};
MouseLeave += (sender, args) =>
{
MouseState = MouseState.OUT;
_hoverAnimationManager.StartNewAnimation(AnimationDirection.Out);
Invalidate();
};
MouseDown += (sender, args) =>
{
if (args.Button == MouseButtons.Left)
{
MouseState = MouseState.DOWN;
_animationManager.StartNewAnimation(AnimationDirection.In, args.Location);
Invalidate();
}
};
MouseUp += (sender, args) =>
{
MouseState = MouseState.HOVER;
Invalidate();
};
}
}
}

View File

@@ -0,0 +1,619 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Text;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace MaterialSkin.Controls
{
public class MaterialForm : Form, IMaterialControl
{
[Browsable(false)]
public int Depth { get; set; }
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
[Browsable(false)]
public MouseState MouseState { get; set; }
public new FormBorderStyle FormBorderStyle { get { return base.FormBorderStyle; } set { base.FormBorderStyle = value; } }
public bool Sizable { get; set; }
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("user32.dll")]
public static extern bool ReleaseCapture();
[DllImport("user32.dll")]
public static extern int TrackPopupMenuEx(IntPtr hmenu, uint fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm);
[DllImport("user32.dll")]
public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
public static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern bool GetMonitorInfo(HandleRef hmonitor, [In, Out] MONITORINFOEX info);
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
public const int WM_MOUSEMOVE = 0x0200;
public const int WM_LBUTTONDOWN = 0x0201;
public const int WM_LBUTTONUP = 0x0202;
public const int WM_LBUTTONDBLCLK = 0x0203;
public const int WM_RBUTTONDOWN = 0x0204;
private const int HTBOTTOMLEFT = 16;
private const int HTBOTTOMRIGHT = 17;
private const int HTLEFT = 10;
private const int HTRIGHT = 11;
private const int HTBOTTOM = 15;
private const int HTTOP = 12;
private const int HTTOPLEFT = 13;
private const int HTTOPRIGHT = 14;
private const int BORDER_WIDTH = 7;
private ResizeDirection _resizeDir;
private ButtonState _buttonState = ButtonState.None;
private const int WMSZ_TOP = 3;
private const int WMSZ_TOPLEFT = 4;
private const int WMSZ_TOPRIGHT = 5;
private const int WMSZ_LEFT = 1;
private const int WMSZ_RIGHT = 2;
private const int WMSZ_BOTTOM = 6;
private const int WMSZ_BOTTOMLEFT = 7;
private const int WMSZ_BOTTOMRIGHT = 8;
private readonly Dictionary<int, int> _resizingLocationsToCmd = new Dictionary<int, int>
{
{HTTOP, WMSZ_TOP},
{HTTOPLEFT, WMSZ_TOPLEFT},
{HTTOPRIGHT, WMSZ_TOPRIGHT},
{HTLEFT, WMSZ_LEFT},
{HTRIGHT, WMSZ_RIGHT},
{HTBOTTOM, WMSZ_BOTTOM},
{HTBOTTOMLEFT, WMSZ_BOTTOMLEFT},
{HTBOTTOMRIGHT, WMSZ_BOTTOMRIGHT}
};
private const int STATUS_BAR_BUTTON_WIDTH = STATUS_BAR_HEIGHT;
private const int STATUS_BAR_HEIGHT = 24;
private const int ACTION_BAR_HEIGHT = 40;
private const uint TPM_LEFTALIGN = 0x0000;
private const uint TPM_RETURNCMD = 0x0100;
private const int WM_SYSCOMMAND = 0x0112;
private const int WS_MINIMIZEBOX = 0x20000;
private const int WS_SYSMENU = 0x00080000;
private const int MONITOR_DEFAULTTONEAREST = 2;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
public class MONITORINFOEX
{
public int cbSize = Marshal.SizeOf(typeof(MONITORINFOEX));
public RECT rcMonitor = new RECT();
public RECT rcWork = new RECT();
public int dwFlags = 0;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public char[] szDevice = new char[32];
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
public int Width()
{
return right - left;
}
public int Height()
{
return bottom - top;
}
}
private enum ResizeDirection
{
BottomLeft,
Left,
Right,
BottomRight,
Bottom,
None
}
private enum ButtonState
{
XOver,
MaxOver,
MinOver,
XDown,
MaxDown,
MinDown,
None
}
private readonly Cursor[] _resizeCursors = { Cursors.SizeNESW, Cursors.SizeWE, Cursors.SizeNWSE, Cursors.SizeWE, Cursors.SizeNS };
private Rectangle _minButtonBounds;
private Rectangle _maxButtonBounds;
private Rectangle _xButtonBounds;
private Rectangle _actionBarBounds;
private Rectangle _statusBarBounds;
private bool _maximized;
private Size _previousSize;
private Point _previousLocation;
private bool _headerMouseDown;
private MouseMessageFilter _mouseMessageFilter;
public MaterialForm()
{
FormBorderStyle = FormBorderStyle.None;
AutoScaleMode = AutoScaleMode.None;
DoubleBuffered = true;
SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
// This enables the form to trigger the MouseMove event even when mouse is over another control
//_mouseMessageFilter = new MouseMessageFilter();
//Application.AddMessageFilter(_mouseMessageFilter);
//MouseMessageFilter.MouseMove += OnGlobalMouseMove;
}
public void RemoveMessageFilter()
{
Application.RemoveMessageFilter(_mouseMessageFilter);
MouseMessageFilter.MouseMove -= OnGlobalMouseMove;
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (DesignMode || IsDisposed) return;
if (m.Msg == WM_LBUTTONDBLCLK)
{
MaximizeWindow(!_maximized);
}
else if (m.Msg == WM_MOUSEMOVE && _maximized &&
(_statusBarBounds.Contains(PointToClient(Cursor.Position)) || _actionBarBounds.Contains(PointToClient(Cursor.Position))) &&
!(_minButtonBounds.Contains(PointToClient(Cursor.Position)) || _maxButtonBounds.Contains(PointToClient(Cursor.Position)) || _xButtonBounds.Contains(PointToClient(Cursor.Position))))
{
if (_headerMouseDown)
{
_maximized = false;
_headerMouseDown = false;
var mousePoint = PointToClient(Cursor.Position);
if (mousePoint.X < Width / 2)
Location = mousePoint.X < _previousSize.Width / 2 ?
new Point(Cursor.Position.X - mousePoint.X, Cursor.Position.Y - mousePoint.Y) :
new Point(Cursor.Position.X - _previousSize.Width / 2, Cursor.Position.Y - mousePoint.Y);
else
Location = Width - mousePoint.X < _previousSize.Width / 2 ?
new Point(Cursor.Position.X - _previousSize.Width + Width - mousePoint.X, Cursor.Position.Y - mousePoint.Y) :
new Point(Cursor.Position.X - _previousSize.Width / 2, Cursor.Position.Y - mousePoint.Y);
Size = _previousSize;
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
else if (m.Msg == WM_LBUTTONDOWN &&
(_statusBarBounds.Contains(PointToClient(Cursor.Position)) || _actionBarBounds.Contains(PointToClient(Cursor.Position))) &&
!(_minButtonBounds.Contains(PointToClient(Cursor.Position)) || _maxButtonBounds.Contains(PointToClient(Cursor.Position)) || _xButtonBounds.Contains(PointToClient(Cursor.Position))))
{
if (!_maximized)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
else
{
_headerMouseDown = true;
}
}
else if (m.Msg == WM_RBUTTONDOWN)
{
Point cursorPos = PointToClient(Cursor.Position);
if (_statusBarBounds.Contains(cursorPos) && !_minButtonBounds.Contains(cursorPos) &&
!_maxButtonBounds.Contains(cursorPos) && !_xButtonBounds.Contains(cursorPos))
{
// Show default system menu when right clicking titlebar
var id = TrackPopupMenuEx(GetSystemMenu(Handle, false), TPM_LEFTALIGN | TPM_RETURNCMD, Cursor.Position.X, Cursor.Position.Y, Handle, IntPtr.Zero);
// Pass the command as a WM_SYSCOMMAND message
SendMessage(Handle, WM_SYSCOMMAND, id, 0);
}
}
else if (m.Msg == WM_NCLBUTTONDOWN)
{
// This re-enables resizing by letting the application know when the
// user is trying to resize a side. This is disabled by default when using WS_SYSMENU.
if (!Sizable) return;
byte bFlag = 0;
// Get which side to resize from
if (_resizingLocationsToCmd.ContainsKey((int)m.WParam))
bFlag = (byte)_resizingLocationsToCmd[(int)m.WParam];
if (bFlag != 0)
SendMessage(Handle, WM_SYSCOMMAND, 0xF000 | bFlag, (int)m.LParam);
}
else if (m.Msg == WM_LBUTTONUP)
{
_headerMouseDown = false;
}
}
public bool DropShadow { get; set; } = true;
protected override CreateParams CreateParams
{
get
{
const int CS_DROPSHADOW = 0x20000;
var par = base.CreateParams;
// WS_SYSMENU: Trigger the creation of the system menu
// WS_MINIMIZEBOX: Allow minimizing from taskbar
par.Style = par.Style | WS_MINIMIZEBOX | WS_SYSMENU; // Turn on the WS_MINIMIZEBOX style flag
if(DropShadow)
par.ClassStyle |= CS_DROPSHADOW;
return par;
}
}
protected override void OnMouseDown(MouseEventArgs e)
{
if (DesignMode) return;
UpdateButtons(e);
if (e.Button == MouseButtons.Left && !_maximized)
ResizeForm(_resizeDir);
base.OnMouseDown(e);
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
if (DesignMode) return;
_buttonState = ButtonState.None;
Invalidate();
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (DesignMode) return;
if (Sizable)
{
//True if the mouse is hovering over a child control
var isChildUnderMouse = GetChildAtPoint(e.Location) != null;
if (e.Location.X < BORDER_WIDTH && e.Location.Y > Height - BORDER_WIDTH && !isChildUnderMouse && !_maximized)
{
_resizeDir = ResizeDirection.BottomLeft;
Cursor = Cursors.SizeNESW;
}
else if (e.Location.X < BORDER_WIDTH && !isChildUnderMouse && !_maximized)
{
_resizeDir = ResizeDirection.Left;
Cursor = Cursors.SizeWE;
}
else if (e.Location.X > Width - BORDER_WIDTH && e.Location.Y > Height - BORDER_WIDTH && !isChildUnderMouse && !_maximized)
{
_resizeDir = ResizeDirection.BottomRight;
Cursor = Cursors.SizeNWSE;
}
else if (e.Location.X > Width - BORDER_WIDTH && !isChildUnderMouse && !_maximized)
{
_resizeDir = ResizeDirection.Right;
Cursor = Cursors.SizeWE;
}
else if (e.Location.Y > Height - BORDER_WIDTH && !isChildUnderMouse && !_maximized)
{
_resizeDir = ResizeDirection.Bottom;
Cursor = Cursors.SizeNS;
}
else
{
_resizeDir = ResizeDirection.None;
//Only reset the cursor when needed, this prevents it from flickering when a child control changes the cursor to its own needs
if (_resizeCursors.Contains(Cursor))
{
Cursor = Cursors.Default;
}
}
}
UpdateButtons(e);
}
protected void OnGlobalMouseMove(object sender, MouseEventArgs e)
{
if (IsDisposed) return;
// Convert to client position and pass to Form.MouseMove
var clientCursorPos = PointToClient(e.Location);
var newE = new MouseEventArgs(MouseButtons.None, 0, clientCursorPos.X, clientCursorPos.Y, 0);
OnMouseMove(newE);
}
private void UpdateButtons(MouseEventArgs e, bool up = false)
{
if (DesignMode) return;
var oldState = _buttonState;
bool showMin = MinimizeBox && ControlBox;
bool showMax = MaximizeBox && ControlBox;
if (e.Button == MouseButtons.Left && !up)
{
if (showMin && !showMax && _maxButtonBounds.Contains(e.Location))
_buttonState = ButtonState.MinDown;
else if (showMin && showMax && _minButtonBounds.Contains(e.Location))
_buttonState = ButtonState.MinDown;
else if (showMax && _maxButtonBounds.Contains(e.Location))
_buttonState = ButtonState.MaxDown;
else if (ControlBox && _xButtonBounds.Contains(e.Location))
_buttonState = ButtonState.XDown;
else
_buttonState = ButtonState.None;
}
else
{
if (showMin && !showMax && _maxButtonBounds.Contains(e.Location))
{
_buttonState = ButtonState.MinOver;
if (oldState == ButtonState.MinDown && up)
WindowState = FormWindowState.Minimized;
}
else if (showMin && showMax && _minButtonBounds.Contains(e.Location))
{
_buttonState = ButtonState.MinOver;
if (oldState == ButtonState.MinDown && up)
WindowState = FormWindowState.Minimized;
}
else if (MaximizeBox && ControlBox && _maxButtonBounds.Contains(e.Location))
{
_buttonState = ButtonState.MaxOver;
if (oldState == ButtonState.MaxDown && up)
MaximizeWindow(!_maximized);
}
else if (ControlBox && _xButtonBounds.Contains(e.Location))
{
_buttonState = ButtonState.XOver;
if (oldState == ButtonState.XDown && up)
Close();
}
else _buttonState = ButtonState.None;
}
if (oldState != _buttonState) Invalidate();
}
public void MaximizeWindow(bool maximize)
{
if (!MaximizeBox || !ControlBox) return;
_maximized = maximize;
if (maximize)
{
var monitorHandle = MonitorFromWindow(Handle, MONITOR_DEFAULTTONEAREST);
var monitorInfo = new MONITORINFOEX();
GetMonitorInfo(new HandleRef(null, monitorHandle), monitorInfo);
_previousSize = Size;
_previousLocation = Location;
//var area=Screen.FromHandle(this.Handle).WorkingArea;
Size = new Size(monitorInfo.rcWork.Width(), monitorInfo.rcWork.Height());
Location = new Point(monitorInfo.rcWork.left, monitorInfo.rcWork.top);
//Size = new Size(area.Width, area.Height);
//Location = new Point(area.Left, area.Top);
}
else
{
Size = _previousSize;
Location = _previousLocation;
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
if (DesignMode) return;
UpdateButtons(e, true);
base.OnMouseUp(e);
ReleaseCapture();
}
private void ResizeForm(ResizeDirection direction)
{
if (DesignMode) return;
var dir = -1;
switch (direction)
{
case ResizeDirection.BottomLeft:
dir = HTBOTTOMLEFT;
break;
case ResizeDirection.Left:
dir = HTLEFT;
break;
case ResizeDirection.Right:
dir = HTRIGHT;
break;
case ResizeDirection.BottomRight:
dir = HTBOTTOMRIGHT;
break;
case ResizeDirection.Bottom:
dir = HTBOTTOM;
break;
}
ReleaseCapture();
if (dir != -1)
{
SendMessage(Handle, WM_NCLBUTTONDOWN, dir, 0);
}
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
_minButtonBounds = new Rectangle((Width - SkinManager.FORM_PADDING / 2) - 3 * STATUS_BAR_BUTTON_WIDTH, 0, STATUS_BAR_BUTTON_WIDTH, STATUS_BAR_HEIGHT);
_maxButtonBounds = new Rectangle((Width - SkinManager.FORM_PADDING / 2) - 2 * STATUS_BAR_BUTTON_WIDTH, 0, STATUS_BAR_BUTTON_WIDTH, STATUS_BAR_HEIGHT);
_xButtonBounds = new Rectangle((Width - SkinManager.FORM_PADDING / 2) - STATUS_BAR_BUTTON_WIDTH, 0, STATUS_BAR_BUTTON_WIDTH, STATUS_BAR_HEIGHT);
_statusBarBounds = new Rectangle(0, 0, Width, STATUS_BAR_HEIGHT);
_actionBarBounds = new Rectangle(0, STATUS_BAR_HEIGHT, Width, ACTION_BAR_HEIGHT);
}
public bool ShowSubHeader { get; set; }
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
g.TextRenderingHint = TextRenderingHint.AntiAlias;
g.Clear(SkinManager.GetApplicationBackgroundColor());
g.FillRectangle(SkinManager.ColorScheme.DarkPrimaryBrush, _statusBarBounds);
if(ShowSubHeader) g.FillRectangle(SkinManager.ColorScheme.PrimaryBrush, _actionBarBounds);
//Draw border
using (var borderPen = new Pen(SkinManager.GetDividersColor(), 1))
{
g.DrawLine(borderPen, new Point(0, _statusBarBounds.Bottom), new Point(0, Height - 2));
g.DrawLine(borderPen, new Point(Width - 1, _statusBarBounds.Bottom), new Point(Width - 1, Height - 2));
g.DrawLine(borderPen, new Point(0, Height - 1), new Point(Width - 1, Height - 1));
}
// Determine whether or not we even should be drawing the buttons.
bool showMin = MinimizeBox && ControlBox;
bool showMax = MaximizeBox && ControlBox;
var hoverBrush = SkinManager.GetFlatButtonHoverBackgroundBrush();
var downBrush = SkinManager.GetFlatButtonPressedBackgroundBrush();
// When MaximizeButton == false, the minimize button will be painted in its place
if (_buttonState == ButtonState.MinOver && showMin)
g.FillRectangle(hoverBrush, showMax ? _minButtonBounds : _maxButtonBounds);
if (_buttonState == ButtonState.MinDown && showMin)
g.FillRectangle(downBrush, showMax ? _minButtonBounds : _maxButtonBounds);
if (_buttonState == ButtonState.MaxOver && showMax)
g.FillRectangle(hoverBrush, _maxButtonBounds);
if (_buttonState == ButtonState.MaxDown && showMax)
g.FillRectangle(downBrush, _maxButtonBounds);
if (_buttonState == ButtonState.XOver && ControlBox)
g.FillRectangle(hoverBrush, _xButtonBounds);
if (_buttonState == ButtonState.XDown && ControlBox)
g.FillRectangle(downBrush, _xButtonBounds);
using (var formButtonsPen = new Pen(SkinManager.ACTION_BAR_TEXT_SECONDARY, 2))
{
// Minimize button.
if (showMin)
{
int x = showMax ? _minButtonBounds.X : _maxButtonBounds.X;
int y = showMax ? _minButtonBounds.Y : _maxButtonBounds.Y;
g.DrawLine(
formButtonsPen,
x + (int)(_minButtonBounds.Width * 0.33),
y + (int)(_minButtonBounds.Height * 0.66),
x + (int)(_minButtonBounds.Width * 0.66),
y + (int)(_minButtonBounds.Height * 0.66)
);
}
// Maximize button
if (showMax)
{
g.DrawRectangle(
formButtonsPen,
_maxButtonBounds.X + (int)(_maxButtonBounds.Width * 0.33),
_maxButtonBounds.Y + (int)(_maxButtonBounds.Height * 0.36),
(int)(_maxButtonBounds.Width * 0.39),
(int)(_maxButtonBounds.Height * 0.31)
);
}
// Close button
if (ControlBox)
{
g.DrawLine(
formButtonsPen,
_xButtonBounds.X + (int)(_xButtonBounds.Width * 0.33),
_xButtonBounds.Y + (int)(_xButtonBounds.Height * 0.33),
_xButtonBounds.X + (int)(_xButtonBounds.Width * 0.66),
_xButtonBounds.Y + (int)(_xButtonBounds.Height * 0.66)
);
g.DrawLine(
formButtonsPen,
_xButtonBounds.X + (int)(_xButtonBounds.Width * 0.66),
_xButtonBounds.Y + (int)(_xButtonBounds.Height * 0.33),
_xButtonBounds.X + (int)(_xButtonBounds.Width * 0.33),
_xButtonBounds.Y + (int)(_xButtonBounds.Height * 0.66));
}
}
//Form title
g.DrawString(Text, SkinManager.ROBOTO_MEDIUM_12, SkinManager.ColorScheme.TextBrush, new Rectangle(SkinManager.FORM_PADDING, STATUS_BAR_HEIGHT, Width-20, ACTION_BAR_HEIGHT), new StringFormat { LineAlignment = StringAlignment.Center,Alignment = StringAlignment.Near });
//Primary title
g.DrawString(PrimaryText, new Font("Roboto",20,FontStyle.Bold),SkinManager.ColorScheme.TextBrush, new Rectangle(SkinManager.FORM_PADDING, STATUS_BAR_HEIGHT, Width, ACTION_BAR_HEIGHT), new StringFormat { LineAlignment = StringAlignment.Center, Alignment = StringAlignment.Center });
g.DrawString(HeaderText, new Font("Roboto", 12, FontStyle.Bold), SkinManager.ColorScheme.TextBrush, new Rectangle(SkinManager.FORM_PADDING, 0, Width, STATUS_BAR_HEIGHT), new StringFormat { LineAlignment = StringAlignment.Center, Alignment = StringAlignment.Near });
}
public string PrimaryText { get; set; }
public string HeaderText { get; set; }
public Font TitleFont { get; set; }
}
public class MouseMessageFilter : IMessageFilter
{
private const int WM_MOUSEMOVE = 0x0200;
public static event MouseEventHandler MouseMove;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_MOUSEMOVE)
{
if (MouseMove != null)
{
int x = Control.MousePosition.X, y = Control.MousePosition.Y;
MouseMove(null, new MouseEventArgs(MouseButtons.None, 0, x, y, 0));
}
}
return false;
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,171 @@
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Threading.Tasks;
using System.Windows.Forms;
using MaterialSkin.Animations;
namespace MaterialSkin.Controls
{
public class MaterialIcon:Control
{
private Image _image;
private Bitmap _bmp;
private AnimationManager _animationManager;
private Point _lastLocation;
private Bitmap _backBuffer = null;
private bool _primary;
public MaterialIcon()
{
Cursor = Cursors.Hand;
Clickable = true;
_animationManager = new AnimationManager(false)
{
Increment = 0.02,
AnimationType = AnimationType.EaseOut
};
_animationManager.OnAnimationProgress += sender => Invalidate();
_animationManager.OnAnimationFinished += AnimationManagerOnOnAnimationFinished;
}
private void AnimationManagerOnOnAnimationFinished(object sender)
{
}
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
public Image Image
{
get { return _image; }
set
{
_image = value;
RebuildIcon();
}
}
public bool Primary
{
get { return _primary; }
set
{
_primary = value;
if (_image == null) return;
RebuildIcon();
}
}
protected override void OnEnabledChanged(EventArgs e)
{
base.OnEnabledChanged(e);
RebuildIcon();
}
protected override void OnResize(EventArgs e)
{
_backBuffer=new Bitmap(Width,Height);
if (_image == null) return;
RebuildIcon();
base.OnResize(e);
}
private void RebuildIcon()
{
Task.Run(() =>
{
lock (_lockObject)
{
var tmp = new Bitmap(_image);
ReplaceColor(tmp, Color.Black,
Enabled
? (_primary
? SkinManager.GetApplicationBackgroundColor()
: SkinManager.ColorScheme.PrimaryColor)
: Color.FromArgb(0xAA, 0xAA, 0xAA));
_bmp = tmp;
Invalidate();
}
});
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
//base.OnPaintBackground(pevent);
}
protected override void OnMouseDown(MouseEventArgs mevent)
{
base.OnMouseDown(mevent);
if (!Enabled) return;
_lastLocation = mevent.Location;
_animationManager.StartNewAnimation(AnimationDirection.In, _lastLocation);
}
public bool Clickable { get; set; }
protected override void OnClick(EventArgs e)
{
if (!Clickable) return;
base.OnClick(e);
}
protected override void OnPaint(PaintEventArgs pe)
{
if (Image == null) return;
if(_bmp == null)return;
if(_backBuffer==null)return;
using (Graphics g=Graphics.FromImage(_backBuffer))
{
g.InterpolationMode = InterpolationMode.Bicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.Clear(_primary? SkinManager.ColorScheme.PrimaryColor : SkinManager.GetApplicationBackgroundColor());
if (_animationManager.IsAnimating())
{
for (int i = 0; i < _animationManager.GetAnimationCount(); i++)
{
var animationValue = _animationManager.GetProgress(i);
var animationSource = _animationManager.GetSource(i);
var rippleBrush = new SolidBrush(Color.FromArgb((int)(51 - (animationValue * 50)), _primary ? SkinManager.GetApplicationBackgroundColor() : SkinManager.ColorScheme.PrimaryColor));
var rippleSize = (int)(animationValue * Width * 2);
g.FillEllipse(rippleBrush, new Rectangle(animationSource.X - rippleSize / 2, animationSource.Y - rippleSize / 2, rippleSize, rippleSize));
}
}
g.DrawImage(_bmp,1,1,Width-2,Height-2);
}
pe.Graphics.DrawImage(_backBuffer, 0,0);
}
object _lockObject = new object();
private void ReplaceColor(Bitmap bmp, Color oldColor, Color newColor)
{
{
var lockedBitmap = bmp;
for (int y = 0; y < lockedBitmap.Height; y++)
{
for (int x = 0; x < lockedBitmap.Width; x++)
{
if (lockedBitmap.GetPixel(x, y).A > 0)
{
lockedBitmap.SetPixel(x, y, newColor);
}
}
}
}
}
}
}

View File

@@ -0,0 +1,44 @@
namespace MaterialSkin.Controls
{
partial class MaterialIndicator
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.SuspendLayout();
//
// MaterialIndicator
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Name = "MaterialIndicator";
this.ResumeLayout(false);
}
#endregion
}
}

View File

@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MaterialSkin.Controls
{
public partial class MaterialIndicator : UserControl
{
private bool _checked;
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
public Color CheckedColor { get; set; }
public Color UncheckedColor { get; set; }
public Color BorderColor { get; set; }
public MaterialIndicator()
{
InitializeComponent();
}
public bool Checked
{
get { return _checked; }
set
{
_checked = value;
Invalidate();
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.FillEllipse(new SolidBrush(Checked?CheckedColor:UncheckedColor),1,1,Width-2,Height-2);
e.Graphics.DrawEllipse(new Pen(BorderColor),1,1,Width-2,Height-2 );
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,115 @@
namespace MaterialSkin.Core.Controls
{
partial class MaterialInputBox
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.materialRaisedButton1 = new MaterialSkin.Controls.MaterialRaisedButton();
this.materialRaisedButton2 = new MaterialSkin.Controls.MaterialRaisedButton();
this.textBox1 = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// materialRaisedButton1
//
this.materialRaisedButton1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.materialRaisedButton1.Cursor = System.Windows.Forms.Cursors.Hand;
this.materialRaisedButton1.Depth = 0;
this.materialRaisedButton1.DrawBorder = false;
this.materialRaisedButton1.Icon = null;
this.materialRaisedButton1.Location = new System.Drawing.Point(440, 88);
this.materialRaisedButton1.MouseState = MaterialSkin.MouseState.HOVER;
this.materialRaisedButton1.Name = "materialRaisedButton1";
this.materialRaisedButton1.Primary = true;
this.materialRaisedButton1.Size = new System.Drawing.Size(128, 48);
this.materialRaisedButton1.TabIndex = 0;
this.materialRaisedButton1.Text = "OK";
this.materialRaisedButton1.UseVisualStyleBackColor = true;
this.materialRaisedButton1.Click += new System.EventHandler(this.materialRaisedButton1_Click);
//
// materialRaisedButton2
//
this.materialRaisedButton2.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.materialRaisedButton2.Cursor = System.Windows.Forms.Cursors.Hand;
this.materialRaisedButton2.Depth = 0;
this.materialRaisedButton2.DrawBorder = true;
this.materialRaisedButton2.Icon = null;
this.materialRaisedButton2.Location = new System.Drawing.Point(304, 88);
this.materialRaisedButton2.MouseState = MaterialSkin.MouseState.HOVER;
this.materialRaisedButton2.Name = "materialRaisedButton2";
this.materialRaisedButton2.Primary = false;
this.materialRaisedButton2.Size = new System.Drawing.Size(128, 48);
this.materialRaisedButton2.TabIndex = 1;
this.materialRaisedButton2.Text = "Cancel";
this.materialRaisedButton2.UseVisualStyleBackColor = true;
this.materialRaisedButton2.Click += new System.EventHandler(this.materialRaisedButton2_Click);
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(16, 56);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(552, 23);
this.textBox1.TabIndex = 0;
this.textBox1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.textBox1_KeyDown);
//
// label1
//
this.label1.AutoSize = true;
this.label1.BackColor = System.Drawing.Color.White;
this.label1.Location = new System.Drawing.Point(16, 32);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(38, 15);
this.label1.TabIndex = 3;
this.label1.Text = "label1";
//
// MaterialInputBox
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(579, 149);
this.Controls.Add(this.label1);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.materialRaisedButton2);
this.Controls.Add(this.materialRaisedButton1);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "MaterialInputBox";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private MaterialSkin.Controls.MaterialRaisedButton materialRaisedButton1;
private MaterialSkin.Controls.MaterialRaisedButton materialRaisedButton2;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Label label1;
}
}

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using MaterialSkin.Controls;
namespace MaterialSkin.Core.Controls
{
public partial class MaterialInputBox : MaterialForm
{
private MaterialInputBox()
{
InitializeComponent();
}
public static DialogResult Prompt(string title, string defaultValue, out string result, bool masked = false)
{
MaterialInputBox box = new MaterialInputBox {label1 = {Text = title}, textBox1 = {Text = defaultValue}};
if (masked) box.textBox1.PasswordChar = '*';
var res= box.ShowDialog();
result = box.textBox1.Text;
return res;
}
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Return)
{
DialogResult = DialogResult.OK;
}
}
private void materialRaisedButton2_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
private void materialRaisedButton1_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
}
}
}

View File

@@ -0,0 +1,60 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,24 @@
using System.ComponentModel;
using System.Windows.Forms;
namespace MaterialSkin.Controls
{
public class MaterialLabel : Label, IMaterialControl
{
[Browsable(false)]
public int Depth { get; set; }
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
[Browsable(false)]
public MouseState MouseState { get; set; }
protected override void OnCreateControl()
{
base.OnCreateControl();
ForeColor = SkinManager.GetPrimaryTextColor();
Font = SkinManager.ROBOTO_REGULAR_11;
BackColorChanged += (sender, args) => ForeColor = SkinManager.GetPrimaryTextColor();
}
}
}

View File

@@ -0,0 +1,163 @@
using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace MaterialSkin.Controls
{
public class MaterialListView : ListView, IMaterialControl
{
[Browsable(false)]
public int Depth { get; set; }
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
[Browsable(false)]
public MouseState MouseState { get; set; }
[Browsable(false)]
public Point MouseLocation { get; set; }
[Browsable(false)]
private ListViewItem HoveredItem { get; set; }
public MaterialListView()
{
GridLines = false;
FullRowSelect = true;
HeaderStyle = ColumnHeaderStyle.Nonclickable;
View = View.Details;
OwnerDraw = true;
ResizeRedraw = true;
BorderStyle = BorderStyle.None;
SetStyle(ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer, true);
//Fix for hovers, by default it doesn't redraw
//TODO: should only redraw when the hovered line changed, this to reduce unnecessary redraws
MouseLocation = new Point(-1, -1);
MouseState = MouseState.OUT;
MouseEnter += delegate
{
MouseState = MouseState.HOVER;
};
MouseLeave += delegate
{
MouseState = MouseState.OUT;
MouseLocation = new Point(-1, -1);
HoveredItem = null;
Invalidate();
};
MouseDown += delegate { MouseState = MouseState.DOWN; };
MouseUp += delegate { MouseState = MouseState.HOVER; };
MouseMove += delegate (object sender, MouseEventArgs args)
{
MouseLocation = args.Location;
var currentHoveredItem = this.GetItemAt(MouseLocation.X, MouseLocation.Y);
if (HoveredItem != currentHoveredItem)
{
HoveredItem = currentHoveredItem;
Invalidate();
}
};
}
protected override void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
{
e.Graphics.FillRectangle(new SolidBrush(SkinManager.GetApplicationBackgroundColor()), new Rectangle(e.Bounds.X, e.Bounds.Y, Width, e.Bounds.Height));
e.Graphics.DrawString(e.Header.Text,
SkinManager.ROBOTO_MEDIUM_10,
SkinManager.GetSecondaryTextBrush(),
new Rectangle(e.Bounds.X + ITEM_PADDING, e.Bounds.Y + ITEM_PADDING, e.Bounds.Width - ITEM_PADDING * 2, e.Bounds.Height - ITEM_PADDING * 2),
getStringFormat());
}
private const int ITEM_PADDING = 12;
protected override void OnDrawItem(DrawListViewItemEventArgs e)
{
//We draw the current line of items (= item with subitems) on a temp bitmap, then draw the bitmap at once. This is to reduce flickering.
var b = new Bitmap(e.Item.Bounds.Width, e.Item.Bounds.Height);
var g = Graphics.FromImage(b);
//always draw default background
g.FillRectangle(new SolidBrush(SkinManager.GetApplicationBackgroundColor()), new Rectangle(new Point(e.Bounds.X, 0), e.Bounds.Size));
if (e.State.HasFlag(ListViewItemStates.Selected))
{
//selected background
g.FillRectangle(SkinManager.GetFlatButtonPressedBackgroundBrush(), new Rectangle(new Point(e.Bounds.X, 0), e.Bounds.Size));
}
else if (e.Bounds.Contains(MouseLocation) && MouseState == MouseState.HOVER)
{
//hover background
g.FillRectangle(SkinManager.GetFlatButtonHoverBackgroundBrush(), new Rectangle(new Point(e.Bounds.X, 0), e.Bounds.Size));
}
//Draw separator
g.DrawLine(new Pen(SkinManager.GetDividersColor()), e.Bounds.Left, 0, e.Bounds.Right, 0);
foreach (ListViewItem.ListViewSubItem subItem in e.Item.SubItems)
{
//Draw text
g.DrawString(subItem.Text, SkinManager.ROBOTO_MEDIUM_10, SkinManager.GetPrimaryTextBrush(),
new Rectangle(subItem.Bounds.X + ITEM_PADDING, ITEM_PADDING, subItem.Bounds.Width - 2 * ITEM_PADDING, subItem.Bounds.Height - 2 * ITEM_PADDING),
getStringFormat());
}
e.Graphics.DrawImage((Image)b.Clone(), new Point(0, e.Item.Bounds.Location.Y));
g.Dispose();
b.Dispose();
}
private StringFormat getStringFormat()
{
return new StringFormat
{
FormatFlags = StringFormatFlags.LineLimit,
Trimming = StringTrimming.EllipsisCharacter,
Alignment = StringAlignment.Near,
LineAlignment = StringAlignment.Center
};
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class LogFont
{
public int lfHeight = 0;
public int lfWidth = 0;
public int lfEscapement = 0;
public int lfOrientation = 0;
public int lfWeight = 0;
public byte lfItalic = 0;
public byte lfUnderline = 0;
public byte lfStrikeOut = 0;
public byte lfCharSet = 0;
public byte lfOutPrecision = 0;
public byte lfClipPrecision = 0;
public byte lfQuality = 0;
public byte lfPitchAndFamily = 0;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string lfFaceName = string.Empty;
}
protected override void OnCreateControl()
{
base.OnCreateControl();
// This hack tries to apply the Roboto (24) font to all ListViewItems in this ListView
// It only succeeds if the font is installed on the system.
// Otherwise, a default sans serif font is used.
var roboto24 = new Font(SkinManager.ROBOTO_MEDIUM_12.FontFamily, 24);
var roboto24Logfont = new LogFont();
roboto24.ToLogFont(roboto24Logfont);
try
{
// Font.FromLogFont is the method used when drawing ListViewItems. I 'test' it in this safer context to avoid unhandled exceptions later.
Font = Font.FromLogFont(roboto24Logfont);
}
catch (ArgumentException)
{
Font = new Font(FontFamily.GenericSansSerif, 24);
}
}
}
}

View File

@@ -0,0 +1,47 @@
namespace MaterialSkin.Controls
{
partial class MaterialLoader
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
SuspendLayout();
//
// MaterialLoader
//
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
ClientSize = new System.Drawing.Size(422, 189);
ControlBox = false;
Name = "MaterialLoader";
StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
ResumeLayout(false);
}
#endregion
}
}

View File

@@ -0,0 +1,139 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MaterialSkin.Controls
{
public partial class MaterialLoader : MaterialForm
{
private static MaterialLoader _instance;
private static Thread _loaderThread;
private static ManualResetEvent _instanceReadyEvent = new ManualResetEvent(false);
private readonly Dictionary<string, (MaterialProgressBar ProgressBar, Label Label)> _loadingProcesses;
private MaterialLoader()
{
InitializeComponent();
RemoveMessageFilter();
_loadingProcesses = new Dictionary<string, (MaterialProgressBar, Label)>();
this.MaximizeBox = false;
this.MinimizeBox = false;
this.StartPosition = FormStartPosition.CenterScreen;
}
public static MaterialLoader Instance
{
get
{
if (_instance == null || _instance.IsDisposed)
{
_instanceReadyEvent.Reset();
_loaderThread = new Thread(() =>
{
_instance = new MaterialLoader();
_instance.Shown += (_, _) =>
{
_instanceReadyEvent.Set();
};
Application.Run(_instance);
});
_loaderThread.SetApartmentState(ApartmentState.STA);
_loaderThread.Start();
_instanceReadyEvent.WaitOne();
}
return _instance;
}
}
public void StartLoading(string title)
{
if (_instance == null || !_instance.Visible)
{
Instance.Invoke(new Action(() =>
{
Instance.Show();
Instance.Visible= true;
}));
}
Instance.Invoke(new Action(() =>
{
if (_loadingProcesses.ContainsKey(title))
{
return; // Prevent duplicate loading processes with the same title
}
var progressBar = new MaterialProgressBar
{
Width = Instance.ClientSize.Width - 20,
Height = 20,
Top = 50 + (_loadingProcesses.Count * 30),
Left = 10,
Style = ProgressBarStyle.Marquee,
MarqueeAnimationSpeed = 30,
Value = 50,
BackColor = Color.White
};
var label = new Label
{
Text = title,
AutoSize = true,
Top = progressBar.Top - 20,
Left = progressBar.Left,
BackColor = Color.White
};
_loadingProcesses[title] = (progressBar, label);
Instance.Controls.Add(label);
Instance.Controls.Add(progressBar);
Instance.Height = 50 + (_loadingProcesses.Count * 30);
Instance.Refresh();
}));
}
public void FinishLoading(string title)
{
if (_instance == null)
{
return;
}
Instance.Invoke(new Action(() =>
{
if (_loadingProcesses.TryGetValue(title, out var components))
{
Instance.Controls.Remove(components.ProgressBar);
Instance.Controls.Remove(components.Label);
_loadingProcesses.Remove(title);
RearrangeProgressBarsAndLabels();
}
if (_loadingProcesses.Count == 0)
{
Instance.Visible= false;
}
}));
}
private void RearrangeProgressBarsAndLabels()
{
int index = 0;
foreach (var components in _loadingProcesses.Values)
{
components.ProgressBar.Top = 50 + (index * 30);
components.Label.Top = components.ProgressBar.Top - 20;
index++;
}
this.Height = 50 + (_loadingProcesses.Count * 30);
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,90 @@
namespace MaterialSkin.Controls
{
partial class MaterialMessageBox
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.pnlButtons = new System.Windows.Forms.FlowLayoutPanel();
this.lblTitle = new System.Windows.Forms.Label();
this.lblText = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// pnlButtons
//
this.pnlButtons.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.pnlButtons.AutoSize = true;
this.pnlButtons.Location = new System.Drawing.Point(280, 204);
this.pnlButtons.Name = "pnlButtons";
this.pnlButtons.Padding = new System.Windows.Forms.Padding(0, 20, 0, 0);
this.pnlButtons.Size = new System.Drawing.Size(140, 100);
this.pnlButtons.TabIndex = 0;
//
// lblTitle
//
this.lblTitle.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.lblTitle.Location = new System.Drawing.Point(0, 20);
this.lblTitle.Name = "lblTitle";
this.lblTitle.Size = new System.Drawing.Size(1340, 40);
this.lblTitle.TabIndex = 1;
this.lblTitle.Text = "label1";
this.lblTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// lblText
//
this.lblText.Location = new System.Drawing.Point(280, 80);
this.lblText.Name = "lblText";
this.lblText.Size = new System.Drawing.Size(680, 100);
this.lblText.TabIndex = 2;
this.lblText.Text = "label1";
this.lblText.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// MaterialMessageBox
//
this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 26F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.ClientSize = new System.Drawing.Size(1338, 312);
this.ControlBox = false;
this.Controls.Add(this.lblText);
this.Controls.Add(this.lblTitle);
this.Controls.Add(this.pnlButtons);
this.Font = new System.Drawing.Font("Roboto", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
this.Margin = new System.Windows.Forms.Padding(6);
this.Name = "MaterialMessageBox";
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.FlowLayoutPanel pnlButtons;
private System.Windows.Forms.Label lblTitle;
private System.Windows.Forms.Label lblText;
}
}

View File

@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MaterialSkin.Controls
{
public partial class MaterialMessageBox : MaterialForm
{
[Browsable(false)]
private MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
private MaterialMessageBox()
{
InitializeComponent();
BackColor = SkinManager.GetApplicationBackgroundColor();
Left = 0;
Width = Screen.PrimaryScreen.WorkingArea.Width;
Top = (Screen.PrimaryScreen.WorkingArea.Height - Height) / 2;
lblTitle.BackColor = SkinManager.ColorScheme.PrimaryColor;
lblTitle.ForeColor= SkinManager.ColorScheme.TextColor;
lblText.Left = (Width - lblText.Width) / 2;
}
private void AlignControls()
{
pnlButtons.Left = (Width - pnlButtons.Width) / 2;
}
public static DialogResult Show(string text)
{
return Show(null, text, string.Empty, MessageBoxButtons.OK);
}
public static DialogResult Show(IWin32Window owner,string text, string caption, MessageBoxButtons buttons)
{
var mb = new MaterialMessageBox();
mb.lblTitle.Text = caption;
mb.lblText.Text = text;
List<DialogResult> results;
switch (buttons)
{
case MessageBoxButtons.OK:
results=new List<DialogResult>(){DialogResult.OK};
break;
case MessageBoxButtons.OKCancel:
results = new List<DialogResult>() { DialogResult.OK,DialogResult.Cancel };
break;
case MessageBoxButtons.AbortRetryIgnore:
results = new List<DialogResult>() { DialogResult.Abort,DialogResult.Retry,DialogResult.Ignore };
break;
case MessageBoxButtons.YesNoCancel:
results = new List<DialogResult>() { DialogResult.Yes,DialogResult.No,DialogResult.Cancel };
break;
case MessageBoxButtons.YesNo:
results = new List<DialogResult>() { DialogResult.Yes,DialogResult.No };
break;
case MessageBoxButtons.RetryCancel:
results = new List<DialogResult>() { DialogResult.Retry,DialogResult.Cancel };
break;
default:
throw new ArgumentOutOfRangeException(nameof(buttons), buttons, null);
}
var btns=Enum.GetNames(typeof(DialogResult));
foreach (var btn in results)
{
MaterialRaisedButton opt = new MaterialRaisedButton();
opt.Size = new Size(180, 60);
opt.Margin = new Padding(10, 20, 10, 0);
opt.Text = Enum.GetName(typeof(DialogResult),btn);
opt.Click += (sender, args) =>
mb.DialogResult = btn;
mb.pnlButtons.Controls.Add(opt);
mb.AlignControls();
}
return mb.ShowDialog(owner);
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,16 @@
using System.ComponentModel;
using System.Windows.Forms;
namespace MaterialSkin.Controls
{
public class MaterialPanel:Panel
{
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.Clear(SkinManager.GetApplicationBackgroundColor());
}
}
}

View File

@@ -0,0 +1,134 @@
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MaterialSkin.Controls
{
/// <summary>
/// Material design-like progress bar
/// </summary>
public class MaterialProgressBar : ProgressBar, IMaterialControl
{
private int _animation;
/// <summary>
/// Initializes a new instance of the <see cref="MaterialProgressBar"/> class.
/// </summary>
public MaterialProgressBar()
{
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
Timer timer = new Timer();
timer.Interval = 33;
timer.Tick += Timer_Tick;
timer.Enabled = true;
}
private void Timer_Tick(object sender, EventArgs e)
{
Invalidate();
}
/// <summary>
/// Gets or sets the depth.
/// </summary>
/// <value>
/// The depth.
/// </value>
[Browsable(false)]
public int Depth { get; set; }
/// <summary>
/// Gets the skin manager.
/// </summary>
/// <value>
/// The skin manager.
/// </value>
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
/// <summary>
/// Gets or sets the state of the mouse.
/// </summary>
/// <value>
/// The state of the mouse.
/// </value>
[Browsable(false)]
public MouseState MouseState { get; set; }
/// <summary>
/// Performs the work of setting the specified bounds of this control.
/// </summary>
/// <param name="x">The new <see cref="P:System.Windows.Forms.Control.Left" /> property value of the control.</param>
/// <param name="y">The new <see cref="P:System.Windows.Forms.Control.Top" /> property value of the control.</param>
/// <param name="width">The new <see cref="P:System.Windows.Forms.Control.Width" /> property value of the control.</param>
/// <param name="height">The new <see cref="P:System.Windows.Forms.Control.Height" /> property value of the control.</param>
/// <param name="specified">A bitwise combination of the <see cref="T:System.Windows.Forms.BoundsSpecified" /> values.</param>
protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
{
base.SetBoundsCore(x, y, width, 5, specified);
}
protected override void CreateHandle()
{
base.CreateHandle();
if (Style == ProgressBarStyle.Marquee)
StartAnimation();
}
private void StartAnimation()
{
_animation = 0;
}
/// <summary>
/// Raises the <see cref="E:System.Windows.Forms.Control.Paint" /> event.
/// </summary>
/// <param name="e">A <see cref="T:System.Windows.Forms.PaintEventArgs" /> that contains the event data.</param>
protected override void OnPaint(PaintEventArgs e)
{
if (Style == ProgressBarStyle.Marquee)
{
try
{
var animationProgress = (int)(e.ClipRectangle.Width * ((double)_animation / Maximum));
var doneProgress = (int)(e.ClipRectangle.Width * ((double)Value / Maximum));
if (doneProgress + animationProgress > e.ClipRectangle.Width)
doneProgress = e.ClipRectangle.Width - animationProgress;
_animation+=Step;
if (_animation >= 100) _animation = -Value;
e.Graphics.FillRectangle(SkinManager.GetDisabledOrHintBrush(), 0, 0, e.ClipRectangle.Width, e.ClipRectangle.Height);
e.Graphics.FillRectangle(SkinManager.ColorScheme.PrimaryBrush, animationProgress, 0, doneProgress, e.ClipRectangle.Height);
//Task.Delay(33).ContinueWith((x) =>
//{
// try
// {
// System.Action a = () => { };
// if (InvokeRequired)
// Invoke(a);
// else
// a();
// }catch{}
//});
}
catch (Exception exception)
{
}
}
else
{
var doneProgress = (int)(e.ClipRectangle.Width * ((double)Value / Maximum));
e.Graphics.FillRectangle(SkinManager.ColorScheme.PrimaryBrush, 0, 0, doneProgress, e.ClipRectangle.Height);
e.Graphics.FillRectangle(SkinManager.GetDisabledOrHintBrush(), doneProgress, 0, e.ClipRectangle.Width, e.ClipRectangle.Height);
}
}
}
}

View File

@@ -0,0 +1,211 @@
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;
using MaterialSkin.Animations;
namespace MaterialSkin.Controls
{
public class MaterialRadioButton : RadioButton, IMaterialControl
{
[Browsable(false)]
public int Depth { get; set; }
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
[Browsable(false)]
public MouseState MouseState { get; set; }
[Browsable(false)]
public Point MouseLocation { get; set; }
private bool ripple;
[Category("Behavior")]
public bool Ripple
{
get { return ripple; }
set
{
ripple = value;
AutoSize = AutoSize; //Make AutoSize directly set the bounds.
if (value)
{
Margin = new Padding(0);
}
Invalidate();
}
}
// animation managers
private readonly AnimationManager _animationManager;
private readonly AnimationManager _rippleAnimationManager;
// size related variables which should be recalculated onsizechanged
private Rectangle _radioButtonBounds;
private int _boxOffset;
// size constants
private const int RADIOBUTTON_SIZE = 19;
private const int RADIOBUTTON_SIZE_HALF = RADIOBUTTON_SIZE / 2;
private const int RADIOBUTTON_OUTER_CIRCLE_WIDTH = 2;
private const int RADIOBUTTON_INNER_CIRCLE_SIZE = RADIOBUTTON_SIZE - (2 * RADIOBUTTON_OUTER_CIRCLE_WIDTH);
public MaterialRadioButton()
{
SetStyle(ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer, true);
_animationManager = new AnimationManager
{
AnimationType = AnimationType.EaseInOut,
Increment = 0.06
};
_rippleAnimationManager = new AnimationManager(false)
{
AnimationType = AnimationType.Linear,
Increment = 0.10,
SecondaryIncrement = 0.08
};
_animationManager.OnAnimationProgress += sender => Invalidate();
_rippleAnimationManager.OnAnimationProgress += sender => Invalidate();
CheckedChanged += (sender, args) => _animationManager.StartNewAnimation(Checked ? AnimationDirection.In : AnimationDirection.Out);
SizeChanged += OnSizeChanged;
Ripple = true;
MouseLocation = new Point(-1, -1);
}
private void OnSizeChanged(object sender, EventArgs eventArgs)
{
_boxOffset = Height / 2 - (int)Math.Ceiling(RADIOBUTTON_SIZE / 2d);
_radioButtonBounds = new Rectangle(_boxOffset, _boxOffset, RADIOBUTTON_SIZE, RADIOBUTTON_SIZE);
}
public override Size GetPreferredSize(Size proposedSize)
{
var width = _boxOffset + 20 + (int)CreateGraphics().MeasureString(Text, SkinManager.ROBOTO_MEDIUM_10).Width;
return Ripple ? new Size(width, 30) : new Size(width, 20);
}
protected override void OnPaint(PaintEventArgs pevent)
{
var g = pevent.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.TextRenderingHint = TextRenderingHint.AntiAlias;
// clear the control
g.Clear(Parent.BackColor);
var RADIOBUTTON_CENTER = _boxOffset + RADIOBUTTON_SIZE_HALF;
var animationProgress = _animationManager.GetProgress();
int colorAlpha = Enabled ? (int)(animationProgress * 255.0) : SkinManager.GetCheckBoxOffDisabledColor().A;
int backgroundAlpha = Enabled ? (int)(SkinManager.GetCheckboxOffColor().A * (1.0 - animationProgress)) : SkinManager.GetCheckBoxOffDisabledColor().A;
float animationSize = (float)(animationProgress * 8f);
float animationSizeHalf = animationSize / 2;
animationSize = (float)(animationProgress * 9f);
var brush = new SolidBrush(Color.FromArgb(colorAlpha, Enabled ? SkinManager.ColorScheme.AccentColor : SkinManager.GetCheckBoxOffDisabledColor()));
var pen = new Pen(brush.Color);
// draw ripple animation
if (Ripple && _rippleAnimationManager.IsAnimating())
{
for (var i = 0; i < _rippleAnimationManager.GetAnimationCount(); i++)
{
var animationValue = _rippleAnimationManager.GetProgress(i);
var animationSource = new Point(RADIOBUTTON_CENTER, RADIOBUTTON_CENTER);
var rippleBrush = new SolidBrush(Color.FromArgb((int)((animationValue * 40)), ((bool)_rippleAnimationManager.GetData(i)[0]) ? Color.Black : brush.Color));
var rippleHeight = (Height % 2 == 0) ? Height - 3 : Height - 2;
var rippleSize = (_rippleAnimationManager.GetDirection(i) == AnimationDirection.InOutIn) ? (int)(rippleHeight * (0.8d + (0.2d * animationValue))) : rippleHeight;
using (var path = DrawHelper.CreateRoundRect(animationSource.X - rippleSize / 2, animationSource.Y - rippleSize / 2, rippleSize, rippleSize, rippleSize / 2))
{
g.FillPath(rippleBrush, path);
}
rippleBrush.Dispose();
}
}
// draw radiobutton circle
Color uncheckedColor = DrawHelper.BlendColor(Parent.BackColor, Enabled ? SkinManager.GetCheckboxOffColor() : SkinManager.GetCheckBoxOffDisabledColor(), backgroundAlpha);
using (var path = DrawHelper.CreateRoundRect(_boxOffset, _boxOffset, RADIOBUTTON_SIZE, RADIOBUTTON_SIZE, 9f))
{
g.FillPath(new SolidBrush(uncheckedColor), path);
if (Enabled)
{
g.FillPath(brush, path);
}
}
g.FillEllipse(
new SolidBrush(Parent.BackColor),
RADIOBUTTON_OUTER_CIRCLE_WIDTH + _boxOffset,
RADIOBUTTON_OUTER_CIRCLE_WIDTH + _boxOffset,
RADIOBUTTON_INNER_CIRCLE_SIZE,
RADIOBUTTON_INNER_CIRCLE_SIZE);
if (Checked)
{
using (var path = DrawHelper.CreateRoundRect(RADIOBUTTON_CENTER - animationSizeHalf, RADIOBUTTON_CENTER - animationSizeHalf, animationSize, animationSize, 4f))
{
g.FillPath(brush, path);
}
}
SizeF stringSize = g.MeasureString(Text, SkinManager.ROBOTO_MEDIUM_10);
g.DrawString(Text, SkinManager.ROBOTO_MEDIUM_10, Enabled ? SkinManager.GetPrimaryTextBrush() : SkinManager.GetDisabledOrHintBrush(), _boxOffset + 22, Height / 2 - stringSize.Height / 2);
brush.Dispose();
pen.Dispose();
}
private bool IsMouseInCheckArea()
{
return _radioButtonBounds.Contains(MouseLocation);
}
protected override void OnCreateControl()
{
base.OnCreateControl();
Font = SkinManager.ROBOTO_MEDIUM_10;
if (DesignMode) return;
MouseState = MouseState.OUT;
MouseEnter += (sender, args) =>
{
MouseState = MouseState.HOVER;
};
MouseLeave += (sender, args) =>
{
MouseLocation = new Point(-1, -1);
MouseState = MouseState.OUT;
};
MouseDown += (sender, args) =>
{
MouseState = MouseState.DOWN;
if (Ripple && args.Button == MouseButtons.Left && IsMouseInCheckArea())
{
_rippleAnimationManager.SecondaryIncrement = 0;
_rippleAnimationManager.StartNewAnimation(AnimationDirection.InOutIn, new object[] { Checked });
}
};
MouseUp += (sender, args) =>
{
MouseState = MouseState.HOVER;
_rippleAnimationManager.SecondaryIncrement = 0.08;
};
MouseMove += (sender, args) =>
{
MouseLocation = args.Location;
Cursor = IsMouseInCheckArea() ? Cursors.Hand : Cursors.Default;
};
}
}
}

View File

@@ -0,0 +1,216 @@
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;
using MaterialSkin.Animations;
using System;
namespace MaterialSkin.Controls
{
public class MaterialRaisedButton : Button, IMaterialControl
{
[Browsable(false)]
public int Depth { get; set; }
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
[Browsable(false)]
public MouseState MouseState { get; set; }
public bool Primary { get; set; }
public bool DrawBorder
{
get { return _drawBorder; }
set
{
_drawBorder = value;
}
}
private readonly AnimationManager _animationManager;
private SizeF _textSize;
private Image _icon;
private bool _drawBorder;
private Point _lastLocation;
private bool _wasClick;
public Image Icon
{
get { return _icon; }
set
{
_icon = value;
if (AutoSize)
Size = GetPreferredSize();
Invalidate();
}
}
public MaterialRaisedButton()
{
Primary = true;
Cursor = Cursors.Hand;
_animationManager = new AnimationManager(false)
{
Increment = 0.02,
AnimationType = AnimationType.EaseOut
};
_animationManager.OnAnimationProgress += sender => Invalidate();
_animationManager.OnAnimationFinished +=AnimationManagerOnOnAnimationFinished;
AutoSizeMode = AutoSizeMode.GrowAndShrink;
}
private void AnimationManagerOnOnAnimationFinished(object o)
{
if (_wasClick)
{
_wasClick = false;
}
}
public override string Text
{
get { return base.Text; }
set
{
base.Text = value;
_textSize = CreateGraphics().MeasureString(value.ToUpper(), SkinManager.ROBOTO_MEDIUM_10);
if (AutoSize)
Size = GetPreferredSize();
Invalidate();
}
}
protected override void OnMouseUp(MouseEventArgs mevent)
{
base.OnMouseUp(mevent);
}
protected override void OnMouseDown(MouseEventArgs mevent)
{
base.OnMouseDown(mevent);
_lastLocation = mevent.Location;
}
protected override void OnClick(EventArgs e)
{
_animationManager.StartNewAnimation(AnimationDirection.In,_lastLocation);
base.OnClick(e);
}
protected override void OnPaint(PaintEventArgs pevent)
{
try
{
var g = pevent.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
//g.TextRenderingHint = TextRenderingHint.AntiAlias;
g.Clear(Parent.BackColor);
using (var backgroundPath = DrawHelper.CreateRoundRect(ClientRectangle.X,
ClientRectangle.Y,
ClientRectangle.Width - 1,
ClientRectangle.Height - 1,
1f))
{
g.FillPath(
Enabled
? (Primary
? SkinManager.ColorScheme.PrimaryBrush
: SkinManager.GetRaisedButtonBackgroundBrush())
: Brushes.DarkGray, backgroundPath);
if (!Primary && this.DrawBorder)
{
g.DrawPath(SkinManager.ColorScheme.PrimaryPen, backgroundPath);
}
}
if (_animationManager.IsAnimating())
{
for (int i = 0; i < _animationManager.GetAnimationCount(); i++)
{
var animationValue = _animationManager.GetProgress(i);
var animationSource = _animationManager.GetSource(i);
var rippleBrush = new SolidBrush(Color.FromArgb((int) (51 - (animationValue * 50)),
Primary ? Color.White : SkinManager.ColorScheme.PrimaryColor));
var rippleSize = (int) (animationValue * Width * 2);
g.FillEllipse(rippleBrush,
new Rectangle(animationSource.X - rippleSize / 2, animationSource.Y - rippleSize / 2,
rippleSize, rippleSize));
}
}
//Icon
var iconRect = new Rectangle(8, 6, 24, 24);
if (string.IsNullOrEmpty(Text))
// Center Icon
iconRect.X += 2;
if (Icon != null)
g.DrawImage(Icon, iconRect);
//Text
var textRect = ClientRectangle;
if (Icon != null)
{
//
// Resize and move Text container
//
// First 8: left padding
// 24: icon width
// Second 4: space between Icon and Text
// Third 8: right padding
textRect.Width -= 8 + 24 + 4 + 8;
// First 8: left padding
// 24: icon width
// Second 4: space between Icon and Text
textRect.X += 8 + 24 + 4;
}
g.DrawString(
Text.ToUpper(),
Font,
Primary ? SkinManager.GetRaisedButtonTextBrush(Primary) : SkinManager.ColorScheme.PrimaryBrush,
textRect,
new StringFormat {Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center});
}
catch
{
}
}
private Size GetPreferredSize()
{
return GetPreferredSize(new Size(0, 0));
}
public override Size GetPreferredSize(Size proposedSize)
{
// Provides extra space for proper padding for content
var extra = 16;
if (Icon != null)
// 24 is for icon size
// 4 is for the space between icon & text
extra += 24 + 4;
return new Size((int)Math.Ceiling(_textSize.Width) + extra, 36);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,22 @@
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace MaterialSkin.Controls
{
public class MaterialTabControl : TabControl, IMaterialControl
{
[Browsable(false)]
public int Depth { get; set; }
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
[Browsable(false)]
public MouseState MouseState { get; set; }
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x1328 && !DesignMode) m.Result = (IntPtr)1;
else base.WndProc(ref m);
}
}
}

View File

@@ -0,0 +1,175 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Text;
using System.Windows.Forms;
using MaterialSkin.Animations;
namespace MaterialSkin.Controls
{
public class MaterialTabSelector : Control, IMaterialControl
{
[Browsable(false)]
public int Depth { get; set; }
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
[Browsable(false)]
public MouseState MouseState { get; set; }
private MaterialTabControl _baseTabControl;
public MaterialTabControl BaseTabControl
{
get { return _baseTabControl; }
set
{
_baseTabControl = value;
if (_baseTabControl == null) return;
_previousSelectedTabIndex = _baseTabControl.SelectedIndex;
_baseTabControl.Deselected += (sender, args) =>
{
_previousSelectedTabIndex = _baseTabControl.SelectedIndex;
};
_baseTabControl.SelectedIndexChanged += (sender, args) =>
{
_animationManager.SetProgress(0);
_animationManager.StartNewAnimation(AnimationDirection.In);
};
_baseTabControl.ControlAdded += delegate
{
Invalidate();
};
_baseTabControl.ControlRemoved += delegate
{
Invalidate();
};
}
}
private int _previousSelectedTabIndex;
private Point _animationSource;
private readonly AnimationManager _animationManager;
private List<Rectangle> _tabRects;
private const int TAB_HEADER_PADDING = 24;
private const int TAB_INDICATOR_HEIGHT = 2;
public MaterialTabSelector()
{
SetStyle(ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer, true);
Height = 48;
_animationManager = new AnimationManager
{
AnimationType = AnimationType.EaseOut,
Increment = 0.04
};
_animationManager.OnAnimationProgress += sender => Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
g.TextRenderingHint = TextRenderingHint.AntiAlias;
g.Clear(SkinManager.ColorScheme.PrimaryColor);
if (_baseTabControl == null) return;
if (!_animationManager.IsAnimating() || _tabRects == null || _tabRects.Count != _baseTabControl.TabCount)
UpdateTabRects();
var animationProgress = _animationManager.GetProgress();
//Click feedback
if (_animationManager.IsAnimating())
{
var rippleBrush = new SolidBrush(Color.FromArgb((int)(51 - (animationProgress * 50)), Color.White));
var rippleSize = (int)(animationProgress * _tabRects[_baseTabControl.SelectedIndex].Width * 1.75);
g.SetClip(_tabRects[_baseTabControl.SelectedIndex]);
g.FillEllipse(rippleBrush, new Rectangle(_animationSource.X - rippleSize / 2, _animationSource.Y - rippleSize / 2, rippleSize, rippleSize));
g.ResetClip();
rippleBrush.Dispose();
}
//Draw tab headers
foreach (TabPage tabPage in _baseTabControl.TabPages)
{
var currentTabIndex = _baseTabControl.TabPages.IndexOf(tabPage);
Brush textBrush = new SolidBrush(Color.FromArgb(CalculateTextAlpha(currentTabIndex, animationProgress), SkinManager.ColorScheme.TextColor));
g.DrawString(tabPage.Text.ToUpper(), SkinManager.ROBOTO_MEDIUM_10, textBrush, _tabRects[currentTabIndex], new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
textBrush.Dispose();
}
//Animate tab indicator
var previousSelectedTabIndexIfHasOne = _previousSelectedTabIndex == -1 ? _baseTabControl.SelectedIndex : _previousSelectedTabIndex;
var previousActiveTabRect = _tabRects[previousSelectedTabIndexIfHasOne];
var activeTabPageRect = _tabRects[_baseTabControl.SelectedIndex];
var y = activeTabPageRect.Bottom - 2;
var x = previousActiveTabRect.X + (int)((activeTabPageRect.X - previousActiveTabRect.X) * animationProgress);
var width = previousActiveTabRect.Width + (int)((activeTabPageRect.Width - previousActiveTabRect.Width) * animationProgress);
g.FillRectangle(SkinManager.ColorScheme.AccentBrush, x, y, width, TAB_INDICATOR_HEIGHT);
}
private int CalculateTextAlpha(int tabIndex, double animationProgress)
{
int primaryA = SkinManager.ACTION_BAR_TEXT.A;
int secondaryA = SkinManager.ACTION_BAR_TEXT_SECONDARY.A;
if (tabIndex == _baseTabControl.SelectedIndex && !_animationManager.IsAnimating())
{
return primaryA;
}
if (tabIndex != _previousSelectedTabIndex && tabIndex != _baseTabControl.SelectedIndex)
{
return secondaryA;
}
if (tabIndex == _previousSelectedTabIndex)
{
return primaryA - (int)((primaryA - secondaryA) * animationProgress);
}
return secondaryA + (int)((primaryA - secondaryA) * animationProgress);
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
if (_tabRects == null) UpdateTabRects();
for (var i = 0; i < _tabRects.Count; i++)
{
if (_tabRects[i].Contains(e.Location))
{
_baseTabControl.SelectedIndex = i;
}
}
_animationSource = e.Location;
}
private void UpdateTabRects()
{
_tabRects = new List<Rectangle>();
//If there isn't a base tab control, the rects shouldn't be calculated
//If there aren't tab pages in the base tab control, the list should just be empty which has been set already; exit the void
if (_baseTabControl == null || _baseTabControl.TabCount == 0) return;
//Calculate the bounds of each tab header specified in the base tab control
using (var b = new Bitmap(1, 1))
{
using (var g = Graphics.FromImage(b))
{
_tabRects.Add(new Rectangle(SkinManager.FORM_PADDING, 0, TAB_HEADER_PADDING * 2 + (int)g.MeasureString(_baseTabControl.TabPages[0].Text, SkinManager.ROBOTO_MEDIUM_10).Width, Height));
for (int i = 1; i < _baseTabControl.TabPages.Count; i++)
{
_tabRects.Add(new Rectangle(_tabRects[i - 1].Right, 0, TAB_HEADER_PADDING * 2 + (int)g.MeasureString(_baseTabControl.TabPages[i].Text, SkinManager.ROBOTO_MEDIUM_10).Width, Height));
}
}
}
}
}
}

View File

@@ -0,0 +1,103 @@
using MaterialSkin.Core.Resources;
namespace MaterialSkin.Controls
{
partial class MaterialUpDown
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.materialIcon2 = new MaterialSkin.Controls.MaterialIcon();
this.materialIcon1 = new MaterialSkin.Controls.MaterialIcon();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.textBox1.Font = new System.Drawing.Font("Roboto", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
this.textBox1.Location = new System.Drawing.Point(80, 20);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(100, 28);
this.textBox1.TabIndex = 13;
this.textBox1.Text = "0000";
this.textBox1.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.textBox1.Click += new System.EventHandler(this.textBox1_Click);
this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
this.textBox1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.textBox1_KeyDown);
this.textBox1.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.textBox1_KeyPress);
this.textBox1.Leave += new System.EventHandler(this.textBox1_Leave);
//
// materialIcon2
//
this.materialIcon2.Clickable = true;
this.materialIcon2.Cursor = System.Windows.Forms.Cursors.Hand;
this.materialIcon2.Image = Resource1.rounded_add_button;
this.materialIcon2.Location = new System.Drawing.Point(200, 0);
this.materialIcon2.Name = "materialIcon2";
this.materialIcon2.Primary = false;
this.materialIcon2.Size = new System.Drawing.Size(64, 64);
this.materialIcon2.TabIndex = 12;
this.materialIcon2.Text = "materialIcon2";
this.materialIcon2.Click += new System.EventHandler(this.materialIcon2_Click);
this.materialIcon2.MouseDown += new System.Windows.Forms.MouseEventHandler(this.materialIcon2_MouseDown);
this.materialIcon2.MouseLeave += new System.EventHandler(this.materialIcon2_MouseLeave);
this.materialIcon2.MouseUp += new System.Windows.Forms.MouseEventHandler(this.materialIcon2_MouseUp);
//
// materialIcon1
//
this.materialIcon1.Clickable = true;
this.materialIcon1.Cursor = System.Windows.Forms.Cursors.Hand;
this.materialIcon1.Image = Resource1.round_delete_button;
this.materialIcon1.Location = new System.Drawing.Point(0, 0);
this.materialIcon1.Name = "materialIcon1";
this.materialIcon1.Primary = false;
this.materialIcon1.Size = new System.Drawing.Size(64, 64);
this.materialIcon1.TabIndex = 11;
this.materialIcon1.Text = "materialIcon1";
this.materialIcon1.Click += new System.EventHandler(this.materialIcon1_Click);
this.materialIcon1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.materialIcon1_MouseDown);
this.materialIcon1.MouseLeave += new System.EventHandler(this.materialIcon1_MouseLeave);
this.materialIcon1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.materialIcon1_MouseUp);
//
// MaterialUpDown
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.Controls.Add(this.textBox1);
this.Controls.Add(this.materialIcon2);
this.Controls.Add(this.materialIcon1);
this.Name = "MaterialUpDown";
this.Size = new System.Drawing.Size(266, 66);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private MaterialIcon materialIcon2;
private MaterialIcon materialIcon1;
private System.Windows.Forms.TextBox textBox1;
}
}

View File

@@ -0,0 +1,256 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MaterialSkin.Controls
{
public partial class MaterialUpDown : UserControl,INotifyPropertyChanged
{
private double _value;
private bool _mouseDown;
private int _direction;
public MaterialUpDown()
{
InitializeComponent();
textBox1.BackColor = SkinManager.GetApplicationBackgroundColor();
AllowDecimal = false;
AllowKeyboard=true;
}
[Browsable(false)]
public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;
public bool AllowDecimal { get; set; }
public bool AllowKeyboard
{
get { return _allowKeyboard; }
set
{
_allowKeyboard = value;
textBox1.ReadOnly = !_allowKeyboard || _readOnly;
}
}
public bool HideControls
{
get { return _hideControls; }
set
{
_hideControls = value;
materialIcon1.Visible = !value;
materialIcon2.Visible = !value;
}
}
public double Value
{
get { return _value; }
set
{
_value = value;
if (_value>Max)
{
_value = Max;
}
if (_value < Min)
{
_value = Min;
}
if (!AllowDecimal)
{
_value = Math.Floor(_value);
}
Action a = ()=> textBox1.Text = _value.ToString();
if (textBox1.InvokeRequired)
textBox1.Invoke(a);
else
a();
}
}
public bool ReadOnly
{
get { return _readOnly; }
set
{
_readOnly = value;
materialIcon1.Enabled = !value;
materialIcon2.Enabled = !value;
textBox1.ReadOnly = !_allowKeyboard || _readOnly;
}
}
public event PropertyChangedEventHandler PropertyChanged= delegate { };
public double Max { get; set; }
public double Min { get; set; }
public double Step { get; set; }
protected override void OnPaintBackground(PaintEventArgs e)
{
e.Graphics.Clear(SkinManager.GetApplicationBackgroundColor());
}
private void materialIcon2_Click(object sender, EventArgs e)
{
}
private void materialIcon1_Click(object sender, EventArgs e)
{
}
private async void HoldCountDown(CancellationToken cancellationSourceToken)
{
await Task.Delay(500);
var startTime = DateTime.Now;
while (_mouseDown&&!cancellationSourceToken.IsCancellationRequested)
{
Value += Step*_direction;
await Task.Delay(100/(int)Math.Max(1,Math.Min(5,(DateTime.Now-startTime).TotalSeconds)));
}
}
private CancellationTokenSource _cancellationSource;
private bool _readOnly;
private bool _allowKeyboard;
private void materialIcon2_MouseDown(object sender, MouseEventArgs e)
{
_cancellationSource =new CancellationTokenSource();
Value += Step;
_mouseDown = true;
_direction = 1;
Task.Run(()=> HoldCountDown(_cancellationSource.Token));
}
private void materialIcon2_MouseUp(object sender, MouseEventArgs e)
{
if (_cancellationSource != null)
{
_cancellationSource.Cancel();
_cancellationSource = null;
}
_mouseDown = false;
PropertyChanged(this,new PropertyChangedEventArgs(nameof(Value)));
}
private void materialIcon1_MouseDown(object sender, MouseEventArgs e)
{
_cancellationSource = new CancellationTokenSource();
Value -= Step;
_mouseDown = true;
_direction = -1;
Task.Run(() => HoldCountDown(_cancellationSource.Token));
}
private void materialIcon1_MouseUp(object sender, MouseEventArgs e)
{
if (_cancellationSource != null)
{
_cancellationSource.Cancel();
_cancellationSource = null;
}
_mouseDown = false;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Value)));
}
private void materialIcon2_MouseLeave(object sender, EventArgs e)
{
materialIcon2_MouseUp(null,null);
}
private void materialIcon1_MouseLeave(object sender, EventArgs e)
{
materialIcon1_MouseUp(null, null);
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) &&
(e.KeyChar != '.'))
{
e.Handled = true;
return;
}
// only allow one decimal point
if ((e.KeyChar == '.') && ((sender as TextBox).Text.IndexOf('.') > -1))
{
e.Handled = true;
return;
}
_validate = true;
}
private CancellationTokenSource _cancellationTokenSource = null;
private bool _validate;
private bool _hideControls;
private void textBox1_Click(object sender, EventArgs e)
{
if (textBox1.ReadOnly) return;
textBox1.SelectAll();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void textBox1_Leave(object sender, EventArgs e)
{
if (double.TryParse((sender as TextBox).Text, NumberStyles.AllowDecimalPoint, CultureInfo.GetCultureInfo("en-us"), out var value))
{
if (_cancellationTokenSource != null) _cancellationTokenSource.Cancel();
_cancellationTokenSource = new CancellationTokenSource();
Task.Run(async () =>
{
var newValue = value;
var token = _cancellationTokenSource.Token;
if (token.IsCancellationRequested) throw new OperationCanceledException();
Value = newValue;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Value)));
});
}
}
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
textBox1_Leave(textBox1,null);
e.Handled = true;
}
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>