├── MaterialSkinExample ├── Resources │ ├── minus.png │ └── plus.png ├── Icons │ ├── ic_settings_black_24dp_1x.png │ └── ic_settings_white_24dp_1x.png ├── App.config ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── Program.cs ├── MainForm.cs ├── MaterialSkinExample.csproj └── MainForm.resx ├── MaterialSkin ├── Resources │ ├── Roboto-Medium.ttf │ └── Roboto-Regular.ttf ├── IMaterialControl.cs ├── Animations │ ├── AnimationDirection.cs │ ├── Animations.cs │ └── AnimationManager.cs ├── Controls │ ├── MaterialTabControl.cs │ ├── MaterialDivider.cs │ ├── MaterialLabel.cs │ ├── MaterialProgressBar.cs │ ├── MaterialMenuStrip.cs │ ├── MaterialRaisedButton.cs │ ├── MaterialListView.cs │ ├── MaterialFlatButton.cs │ ├── MaterialTabSelector.cs │ ├── MaterialContextMenuStrip.cs │ ├── MaterialRadioButton.cs │ ├── MaterialCheckbox.cs │ └── MaterialForm.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── DrawHelper.cs ├── MaterialSkin.csproj ├── ColorScheme.cs └── MaterialSkinManager.cs ├── .github └── FUNDING.yml ├── LICENSE ├── MaterialSkin.sln ├── .gitattributes ├── .gitignore └── README.md /MaterialSkinExample/Resources/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IgnaceMaes/MaterialSkin/HEAD/MaterialSkinExample/Resources/minus.png -------------------------------------------------------------------------------- /MaterialSkinExample/Resources/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IgnaceMaes/MaterialSkin/HEAD/MaterialSkinExample/Resources/plus.png -------------------------------------------------------------------------------- /MaterialSkin/Resources/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IgnaceMaes/MaterialSkin/HEAD/MaterialSkin/Resources/Roboto-Medium.ttf -------------------------------------------------------------------------------- /MaterialSkin/Resources/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IgnaceMaes/MaterialSkin/HEAD/MaterialSkin/Resources/Roboto-Regular.ttf -------------------------------------------------------------------------------- /MaterialSkinExample/Icons/ic_settings_black_24dp_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IgnaceMaes/MaterialSkin/HEAD/MaterialSkinExample/Icons/ic_settings_black_24dp_1x.png -------------------------------------------------------------------------------- /MaterialSkinExample/Icons/ic_settings_white_24dp_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IgnaceMaes/MaterialSkin/HEAD/MaterialSkinExample/Icons/ic_settings_white_24dp_1x.png -------------------------------------------------------------------------------- /MaterialSkinExample/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /MaterialSkinExample/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MaterialSkin/IMaterialControl.cs: -------------------------------------------------------------------------------- 1 | namespace MaterialSkin 2 | { 3 | public interface IMaterialControl 4 | { 5 | int Depth { get; set; } 6 | MaterialSkinManager SkinManager { get; } 7 | MouseState MouseState { get; set; } 8 | 9 | } 10 | 11 | public enum MouseState 12 | { 13 | HOVER, 14 | DOWN, 15 | OUT 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /MaterialSkinExample/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace MaterialSkinExample 5 | { 6 | internal static class Program 7 | { 8 | [STAThread] 9 | private static void Main() 10 | { 11 | Application.EnableVisualStyles(); 12 | Application.SetCompatibleTextRenderingDefault(false); 13 | Application.Run(new MainForm()); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /MaterialSkin/Animations/AnimationDirection.cs: -------------------------------------------------------------------------------- 1 | namespace MaterialSkin.Animations 2 | { 3 | enum AnimationDirection 4 | { 5 | In, //In. Stops if finished. 6 | Out, //Out. Stops if finished. 7 | InOutIn, //Same as In, but changes to InOutOut if finished. 8 | InOutOut, //Same as Out. 9 | InOutRepeatingIn, // Same as In, but changes to InOutRepeatingOut if finished. 10 | InOutRepeatingOut // Same as Out, but changes to InOutRepeatingIn if finished. 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /MaterialSkin/Controls/MaterialTabControl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Windows.Forms; 4 | 5 | namespace MaterialSkin.Controls 6 | { 7 | public class MaterialTabControl : TabControl, IMaterialControl 8 | { 9 | [Browsable(false)] 10 | public int Depth { get; set; } 11 | [Browsable(false)] 12 | public MaterialSkinManager SkinManager => MaterialSkinManager.Instance; 13 | [Browsable(false)] 14 | public MouseState MouseState { get; set; } 15 | 16 | protected override void WndProc(ref Message m) 17 | { 18 | if (m.Msg == 0x1328 && !DesignMode) m.Result = (IntPtr)1; 19 | else base.WndProc(ref m); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /MaterialSkin/Controls/MaterialDivider.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Windows.Forms; 3 | 4 | namespace MaterialSkin.Controls 5 | { 6 | public sealed class MaterialDivider : Control, IMaterialControl 7 | { 8 | [Browsable(false)] 9 | public int Depth { get; set; } 10 | [Browsable(false)] 11 | public MaterialSkinManager SkinManager => MaterialSkinManager.Instance; 12 | [Browsable(false)] 13 | public MouseState MouseState { get; set; } 14 | 15 | public MaterialDivider() 16 | { 17 | SetStyle(ControlStyles.SupportsTransparentBackColor, true); 18 | Height = 1; 19 | BackColor = SkinManager.GetDividersColor(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | # github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | github: ['IgnaceMaes'] 5 | # patreon: # Replace with a single Patreon username 6 | # open_collective: # Replace with a single Open Collective username 7 | # ko_fi: # Replace with a single Ko-fi username 8 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 9 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 10 | # liberapay: # Replace with a single Liberapay username 11 | # issuehunt: # Replace with a single IssueHunt username 12 | # otechie: # Replace with a single Otechie username 13 | # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /MaterialSkin/Controls/MaterialLabel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Windows.Forms; 3 | 4 | namespace MaterialSkin.Controls 5 | { 6 | public class MaterialLabel : Label, IMaterialControl 7 | { 8 | [Browsable(false)] 9 | public int Depth { get; set; } 10 | [Browsable(false)] 11 | public MaterialSkinManager SkinManager => MaterialSkinManager.Instance; 12 | [Browsable(false)] 13 | public MouseState MouseState { get; set; } 14 | protected override void OnCreateControl() 15 | { 16 | base.OnCreateControl(); 17 | 18 | ForeColor = SkinManager.GetPrimaryTextColor(); 19 | Font = SkinManager.ROBOTO_REGULAR_11; 20 | 21 | BackColorChanged += (sender, args) => ForeColor = SkinManager.GetPrimaryTextColor(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Ignace Maes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MaterialSkinExample/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace MaterialSkinExample.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /MaterialSkin/Animations/Animations.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MaterialSkin.Animations 4 | { 5 | enum AnimationType 6 | { 7 | Linear, 8 | EaseInOut, 9 | EaseOut, 10 | CustomQuadratic 11 | } 12 | 13 | static class AnimationLinear 14 | { 15 | public static double CalculateProgress(double progress) 16 | { 17 | return progress; 18 | } 19 | } 20 | 21 | static class AnimationEaseInOut 22 | { 23 | public static double PI = Math.PI; 24 | public static double PI_HALF = Math.PI / 2; 25 | 26 | public static double CalculateProgress(double progress) 27 | { 28 | return EaseInOut(progress); 29 | } 30 | 31 | private static double EaseInOut(double s) 32 | { 33 | return s - Math.Sin(s * 2 * PI) / (2 * PI); 34 | } 35 | } 36 | 37 | public static class AnimationEaseOut 38 | { 39 | public static double CalculateProgress(double progress) 40 | { 41 | return -1 * progress * (progress - 2); 42 | } 43 | } 44 | 45 | public static class AnimationCustomQuadratic 46 | { 47 | public static double CalculateProgress(double progress) 48 | { 49 | var kickoff = 0.6; 50 | return 1 - Math.Cos((Math.Max(progress, kickoff) - kickoff) * Math.PI / (2 - (2 * kickoff))); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /MaterialSkin/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("MaterialSkin")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("MaterialSkin")] 12 | [assembly: AssemblyCopyright("Copyright © 2014")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("52781de3-a323-49ee-9a4f-c67280f8d328")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /MaterialSkinExample/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("MaterialSkinExample")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("MaterialSkinExample")] 12 | [assembly: AssemblyCopyright("Copyright © 2014")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("b3fe1c46-7ac9-4dc9-bfe7-f66f3136e410")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /MaterialSkin.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaterialSkinExample", "MaterialSkinExample\MaterialSkinExample.csproj", "{47409AA5-62AE-4189-8E83-C471502DF5E9}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaterialSkin", "MaterialSkin\MaterialSkin.csproj", "{8EB7611B-68CD-4B8B-987A-11717E2B250C}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {47409AA5-62AE-4189-8E83-C471502DF5E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {47409AA5-62AE-4189-8E83-C471502DF5E9}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {47409AA5-62AE-4189-8E83-C471502DF5E9}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {47409AA5-62AE-4189-8E83-C471502DF5E9}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {8EB7611B-68CD-4B8B-987A-11717E2B250C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {8EB7611B-68CD-4B8B-987A-11717E2B250C}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {8EB7611B-68CD-4B8B-987A-11717E2B250C}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {8EB7611B-68CD-4B8B-987A-11717E2B250C}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /MaterialSkin/DrawHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Drawing.Drawing2D; 3 | 4 | namespace MaterialSkin 5 | { 6 | static class DrawHelper 7 | { 8 | public static GraphicsPath CreateRoundRect(float x, float y, float width, float height, float radius) 9 | { 10 | var gp = new GraphicsPath(); 11 | gp.AddLine(x + radius, y, x + width - (radius * 2), y); 12 | gp.AddArc(x + width - (radius * 2), y, radius * 2, radius * 2, 270, 90); 13 | gp.AddLine(x + width, y + radius, x + width, y + height - (radius * 2)); 14 | gp.AddArc(x + width - (radius * 2), y + height - (radius * 2), radius * 2, radius * 2, 0, 90); 15 | gp.AddLine(x + width - (radius * 2), y + height, x + radius, y + height); 16 | gp.AddArc(x, y + height - (radius * 2), radius * 2, radius * 2, 90, 90); 17 | gp.AddLine(x, y + height - (radius * 2), x, y + radius); 18 | gp.AddArc(x, y, radius * 2, radius * 2, 180, 90); 19 | gp.CloseFigure(); 20 | return gp; 21 | } 22 | 23 | public static GraphicsPath CreateRoundRect(Rectangle rect, float radius) 24 | { 25 | return CreateRoundRect(rect.X, rect.Y, rect.Width, rect.Height, radius); 26 | } 27 | 28 | public static Color BlendColor(Color backgroundColor, Color frontColor, double blend) 29 | { 30 | var ratio = blend / 255d; 31 | var invRatio = 1d - ratio; 32 | var r = (int)((backgroundColor.R * invRatio) + (frontColor.R * ratio)); 33 | var g = (int)((backgroundColor.G * invRatio) + (frontColor.G * ratio)); 34 | var b = (int)((backgroundColor.B * invRatio) + (frontColor.B * ratio)); 35 | return Color.FromArgb(r, g, b); 36 | } 37 | 38 | public static Color BlendColor(Color backgroundColor, Color frontColor) 39 | { 40 | return BlendColor(backgroundColor, frontColor, frontColor.A); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /MaterialSkinExample/MainForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using MaterialSkin; 4 | using MaterialSkin.Controls; 5 | 6 | namespace MaterialSkinExample 7 | { 8 | public partial class MainForm : MaterialForm 9 | { 10 | private readonly MaterialSkinManager materialSkinManager; 11 | public MainForm() 12 | { 13 | InitializeComponent(); 14 | 15 | // Initialize MaterialSkinManager 16 | materialSkinManager = MaterialSkinManager.Instance; 17 | materialSkinManager.AddFormToManage(this); 18 | materialSkinManager.Theme = MaterialSkinManager.Themes.LIGHT; 19 | materialSkinManager.ColorScheme = new ColorScheme(Primary.BlueGrey800, Primary.BlueGrey900, Primary.BlueGrey500, Accent.LightBlue200, TextShade.WHITE); 20 | 21 | // Add dummy data to the listview 22 | seedListView(); 23 | } 24 | 25 | private void seedListView() 26 | { 27 | //Define 28 | var data = new[] 29 | { 30 | new []{"Lollipop", "392", "0.2", "0"}, 31 | new []{"KitKat", "518", "26.0", "7"}, 32 | new []{"Ice cream sandwich", "237", "9.0", "4.3"}, 33 | new []{"Jelly Bean", "375", "0.0", "0.0"}, 34 | new []{"Honeycomb", "408", "3.2", "6.5"} 35 | }; 36 | 37 | //Add 38 | foreach (string[] version in data) 39 | { 40 | var item = new ListViewItem(version); 41 | materialListView1.Items.Add(item); 42 | } 43 | } 44 | 45 | private void materialButton1_Click(object sender, EventArgs e) 46 | { 47 | materialSkinManager.Theme = materialSkinManager.Theme == MaterialSkinManager.Themes.DARK ? MaterialSkinManager.Themes.LIGHT : MaterialSkinManager.Themes.DARK; 48 | } 49 | 50 | private int colorSchemeIndex; 51 | private void materialRaisedButton1_Click(object sender, EventArgs e) 52 | { 53 | colorSchemeIndex++; 54 | if (colorSchemeIndex > 2) colorSchemeIndex = 0; 55 | 56 | //These are just example color schemes 57 | switch (colorSchemeIndex) 58 | { 59 | case 0: 60 | materialSkinManager.ColorScheme = new ColorScheme(Primary.BlueGrey800, Primary.BlueGrey900, Primary.BlueGrey500, Accent.LightBlue200, TextShade.WHITE); 61 | break; 62 | case 1: 63 | materialSkinManager.ColorScheme = new ColorScheme(Primary.Indigo500, Primary.Indigo700, Primary.Indigo100, Accent.Pink200, TextShade.WHITE); 64 | break; 65 | case 2: 66 | materialSkinManager.ColorScheme = new ColorScheme(Primary.Green600, Primary.Green700, Primary.Green200, Accent.Red100, TextShade.WHITE); 67 | break; 68 | } 69 | } 70 | 71 | private void materialRaisedButton2_Click(object sender, EventArgs e) 72 | { 73 | materialProgressBar1.Value = Math.Min(materialProgressBar1.Value + 10, 100); 74 | } 75 | 76 | private void materialFlatButton4_Click(object sender, EventArgs e) 77 | { 78 | materialProgressBar1.Value = Math.Max(materialProgressBar1.Value - 10, 0); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /MaterialSkin/Controls/MaterialProgressBar.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Windows.Forms; 3 | 4 | namespace MaterialSkin.Controls 5 | { 6 | /// 7 | /// Material design-like progress bar 8 | /// 9 | public class MaterialProgressBar : ProgressBar, IMaterialControl 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | public MaterialProgressBar() 15 | { 16 | SetStyle(ControlStyles.UserPaint, true); 17 | SetStyle(ControlStyles.OptimizedDoubleBuffer, true); 18 | } 19 | 20 | /// 21 | /// Gets or sets the depth. 22 | /// 23 | /// 24 | /// The depth. 25 | /// 26 | [Browsable(false)] 27 | public int Depth { get; set; } 28 | 29 | /// 30 | /// Gets the skin manager. 31 | /// 32 | /// 33 | /// The skin manager. 34 | /// 35 | [Browsable(false)] 36 | public MaterialSkinManager SkinManager => MaterialSkinManager.Instance; 37 | 38 | /// 39 | /// Gets or sets the state of the mouse. 40 | /// 41 | /// 42 | /// The state of the mouse. 43 | /// 44 | [Browsable(false)] 45 | public MouseState MouseState { get; set; } 46 | 47 | /// 48 | /// Performs the work of setting the specified bounds of this control. 49 | /// 50 | /// The new property value of the control. 51 | /// The new property value of the control. 52 | /// The new property value of the control. 53 | /// The new property value of the control. 54 | /// A bitwise combination of the values. 55 | protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) 56 | { 57 | base.SetBoundsCore(x, y, width, 5, specified); 58 | } 59 | 60 | /// 61 | /// Raises the event. 62 | /// 63 | /// A that contains the event data. 64 | protected override void OnPaint(PaintEventArgs e) 65 | { 66 | var doneProgress = (int)(e.ClipRectangle.Width * ((double)Value / Maximum)); 67 | e.Graphics.FillRectangle(SkinManager.ColorScheme.PrimaryBrush, 0, 0, doneProgress, e.ClipRectangle.Height); 68 | e.Graphics.FillRectangle(SkinManager.GetDisabledOrHintBrush(), doneProgress, 0, e.ClipRectangle.Width, e.ClipRectangle.Height); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /MaterialSkin/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace MaterialSkin.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MaterialSkin.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Byte[]. 65 | /// 66 | internal static byte[] Roboto_Medium { 67 | get { 68 | object obj = ResourceManager.GetObject("Roboto_Medium", resourceCulture); 69 | return ((byte[])(obj)); 70 | } 71 | } 72 | 73 | /// 74 | /// Looks up a localized resource of type System.Byte[]. 75 | /// 76 | internal static byte[] Roboto_Regular { 77 | get { 78 | object obj = ResourceManager.GetObject("Roboto_Regular", resourceCulture); 79 | return ((byte[])(obj)); 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # Roslyn cache directories 20 | *.ide/ 21 | 22 | # MSTest test Results 23 | [Tt]est[Rr]esult*/ 24 | [Bb]uild[Ll]og.* 25 | 26 | #NUNIT 27 | *.VisualState.xml 28 | TestResult.xml 29 | 30 | # Build Results of an ATL Project 31 | [Dd]ebugPS/ 32 | [Rr]eleasePS/ 33 | dlldata.c 34 | 35 | *_i.c 36 | *_p.c 37 | *_i.h 38 | *.ilk 39 | *.meta 40 | *.obj 41 | *.pch 42 | *.pdb 43 | *.pgc 44 | *.pgd 45 | *.rsp 46 | *.sbr 47 | *.tlb 48 | *.tli 49 | *.tlh 50 | *.tmp 51 | *.tmp_proj 52 | *.log 53 | *.vspscc 54 | *.vssscc 55 | .builds 56 | *.pidb 57 | *.svclog 58 | *.scc 59 | 60 | # Chutzpah Test files 61 | _Chutzpah* 62 | 63 | # Visual C++ cache files 64 | ipch/ 65 | *.aps 66 | *.ncb 67 | *.opensdf 68 | *.sdf 69 | *.cachefile 70 | 71 | # Visual Studio profiler 72 | *.psess 73 | *.vsp 74 | *.vspx 75 | 76 | # TFS 2012 Local Workspace 77 | $tf/ 78 | 79 | # Guidance Automation Toolkit 80 | *.gpState 81 | 82 | # ReSharper is a .NET coding add-in 83 | _ReSharper*/ 84 | *.[Rr]e[Ss]harper 85 | *.DotSettings.user 86 | 87 | # JustCode is a .NET coding addin-in 88 | .JustCode 89 | 90 | # TeamCity is a build add-in 91 | _TeamCity* 92 | 93 | # DotCover is a Code Coverage Tool 94 | *.dotCover 95 | 96 | # NCrunch 97 | _NCrunch_* 98 | .*crunch*.local.xml 99 | 100 | # MightyMoose 101 | *.mm.* 102 | AutoTest.Net/ 103 | 104 | # Web workbench (sass) 105 | .sass-cache/ 106 | 107 | # Installshield output folder 108 | [Ee]xpress/ 109 | 110 | # DocProject is a documentation generator add-in 111 | DocProject/buildhelp/ 112 | DocProject/Help/*.HxT 113 | DocProject/Help/*.HxC 114 | DocProject/Help/*.hhc 115 | DocProject/Help/*.hhk 116 | DocProject/Help/*.hhp 117 | DocProject/Help/Html2 118 | DocProject/Help/html 119 | 120 | # Click-Once directory 121 | publish/ 122 | 123 | # Publish Web Output 124 | *.[Pp]ublish.xml 125 | *.azurePubxml 126 | ## TODO: Comment the next line if you want to checkin your 127 | ## web deploy settings but do note that will include unencrypted 128 | ## passwords 129 | #*.pubxml 130 | 131 | # NuGet Packages Directory 132 | packages/* 133 | ## TODO: If the tool you use requires repositories.config 134 | ## uncomment the next line 135 | #!packages/repositories.config 136 | 137 | # Enable "build/" folder in the NuGet Packages folder since 138 | # NuGet packages use it for MSBuild targets. 139 | # This line needs to be after the ignore of the build folder 140 | # (and the packages folder if the line above has been uncommented) 141 | !packages/build/ 142 | 143 | # Windows Azure Build Output 144 | csx/ 145 | *.build.csdef 146 | 147 | # Windows Store app package directory 148 | AppPackages/ 149 | 150 | # Others 151 | sql/ 152 | *.Cache 153 | ClientBin/ 154 | [Ss]tyle[Cc]op.* 155 | ~$* 156 | *~ 157 | *.dbmdl 158 | *.dbproj.schemaview 159 | *.pfx 160 | *.publishsettings 161 | node_modules/ 162 | 163 | # RIA/Silverlight projects 164 | Generated_Code/ 165 | 166 | # Backup & report files from converting an old project file 167 | # to a newer Visual Studio version. Backup files are not needed, 168 | # because we have git ;-) 169 | _UpgradeReport_Files/ 170 | Backup*/ 171 | UpgradeLog*.XML 172 | UpgradeLog*.htm 173 | 174 | # SQL Server files 175 | *.mdf 176 | *.ldf 177 | 178 | # Business Intelligence projects 179 | *.rdl.data 180 | *.bim.layout 181 | *.bim_*.settings 182 | 183 | # Microsoft Fakes 184 | FakesAssemblies/ 185 | 186 | # LightSwitch generated files 187 | GeneratedArtifacts/ 188 | _Pvt_Extensions/ 189 | ModelManifest.xml -------------------------------------------------------------------------------- /MaterialSkinExample/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace MaterialSkinExample.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MaterialSkinExample.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Drawing.Bitmap. 65 | /// 66 | internal static System.Drawing.Bitmap minus { 67 | get { 68 | object obj = ResourceManager.GetObject("minus", resourceCulture); 69 | return ((System.Drawing.Bitmap)(obj)); 70 | } 71 | } 72 | 73 | /// 74 | /// Looks up a localized resource of type System.Drawing.Bitmap. 75 | /// 76 | internal static System.Drawing.Bitmap plus { 77 | get { 78 | object obj = ResourceManager.GetObject("plus", resourceCulture); 79 | return ((System.Drawing.Bitmap)(obj)); 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /MaterialSkinExample/MaterialSkinExample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {47409AA5-62AE-4189-8E83-C471502DF5E9} 8 | WinExe 9 | Properties 10 | MaterialSkinExample 11 | MaterialSkinExample 12 | v4.6.1 13 | 512 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | Form 44 | 45 | 46 | MainForm.cs 47 | 48 | 49 | 50 | 51 | MainForm.cs 52 | 53 | 54 | ResXFileCodeGenerator 55 | Resources.Designer.cs 56 | Designer 57 | 58 | 59 | True 60 | Resources.resx 61 | True 62 | 63 | 64 | SettingsSingleFileGenerator 65 | Settings.Designer.cs 66 | 67 | 68 | True 69 | Settings.settings 70 | True 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | {8eb7611b-68cd-4b8b-987a-11717e2b250c} 79 | MaterialSkin 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 96 | -------------------------------------------------------------------------------- /MaterialSkin/MaterialSkin.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {8EB7611B-68CD-4B8B-987A-11717E2B250C} 8 | Library 9 | Properties 10 | MaterialSkin 11 | MaterialSkin 12 | v4.6.1 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | Component 46 | 47 | 48 | Component 49 | 50 | 51 | Component 52 | 53 | 54 | Component 55 | 56 | 57 | Form 58 | 59 | 60 | Component 61 | 62 | 63 | Component 64 | 65 | 66 | Component 67 | 68 | 69 | Component 70 | 71 | 72 | Component 73 | 74 | 75 | Component 76 | 77 | 78 | Component 79 | 80 | 81 | 82 | 83 | Component 84 | 85 | 86 | 87 | 88 | True 89 | True 90 | Resources.resx 91 | 92 | 93 | 94 | 95 | ResXFileCodeGenerator 96 | Resources.Designer.cs 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 113 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MaterialSkin for .NET WinForms 2 | ===================== 3 | 4 | Theming .NET WinForms, C# or VB.Net, to Google's Material Design Principles. 5 | 6 | ![alt tag](http://i.imgur.com/JAttoOo.png) 7 | 8 | *High quality images can be found at the bottom of this page.* 9 | 10 | --- 11 | 12 | #### Current state of the MaterialSkin components 13 | Component | Supported | Dark & light version | Disabled mode | Animated 14 | --- | --- | --- | --- | --- 15 | Checkbox | Yes | Yes | Yes | Yes 16 | Divider | Yes | Yes | N/A | N/A 17 | Flat Button | Yes | Yes | Yes | Yes 18 | Label | Yes | Yes | N/A | N/A 19 | Radio Button | Yes | Yes | Yes | Yes 20 | Raised Button | Yes | Yes | Yes | Yes 21 | Single-line text field | Yes | Yes | No | Yes 22 | TabControl | Yes | N/A | N/A | Yes 23 | ContextMenuStrip | Yes | Yes | Yes | Yes 24 | ListView | Yes | Yes | No | No 25 | ProgressBar | Yes | Yes | No | No 26 | FloatingActionButton | No | No | No | No 27 | Dialogs | No | No | No | No 28 | Switch | No | No | No | No 29 | More... | No | No | No | No 30 | 31 | --- 32 | 33 | #### Implementing MaterialSkin in your application 34 | 35 | **1. Add the library to your project** 36 | 37 | You can do this on multiple ways. The easiest way would be adding the [NuGet Package](https://www.nuget.org/packages/MaterialSkin/). Right click on your project and click 'Manage NuGet Packages...'. Search for 'MaterialSkin' and click on install. Once installed the library will be included in your project references. (Or install it through the package manager console: PM> Install-Package MaterialSkin) 38 | 39 | Another way of doing this step would be cloning the project from GitHub, compiling the library yourself and adding it as a reference. 40 | 41 | **2. Add the MaterialSkin components to your ToolBox** 42 | 43 | If you have installed the NuGet package, the MaterialSkin.dll file should be in the folder //bin/Debug. Simply drag the MaterialSkin.dll file into your IDE's ToolBox and all the controls should be added there. 44 | 45 | **3. Inherit from MaterialForm** 46 | 47 | Open the code behind your Form you wish to skin. Make it inherit from MaterialForm rather than Form. Don't forget to put the library in your imports, so it can find the MaterialForm class! 48 | 49 | C# (Form1.cs) 50 | ```cs 51 | public partial class Form1 : MaterialForm 52 | ``` 53 | 54 | VB.NET (Form1.Designer.vb) 55 | ```vb 56 | Partial Class Form1 57 | Inherits MaterialSkin.Controls.MaterialForm 58 | ``` 59 | 60 | **4. Initialize your colorscheme** 61 | 62 | Set your preferred colors & theme. Also add the form to the manager so it keeps updated if the color scheme or theme changes later on. 63 | 64 | C# (Form1.cs) 65 | ```cs 66 | public Form1() 67 | { 68 | InitializeComponent(); 69 | 70 | var materialSkinManager = MaterialSkinManager.Instance; 71 | materialSkinManager.AddFormToManage(this); 72 | materialSkinManager.Theme = MaterialSkinManager.Themes.LIGHT; 73 | materialSkinManager.ColorScheme = new ColorScheme(Primary.BlueGrey800, Primary.BlueGrey900, Primary.BlueGrey500, Accent.LightBlue200, TextShade.WHITE); 74 | } 75 | ``` 76 | 77 | VB.NET (Form1.vb) 78 | ```vb 79 | Imports MaterialSkin 80 | 81 | Public Class Form1 82 | 83 | Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 84 | Dim SkinManager As MaterialSkinManager = MaterialSkinManager.Instance 85 | SkinManager.AddFormToManage(Me) 86 | SkinManager.Theme = MaterialSkinManager.Themes.LIGHT 87 | SkinManager.ColorScheme = New ColorScheme(Primary.BlueGrey800, Primary.BlueGrey900, Primary.BlueGrey500, Accent.LightBlue200, TextShade.WHITE) 88 | End Sub 89 | End Class 90 | ``` 91 | 92 | --- 93 | 94 | #### Material Design in WPF 95 | 96 | If you love .NET and Material Design, you should definitely check out [Material Design Xaml Toolkit](https://github.com/ButchersBoy/MaterialDesignInXamlToolkit) by ButchersBoy. It's a similar project but for WPF instead of WinForms. 97 | 98 | --- 99 | 100 | 101 | #### State of the project 102 | 103 | This project is no longer under active development. Though, contributions are still welcome and the community will likely still help if you open an issue. 104 | 105 | --- 106 | 107 | #### Contact 108 | 109 | If you wish to contact me for anything you can get in touch at: 110 | 111 | - Twitter: https://twitter.com/Ignace_Maes 112 | - Personal Website: http://ignacemaes.com 113 | 114 | --- 115 | 116 | #### Images 117 | 118 | ![alt tag](http://i.imgur.com/Ub0N9Xf.png) 119 | 120 | *A simple demo interface with MaterialSkin components.* 121 | 122 | ![alt tag](http://i.imgur.com/eIAtRkc.png) 123 | 124 | *The MaterialSkin checkboxes.* 125 | 126 | ![alt tag](http://i.imgur.com/sAPyvdH.png) 127 | 128 | *The MaterialSkin radiobuttons.* 129 | 130 | ![alt tag](http://i.imgur.com/3Zpuv6x.png) 131 | 132 | *The MaterialSkin ListView.* 133 | 134 | ![alt tag](http://i.imgur.com/07MrJZQ.png) 135 | 136 | *MaterialSkin using a custom color scheme.* 137 | -------------------------------------------------------------------------------- /MaterialSkin/Controls/MaterialMenuStrip.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Drawing.Drawing2D; 5 | using System.Drawing.Text; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace MaterialSkin.Controls 12 | { 13 | public class MaterialMenuStrip : MenuStrip, IMaterialControl 14 | { 15 | public int Depth { get; set; } 16 | public MaterialSkinManager SkinManager { get { return MaterialSkinManager.Instance; } } 17 | public MouseState MouseState { get; set; } 18 | 19 | public MaterialMenuStrip() 20 | { 21 | Renderer = new MaterialMenuStripRender(); 22 | 23 | if (DesignMode) 24 | { 25 | Dock = DockStyle.None; 26 | Anchor |= AnchorStyles.Right; 27 | AutoSize = false; 28 | Location = new Point(0, 28); 29 | } 30 | } 31 | 32 | protected override void OnCreateControl() 33 | { 34 | base.OnCreateControl(); 35 | Font = SkinManager.ROBOTO_MEDIUM_10; 36 | BackColor = SkinManager.PrimaryColor; 37 | } 38 | } 39 | 40 | internal class MaterialMenuStripRender : ToolStripProfessionalRenderer, IMaterialControl 41 | { 42 | //Properties for managing the material design properties 43 | public int Depth { get; set; } 44 | public MaterialSkinManager SkinManager { get { return MaterialSkinManager.Instance; } } 45 | public MouseState MouseState { get; set; } 46 | 47 | protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e) 48 | { 49 | var g = e.Graphics; 50 | g.TextRenderingHint = TextRenderingHint.AntiAlias; 51 | 52 | if (e.Item.IsOnDropDown) 53 | { 54 | var itemRect = GetItemRect(e.Item); 55 | var textRect = new Rectangle(24, itemRect.Y, itemRect.Width - (24 + 16), itemRect.Height); 56 | g.DrawString(e.Text, SkinManager.ROBOTO_MEDIUM_10, e.Item.Enabled ? SkinManager.GetMainTextBrush() : SkinManager.GetDisabledOrHintBrush(), textRect, new StringFormat() { LineAlignment = StringAlignment.Center }); 57 | } 58 | else 59 | { 60 | g.DrawString(e.Text, SkinManager.ROBOTO_MEDIUM_10, Brushes.White, e.TextRectangle, new StringFormat() { LineAlignment = StringAlignment.Center }); 61 | } 62 | } 63 | 64 | protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e) 65 | { 66 | var g = e.Graphics; 67 | g.Clear(SkinManager.PrimaryColor); 68 | 69 | //Draw background 70 | var itemRect = GetItemRect(e.Item); 71 | if (e.Item.IsOnDropDown) 72 | { 73 | g.FillRectangle(e.Item.Selected && e.Item.Enabled ? SkinManager.GetCmsSelectedItemBrush() : new SolidBrush(SkinManager.GetApplicationBackgroundColor()), itemRect); 74 | } 75 | else 76 | { 77 | g.FillRectangle(e.Item.Selected ? SkinManager.GetFlatButtonPressedBackgroundBrush() : SkinManager.PrimaryColorBrush, itemRect); 78 | } 79 | 80 | //Ripple animation 81 | var toolStrip = e.ToolStrip as MaterialContextMenuStrip; 82 | if (toolStrip != null) 83 | { 84 | var animationManager = toolStrip.animationManager; 85 | var animationSource = toolStrip.animationSource; 86 | if (toolStrip.animationManager.IsAnimating() && e.Item.Bounds.Contains(animationSource)) 87 | { 88 | for (int i = 0; i < animationManager.GetAnimationCount(); i++) 89 | { 90 | var animationValue = animationManager.GetProgress(i); 91 | var rippleBrush = new SolidBrush(Color.FromArgb((int)(51 - (animationValue * 50)), Color.Black)); 92 | var rippleSize = (int)(animationValue * itemRect.Width * 2.5); 93 | g.FillEllipse(rippleBrush, new Rectangle(animationSource.X - rippleSize / 2, itemRect.Y - itemRect.Height, rippleSize, itemRect.Height * 3)); 94 | } 95 | } 96 | } 97 | } 98 | 99 | protected override void OnRenderImageMargin(ToolStripRenderEventArgs e) 100 | { 101 | //base.OnRenderImageMargin(e); 102 | } 103 | 104 | protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e) 105 | { 106 | var g = e.Graphics; 107 | 108 | g.FillRectangle(new SolidBrush(SkinManager.GetApplicationBackgroundColor()), e.Item.Bounds); 109 | 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)); 110 | } 111 | 112 | protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e) 113 | { 114 | //var g = e.Graphics; 115 | 116 | //g.DrawRectangle(new Pen(SkinManager.GetDividersColor()), new Rectangle(e.AffectedBounds.X, e.AffectedBounds.Y, e.AffectedBounds.Width - 1, e.AffectedBounds.Height - 1)); 117 | } 118 | 119 | protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e) 120 | { 121 | var g = e.Graphics; 122 | const int ARROW_SIZE = 4; 123 | 124 | var arrowMiddle = new Point(e.ArrowRectangle.X + e.ArrowRectangle.Width / 2, e.ArrowRectangle.Y + e.ArrowRectangle.Height / 2); 125 | var arrowBrush = e.Item.Enabled ? SkinManager.GetMainTextBrush() : SkinManager.GetDisabledOrHintBrush(); 126 | using (var arrowPath = new GraphicsPath()) 127 | { 128 | 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) }); 129 | arrowPath.CloseFigure(); 130 | 131 | g.FillPath(arrowBrush, arrowPath); 132 | } 133 | } 134 | 135 | private Rectangle GetItemRect(ToolStripItem item) 136 | { 137 | return new Rectangle(0, item.ContentRectangle.Y, item.ContentRectangle.Width + 4, item.ContentRectangle.Height); 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /MaterialSkin/Controls/MaterialRaisedButton.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Drawing; 3 | using System.Drawing.Drawing2D; 4 | using System.Drawing.Text; 5 | using System.Windows.Forms; 6 | using MaterialSkin.Animations; 7 | using System; 8 | 9 | namespace MaterialSkin.Controls 10 | { 11 | public class MaterialRaisedButton : Button, IMaterialControl 12 | { 13 | [Browsable(false)] 14 | public int Depth { get; set; } 15 | [Browsable(false)] 16 | public MaterialSkinManager SkinManager => MaterialSkinManager.Instance; 17 | [Browsable(false)] 18 | public MouseState MouseState { get; set; } 19 | public bool Primary { get; set; } 20 | 21 | private readonly AnimationManager _animationManager; 22 | 23 | private SizeF _textSize; 24 | 25 | private Image _icon; 26 | public Image Icon 27 | { 28 | get { return _icon; } 29 | set 30 | { 31 | _icon = value; 32 | if (AutoSize) 33 | Size = GetPreferredSize(); 34 | Invalidate(); 35 | } 36 | } 37 | 38 | public MaterialRaisedButton() 39 | { 40 | Primary = true; 41 | 42 | _animationManager = new AnimationManager(false) 43 | { 44 | Increment = 0.03, 45 | AnimationType = AnimationType.EaseOut 46 | }; 47 | _animationManager.OnAnimationProgress += sender => Invalidate(); 48 | 49 | AutoSizeMode = AutoSizeMode.GrowAndShrink; 50 | AutoSize = true; 51 | } 52 | 53 | public override string Text 54 | { 55 | get { return base.Text; } 56 | set 57 | { 58 | base.Text = value; 59 | _textSize = CreateGraphics().MeasureString(value.ToUpper(), SkinManager.ROBOTO_MEDIUM_10); 60 | if (AutoSize) 61 | Size = GetPreferredSize(); 62 | Invalidate(); 63 | } 64 | } 65 | 66 | protected override void OnMouseUp(MouseEventArgs mevent) 67 | { 68 | base.OnMouseUp(mevent); 69 | 70 | _animationManager.StartNewAnimation(AnimationDirection.In, mevent.Location); 71 | } 72 | 73 | protected override void OnPaint(PaintEventArgs pevent) 74 | { 75 | var g = pevent.Graphics; 76 | g.SmoothingMode = SmoothingMode.AntiAlias; 77 | g.TextRenderingHint = TextRenderingHint.AntiAlias; 78 | 79 | g.Clear(Parent.BackColor); 80 | 81 | using (var backgroundPath = DrawHelper.CreateRoundRect(ClientRectangle.X, 82 | ClientRectangle.Y, 83 | ClientRectangle.Width - 1, 84 | ClientRectangle.Height - 1, 85 | 1f)) 86 | { 87 | g.FillPath(Primary ? SkinManager.ColorScheme.PrimaryBrush : SkinManager.GetRaisedButtonBackgroundBrush(), backgroundPath); 88 | } 89 | 90 | if (_animationManager.IsAnimating()) 91 | { 92 | for (int i = 0; i < _animationManager.GetAnimationCount(); i++) 93 | { 94 | var animationValue = _animationManager.GetProgress(i); 95 | var animationSource = _animationManager.GetSource(i); 96 | var rippleBrush = new SolidBrush(Color.FromArgb((int)(51 - (animationValue * 50)), Color.White)); 97 | var rippleSize = (int)(animationValue * Width * 2); 98 | g.FillEllipse(rippleBrush, new Rectangle(animationSource.X - rippleSize / 2, animationSource.Y - rippleSize / 2, rippleSize, rippleSize)); 99 | } 100 | } 101 | 102 | //Icon 103 | var iconRect = new Rectangle(8, 6, 24, 24); 104 | 105 | if (string.IsNullOrEmpty(Text)) 106 | // Center Icon 107 | iconRect.X += 2; 108 | 109 | if (Icon != null) 110 | g.DrawImage(Icon, iconRect); 111 | 112 | //Text 113 | var textRect = ClientRectangle; 114 | 115 | if (Icon != null) 116 | { 117 | // 118 | // Resize and move Text container 119 | // 120 | 121 | // First 8: left padding 122 | // 24: icon width 123 | // Second 4: space between Icon and Text 124 | // Third 8: right padding 125 | textRect.Width -= 8 + 24 + 4 + 8; 126 | 127 | // First 8: left padding 128 | // 24: icon width 129 | // Second 4: space between Icon and Text 130 | textRect.X += 8 + 24 + 4; 131 | } 132 | 133 | g.DrawString( 134 | Text.ToUpper(), 135 | SkinManager.ROBOTO_MEDIUM_10, 136 | SkinManager.GetRaisedButtonTextBrush(Primary), 137 | textRect, 138 | new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }); 139 | } 140 | 141 | private Size GetPreferredSize() 142 | { 143 | return GetPreferredSize(new Size(0, 0)); 144 | } 145 | 146 | public override Size GetPreferredSize(Size proposedSize) 147 | { 148 | // Provides extra space for proper padding for content 149 | var extra = 16; 150 | 151 | if (Icon != null) 152 | // 24 is for icon size 153 | // 4 is for the space between icon & text 154 | extra += 24 + 4; 155 | 156 | return new Size((int)Math.Ceiling(_textSize.Width) + extra, 36); 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /MaterialSkin/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\Roboto-Medium.ttf;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 123 | 124 | 125 | ..\Resources\Roboto-Regular.ttf;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 126 | 127 | -------------------------------------------------------------------------------- /MaterialSkinExample/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\minus.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | 125 | ..\Resources\plus.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 126 | 127 | -------------------------------------------------------------------------------- /MaterialSkinExample/MainForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | materialLabel1 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sed enim sodales, eleifend ex non, laoreet est. Praesent rhoncus lorem non nibh tincidunt, in semper nibh faucibus. Vivamus id ullamcorper mi, at venenatis sapien. Suspendisse justo erat, maximus vel viverra et, posuere non odio. Phasellus vitae metus augue. Morbi facilisis neque nec arcu gravida, sagittis fringilla leo dapibus. In eu malesuada metus. 122 | 123 | 124 | 17, 17 125 | 126 | -------------------------------------------------------------------------------- /MaterialSkin/Controls/MaterialListView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Runtime.InteropServices; 5 | using System.Windows.Forms; 6 | 7 | namespace MaterialSkin.Controls 8 | { 9 | public class MaterialListView : ListView, IMaterialControl 10 | { 11 | [Browsable(false)] 12 | public int Depth { get; set; } 13 | [Browsable(false)] 14 | public MaterialSkinManager SkinManager => MaterialSkinManager.Instance; 15 | [Browsable(false)] 16 | public MouseState MouseState { get; set; } 17 | [Browsable(false)] 18 | public Point MouseLocation { get; set; } 19 | [Browsable(false)] 20 | private ListViewItem HoveredItem { get; set; } 21 | 22 | public MaterialListView() 23 | { 24 | GridLines = false; 25 | FullRowSelect = true; 26 | HeaderStyle = ColumnHeaderStyle.Nonclickable; 27 | View = View.Details; 28 | OwnerDraw = true; 29 | ResizeRedraw = true; 30 | BorderStyle = BorderStyle.None; 31 | SetStyle(ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer, true); 32 | 33 | //Fix for hovers, by default it doesn't redraw 34 | //TODO: should only redraw when the hovered line changed, this to reduce unnecessary redraws 35 | MouseLocation = new Point(-1, -1); 36 | MouseState = MouseState.OUT; 37 | MouseEnter += delegate 38 | { 39 | MouseState = MouseState.HOVER; 40 | }; 41 | MouseLeave += delegate 42 | { 43 | MouseState = MouseState.OUT; 44 | MouseLocation = new Point(-1, -1); 45 | HoveredItem = null; 46 | Invalidate(); 47 | }; 48 | MouseDown += delegate { MouseState = MouseState.DOWN; }; 49 | MouseUp += delegate { MouseState = MouseState.HOVER; }; 50 | MouseMove += delegate (object sender, MouseEventArgs args) 51 | { 52 | MouseLocation = args.Location; 53 | var currentHoveredItem = this.GetItemAt(MouseLocation.X, MouseLocation.Y); 54 | if (HoveredItem != currentHoveredItem) 55 | { 56 | HoveredItem = currentHoveredItem; 57 | Invalidate(); 58 | } 59 | }; 60 | } 61 | 62 | protected override void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e) 63 | { 64 | e.Graphics.FillRectangle(new SolidBrush(SkinManager.GetApplicationBackgroundColor()), new Rectangle(e.Bounds.X, e.Bounds.Y, Width, e.Bounds.Height)); 65 | e.Graphics.DrawString(e.Header.Text, 66 | SkinManager.ROBOTO_MEDIUM_10, 67 | SkinManager.GetSecondaryTextBrush(), 68 | new Rectangle(e.Bounds.X + ITEM_PADDING, e.Bounds.Y + ITEM_PADDING, e.Bounds.Width - ITEM_PADDING * 2, e.Bounds.Height - ITEM_PADDING * 2), 69 | getStringFormat()); 70 | } 71 | 72 | private const int ITEM_PADDING = 12; 73 | protected override void OnDrawItem(DrawListViewItemEventArgs e) 74 | { 75 | //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. 76 | var b = new Bitmap(e.Item.Bounds.Width, e.Item.Bounds.Height); 77 | var g = Graphics.FromImage(b); 78 | 79 | //always draw default background 80 | g.FillRectangle(new SolidBrush(SkinManager.GetApplicationBackgroundColor()), new Rectangle(new Point(e.Bounds.X, 0), e.Bounds.Size)); 81 | 82 | if (e.State.HasFlag(ListViewItemStates.Selected)) 83 | { 84 | //selected background 85 | g.FillRectangle(SkinManager.GetFlatButtonPressedBackgroundBrush(), new Rectangle(new Point(e.Bounds.X, 0), e.Bounds.Size)); 86 | } 87 | else if (e.Bounds.Contains(MouseLocation) && MouseState == MouseState.HOVER) 88 | { 89 | //hover background 90 | g.FillRectangle(SkinManager.GetFlatButtonHoverBackgroundBrush(), new Rectangle(new Point(e.Bounds.X, 0), e.Bounds.Size)); 91 | } 92 | 93 | 94 | //Draw separator 95 | g.DrawLine(new Pen(SkinManager.GetDividersColor()), e.Bounds.Left, 0, e.Bounds.Right, 0); 96 | 97 | foreach (ListViewItem.ListViewSubItem subItem in e.Item.SubItems) 98 | { 99 | //Draw text 100 | g.DrawString(subItem.Text, SkinManager.ROBOTO_MEDIUM_10, SkinManager.GetPrimaryTextBrush(), 101 | new Rectangle(subItem.Bounds.X + ITEM_PADDING, ITEM_PADDING, subItem.Bounds.Width - 2 * ITEM_PADDING, subItem.Bounds.Height - 2 * ITEM_PADDING), 102 | getStringFormat()); 103 | } 104 | 105 | e.Graphics.DrawImage((Image)b.Clone(), new Point(0, e.Item.Bounds.Location.Y)); 106 | g.Dispose(); 107 | b.Dispose(); 108 | } 109 | 110 | private StringFormat getStringFormat() 111 | { 112 | return new StringFormat 113 | { 114 | FormatFlags = StringFormatFlags.LineLimit, 115 | Trimming = StringTrimming.EllipsisCharacter, 116 | Alignment = StringAlignment.Near, 117 | LineAlignment = StringAlignment.Center 118 | }; 119 | } 120 | 121 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 122 | public class LogFont 123 | { 124 | public int lfHeight = 0; 125 | public int lfWidth = 0; 126 | public int lfEscapement = 0; 127 | public int lfOrientation = 0; 128 | public int lfWeight = 0; 129 | public byte lfItalic = 0; 130 | public byte lfUnderline = 0; 131 | public byte lfStrikeOut = 0; 132 | public byte lfCharSet = 0; 133 | public byte lfOutPrecision = 0; 134 | public byte lfClipPrecision = 0; 135 | public byte lfQuality = 0; 136 | public byte lfPitchAndFamily = 0; 137 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] 138 | public string lfFaceName = string.Empty; 139 | } 140 | 141 | protected override void OnCreateControl() 142 | { 143 | base.OnCreateControl(); 144 | 145 | // This hack tries to apply the Roboto (24) font to all ListViewItems in this ListView 146 | // It only succeeds if the font is installed on the system. 147 | // Otherwise, a default sans serif font is used. 148 | var roboto24 = new Font(SkinManager.ROBOTO_MEDIUM_12.FontFamily, 24); 149 | var roboto24Logfont = new LogFont(); 150 | roboto24.ToLogFont(roboto24Logfont); 151 | 152 | try 153 | { 154 | // Font.FromLogFont is the method used when drawing ListViewItems. I 'test' it in this safer context to avoid unhandled exceptions later. 155 | Font = Font.FromLogFont(roboto24Logfont); 156 | } 157 | catch (ArgumentException) 158 | { 159 | Font = new Font(FontFamily.GenericSansSerif, 24); 160 | } 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /MaterialSkin/Controls/MaterialFlatButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Drawing.Drawing2D; 5 | using System.Drawing.Text; 6 | using System.Windows.Forms; 7 | using MaterialSkin.Animations; 8 | 9 | namespace MaterialSkin.Controls 10 | { 11 | public class MaterialFlatButton : Button, IMaterialControl 12 | { 13 | [Browsable(false)] 14 | public int Depth { get; set; } 15 | [Browsable(false)] 16 | public MaterialSkinManager SkinManager => MaterialSkinManager.Instance; 17 | [Browsable(false)] 18 | public MouseState MouseState { get; set; } 19 | public bool Primary { get; set; } 20 | 21 | private readonly AnimationManager _animationManager; 22 | private readonly AnimationManager _hoverAnimationManager; 23 | 24 | private SizeF _textSize; 25 | 26 | private Image _icon; 27 | public Image Icon 28 | { 29 | get { return _icon; } 30 | set 31 | { 32 | _icon = value; 33 | if (AutoSize) 34 | Size = GetPreferredSize(); 35 | Invalidate(); 36 | } 37 | } 38 | 39 | public MaterialFlatButton() 40 | { 41 | Primary = false; 42 | 43 | _animationManager = new AnimationManager(false) 44 | { 45 | Increment = 0.03, 46 | AnimationType = AnimationType.EaseOut 47 | }; 48 | _hoverAnimationManager = new AnimationManager 49 | { 50 | Increment = 0.07, 51 | AnimationType = AnimationType.Linear 52 | }; 53 | 54 | _hoverAnimationManager.OnAnimationProgress += sender => Invalidate(); 55 | _animationManager.OnAnimationProgress += sender => Invalidate(); 56 | 57 | AutoSizeMode = AutoSizeMode.GrowAndShrink; 58 | AutoSize = true; 59 | Margin = new Padding(4, 6, 4, 6); 60 | Padding = new Padding(0); 61 | } 62 | 63 | public override string Text 64 | { 65 | get { return base.Text; } 66 | set 67 | { 68 | base.Text = value; 69 | _textSize = CreateGraphics().MeasureString(value.ToUpper(), SkinManager.ROBOTO_MEDIUM_10); 70 | if (AutoSize) 71 | Size = GetPreferredSize(); 72 | Invalidate(); 73 | } 74 | } 75 | 76 | protected override void OnPaint(PaintEventArgs pevent) 77 | { 78 | var g = pevent.Graphics; 79 | g.TextRenderingHint = TextRenderingHint.AntiAlias; 80 | 81 | g.Clear(Parent.BackColor); 82 | 83 | //Hover 84 | Color c = SkinManager.GetFlatButtonHoverBackgroundColor(); 85 | using (Brush b = new SolidBrush(Color.FromArgb((int)(_hoverAnimationManager.GetProgress() * c.A), c.RemoveAlpha()))) 86 | g.FillRectangle(b, ClientRectangle); 87 | 88 | //Ripple 89 | if (_animationManager.IsAnimating()) 90 | { 91 | g.SmoothingMode = SmoothingMode.AntiAlias; 92 | for (var i = 0; i < _animationManager.GetAnimationCount(); i++) 93 | { 94 | var animationValue = _animationManager.GetProgress(i); 95 | var animationSource = _animationManager.GetSource(i); 96 | 97 | using (Brush rippleBrush = new SolidBrush(Color.FromArgb((int)(101 - (animationValue * 100)), Color.Black))) 98 | { 99 | var rippleSize = (int)(animationValue * Width * 2); 100 | g.FillEllipse(rippleBrush, new Rectangle(animationSource.X - rippleSize / 2, animationSource.Y - rippleSize / 2, rippleSize, rippleSize)); 101 | } 102 | } 103 | g.SmoothingMode = SmoothingMode.None; 104 | } 105 | 106 | //Icon 107 | var iconRect = new Rectangle(8, 6, 24, 24); 108 | 109 | if (string.IsNullOrEmpty(Text)) 110 | // Center Icon 111 | iconRect.X += 2; 112 | 113 | if (Icon != null) 114 | g.DrawImage(Icon, iconRect); 115 | 116 | //Text 117 | var textRect = ClientRectangle; 118 | 119 | if (Icon != null) 120 | { 121 | // 122 | // Resize and move Text container 123 | // 124 | 125 | // First 8: left padding 126 | // 24: icon width 127 | // Second 4: space between Icon and Text 128 | // Third 8: right padding 129 | textRect.Width -= 8 + 24 + 4 + 8; 130 | 131 | // First 8: left padding 132 | // 24: icon width 133 | // Second 4: space between Icon and Text 134 | textRect.X += 8 + 24 + 4; 135 | } 136 | 137 | g.DrawString( 138 | Text.ToUpper(), 139 | SkinManager.ROBOTO_MEDIUM_10, 140 | Enabled ? (Primary ? SkinManager.ColorScheme.PrimaryBrush : SkinManager.GetPrimaryTextBrush()) : SkinManager.GetFlatButtonDisabledTextBrush(), 141 | textRect, 142 | new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center } 143 | ); 144 | } 145 | 146 | private Size GetPreferredSize() 147 | { 148 | return GetPreferredSize(new Size(0, 0)); 149 | } 150 | 151 | public override Size GetPreferredSize(Size proposedSize) 152 | { 153 | // Provides extra space for proper padding for content 154 | var extra = 16; 155 | 156 | if (Icon != null) 157 | // 24 is for icon size 158 | // 4 is for the space between icon & text 159 | extra += 24 + 4; 160 | 161 | return new Size((int)Math.Ceiling(_textSize.Width) + extra, 36); 162 | } 163 | 164 | protected override void OnCreateControl() 165 | { 166 | base.OnCreateControl(); 167 | if (DesignMode) return; 168 | 169 | MouseState = MouseState.OUT; 170 | MouseEnter += (sender, args) => 171 | { 172 | MouseState = MouseState.HOVER; 173 | _hoverAnimationManager.StartNewAnimation(AnimationDirection.In); 174 | Invalidate(); 175 | }; 176 | MouseLeave += (sender, args) => 177 | { 178 | MouseState = MouseState.OUT; 179 | _hoverAnimationManager.StartNewAnimation(AnimationDirection.Out); 180 | Invalidate(); 181 | }; 182 | MouseDown += (sender, args) => 183 | { 184 | if (args.Button == MouseButtons.Left) 185 | { 186 | MouseState = MouseState.DOWN; 187 | 188 | _animationManager.StartNewAnimation(AnimationDirection.In, args.Location); 189 | Invalidate(); 190 | } 191 | }; 192 | MouseUp += (sender, args) => 193 | { 194 | MouseState = MouseState.HOVER; 195 | 196 | Invalidate(); 197 | }; 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /MaterialSkin/Controls/MaterialTabSelector.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Drawing.Text; 5 | using System.Windows.Forms; 6 | using MaterialSkin.Animations; 7 | 8 | namespace MaterialSkin.Controls 9 | { 10 | public class MaterialTabSelector : Control, IMaterialControl 11 | { 12 | [Browsable(false)] 13 | public int Depth { get; set; } 14 | [Browsable(false)] 15 | public MaterialSkinManager SkinManager => MaterialSkinManager.Instance; 16 | [Browsable(false)] 17 | public MouseState MouseState { get; set; } 18 | 19 | private MaterialTabControl _baseTabControl; 20 | public MaterialTabControl BaseTabControl 21 | { 22 | get { return _baseTabControl; } 23 | set 24 | { 25 | _baseTabControl = value; 26 | if (_baseTabControl == null) return; 27 | _previousSelectedTabIndex = _baseTabControl.SelectedIndex; 28 | _baseTabControl.Deselected += (sender, args) => 29 | { 30 | _previousSelectedTabIndex = _baseTabControl.SelectedIndex; 31 | }; 32 | _baseTabControl.SelectedIndexChanged += (sender, args) => 33 | { 34 | _animationManager.SetProgress(0); 35 | _animationManager.StartNewAnimation(AnimationDirection.In); 36 | }; 37 | _baseTabControl.ControlAdded += delegate 38 | { 39 | Invalidate(); 40 | }; 41 | _baseTabControl.ControlRemoved += delegate 42 | { 43 | Invalidate(); 44 | }; 45 | } 46 | } 47 | 48 | private int _previousSelectedTabIndex; 49 | private Point _animationSource; 50 | private readonly AnimationManager _animationManager; 51 | 52 | private List _tabRects; 53 | private const int TAB_HEADER_PADDING = 24; 54 | private const int TAB_INDICATOR_HEIGHT = 2; 55 | 56 | public MaterialTabSelector() 57 | { 58 | SetStyle(ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer, true); 59 | Height = 48; 60 | 61 | _animationManager = new AnimationManager 62 | { 63 | AnimationType = AnimationType.EaseOut, 64 | Increment = 0.04 65 | }; 66 | _animationManager.OnAnimationProgress += sender => Invalidate(); 67 | } 68 | 69 | protected override void OnPaint(PaintEventArgs e) 70 | { 71 | var g = e.Graphics; 72 | g.TextRenderingHint = TextRenderingHint.AntiAlias; 73 | 74 | g.Clear(SkinManager.ColorScheme.PrimaryColor); 75 | 76 | if (_baseTabControl == null) return; 77 | 78 | if (!_animationManager.IsAnimating() || _tabRects == null || _tabRects.Count != _baseTabControl.TabCount) 79 | UpdateTabRects(); 80 | 81 | var animationProgress = _animationManager.GetProgress(); 82 | 83 | //Click feedback 84 | if (_animationManager.IsAnimating()) 85 | { 86 | var rippleBrush = new SolidBrush(Color.FromArgb((int)(51 - (animationProgress * 50)), Color.White)); 87 | var rippleSize = (int)(animationProgress * _tabRects[_baseTabControl.SelectedIndex].Width * 1.75); 88 | 89 | g.SetClip(_tabRects[_baseTabControl.SelectedIndex]); 90 | g.FillEllipse(rippleBrush, new Rectangle(_animationSource.X - rippleSize / 2, _animationSource.Y - rippleSize / 2, rippleSize, rippleSize)); 91 | g.ResetClip(); 92 | rippleBrush.Dispose(); 93 | } 94 | 95 | //Draw tab headers 96 | foreach (TabPage tabPage in _baseTabControl.TabPages) 97 | { 98 | var currentTabIndex = _baseTabControl.TabPages.IndexOf(tabPage); 99 | Brush textBrush = new SolidBrush(Color.FromArgb(CalculateTextAlpha(currentTabIndex, animationProgress), SkinManager.ColorScheme.TextColor)); 100 | 101 | g.DrawString(tabPage.Text.ToUpper(), SkinManager.ROBOTO_MEDIUM_10, textBrush, _tabRects[currentTabIndex], new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }); 102 | textBrush.Dispose(); 103 | } 104 | 105 | //Animate tab indicator 106 | var previousSelectedTabIndexIfHasOne = _previousSelectedTabIndex == -1 ? _baseTabControl.SelectedIndex : _previousSelectedTabIndex; 107 | var previousActiveTabRect = _tabRects[previousSelectedTabIndexIfHasOne]; 108 | var activeTabPageRect = _tabRects[_baseTabControl.SelectedIndex]; 109 | 110 | var y = activeTabPageRect.Bottom - 2; 111 | var x = previousActiveTabRect.X + (int)((activeTabPageRect.X - previousActiveTabRect.X) * animationProgress); 112 | var width = previousActiveTabRect.Width + (int)((activeTabPageRect.Width - previousActiveTabRect.Width) * animationProgress); 113 | 114 | g.FillRectangle(SkinManager.ColorScheme.AccentBrush, x, y, width, TAB_INDICATOR_HEIGHT); 115 | } 116 | 117 | private int CalculateTextAlpha(int tabIndex, double animationProgress) 118 | { 119 | int primaryA = SkinManager.ACTION_BAR_TEXT.A; 120 | int secondaryA = SkinManager.ACTION_BAR_TEXT_SECONDARY.A; 121 | 122 | if (tabIndex == _baseTabControl.SelectedIndex && !_animationManager.IsAnimating()) 123 | { 124 | return primaryA; 125 | } 126 | if (tabIndex != _previousSelectedTabIndex && tabIndex != _baseTabControl.SelectedIndex) 127 | { 128 | return secondaryA; 129 | } 130 | if (tabIndex == _previousSelectedTabIndex) 131 | { 132 | return primaryA - (int)((primaryA - secondaryA) * animationProgress); 133 | } 134 | return secondaryA + (int)((primaryA - secondaryA) * animationProgress); 135 | } 136 | 137 | protected override void OnMouseUp(MouseEventArgs e) 138 | { 139 | base.OnMouseUp(e); 140 | 141 | if (_tabRects == null) UpdateTabRects(); 142 | for (var i = 0; i < _tabRects.Count; i++) 143 | { 144 | if (_tabRects[i].Contains(e.Location)) 145 | { 146 | _baseTabControl.SelectedIndex = i; 147 | } 148 | } 149 | 150 | _animationSource = e.Location; 151 | } 152 | 153 | private void UpdateTabRects() 154 | { 155 | _tabRects = new List(); 156 | 157 | //If there isn't a base tab control, the rects shouldn't be calculated 158 | //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 159 | if (_baseTabControl == null || _baseTabControl.TabCount == 0) return; 160 | 161 | //Calculate the bounds of each tab header specified in the base tab control 162 | using (var b = new Bitmap(1, 1)) 163 | { 164 | using (var g = Graphics.FromImage(b)) 165 | { 166 | _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)); 167 | for (int i = 1; i < _baseTabControl.TabPages.Count; i++) 168 | { 169 | _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)); 170 | } 171 | } 172 | } 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /MaterialSkin/Controls/MaterialContextMenuStrip.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Drawing; 3 | using System.Drawing.Drawing2D; 4 | using System.Drawing.Text; 5 | using System.Windows.Forms; 6 | using MaterialSkin.Animations; 7 | 8 | namespace MaterialSkin.Controls 9 | { 10 | public class MaterialContextMenuStrip : ContextMenuStrip, IMaterialControl 11 | { 12 | //Properties for managing the material design properties 13 | [Browsable(false)] 14 | public int Depth { get; set; } 15 | [Browsable(false)] 16 | public MaterialSkinManager SkinManager => MaterialSkinManager.Instance; 17 | [Browsable(false)] 18 | public MouseState MouseState { get; set; } 19 | 20 | 21 | internal AnimationManager AnimationManager; 22 | internal Point AnimationSource; 23 | 24 | public delegate void ItemClickStart(object sender, ToolStripItemClickedEventArgs e); 25 | public event ItemClickStart OnItemClickStart; 26 | 27 | public MaterialContextMenuStrip() 28 | { 29 | Renderer = new MaterialToolStripRender(); 30 | 31 | AnimationManager = new AnimationManager(false) 32 | { 33 | Increment = 0.07, 34 | AnimationType = AnimationType.Linear 35 | }; 36 | AnimationManager.OnAnimationProgress += sender => Invalidate(); 37 | AnimationManager.OnAnimationFinished += sender => OnItemClicked(_delayesArgs); 38 | 39 | BackColor = SkinManager.GetApplicationBackgroundColor(); 40 | } 41 | 42 | protected override void OnMouseUp(MouseEventArgs mea) 43 | { 44 | base.OnMouseUp(mea); 45 | 46 | AnimationSource = mea.Location; 47 | } 48 | 49 | private ToolStripItemClickedEventArgs _delayesArgs; 50 | protected override void OnItemClicked(ToolStripItemClickedEventArgs e) 51 | { 52 | if (e.ClickedItem != null && !(e.ClickedItem is ToolStripSeparator)) 53 | { 54 | if (e == _delayesArgs) 55 | { 56 | //The event has been fired manualy because the args are the ones we saved for delay 57 | base.OnItemClicked(e); 58 | } 59 | else 60 | { 61 | //Interrupt the default on click, saving the args for the delay which is needed to display the animaton 62 | _delayesArgs = e; 63 | 64 | //Fire custom event to trigger actions directly but keep cms open 65 | OnItemClickStart?.Invoke(this, e); 66 | 67 | //Start animation 68 | AnimationManager.StartNewAnimation(AnimationDirection.In); 69 | } 70 | } 71 | } 72 | } 73 | 74 | public class MaterialToolStripMenuItem : ToolStripMenuItem 75 | { 76 | public MaterialToolStripMenuItem() 77 | { 78 | AutoSize = false; 79 | Size = new Size(120, 30); 80 | } 81 | 82 | protected override ToolStripDropDown CreateDefaultDropDown() 83 | { 84 | var baseDropDown = base.CreateDefaultDropDown(); 85 | if (DesignMode) return baseDropDown; 86 | 87 | var defaultDropDown = new MaterialContextMenuStrip(); 88 | defaultDropDown.Items.AddRange(baseDropDown.Items); 89 | 90 | return defaultDropDown; 91 | } 92 | } 93 | 94 | internal class MaterialToolStripRender : ToolStripProfessionalRenderer, IMaterialControl 95 | { 96 | //Properties for managing the material design properties 97 | public int Depth { get; set; } 98 | public MaterialSkinManager SkinManager => MaterialSkinManager.Instance; 99 | public MouseState MouseState { get; set; } 100 | 101 | 102 | protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e) 103 | { 104 | var g = e.Graphics; 105 | g.TextRenderingHint = TextRenderingHint.AntiAlias; 106 | 107 | var itemRect = GetItemRect(e.Item); 108 | var textRect = new Rectangle(24, itemRect.Y, itemRect.Width - (24 + 16), itemRect.Height); 109 | g.DrawString( 110 | e.Text, 111 | SkinManager.ROBOTO_MEDIUM_10, 112 | e.Item.Enabled ? SkinManager.GetPrimaryTextBrush() : SkinManager.GetDisabledOrHintBrush(), 113 | textRect, 114 | new StringFormat { LineAlignment = StringAlignment.Center }); 115 | } 116 | 117 | protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e) 118 | { 119 | var g = e.Graphics; 120 | g.Clear(SkinManager.GetApplicationBackgroundColor()); 121 | 122 | //Draw background 123 | var itemRect = GetItemRect(e.Item); 124 | g.FillRectangle(e.Item.Selected && e.Item.Enabled ? SkinManager.GetCmsSelectedItemBrush() : new SolidBrush(SkinManager.GetApplicationBackgroundColor()), itemRect); 125 | 126 | //Ripple animation 127 | var toolStrip = e.ToolStrip as MaterialContextMenuStrip; 128 | if (toolStrip != null) 129 | { 130 | var animationManager = toolStrip.AnimationManager; 131 | var animationSource = toolStrip.AnimationSource; 132 | if (toolStrip.AnimationManager.IsAnimating() && e.Item.Bounds.Contains(animationSource)) 133 | { 134 | for (int i = 0; i < animationManager.GetAnimationCount(); i++) 135 | { 136 | var animationValue = animationManager.GetProgress(i); 137 | var rippleBrush = new SolidBrush(Color.FromArgb((int)(51 - (animationValue * 50)), Color.Black)); 138 | var rippleSize = (int)(animationValue * itemRect.Width * 2.5); 139 | g.FillEllipse(rippleBrush, new Rectangle(animationSource.X - rippleSize / 2, itemRect.Y - itemRect.Height, rippleSize, itemRect.Height * 3)); 140 | } 141 | } 142 | } 143 | } 144 | 145 | protected override void OnRenderImageMargin(ToolStripRenderEventArgs e) 146 | { 147 | //base.OnRenderImageMargin(e); 148 | } 149 | 150 | protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e) 151 | { 152 | var g = e.Graphics; 153 | 154 | g.FillRectangle(new SolidBrush(SkinManager.GetApplicationBackgroundColor()), e.Item.Bounds); 155 | g.DrawLine( 156 | new Pen(SkinManager.GetDividersColor()), 157 | new Point(e.Item.Bounds.Left, e.Item.Bounds.Height / 2), 158 | new Point(e.Item.Bounds.Right, e.Item.Bounds.Height / 2)); 159 | } 160 | 161 | protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e) 162 | { 163 | var g = e.Graphics; 164 | 165 | g.DrawRectangle( 166 | new Pen(SkinManager.GetDividersColor()), 167 | new Rectangle(e.AffectedBounds.X, e.AffectedBounds.Y, e.AffectedBounds.Width - 1, e.AffectedBounds.Height - 1)); 168 | } 169 | 170 | protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e) 171 | { 172 | var g = e.Graphics; 173 | const int ARROW_SIZE = 4; 174 | 175 | var arrowMiddle = new Point(e.ArrowRectangle.X + e.ArrowRectangle.Width / 2, e.ArrowRectangle.Y + e.ArrowRectangle.Height / 2); 176 | var arrowBrush = e.Item.Enabled ? SkinManager.GetPrimaryTextBrush() : SkinManager.GetDisabledOrHintBrush(); 177 | using (var arrowPath = new GraphicsPath()) 178 | { 179 | arrowPath.AddLines( 180 | new[] { 181 | new Point(arrowMiddle.X - ARROW_SIZE, arrowMiddle.Y - ARROW_SIZE), 182 | new Point(arrowMiddle.X, arrowMiddle.Y), 183 | new Point(arrowMiddle.X - ARROW_SIZE, arrowMiddle.Y + ARROW_SIZE) }); 184 | arrowPath.CloseFigure(); 185 | 186 | g.FillPath(arrowBrush, arrowPath); 187 | } 188 | } 189 | 190 | private Rectangle GetItemRect(ToolStripItem item) 191 | { 192 | return new Rectangle(0, item.ContentRectangle.Y, item.ContentRectangle.Width + 4, item.ContentRectangle.Height); 193 | } 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /MaterialSkin/Controls/MaterialRadioButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Drawing.Drawing2D; 5 | using System.Drawing.Text; 6 | using System.Windows.Forms; 7 | using MaterialSkin.Animations; 8 | 9 | namespace MaterialSkin.Controls 10 | { 11 | public class MaterialRadioButton : RadioButton, IMaterialControl 12 | { 13 | [Browsable(false)] 14 | public int Depth { get; set; } 15 | [Browsable(false)] 16 | public MaterialSkinManager SkinManager => MaterialSkinManager.Instance; 17 | [Browsable(false)] 18 | public MouseState MouseState { get; set; } 19 | [Browsable(false)] 20 | public Point MouseLocation { get; set; } 21 | 22 | private bool ripple; 23 | [Category("Behavior")] 24 | public bool Ripple 25 | { 26 | get { return ripple; } 27 | set 28 | { 29 | ripple = value; 30 | AutoSize = AutoSize; //Make AutoSize directly set the bounds. 31 | 32 | if (value) 33 | { 34 | Margin = new Padding(0); 35 | } 36 | 37 | Invalidate(); 38 | } 39 | } 40 | 41 | // animation managers 42 | private readonly AnimationManager _animationManager; 43 | private readonly AnimationManager _rippleAnimationManager; 44 | 45 | // size related variables which should be recalculated onsizechanged 46 | private Rectangle _radioButtonBounds; 47 | private int _boxOffset; 48 | 49 | // size constants 50 | private const int RADIOBUTTON_SIZE = 19; 51 | private const int RADIOBUTTON_SIZE_HALF = RADIOBUTTON_SIZE / 2; 52 | private const int RADIOBUTTON_OUTER_CIRCLE_WIDTH = 2; 53 | private const int RADIOBUTTON_INNER_CIRCLE_SIZE = RADIOBUTTON_SIZE - (2 * RADIOBUTTON_OUTER_CIRCLE_WIDTH); 54 | 55 | public MaterialRadioButton() 56 | { 57 | SetStyle(ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer, true); 58 | 59 | _animationManager = new AnimationManager 60 | { 61 | AnimationType = AnimationType.EaseInOut, 62 | Increment = 0.06 63 | }; 64 | _rippleAnimationManager = new AnimationManager(false) 65 | { 66 | AnimationType = AnimationType.Linear, 67 | Increment = 0.10, 68 | SecondaryIncrement = 0.08 69 | }; 70 | _animationManager.OnAnimationProgress += sender => Invalidate(); 71 | _rippleAnimationManager.OnAnimationProgress += sender => Invalidate(); 72 | 73 | CheckedChanged += (sender, args) => _animationManager.StartNewAnimation(Checked ? AnimationDirection.In : AnimationDirection.Out); 74 | 75 | SizeChanged += OnSizeChanged; 76 | 77 | Ripple = true; 78 | MouseLocation = new Point(-1, -1); 79 | } 80 | private void OnSizeChanged(object sender, EventArgs eventArgs) 81 | { 82 | _boxOffset = Height / 2 - (int)Math.Ceiling(RADIOBUTTON_SIZE / 2d); 83 | _radioButtonBounds = new Rectangle(_boxOffset, _boxOffset, RADIOBUTTON_SIZE, RADIOBUTTON_SIZE); 84 | } 85 | 86 | public override Size GetPreferredSize(Size proposedSize) 87 | { 88 | var width = _boxOffset + 20 + (int)CreateGraphics().MeasureString(Text, SkinManager.ROBOTO_MEDIUM_10).Width; 89 | return Ripple ? new Size(width, 30) : new Size(width, 20); 90 | } 91 | 92 | protected override void OnPaint(PaintEventArgs pevent) 93 | { 94 | var g = pevent.Graphics; 95 | g.SmoothingMode = SmoothingMode.AntiAlias; 96 | g.TextRenderingHint = TextRenderingHint.AntiAlias; 97 | 98 | // clear the control 99 | g.Clear(Parent.BackColor); 100 | 101 | var RADIOBUTTON_CENTER = _boxOffset + RADIOBUTTON_SIZE_HALF; 102 | 103 | var animationProgress = _animationManager.GetProgress(); 104 | 105 | int colorAlpha = Enabled ? (int)(animationProgress * 255.0) : SkinManager.GetCheckBoxOffDisabledColor().A; 106 | int backgroundAlpha = Enabled ? (int)(SkinManager.GetCheckboxOffColor().A * (1.0 - animationProgress)) : SkinManager.GetCheckBoxOffDisabledColor().A; 107 | float animationSize = (float)(animationProgress * 8f); 108 | float animationSizeHalf = animationSize / 2; 109 | animationSize = (float)(animationProgress * 9f); 110 | 111 | var brush = new SolidBrush(Color.FromArgb(colorAlpha, Enabled ? SkinManager.ColorScheme.AccentColor : SkinManager.GetCheckBoxOffDisabledColor())); 112 | var pen = new Pen(brush.Color); 113 | 114 | // draw ripple animation 115 | if (Ripple && _rippleAnimationManager.IsAnimating()) 116 | { 117 | for (var i = 0; i < _rippleAnimationManager.GetAnimationCount(); i++) 118 | { 119 | var animationValue = _rippleAnimationManager.GetProgress(i); 120 | var animationSource = new Point(RADIOBUTTON_CENTER, RADIOBUTTON_CENTER); 121 | var rippleBrush = new SolidBrush(Color.FromArgb((int)((animationValue * 40)), ((bool)_rippleAnimationManager.GetData(i)[0]) ? Color.Black : brush.Color)); 122 | var rippleHeight = (Height % 2 == 0) ? Height - 3 : Height - 2; 123 | var rippleSize = (_rippleAnimationManager.GetDirection(i) == AnimationDirection.InOutIn) ? (int)(rippleHeight * (0.8d + (0.2d * animationValue))) : rippleHeight; 124 | using (var path = DrawHelper.CreateRoundRect(animationSource.X - rippleSize / 2, animationSource.Y - rippleSize / 2, rippleSize, rippleSize, rippleSize / 2)) 125 | { 126 | g.FillPath(rippleBrush, path); 127 | } 128 | 129 | rippleBrush.Dispose(); 130 | } 131 | } 132 | 133 | // draw radiobutton circle 134 | Color uncheckedColor = DrawHelper.BlendColor(Parent.BackColor, Enabled ? SkinManager.GetCheckboxOffColor() : SkinManager.GetCheckBoxOffDisabledColor(), backgroundAlpha); 135 | 136 | using (var path = DrawHelper.CreateRoundRect(_boxOffset, _boxOffset, RADIOBUTTON_SIZE, RADIOBUTTON_SIZE, 9f)) 137 | { 138 | g.FillPath(new SolidBrush(uncheckedColor), path); 139 | 140 | if (Enabled) 141 | { 142 | g.FillPath(brush, path); 143 | } 144 | } 145 | 146 | g.FillEllipse( 147 | new SolidBrush(Parent.BackColor), 148 | RADIOBUTTON_OUTER_CIRCLE_WIDTH + _boxOffset, 149 | RADIOBUTTON_OUTER_CIRCLE_WIDTH + _boxOffset, 150 | RADIOBUTTON_INNER_CIRCLE_SIZE, 151 | RADIOBUTTON_INNER_CIRCLE_SIZE); 152 | 153 | if (Checked) 154 | { 155 | using (var path = DrawHelper.CreateRoundRect(RADIOBUTTON_CENTER - animationSizeHalf, RADIOBUTTON_CENTER - animationSizeHalf, animationSize, animationSize, 4f)) 156 | { 157 | g.FillPath(brush, path); 158 | } 159 | } 160 | SizeF stringSize = g.MeasureString(Text, SkinManager.ROBOTO_MEDIUM_10); 161 | g.DrawString(Text, SkinManager.ROBOTO_MEDIUM_10, Enabled ? SkinManager.GetPrimaryTextBrush() : SkinManager.GetDisabledOrHintBrush(), _boxOffset + 22, Height / 2 - stringSize.Height / 2); 162 | 163 | brush.Dispose(); 164 | pen.Dispose(); 165 | } 166 | 167 | private bool IsMouseInCheckArea() 168 | { 169 | return _radioButtonBounds.Contains(MouseLocation); 170 | } 171 | 172 | protected override void OnCreateControl() 173 | { 174 | base.OnCreateControl(); 175 | Font = SkinManager.ROBOTO_MEDIUM_10; 176 | 177 | if (DesignMode) return; 178 | 179 | MouseState = MouseState.OUT; 180 | MouseEnter += (sender, args) => 181 | { 182 | MouseState = MouseState.HOVER; 183 | }; 184 | MouseLeave += (sender, args) => 185 | { 186 | MouseLocation = new Point(-1, -1); 187 | MouseState = MouseState.OUT; 188 | }; 189 | MouseDown += (sender, args) => 190 | { 191 | MouseState = MouseState.DOWN; 192 | 193 | if (Ripple && args.Button == MouseButtons.Left && IsMouseInCheckArea()) 194 | { 195 | _rippleAnimationManager.SecondaryIncrement = 0; 196 | _rippleAnimationManager.StartNewAnimation(AnimationDirection.InOutIn, new object[] { Checked }); 197 | } 198 | }; 199 | MouseUp += (sender, args) => 200 | { 201 | MouseState = MouseState.HOVER; 202 | _rippleAnimationManager.SecondaryIncrement = 0.08; 203 | }; 204 | MouseMove += (sender, args) => 205 | { 206 | MouseLocation = args.Location; 207 | Cursor = IsMouseInCheckArea() ? Cursors.Hand : Cursors.Default; 208 | }; 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /MaterialSkin/Controls/MaterialCheckbox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Drawing.Drawing2D; 5 | using System.Drawing.Text; 6 | using System.Windows.Forms; 7 | using MaterialSkin.Animations; 8 | 9 | namespace MaterialSkin.Controls 10 | { 11 | public class MaterialCheckBox : CheckBox, IMaterialControl 12 | { 13 | [Browsable(false)] 14 | public int Depth { get; set; } 15 | [Browsable(false)] 16 | public MaterialSkinManager SkinManager => MaterialSkinManager.Instance; 17 | [Browsable(false)] 18 | public MouseState MouseState { get; set; } 19 | [Browsable(false)] 20 | public Point MouseLocation { get; set; } 21 | 22 | private bool _ripple; 23 | [Category("Behavior")] 24 | public bool Ripple 25 | { 26 | get { return _ripple; } 27 | set 28 | { 29 | _ripple = value; 30 | AutoSize = AutoSize; //Make AutoSize directly set the bounds. 31 | 32 | if (value) 33 | { 34 | Margin = new Padding(0); 35 | } 36 | 37 | Invalidate(); 38 | } 39 | } 40 | 41 | private readonly AnimationManager _animationManager; 42 | private readonly AnimationManager _rippleAnimationManager; 43 | 44 | private const int CHECKBOX_SIZE = 18; 45 | private const int CHECKBOX_SIZE_HALF = CHECKBOX_SIZE / 2; 46 | private const int CHECKBOX_INNER_BOX_SIZE = CHECKBOX_SIZE - 4; 47 | 48 | private int _boxOffset; 49 | private Rectangle _boxRectangle; 50 | 51 | public MaterialCheckBox() 52 | { 53 | _animationManager = new AnimationManager 54 | { 55 | AnimationType = AnimationType.EaseInOut, 56 | Increment = 0.05 57 | }; 58 | _rippleAnimationManager = new AnimationManager(false) 59 | { 60 | AnimationType = AnimationType.Linear, 61 | Increment = 0.10, 62 | SecondaryIncrement = 0.08 63 | }; 64 | _animationManager.OnAnimationProgress += sender => Invalidate(); 65 | _rippleAnimationManager.OnAnimationProgress += sender => Invalidate(); 66 | 67 | CheckedChanged += (sender, args) => 68 | { 69 | _animationManager.StartNewAnimation(Checked ? AnimationDirection.In : AnimationDirection.Out); 70 | }; 71 | 72 | Ripple = true; 73 | MouseLocation = new Point(-1, -1); 74 | } 75 | 76 | protected override void OnSizeChanged(EventArgs e) 77 | { 78 | base.OnSizeChanged(e); 79 | 80 | _boxOffset = Height / 2 - 9; 81 | _boxRectangle = new Rectangle(_boxOffset, _boxOffset, CHECKBOX_SIZE - 1, CHECKBOX_SIZE - 1); 82 | } 83 | 84 | public override Size GetPreferredSize(Size proposedSize) 85 | { 86 | var w = _boxOffset + CHECKBOX_SIZE + 2 + (int)CreateGraphics().MeasureString(Text, SkinManager.ROBOTO_MEDIUM_10).Width; 87 | return Ripple ? new Size(w, 30) : new Size(w, 20); 88 | } 89 | 90 | private static readonly Point[] CheckmarkLine = { new Point(3, 8), new Point(7, 12), new Point(14, 5) }; 91 | private const int TEXT_OFFSET = 22; 92 | protected override void OnPaint(PaintEventArgs pevent) 93 | { 94 | var g = pevent.Graphics; 95 | g.SmoothingMode = SmoothingMode.AntiAlias; 96 | g.TextRenderingHint = TextRenderingHint.AntiAlias; 97 | 98 | // clear the control 99 | g.Clear(Parent.BackColor); 100 | 101 | var CHECKBOX_CENTER = _boxOffset + CHECKBOX_SIZE_HALF - 1; 102 | 103 | var animationProgress = _animationManager.GetProgress(); 104 | 105 | var colorAlpha = Enabled ? (int)(animationProgress * 255.0) : SkinManager.GetCheckBoxOffDisabledColor().A; 106 | var backgroundAlpha = Enabled ? (int)(SkinManager.GetCheckboxOffColor().A * (1.0 - animationProgress)) : SkinManager.GetCheckBoxOffDisabledColor().A; 107 | 108 | var brush = new SolidBrush(Color.FromArgb(colorAlpha, Enabled ? SkinManager.ColorScheme.AccentColor : SkinManager.GetCheckBoxOffDisabledColor())); 109 | var brush3 = new SolidBrush(Enabled ? SkinManager.ColorScheme.AccentColor : SkinManager.GetCheckBoxOffDisabledColor()); 110 | var pen = new Pen(brush.Color); 111 | 112 | // draw ripple animation 113 | if (Ripple && _rippleAnimationManager.IsAnimating()) 114 | { 115 | for (var i = 0; i < _rippleAnimationManager.GetAnimationCount(); i++) 116 | { 117 | var animationValue = _rippleAnimationManager.GetProgress(i); 118 | var animationSource = new Point(CHECKBOX_CENTER, CHECKBOX_CENTER); 119 | var rippleBrush = new SolidBrush(Color.FromArgb((int)((animationValue * 40)), ((bool)_rippleAnimationManager.GetData(i)[0]) ? Color.Black : brush.Color)); 120 | var rippleHeight = (Height % 2 == 0) ? Height - 3 : Height - 2; 121 | var rippleSize = (_rippleAnimationManager.GetDirection(i) == AnimationDirection.InOutIn) ? (int)(rippleHeight * (0.8d + (0.2d * animationValue))) : rippleHeight; 122 | using (var path = DrawHelper.CreateRoundRect(animationSource.X - rippleSize / 2, animationSource.Y - rippleSize / 2, rippleSize, rippleSize, rippleSize / 2)) 123 | { 124 | g.FillPath(rippleBrush, path); 125 | } 126 | 127 | rippleBrush.Dispose(); 128 | } 129 | } 130 | 131 | brush3.Dispose(); 132 | 133 | var checkMarkLineFill = new Rectangle(_boxOffset, _boxOffset, (int)(17.0 * animationProgress), 17); 134 | using (var checkmarkPath = DrawHelper.CreateRoundRect(_boxOffset, _boxOffset, 17, 17, 1f)) 135 | { 136 | var brush2 = new SolidBrush(DrawHelper.BlendColor(Parent.BackColor, Enabled ? SkinManager.GetCheckboxOffColor() : SkinManager.GetCheckBoxOffDisabledColor(), backgroundAlpha)); 137 | var pen2 = new Pen(brush2.Color); 138 | g.FillPath(brush2, checkmarkPath); 139 | g.DrawPath(pen2, checkmarkPath); 140 | 141 | g.FillRectangle(new SolidBrush(Parent.BackColor), _boxOffset + 2, _boxOffset + 2, CHECKBOX_INNER_BOX_SIZE - 1, CHECKBOX_INNER_BOX_SIZE - 1); 142 | g.DrawRectangle(new Pen(Parent.BackColor), _boxOffset + 2, _boxOffset + 2, CHECKBOX_INNER_BOX_SIZE - 1, CHECKBOX_INNER_BOX_SIZE - 1); 143 | 144 | brush2.Dispose(); 145 | pen2.Dispose(); 146 | 147 | if (Enabled) 148 | { 149 | g.FillPath(brush, checkmarkPath); 150 | g.DrawPath(pen, checkmarkPath); 151 | } 152 | else if (Checked) 153 | { 154 | g.SmoothingMode = SmoothingMode.None; 155 | g.FillRectangle(brush, _boxOffset + 2, _boxOffset + 2, CHECKBOX_INNER_BOX_SIZE, CHECKBOX_INNER_BOX_SIZE); 156 | g.SmoothingMode = SmoothingMode.AntiAlias; 157 | } 158 | 159 | g.DrawImageUnscaledAndClipped(DrawCheckMarkBitmap(), checkMarkLineFill); 160 | } 161 | 162 | // draw checkbox text 163 | SizeF stringSize = g.MeasureString(Text, SkinManager.ROBOTO_MEDIUM_10); 164 | g.DrawString( 165 | Text, 166 | SkinManager.ROBOTO_MEDIUM_10, 167 | Enabled ? SkinManager.GetPrimaryTextBrush() : SkinManager.GetDisabledOrHintBrush(), 168 | _boxOffset + TEXT_OFFSET, Height / 2 - stringSize.Height / 2); 169 | 170 | // dispose used paint objects 171 | pen.Dispose(); 172 | brush.Dispose(); 173 | } 174 | 175 | private Bitmap DrawCheckMarkBitmap() 176 | { 177 | var checkMark = new Bitmap(CHECKBOX_SIZE, CHECKBOX_SIZE); 178 | var g = Graphics.FromImage(checkMark); 179 | 180 | // clear everything, transparent 181 | g.Clear(Color.Transparent); 182 | 183 | // draw the checkmark lines 184 | using (var pen = new Pen(Parent.BackColor, 2)) 185 | { 186 | g.DrawLines(pen, CheckmarkLine); 187 | } 188 | 189 | return checkMark; 190 | } 191 | 192 | public override bool AutoSize 193 | { 194 | get { return base.AutoSize; } 195 | set 196 | { 197 | base.AutoSize = value; 198 | if (value) 199 | { 200 | Size = new Size(10, 10); 201 | } 202 | } 203 | } 204 | 205 | private bool IsMouseInCheckArea() 206 | { 207 | return _boxRectangle.Contains(MouseLocation); 208 | } 209 | 210 | protected override void OnCreateControl() 211 | { 212 | base.OnCreateControl(); 213 | Font = SkinManager.ROBOTO_MEDIUM_10; 214 | 215 | if (DesignMode) return; 216 | 217 | MouseState = MouseState.OUT; 218 | MouseEnter += (sender, args) => 219 | { 220 | MouseState = MouseState.HOVER; 221 | }; 222 | MouseLeave += (sender, args) => 223 | { 224 | MouseLocation = new Point(-1, -1); 225 | MouseState = MouseState.OUT; 226 | }; 227 | MouseDown += (sender, args) => 228 | { 229 | MouseState = MouseState.DOWN; 230 | 231 | if (Ripple && args.Button == MouseButtons.Left && IsMouseInCheckArea()) 232 | { 233 | _rippleAnimationManager.SecondaryIncrement = 0; 234 | _rippleAnimationManager.StartNewAnimation(AnimationDirection.InOutIn, new object[] { Checked }); 235 | } 236 | }; 237 | MouseUp += (sender, args) => 238 | { 239 | MouseState = MouseState.HOVER; 240 | _rippleAnimationManager.SecondaryIncrement = 0.08; 241 | }; 242 | MouseMove += (sender, args) => 243 | { 244 | MouseLocation = args.Location; 245 | Cursor = IsMouseInCheckArea() ? Cursors.Hand : Cursors.Default; 246 | }; 247 | } 248 | 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /MaterialSkin/ColorScheme.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | 3 | namespace MaterialSkin 4 | { 5 | public class ColorScheme 6 | { 7 | public readonly Color PrimaryColor, DarkPrimaryColor, LightPrimaryColor, AccentColor, TextColor; 8 | public readonly Pen PrimaryPen, DarkPrimaryPen, LightPrimaryPen, AccentPen, TextPen; 9 | public readonly Brush PrimaryBrush, DarkPrimaryBrush, LightPrimaryBrush, AccentBrush, TextBrush; 10 | 11 | /// 12 | /// Defines the Color Scheme to be used for all forms. 13 | /// 14 | /// The primary color, a -500 color is suggested here. 15 | /// A darker version of the primary color, a -700 color is suggested here. 16 | /// A lighter version of the primary color, a -100 color is suggested here. 17 | /// The accent color, a -200 color is suggested here. 18 | /// The text color, the one with the highest contrast is suggested. 19 | public ColorScheme(Primary primary, Primary darkPrimary, Primary lightPrimary, Accent accent, TextShade textShade) 20 | { 21 | //Color 22 | PrimaryColor = ((int)primary).ToColor(); 23 | DarkPrimaryColor = ((int)darkPrimary).ToColor(); 24 | LightPrimaryColor = ((int)lightPrimary).ToColor(); 25 | AccentColor = ((int)accent).ToColor(); 26 | TextColor = ((int)textShade).ToColor(); 27 | 28 | //Pen 29 | PrimaryPen = new Pen(PrimaryColor); 30 | DarkPrimaryPen = new Pen(DarkPrimaryColor); 31 | LightPrimaryPen = new Pen(LightPrimaryColor); 32 | AccentPen = new Pen(AccentColor); 33 | TextPen = new Pen(TextColor); 34 | 35 | //Brush 36 | PrimaryBrush = new SolidBrush(PrimaryColor); 37 | DarkPrimaryBrush = new SolidBrush(DarkPrimaryColor); 38 | LightPrimaryBrush = new SolidBrush(LightPrimaryColor); 39 | AccentBrush = new SolidBrush(AccentColor); 40 | TextBrush = new SolidBrush(TextColor); 41 | } 42 | } 43 | 44 | public static class ColorExtension 45 | { 46 | /// 47 | /// Convert an integer number to a Color. 48 | /// 49 | /// 50 | public static Color ToColor(this int argb) 51 | { 52 | return Color.FromArgb( 53 | (argb & 0xff0000) >> 16, 54 | (argb & 0xff00) >> 8, 55 | argb & 0xff); 56 | } 57 | 58 | /// 59 | /// Removes the alpha component of a color. 60 | /// 61 | /// 62 | /// 63 | public static Color RemoveAlpha(this Color color) 64 | { 65 | return Color.FromArgb(color.R, color.G, color.B); 66 | } 67 | 68 | /// 69 | /// Converts a 0-100 integer to a 0-255 color component. 70 | /// 71 | /// 72 | /// 73 | public static int PercentageToColorComponent(this int percentage) 74 | { 75 | return (int)((percentage / 100d) * 255d); 76 | } 77 | } 78 | 79 | //Color constantes 80 | public enum TextShade 81 | { 82 | WHITE = 0xFFFFFF, 83 | BLACK = 0x212121 84 | } 85 | 86 | public enum Primary 87 | { 88 | Red50 = 0xFFEBEE, 89 | Red100 = 0xFFCDD2, 90 | Red200 = 0xEF9A9A, 91 | Red300 = 0xE57373, 92 | Red400 = 0xEF5350, 93 | Red500 = 0xF44336, 94 | Red600 = 0xE53935, 95 | Red700 = 0xD32F2F, 96 | Red800 = 0xC62828, 97 | Red900 = 0xB71C1C, 98 | Pink50 = 0xFCE4EC, 99 | Pink100 = 0xF8BBD0, 100 | Pink200 = 0xF48FB1, 101 | Pink300 = 0xF06292, 102 | Pink400 = 0xEC407A, 103 | Pink500 = 0xE91E63, 104 | Pink600 = 0xD81B60, 105 | Pink700 = 0xC2185B, 106 | Pink800 = 0xAD1457, 107 | Pink900 = 0x880E4F, 108 | Purple50 = 0xF3E5F5, 109 | Purple100 = 0xE1BEE7, 110 | Purple200 = 0xCE93D8, 111 | Purple300 = 0xBA68C8, 112 | Purple400 = 0xAB47BC, 113 | Purple500 = 0x9C27B0, 114 | Purple600 = 0x8E24AA, 115 | Purple700 = 0x7B1FA2, 116 | Purple800 = 0x6A1B9A, 117 | Purple900 = 0x4A148C, 118 | DeepPurple50 = 0xEDE7F6, 119 | DeepPurple100 = 0xD1C4E9, 120 | DeepPurple200 = 0xB39DDB, 121 | DeepPurple300 = 0x9575CD, 122 | DeepPurple400 = 0x7E57C2, 123 | DeepPurple500 = 0x673AB7, 124 | DeepPurple600 = 0x5E35B1, 125 | DeepPurple700 = 0x512DA8, 126 | DeepPurple800 = 0x4527A0, 127 | DeepPurple900 = 0x311B92, 128 | Indigo50 = 0xE8EAF6, 129 | Indigo100 = 0xC5CAE9, 130 | Indigo200 = 0x9FA8DA, 131 | Indigo300 = 0x7986CB, 132 | Indigo400 = 0x5C6BC0, 133 | Indigo500 = 0x3F51B5, 134 | Indigo600 = 0x3949AB, 135 | Indigo700 = 0x303F9F, 136 | Indigo800 = 0x283593, 137 | Indigo900 = 0x1A237E, 138 | Blue50 = 0xE3F2FD, 139 | Blue100 = 0xBBDEFB, 140 | Blue200 = 0x90CAF9, 141 | Blue300 = 0x64B5F6, 142 | Blue400 = 0x42A5F5, 143 | Blue500 = 0x2196F3, 144 | Blue600 = 0x1E88E5, 145 | Blue700 = 0x1976D2, 146 | Blue800 = 0x1565C0, 147 | Blue900 = 0x0D47A1, 148 | LightBlue50 = 0xE1F5FE, 149 | LightBlue100 = 0xB3E5FC, 150 | LightBlue200 = 0x81D4FA, 151 | LightBlue300 = 0x4FC3F7, 152 | LightBlue400 = 0x29B6F6, 153 | LightBlue500 = 0x03A9F4, 154 | LightBlue600 = 0x039BE5, 155 | LightBlue700 = 0x0288D1, 156 | LightBlue800 = 0x0277BD, 157 | LightBlue900 = 0x01579B, 158 | Cyan50 = 0xE0F7FA, 159 | Cyan100 = 0xB2EBF2, 160 | Cyan200 = 0x80DEEA, 161 | Cyan300 = 0x4DD0E1, 162 | Cyan400 = 0x26C6DA, 163 | Cyan500 = 0x00BCD4, 164 | Cyan600 = 0x00ACC1, 165 | Cyan700 = 0x0097A7, 166 | Cyan800 = 0x00838F, 167 | Cyan900 = 0x006064, 168 | Teal50 = 0xE0F2F1, 169 | Teal100 = 0xB2DFDB, 170 | Teal200 = 0x80CBC4, 171 | Teal300 = 0x4DB6AC, 172 | Teal400 = 0x26A69A, 173 | Teal500 = 0x009688, 174 | Teal600 = 0x00897B, 175 | Teal700 = 0x00796B, 176 | Teal800 = 0x00695C, 177 | Teal900 = 0x004D40, 178 | Green50 = 0xE8F5E9, 179 | Green100 = 0xC8E6C9, 180 | Green200 = 0xA5D6A7, 181 | Green300 = 0x81C784, 182 | Green400 = 0x66BB6A, 183 | Green500 = 0x4CAF50, 184 | Green600 = 0x43A047, 185 | Green700 = 0x388E3C, 186 | Green800 = 0x2E7D32, 187 | Green900 = 0x1B5E20, 188 | LightGreen50 = 0xF1F8E9, 189 | LightGreen100 = 0xDCEDC8, 190 | LightGreen200 = 0xC5E1A5, 191 | LightGreen300 = 0xAED581, 192 | LightGreen400 = 0x9CCC65, 193 | LightGreen500 = 0x8BC34A, 194 | LightGreen600 = 0x7CB342, 195 | LightGreen700 = 0x689F38, 196 | LightGreen800 = 0x558B2F, 197 | LightGreen900 = 0x33691E, 198 | Lime50 = 0xF9FBE7, 199 | Lime100 = 0xF0F4C3, 200 | Lime200 = 0xE6EE9C, 201 | Lime300 = 0xDCE775, 202 | Lime400 = 0xD4E157, 203 | Lime500 = 0xCDDC39, 204 | Lime600 = 0xC0CA33, 205 | Lime700 = 0xAFB42B, 206 | Lime800 = 0x9E9D24, 207 | Lime900 = 0x827717, 208 | Yellow50 = 0xFFFDE7, 209 | Yellow100 = 0xFFF9C4, 210 | Yellow200 = 0xFFF59D, 211 | Yellow300 = 0xFFF176, 212 | Yellow400 = 0xFFEE58, 213 | Yellow500 = 0xFFEB3B, 214 | Yellow600 = 0xFDD835, 215 | Yellow700 = 0xFBC02D, 216 | Yellow800 = 0xF9A825, 217 | Yellow900 = 0xF57F17, 218 | Amber50 = 0xFFF8E1, 219 | Amber100 = 0xFFECB3, 220 | Amber200 = 0xFFE082, 221 | Amber300 = 0xFFD54F, 222 | Amber400 = 0xFFCA28, 223 | Amber500 = 0xFFC107, 224 | Amber600 = 0xFFB300, 225 | Amber700 = 0xFFA000, 226 | Amber800 = 0xFF8F00, 227 | Amber900 = 0xFF6F00, 228 | Orange50 = 0xFFF3E0, 229 | Orange100 = 0xFFE0B2, 230 | Orange200 = 0xFFCC80, 231 | Orange300 = 0xFFB74D, 232 | Orange400 = 0xFFA726, 233 | Orange500 = 0xFF9800, 234 | Orange600 = 0xFB8C00, 235 | Orange700 = 0xF57C00, 236 | Orange800 = 0xEF6C00, 237 | Orange900 = 0xE65100, 238 | DeepOrange50 = 0xFBE9E7, 239 | DeepOrange100 = 0xFFCCBC, 240 | DeepOrange200 = 0xFFAB91, 241 | DeepOrange300 = 0xFF8A65, 242 | DeepOrange400 = 0xFF7043, 243 | DeepOrange500 = 0xFF5722, 244 | DeepOrange600 = 0xF4511E, 245 | DeepOrange700 = 0xE64A19, 246 | DeepOrange800 = 0xD84315, 247 | DeepOrange900 = 0xBF360C, 248 | Brown50 = 0xEFEBE9, 249 | Brown100 = 0xD7CCC8, 250 | Brown200 = 0xBCAAA4, 251 | Brown300 = 0xA1887F, 252 | Brown400 = 0x8D6E63, 253 | Brown500 = 0x795548, 254 | Brown600 = 0x6D4C41, 255 | Brown700 = 0x5D4037, 256 | Brown800 = 0x4E342E, 257 | Brown900 = 0x3E2723, 258 | Grey50 = 0xFAFAFA, 259 | Grey100 = 0xF5F5F5, 260 | Grey200 = 0xEEEEEE, 261 | Grey300 = 0xE0E0E0, 262 | Grey400 = 0xBDBDBD, 263 | Grey500 = 0x9E9E9E, 264 | Grey600 = 0x757575, 265 | Grey700 = 0x616161, 266 | Grey800 = 0x424242, 267 | Grey900 = 0x212121, 268 | BlueGrey50 = 0xECEFF1, 269 | BlueGrey100 = 0xCFD8DC, 270 | BlueGrey200 = 0xB0BEC5, 271 | BlueGrey300 = 0x90A4AE, 272 | BlueGrey400 = 0x78909C, 273 | BlueGrey500 = 0x607D8B, 274 | BlueGrey600 = 0x546E7A, 275 | BlueGrey700 = 0x455A64, 276 | BlueGrey800 = 0x37474F, 277 | BlueGrey900 = 0x263238 278 | } 279 | 280 | public enum Accent 281 | { 282 | Red100 = 0xFF8A80, 283 | Red200 = 0xFF5252, 284 | Red400 = 0xFF1744, 285 | Red700 = 0xD50000, 286 | Pink100 = 0xFF80AB, 287 | Pink200 = 0xFF4081, 288 | Pink400 = 0xF50057, 289 | Pink700 = 0xC51162, 290 | Purple100 = 0xEA80FC, 291 | Purple200 = 0xE040FB, 292 | Purple400 = 0xD500F9, 293 | Purple700 = 0xAA00FF, 294 | DeepPurple100 = 0xB388FF, 295 | DeepPurple200 = 0x7C4DFF, 296 | DeepPurple400 = 0x651FFF, 297 | DeepPurple700 = 0x6200EA, 298 | Indigo100 = 0x8C9EFF, 299 | Indigo200 = 0x536DFE, 300 | Indigo400 = 0x3D5AFE, 301 | Indigo700 = 0x304FFE, 302 | Blue100 = 0x82B1FF, 303 | Blue200 = 0x448AFF, 304 | Blue400 = 0x2979FF, 305 | Blue700 = 0x2962FF, 306 | LightBlue100 = 0x80D8FF, 307 | LightBlue200 = 0x40C4FF, 308 | LightBlue400 = 0x00B0FF, 309 | LightBlue700 = 0x0091EA, 310 | Cyan100 = 0x84FFFF, 311 | Cyan200 = 0x18FFFF, 312 | Cyan400 = 0x00E5FF, 313 | Cyan700 = 0x00B8D4, 314 | Teal100 = 0xA7FFEB, 315 | Teal200 = 0x64FFDA, 316 | Teal400 = 0x1DE9B6, 317 | Teal700 = 0x00BFA5, 318 | Green100 = 0xB9F6CA, 319 | Green200 = 0x69F0AE, 320 | Green400 = 0x00E676, 321 | Green700 = 0x00C853, 322 | LightGreen100 = 0xCCFF90, 323 | LightGreen200 = 0xB2FF59, 324 | LightGreen400 = 0x76FF03, 325 | LightGreen700 = 0x64DD17, 326 | Lime100 = 0xF4FF81, 327 | Lime200 = 0xEEFF41, 328 | Lime400 = 0xC6FF00, 329 | Lime700 = 0xAEEA00, 330 | Yellow100 = 0xFFFF8D, 331 | Yellow200 = 0xFFFF00, 332 | Yellow400 = 0xFFEA00, 333 | Yellow700 = 0xFFD600, 334 | Amber100 = 0xFFE57F, 335 | Amber200 = 0xFFD740, 336 | Amber400 = 0xFFC400, 337 | Amber700 = 0xFFAB00, 338 | Orange100 = 0xFFD180, 339 | Orange200 = 0xFFAB40, 340 | Orange400 = 0xFF9100, 341 | Orange700 = 0xFF6D00, 342 | DeepOrange100 = 0xFF9E80, 343 | DeepOrange200 = 0xFF6E40, 344 | DeepOrange400 = 0xFF3D00, 345 | DeepOrange700 = 0xDD2C00 346 | } 347 | } 348 | -------------------------------------------------------------------------------- /MaterialSkin/Animations/AnimationManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Windows.Forms; 5 | 6 | namespace MaterialSkin.Animations 7 | { 8 | class AnimationManager 9 | { 10 | public bool InterruptAnimation { get; set; } 11 | public double Increment { get; set; } 12 | public double SecondaryIncrement { get; set; } 13 | public AnimationType AnimationType { get; set; } 14 | public bool Singular { get; set; } 15 | 16 | public delegate void AnimationFinished(object sender); 17 | public event AnimationFinished OnAnimationFinished; 18 | 19 | public delegate void AnimationProgress(object sender); 20 | public event AnimationProgress OnAnimationProgress; 21 | 22 | private readonly List _animationProgresses; 23 | private readonly List _animationSources; 24 | private readonly List _animationDirections; 25 | private readonly List _animationDatas; 26 | 27 | private const double MIN_VALUE = 0.00; 28 | private const double MAX_VALUE = 1.00; 29 | 30 | private readonly Timer _animationTimer = new Timer { Interval = 5, Enabled = false }; 31 | 32 | /// 33 | /// Constructor 34 | /// 35 | /// If true, only one animation is supported. The current animation will be replaced with the new one. If false, a new animation is added to the list. 36 | public AnimationManager(bool singular = true) 37 | { 38 | _animationProgresses = new List(); 39 | _animationSources = new List(); 40 | _animationDirections = new List(); 41 | _animationDatas = new List(); 42 | 43 | Increment = 0.03; 44 | SecondaryIncrement = 0.03; 45 | AnimationType = AnimationType.Linear; 46 | InterruptAnimation = true; 47 | Singular = singular; 48 | 49 | if (Singular) 50 | { 51 | _animationProgresses.Add(0); 52 | _animationSources.Add(new Point(0, 0)); 53 | _animationDirections.Add(AnimationDirection.In); 54 | } 55 | 56 | _animationTimer.Tick += AnimationTimerOnTick; 57 | } 58 | 59 | private void AnimationTimerOnTick(object sender, EventArgs eventArgs) 60 | { 61 | for (var i = 0; i < _animationProgresses.Count; i++) 62 | { 63 | UpdateProgress(i); 64 | 65 | if (!Singular) 66 | { 67 | if ((_animationDirections[i] == AnimationDirection.InOutIn && _animationProgresses[i] == MAX_VALUE)) 68 | { 69 | _animationDirections[i] = AnimationDirection.InOutOut; 70 | } 71 | else if ((_animationDirections[i] == AnimationDirection.InOutRepeatingIn && _animationProgresses[i] == MIN_VALUE)) 72 | { 73 | _animationDirections[i] = AnimationDirection.InOutRepeatingOut; 74 | } 75 | else if ((_animationDirections[i] == AnimationDirection.InOutRepeatingOut && _animationProgresses[i] == MIN_VALUE)) 76 | { 77 | _animationDirections[i] = AnimationDirection.InOutRepeatingIn; 78 | } 79 | else if ( 80 | (_animationDirections[i] == AnimationDirection.In && _animationProgresses[i] == MAX_VALUE) || 81 | (_animationDirections[i] == AnimationDirection.Out && _animationProgresses[i] == MIN_VALUE) || 82 | (_animationDirections[i] == AnimationDirection.InOutOut && _animationProgresses[i] == MIN_VALUE)) 83 | { 84 | _animationProgresses.RemoveAt(i); 85 | _animationSources.RemoveAt(i); 86 | _animationDirections.RemoveAt(i); 87 | _animationDatas.RemoveAt(i); 88 | } 89 | } 90 | else 91 | { 92 | if ((_animationDirections[i] == AnimationDirection.InOutIn && _animationProgresses[i] == MAX_VALUE)) 93 | { 94 | _animationDirections[i] = AnimationDirection.InOutOut; 95 | } 96 | else if ((_animationDirections[i] == AnimationDirection.InOutRepeatingIn && _animationProgresses[i] == MAX_VALUE)) 97 | { 98 | _animationDirections[i] = AnimationDirection.InOutRepeatingOut; 99 | } 100 | else if ((_animationDirections[i] == AnimationDirection.InOutRepeatingOut && _animationProgresses[i] == MIN_VALUE)) 101 | { 102 | _animationDirections[i] = AnimationDirection.InOutRepeatingIn; 103 | } 104 | } 105 | } 106 | 107 | OnAnimationProgress?.Invoke(this); 108 | } 109 | 110 | public bool IsAnimating() 111 | { 112 | return _animationTimer.Enabled; 113 | } 114 | 115 | public void StartNewAnimation(AnimationDirection animationDirection, object[] data = null) 116 | { 117 | StartNewAnimation(animationDirection, new Point(0, 0), data); 118 | } 119 | 120 | public void StartNewAnimation(AnimationDirection animationDirection, Point animationSource, object[] data = null) 121 | { 122 | if (!IsAnimating() || InterruptAnimation) 123 | { 124 | if (Singular && _animationDirections.Count > 0) 125 | { 126 | _animationDirections[0] = animationDirection; 127 | } 128 | else 129 | { 130 | _animationDirections.Add(animationDirection); 131 | } 132 | 133 | if (Singular && _animationSources.Count > 0) 134 | { 135 | _animationSources[0] = animationSource; 136 | } 137 | else 138 | { 139 | _animationSources.Add(animationSource); 140 | } 141 | 142 | if (!(Singular && _animationProgresses.Count > 0)) 143 | { 144 | switch (_animationDirections[_animationDirections.Count - 1]) 145 | { 146 | case AnimationDirection.InOutRepeatingIn: 147 | case AnimationDirection.InOutIn: 148 | case AnimationDirection.In: 149 | _animationProgresses.Add(MIN_VALUE); 150 | break; 151 | case AnimationDirection.InOutRepeatingOut: 152 | case AnimationDirection.InOutOut: 153 | case AnimationDirection.Out: 154 | _animationProgresses.Add(MAX_VALUE); 155 | break; 156 | default: 157 | throw new Exception("Invalid AnimationDirection"); 158 | } 159 | } 160 | 161 | if (Singular && _animationDatas.Count > 0) 162 | { 163 | _animationDatas[0] = data ?? new object[] { }; 164 | } 165 | else 166 | { 167 | _animationDatas.Add(data ?? new object[] { }); 168 | } 169 | 170 | } 171 | 172 | _animationTimer.Start(); 173 | } 174 | 175 | public void UpdateProgress(int index) 176 | { 177 | switch (_animationDirections[index]) 178 | { 179 | case AnimationDirection.InOutRepeatingIn: 180 | case AnimationDirection.InOutIn: 181 | case AnimationDirection.In: 182 | IncrementProgress(index); 183 | break; 184 | case AnimationDirection.InOutRepeatingOut: 185 | case AnimationDirection.InOutOut: 186 | case AnimationDirection.Out: 187 | DecrementProgress(index); 188 | break; 189 | default: 190 | throw new Exception("No AnimationDirection has been set"); 191 | } 192 | } 193 | 194 | private void IncrementProgress(int index) 195 | { 196 | _animationProgresses[index] += Increment; 197 | if (_animationProgresses[index] > MAX_VALUE) 198 | { 199 | _animationProgresses[index] = MAX_VALUE; 200 | 201 | for (int i = 0; i < GetAnimationCount(); i++) 202 | { 203 | if (_animationDirections[i] == AnimationDirection.InOutIn) return; 204 | if (_animationDirections[i] == AnimationDirection.InOutRepeatingIn) return; 205 | if (_animationDirections[i] == AnimationDirection.InOutRepeatingOut) return; 206 | if (_animationDirections[i] == AnimationDirection.InOutOut && _animationProgresses[i] != MAX_VALUE) return; 207 | if (_animationDirections[i] == AnimationDirection.In && _animationProgresses[i] != MAX_VALUE) return; 208 | } 209 | 210 | _animationTimer.Stop(); 211 | OnAnimationFinished?.Invoke(this); 212 | } 213 | } 214 | 215 | private void DecrementProgress(int index) 216 | { 217 | _animationProgresses[index] -= (_animationDirections[index] == AnimationDirection.InOutOut || _animationDirections[index] == AnimationDirection.InOutRepeatingOut) ? SecondaryIncrement : Increment; 218 | if (_animationProgresses[index] < MIN_VALUE) 219 | { 220 | _animationProgresses[index] = MIN_VALUE; 221 | 222 | for (var i = 0; i < GetAnimationCount(); i++) 223 | { 224 | if (_animationDirections[i] == AnimationDirection.InOutIn) return; 225 | if (_animationDirections[i] == AnimationDirection.InOutRepeatingIn) return; 226 | if (_animationDirections[i] == AnimationDirection.InOutRepeatingOut) return; 227 | if (_animationDirections[i] == AnimationDirection.InOutOut && _animationProgresses[i] != MIN_VALUE) return; 228 | if (_animationDirections[i] == AnimationDirection.Out && _animationProgresses[i] != MIN_VALUE) return; 229 | } 230 | 231 | _animationTimer.Stop(); 232 | OnAnimationFinished?.Invoke(this); 233 | } 234 | } 235 | 236 | public double GetProgress() 237 | { 238 | if (!Singular) 239 | throw new Exception("Animation is not set to Singular."); 240 | 241 | if (_animationProgresses.Count == 0) 242 | throw new Exception("Invalid animation"); 243 | 244 | return GetProgress(0); 245 | } 246 | 247 | public double GetProgress(int index) 248 | { 249 | if (!(index < GetAnimationCount())) 250 | throw new IndexOutOfRangeException("Invalid animation index"); 251 | 252 | switch (AnimationType) 253 | { 254 | case AnimationType.Linear: 255 | return AnimationLinear.CalculateProgress(_animationProgresses[index]); 256 | case AnimationType.EaseInOut: 257 | return AnimationEaseInOut.CalculateProgress(_animationProgresses[index]); 258 | case AnimationType.EaseOut: 259 | return AnimationEaseOut.CalculateProgress(_animationProgresses[index]); 260 | case AnimationType.CustomQuadratic: 261 | return AnimationCustomQuadratic.CalculateProgress(_animationProgresses[index]); 262 | default: 263 | throw new NotImplementedException("The given AnimationType is not implemented"); 264 | } 265 | 266 | } 267 | 268 | public Point GetSource(int index) 269 | { 270 | if (!(index < GetAnimationCount())) 271 | throw new IndexOutOfRangeException("Invalid animation index"); 272 | 273 | return _animationSources[index]; 274 | } 275 | 276 | public Point GetSource() 277 | { 278 | if (!Singular) 279 | throw new Exception("Animation is not set to Singular."); 280 | 281 | if (_animationSources.Count == 0) 282 | throw new Exception("Invalid animation"); 283 | 284 | return _animationSources[0]; 285 | } 286 | 287 | public AnimationDirection GetDirection() 288 | { 289 | if (!Singular) 290 | throw new Exception("Animation is not set to Singular."); 291 | 292 | if (_animationDirections.Count == 0) 293 | throw new Exception("Invalid animation"); 294 | 295 | return _animationDirections[0]; 296 | } 297 | 298 | public AnimationDirection GetDirection(int index) 299 | { 300 | if (!(index < _animationDirections.Count)) 301 | throw new IndexOutOfRangeException("Invalid animation index"); 302 | 303 | return _animationDirections[index]; 304 | } 305 | 306 | public object[] GetData() 307 | { 308 | if (!Singular) 309 | throw new Exception("Animation is not set to Singular."); 310 | 311 | if (_animationDatas.Count == 0) 312 | throw new Exception("Invalid animation"); 313 | 314 | return _animationDatas[0]; 315 | } 316 | 317 | public object[] GetData(int index) 318 | { 319 | if (!(index < _animationDatas.Count)) 320 | throw new IndexOutOfRangeException("Invalid animation index"); 321 | 322 | return _animationDatas[index]; 323 | } 324 | 325 | public int GetAnimationCount() 326 | { 327 | return _animationProgresses.Count; 328 | } 329 | 330 | public void SetProgress(double progress) 331 | { 332 | if (!Singular) 333 | throw new Exception("Animation is not set to Singular."); 334 | 335 | if (_animationProgresses.Count == 0) 336 | throw new Exception("Invalid animation"); 337 | 338 | _animationProgresses[0] = progress; 339 | } 340 | 341 | public void SetDirection(AnimationDirection direction) 342 | { 343 | if (!Singular) 344 | throw new Exception("Animation is not set to Singular."); 345 | 346 | if (_animationProgresses.Count == 0) 347 | throw new Exception("Invalid animation"); 348 | 349 | _animationDirections[0] = direction; 350 | } 351 | 352 | public void SetData(object[] data) 353 | { 354 | if (!Singular) 355 | throw new Exception("Animation is not set to Singular."); 356 | 357 | if (_animationDatas.Count == 0) 358 | throw new Exception("Invalid animation"); 359 | 360 | _animationDatas[0] = data; 361 | } 362 | } 363 | } 364 | -------------------------------------------------------------------------------- /MaterialSkin/MaterialSkinManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Drawing.Text; 5 | using System.Linq; 6 | using System.Runtime.InteropServices; 7 | using System.Windows.Forms; 8 | using MaterialSkin.Controls; 9 | using MaterialSkin.Properties; 10 | 11 | namespace MaterialSkin 12 | { 13 | public class MaterialSkinManager 14 | { 15 | //Singleton instance 16 | private static MaterialSkinManager _instance; 17 | 18 | //Forms to control 19 | private readonly List _formsToManage = new List(); 20 | 21 | //Theme 22 | private Themes _theme; 23 | public Themes Theme 24 | { 25 | get { return _theme; } 26 | set 27 | { 28 | _theme = value; 29 | UpdateBackgrounds(); 30 | } 31 | } 32 | 33 | private ColorScheme _colorScheme; 34 | public ColorScheme ColorScheme 35 | { 36 | get { return _colorScheme; } 37 | set 38 | { 39 | _colorScheme = value; 40 | UpdateBackgrounds(); 41 | } 42 | } 43 | 44 | public enum Themes : byte 45 | { 46 | LIGHT, 47 | DARK 48 | } 49 | 50 | //Constant color values 51 | private static readonly Color PRIMARY_TEXT_BLACK = Color.FromArgb(222, 0, 0, 0); 52 | private static readonly Brush PRIMARY_TEXT_BLACK_BRUSH = new SolidBrush(PRIMARY_TEXT_BLACK); 53 | public static Color SECONDARY_TEXT_BLACK = Color.FromArgb(138, 0, 0, 0); 54 | public static Brush SECONDARY_TEXT_BLACK_BRUSH = new SolidBrush(SECONDARY_TEXT_BLACK); 55 | private static readonly Color DISABLED_OR_HINT_TEXT_BLACK = Color.FromArgb(66, 0, 0, 0); 56 | private static readonly Brush DISABLED_OR_HINT_TEXT_BLACK_BRUSH = new SolidBrush(DISABLED_OR_HINT_TEXT_BLACK); 57 | private static readonly Color DIVIDERS_BLACK = Color.FromArgb(31, 0, 0, 0); 58 | private static readonly Brush DIVIDERS_BLACK_BRUSH = new SolidBrush(DIVIDERS_BLACK); 59 | 60 | private static readonly Color PRIMARY_TEXT_WHITE = Color.FromArgb(255, 255, 255, 255); 61 | private static readonly Brush PRIMARY_TEXT_WHITE_BRUSH = new SolidBrush(PRIMARY_TEXT_WHITE); 62 | public static Color SECONDARY_TEXT_WHITE = Color.FromArgb(179, 255, 255, 255); 63 | public static Brush SECONDARY_TEXT_WHITE_BRUSH = new SolidBrush(SECONDARY_TEXT_WHITE); 64 | private static readonly Color DISABLED_OR_HINT_TEXT_WHITE = Color.FromArgb(77, 255, 255, 255); 65 | private static readonly Brush DISABLED_OR_HINT_TEXT_WHITE_BRUSH = new SolidBrush(DISABLED_OR_HINT_TEXT_WHITE); 66 | private static readonly Color DIVIDERS_WHITE = Color.FromArgb(31, 255, 255, 255); 67 | private static readonly Brush DIVIDERS_WHITE_BRUSH = new SolidBrush(DIVIDERS_WHITE); 68 | 69 | // Checkbox colors 70 | private static readonly Color CHECKBOX_OFF_LIGHT = Color.FromArgb(138, 0, 0, 0); 71 | private static readonly Brush CHECKBOX_OFF_LIGHT_BRUSH = new SolidBrush(CHECKBOX_OFF_LIGHT); 72 | private static readonly Color CHECKBOX_OFF_DISABLED_LIGHT = Color.FromArgb(66, 0, 0, 0); 73 | private static readonly Brush CHECKBOX_OFF_DISABLED_LIGHT_BRUSH = new SolidBrush(CHECKBOX_OFF_DISABLED_LIGHT); 74 | 75 | private static readonly Color CHECKBOX_OFF_DARK = Color.FromArgb(179, 255, 255, 255); 76 | private static readonly Brush CHECKBOX_OFF_DARK_BRUSH = new SolidBrush(CHECKBOX_OFF_DARK); 77 | private static readonly Color CHECKBOX_OFF_DISABLED_DARK = Color.FromArgb(77, 255, 255, 255); 78 | private static readonly Brush CHECKBOX_OFF_DISABLED_DARK_BRUSH = new SolidBrush(CHECKBOX_OFF_DISABLED_DARK); 79 | 80 | //Raised button 81 | private static readonly Color RAISED_BUTTON_BACKGROUND = Color.FromArgb(255, 255, 255, 255); 82 | private static readonly Brush RAISED_BUTTON_BACKGROUND_BRUSH = new SolidBrush(RAISED_BUTTON_BACKGROUND); 83 | private static readonly Color RAISED_BUTTON_TEXT_LIGHT = PRIMARY_TEXT_WHITE; 84 | private static readonly Brush RAISED_BUTTON_TEXT_LIGHT_BRUSH = new SolidBrush(RAISED_BUTTON_TEXT_LIGHT); 85 | private static readonly Color RAISED_BUTTON_TEXT_DARK = PRIMARY_TEXT_BLACK; 86 | private static readonly Brush RAISED_BUTTON_TEXT_DARK_BRUSH = new SolidBrush(RAISED_BUTTON_TEXT_DARK); 87 | 88 | //Flat button 89 | private static readonly Color FLAT_BUTTON_BACKGROUND_HOVER_LIGHT = Color.FromArgb(20.PercentageToColorComponent(), 0x999999.ToColor()); 90 | private static readonly Brush FLAT_BUTTON_BACKGROUND_HOVER_LIGHT_BRUSH = new SolidBrush(FLAT_BUTTON_BACKGROUND_HOVER_LIGHT); 91 | private static readonly Color FLAT_BUTTON_BACKGROUND_PRESSED_LIGHT = Color.FromArgb(40.PercentageToColorComponent(), 0x999999.ToColor()); 92 | private static readonly Brush FLAT_BUTTON_BACKGROUND_PRESSED_LIGHT_BRUSH = new SolidBrush(FLAT_BUTTON_BACKGROUND_PRESSED_LIGHT); 93 | private static readonly Color FLAT_BUTTON_DISABLEDTEXT_LIGHT = Color.FromArgb(26.PercentageToColorComponent(), 0x000000.ToColor()); 94 | private static readonly Brush FLAT_BUTTON_DISABLEDTEXT_LIGHT_BRUSH = new SolidBrush(FLAT_BUTTON_DISABLEDTEXT_LIGHT); 95 | 96 | private static readonly Color FLAT_BUTTON_BACKGROUND_HOVER_DARK = Color.FromArgb(15.PercentageToColorComponent(), 0xCCCCCC.ToColor()); 97 | private static readonly Brush FLAT_BUTTON_BACKGROUND_HOVER_DARK_BRUSH = new SolidBrush(FLAT_BUTTON_BACKGROUND_HOVER_DARK); 98 | private static readonly Color FLAT_BUTTON_BACKGROUND_PRESSED_DARK = Color.FromArgb(25.PercentageToColorComponent(), 0xCCCCCC.ToColor()); 99 | private static readonly Brush FLAT_BUTTON_BACKGROUND_PRESSED_DARK_BRUSH = new SolidBrush(FLAT_BUTTON_BACKGROUND_PRESSED_DARK); 100 | private static readonly Color FLAT_BUTTON_DISABLEDTEXT_DARK = Color.FromArgb(30.PercentageToColorComponent(), 0xFFFFFF.ToColor()); 101 | private static readonly Brush FLAT_BUTTON_DISABLEDTEXT_DARK_BRUSH = new SolidBrush(FLAT_BUTTON_DISABLEDTEXT_DARK); 102 | 103 | //ContextMenuStrip 104 | private static readonly Color CMS_BACKGROUND_LIGHT_HOVER = Color.FromArgb(255, 238, 238, 238); 105 | private static readonly Brush CMS_BACKGROUND_HOVER_LIGHT_BRUSH = new SolidBrush(CMS_BACKGROUND_LIGHT_HOVER); 106 | 107 | private static readonly Color CMS_BACKGROUND_DARK_HOVER = Color.FromArgb(38, 204, 204, 204); 108 | private static readonly Brush CMS_BACKGROUND_HOVER_DARK_BRUSH = new SolidBrush(CMS_BACKGROUND_DARK_HOVER); 109 | 110 | //Application background 111 | private static readonly Color BACKGROUND_LIGHT = Color.FromArgb(255, 255, 255, 255); 112 | private static Brush BACKGROUND_LIGHT_BRUSH = new SolidBrush(BACKGROUND_LIGHT); 113 | 114 | private static readonly Color BACKGROUND_DARK = Color.FromArgb(255, 51, 51, 51); 115 | private static Brush BACKGROUND_DARK_BRUSH = new SolidBrush(BACKGROUND_DARK); 116 | 117 | //Application action bar 118 | public readonly Color ACTION_BAR_TEXT = Color.FromArgb(255, 255, 255, 255); 119 | public readonly Brush ACTION_BAR_TEXT_BRUSH = new SolidBrush(Color.FromArgb(255, 255, 255, 255)); 120 | public readonly Color ACTION_BAR_TEXT_SECONDARY = Color.FromArgb(153, 255, 255, 255); 121 | public readonly Brush ACTION_BAR_TEXT_SECONDARY_BRUSH = new SolidBrush(Color.FromArgb(153, 255, 255, 255)); 122 | 123 | public Color GetPrimaryTextColor() 124 | { 125 | return Theme == Themes.LIGHT ? PRIMARY_TEXT_BLACK : PRIMARY_TEXT_WHITE; 126 | } 127 | 128 | public Brush GetPrimaryTextBrush() 129 | { 130 | return Theme == Themes.LIGHT ? PRIMARY_TEXT_BLACK_BRUSH : PRIMARY_TEXT_WHITE_BRUSH; 131 | } 132 | 133 | public Color GetSecondaryTextColor() 134 | { 135 | return Theme == Themes.LIGHT ? SECONDARY_TEXT_BLACK : SECONDARY_TEXT_WHITE; 136 | } 137 | 138 | public Brush GetSecondaryTextBrush() 139 | { 140 | return Theme == Themes.LIGHT ? SECONDARY_TEXT_BLACK_BRUSH : SECONDARY_TEXT_WHITE_BRUSH; 141 | } 142 | 143 | public Color GetDisabledOrHintColor() 144 | { 145 | return Theme == Themes.LIGHT ? DISABLED_OR_HINT_TEXT_BLACK : DISABLED_OR_HINT_TEXT_WHITE; 146 | } 147 | 148 | public Brush GetDisabledOrHintBrush() 149 | { 150 | return Theme == Themes.LIGHT ? DISABLED_OR_HINT_TEXT_BLACK_BRUSH : DISABLED_OR_HINT_TEXT_WHITE_BRUSH; 151 | } 152 | 153 | public Color GetDividersColor() 154 | { 155 | return Theme == Themes.LIGHT ? DIVIDERS_BLACK : DIVIDERS_WHITE; 156 | } 157 | 158 | public Brush GetDividersBrush() 159 | { 160 | return Theme == Themes.LIGHT ? DIVIDERS_BLACK_BRUSH : DIVIDERS_WHITE_BRUSH; 161 | } 162 | 163 | public Color GetCheckboxOffColor() 164 | { 165 | return Theme == Themes.LIGHT ? CHECKBOX_OFF_LIGHT : CHECKBOX_OFF_DARK; 166 | } 167 | 168 | public Brush GetCheckboxOffBrush() 169 | { 170 | return Theme == Themes.LIGHT ? CHECKBOX_OFF_LIGHT_BRUSH : CHECKBOX_OFF_DARK_BRUSH; 171 | } 172 | 173 | public Color GetCheckBoxOffDisabledColor() 174 | { 175 | return Theme == Themes.LIGHT ? CHECKBOX_OFF_DISABLED_LIGHT : CHECKBOX_OFF_DISABLED_DARK; 176 | } 177 | 178 | public Brush GetCheckBoxOffDisabledBrush() 179 | { 180 | return Theme == Themes.LIGHT ? CHECKBOX_OFF_DISABLED_LIGHT_BRUSH : CHECKBOX_OFF_DISABLED_DARK_BRUSH; 181 | } 182 | 183 | public Brush GetRaisedButtonBackgroundBrush() 184 | { 185 | return RAISED_BUTTON_BACKGROUND_BRUSH; 186 | } 187 | 188 | public Brush GetRaisedButtonTextBrush(bool primary) 189 | { 190 | return primary ? RAISED_BUTTON_TEXT_LIGHT_BRUSH : RAISED_BUTTON_TEXT_DARK_BRUSH; 191 | } 192 | 193 | public Color GetFlatButtonHoverBackgroundColor() 194 | { 195 | return Theme == Themes.LIGHT ? FLAT_BUTTON_BACKGROUND_HOVER_LIGHT : FLAT_BUTTON_BACKGROUND_HOVER_DARK; 196 | } 197 | 198 | public Brush GetFlatButtonHoverBackgroundBrush() 199 | { 200 | return Theme == Themes.LIGHT ? FLAT_BUTTON_BACKGROUND_HOVER_LIGHT_BRUSH : FLAT_BUTTON_BACKGROUND_HOVER_DARK_BRUSH; 201 | } 202 | 203 | public Color GetFlatButtonPressedBackgroundColor() 204 | { 205 | return Theme == Themes.LIGHT ? FLAT_BUTTON_BACKGROUND_PRESSED_LIGHT : FLAT_BUTTON_BACKGROUND_PRESSED_DARK; 206 | } 207 | 208 | public Brush GetFlatButtonPressedBackgroundBrush() 209 | { 210 | return Theme == Themes.LIGHT ? FLAT_BUTTON_BACKGROUND_PRESSED_LIGHT_BRUSH : FLAT_BUTTON_BACKGROUND_PRESSED_DARK_BRUSH; 211 | } 212 | 213 | public Brush GetFlatButtonDisabledTextBrush() 214 | { 215 | return Theme == Themes.LIGHT ? FLAT_BUTTON_DISABLEDTEXT_LIGHT_BRUSH : FLAT_BUTTON_DISABLEDTEXT_DARK_BRUSH; 216 | } 217 | 218 | public Brush GetCmsSelectedItemBrush() 219 | { 220 | return Theme == Themes.LIGHT ? CMS_BACKGROUND_HOVER_LIGHT_BRUSH : CMS_BACKGROUND_HOVER_DARK_BRUSH; 221 | } 222 | 223 | public Color GetApplicationBackgroundColor() 224 | { 225 | return Theme == Themes.LIGHT ? BACKGROUND_LIGHT : BACKGROUND_DARK; 226 | } 227 | 228 | //Roboto font 229 | public Font ROBOTO_MEDIUM_12; 230 | public Font ROBOTO_REGULAR_11; 231 | public Font ROBOTO_MEDIUM_11; 232 | public Font ROBOTO_MEDIUM_10; 233 | 234 | //Other constants 235 | public int FORM_PADDING = 14; 236 | 237 | [DllImport("gdi32.dll")] 238 | private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont, IntPtr pvd, [In] ref uint pcFonts); 239 | 240 | private MaterialSkinManager() 241 | { 242 | ROBOTO_MEDIUM_12 = new Font(LoadFont(Resources.Roboto_Medium), 12f); 243 | ROBOTO_MEDIUM_10 = new Font(LoadFont(Resources.Roboto_Medium), 10f); 244 | ROBOTO_REGULAR_11 = new Font(LoadFont(Resources.Roboto_Regular), 11f); 245 | ROBOTO_MEDIUM_11 = new Font(LoadFont(Resources.Roboto_Medium), 11f); 246 | Theme = Themes.LIGHT; 247 | ColorScheme = new ColorScheme(Primary.BlueGrey800, Primary.BlueGrey900, Primary.BlueGrey500, Accent.LightBlue200, TextShade.WHITE); 248 | } 249 | 250 | public static MaterialSkinManager Instance => _instance ?? (_instance = new MaterialSkinManager()); 251 | 252 | public void AddFormToManage(MaterialForm materialForm) 253 | { 254 | _formsToManage.Add(materialForm); 255 | UpdateBackgrounds(); 256 | } 257 | 258 | public void RemoveFormToManage(MaterialForm materialForm) 259 | { 260 | _formsToManage.Remove(materialForm); 261 | } 262 | 263 | private readonly PrivateFontCollection privateFontCollection = new PrivateFontCollection(); 264 | 265 | private FontFamily LoadFont(byte[] fontResource) 266 | { 267 | int dataLength = fontResource.Length; 268 | IntPtr fontPtr = Marshal.AllocCoTaskMem(dataLength); 269 | Marshal.Copy(fontResource, 0, fontPtr, dataLength); 270 | 271 | uint cFonts = 0; 272 | AddFontMemResourceEx(fontPtr, (uint)fontResource.Length, IntPtr.Zero, ref cFonts); 273 | privateFontCollection.AddMemoryFont(fontPtr, dataLength); 274 | 275 | return privateFontCollection.Families.Last(); 276 | } 277 | 278 | private void UpdateBackgrounds() 279 | { 280 | var newBackColor = GetApplicationBackgroundColor(); 281 | foreach (var materialForm in _formsToManage) 282 | { 283 | materialForm.BackColor = newBackColor; 284 | UpdateControl(materialForm, newBackColor); 285 | } 286 | } 287 | 288 | private void UpdateToolStrip(ToolStrip toolStrip, Color newBackColor) 289 | { 290 | if (toolStrip == null) return; 291 | 292 | toolStrip.BackColor = newBackColor; 293 | foreach (ToolStripItem control in toolStrip.Items) 294 | { 295 | control.BackColor = newBackColor; 296 | if (control is MaterialToolStripMenuItem && (control as MaterialToolStripMenuItem).HasDropDown) 297 | { 298 | 299 | //recursive call 300 | UpdateToolStrip((control as MaterialToolStripMenuItem).DropDown, newBackColor); 301 | } 302 | } 303 | } 304 | 305 | private void UpdateControl(Control controlToUpdate, Color newBackColor) 306 | { 307 | if (controlToUpdate == null) return; 308 | 309 | if (controlToUpdate.ContextMenuStrip != null) 310 | { 311 | UpdateToolStrip(controlToUpdate.ContextMenuStrip, newBackColor); 312 | } 313 | var tabControl = controlToUpdate as MaterialTabControl; 314 | if (tabControl != null) 315 | { 316 | foreach (TabPage tabPage in tabControl.TabPages) 317 | { 318 | tabPage.BackColor = newBackColor; 319 | } 320 | } 321 | 322 | if (controlToUpdate is MaterialDivider) 323 | { 324 | controlToUpdate.BackColor = GetDividersColor(); 325 | } 326 | 327 | if (controlToUpdate is MaterialListView) 328 | { 329 | controlToUpdate.BackColor = newBackColor; 330 | 331 | } 332 | 333 | //recursive call 334 | foreach (Control control in controlToUpdate.Controls) 335 | { 336 | UpdateControl(control, newBackColor); 337 | } 338 | 339 | controlToUpdate.Invalidate(); 340 | } 341 | } 342 | } 343 | -------------------------------------------------------------------------------- /MaterialSkin/Controls/MaterialForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Drawing.Text; 6 | using System.Linq; 7 | using System.Runtime.InteropServices; 8 | using System.Windows.Forms; 9 | 10 | namespace MaterialSkin.Controls 11 | { 12 | public class MaterialForm : Form, IMaterialControl 13 | { 14 | [Browsable(false)] 15 | public int Depth { get; set; } 16 | [Browsable(false)] 17 | public MaterialSkinManager SkinManager => MaterialSkinManager.Instance; 18 | [Browsable(false)] 19 | public MouseState MouseState { get; set; } 20 | public new FormBorderStyle FormBorderStyle { get { return base.FormBorderStyle; } set { base.FormBorderStyle = value; } } 21 | public bool Sizable { get; set; } 22 | 23 | [DllImport("user32.dll")] 24 | public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); 25 | 26 | [DllImport("user32.dll")] 27 | public static extern bool ReleaseCapture(); 28 | 29 | [DllImport("user32.dll")] 30 | public static extern int TrackPopupMenuEx(IntPtr hmenu, uint fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm); 31 | 32 | [DllImport("user32.dll")] 33 | public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); 34 | 35 | [DllImport("user32.dll")] 36 | public static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags); 37 | 38 | [DllImport("User32.dll", CharSet = CharSet.Auto)] 39 | public static extern bool GetMonitorInfo(HandleRef hmonitor, [In, Out] MONITORINFOEX info); 40 | 41 | public const int WM_NCLBUTTONDOWN = 0xA1; 42 | public const int HT_CAPTION = 0x2; 43 | public const int WM_MOUSEMOVE = 0x0200; 44 | public const int WM_LBUTTONDOWN = 0x0201; 45 | public const int WM_LBUTTONUP = 0x0202; 46 | public const int WM_LBUTTONDBLCLK = 0x0203; 47 | public const int WM_RBUTTONDOWN = 0x0204; 48 | private const int HTBOTTOMLEFT = 16; 49 | private const int HTBOTTOMRIGHT = 17; 50 | private const int HTLEFT = 10; 51 | private const int HTRIGHT = 11; 52 | private const int HTBOTTOM = 15; 53 | private const int HTTOP = 12; 54 | private const int HTTOPLEFT = 13; 55 | private const int HTTOPRIGHT = 14; 56 | private const int BORDER_WIDTH = 7; 57 | private ResizeDirection _resizeDir; 58 | private ButtonState _buttonState = ButtonState.None; 59 | 60 | private const int WMSZ_TOP = 3; 61 | private const int WMSZ_TOPLEFT = 4; 62 | private const int WMSZ_TOPRIGHT = 5; 63 | private const int WMSZ_LEFT = 1; 64 | private const int WMSZ_RIGHT = 2; 65 | private const int WMSZ_BOTTOM = 6; 66 | private const int WMSZ_BOTTOMLEFT = 7; 67 | private const int WMSZ_BOTTOMRIGHT = 8; 68 | 69 | private readonly Dictionary _resizingLocationsToCmd = new Dictionary 70 | { 71 | {HTTOP, WMSZ_TOP}, 72 | {HTTOPLEFT, WMSZ_TOPLEFT}, 73 | {HTTOPRIGHT, WMSZ_TOPRIGHT}, 74 | {HTLEFT, WMSZ_LEFT}, 75 | {HTRIGHT, WMSZ_RIGHT}, 76 | {HTBOTTOM, WMSZ_BOTTOM}, 77 | {HTBOTTOMLEFT, WMSZ_BOTTOMLEFT}, 78 | {HTBOTTOMRIGHT, WMSZ_BOTTOMRIGHT} 79 | }; 80 | 81 | private const int STATUS_BAR_BUTTON_WIDTH = STATUS_BAR_HEIGHT; 82 | private const int STATUS_BAR_HEIGHT = 24; 83 | private const int ACTION_BAR_HEIGHT = 40; 84 | 85 | private const uint TPM_LEFTALIGN = 0x0000; 86 | private const uint TPM_RETURNCMD = 0x0100; 87 | 88 | private const int WM_SYSCOMMAND = 0x0112; 89 | private const int WS_MINIMIZEBOX = 0x20000; 90 | private const int WS_SYSMENU = 0x00080000; 91 | 92 | private const int MONITOR_DEFAULTTONEAREST = 2; 93 | 94 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)] 95 | public class MONITORINFOEX 96 | { 97 | public int cbSize = Marshal.SizeOf(typeof(MONITORINFOEX)); 98 | public RECT rcMonitor = new RECT(); 99 | public RECT rcWork = new RECT(); 100 | public int dwFlags = 0; 101 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 102 | public char[] szDevice = new char[32]; 103 | } 104 | 105 | [StructLayout(LayoutKind.Sequential)] 106 | public struct RECT 107 | { 108 | public int left; 109 | public int top; 110 | public int right; 111 | public int bottom; 112 | 113 | public int Width() 114 | { 115 | return right - left; 116 | } 117 | 118 | public int Height() 119 | { 120 | return bottom - top; 121 | } 122 | } 123 | 124 | private enum ResizeDirection 125 | { 126 | BottomLeft, 127 | Left, 128 | Right, 129 | BottomRight, 130 | Bottom, 131 | None 132 | } 133 | 134 | private enum ButtonState 135 | { 136 | XOver, 137 | MaxOver, 138 | MinOver, 139 | XDown, 140 | MaxDown, 141 | MinDown, 142 | None 143 | } 144 | 145 | private readonly Cursor[] _resizeCursors = { Cursors.SizeNESW, Cursors.SizeWE, Cursors.SizeNWSE, Cursors.SizeWE, Cursors.SizeNS }; 146 | 147 | private Rectangle _minButtonBounds; 148 | private Rectangle _maxButtonBounds; 149 | private Rectangle _xButtonBounds; 150 | private Rectangle _actionBarBounds; 151 | private Rectangle _statusBarBounds; 152 | 153 | private bool _maximized; 154 | private Size _previousSize; 155 | private Point _previousLocation; 156 | private bool _headerMouseDown; 157 | 158 | public MaterialForm() 159 | { 160 | FormBorderStyle = FormBorderStyle.None; 161 | Sizable = true; 162 | DoubleBuffered = true; 163 | SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true); 164 | 165 | // This enables the form to trigger the MouseMove event even when mouse is over another control 166 | Application.AddMessageFilter(new MouseMessageFilter()); 167 | MouseMessageFilter.MouseMove += OnGlobalMouseMove; 168 | } 169 | 170 | protected override void WndProc(ref Message m) 171 | { 172 | base.WndProc(ref m); 173 | if (DesignMode || IsDisposed) return; 174 | 175 | if (m.Msg == WM_LBUTTONDBLCLK) 176 | { 177 | MaximizeWindow(!_maximized); 178 | } 179 | else if (m.Msg == WM_MOUSEMOVE && _maximized && 180 | (_statusBarBounds.Contains(PointToClient(Cursor.Position)) || _actionBarBounds.Contains(PointToClient(Cursor.Position))) && 181 | !(_minButtonBounds.Contains(PointToClient(Cursor.Position)) || _maxButtonBounds.Contains(PointToClient(Cursor.Position)) || _xButtonBounds.Contains(PointToClient(Cursor.Position)))) 182 | { 183 | if (_headerMouseDown) 184 | { 185 | _maximized = false; 186 | _headerMouseDown = false; 187 | 188 | var mousePoint = PointToClient(Cursor.Position); 189 | if (mousePoint.X < Width / 2) 190 | Location = mousePoint.X < _previousSize.Width / 2 ? 191 | new Point(Cursor.Position.X - mousePoint.X, Cursor.Position.Y - mousePoint.Y) : 192 | new Point(Cursor.Position.X - _previousSize.Width / 2, Cursor.Position.Y - mousePoint.Y); 193 | else 194 | Location = Width - mousePoint.X < _previousSize.Width / 2 ? 195 | new Point(Cursor.Position.X - _previousSize.Width + Width - mousePoint.X, Cursor.Position.Y - mousePoint.Y) : 196 | new Point(Cursor.Position.X - _previousSize.Width / 2, Cursor.Position.Y - mousePoint.Y); 197 | 198 | Size = _previousSize; 199 | ReleaseCapture(); 200 | SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0); 201 | } 202 | } 203 | else if (m.Msg == WM_LBUTTONDOWN && 204 | (_statusBarBounds.Contains(PointToClient(Cursor.Position)) || _actionBarBounds.Contains(PointToClient(Cursor.Position))) && 205 | !(_minButtonBounds.Contains(PointToClient(Cursor.Position)) || _maxButtonBounds.Contains(PointToClient(Cursor.Position)) || _xButtonBounds.Contains(PointToClient(Cursor.Position)))) 206 | { 207 | if (!_maximized) 208 | { 209 | ReleaseCapture(); 210 | SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0); 211 | } 212 | else 213 | { 214 | _headerMouseDown = true; 215 | } 216 | } 217 | else if (m.Msg == WM_RBUTTONDOWN) 218 | { 219 | Point cursorPos = PointToClient(Cursor.Position); 220 | 221 | if (_statusBarBounds.Contains(cursorPos) && !_minButtonBounds.Contains(cursorPos) && 222 | !_maxButtonBounds.Contains(cursorPos) && !_xButtonBounds.Contains(cursorPos)) 223 | { 224 | // Show default system menu when right clicking titlebar 225 | var id = TrackPopupMenuEx(GetSystemMenu(Handle, false), TPM_LEFTALIGN | TPM_RETURNCMD, Cursor.Position.X, Cursor.Position.Y, Handle, IntPtr.Zero); 226 | 227 | // Pass the command as a WM_SYSCOMMAND message 228 | SendMessage(Handle, WM_SYSCOMMAND, id, 0); 229 | } 230 | } 231 | else if (m.Msg == WM_NCLBUTTONDOWN) 232 | { 233 | // This re-enables resizing by letting the application know when the 234 | // user is trying to resize a side. This is disabled by default when using WS_SYSMENU. 235 | if (!Sizable) return; 236 | 237 | byte bFlag = 0; 238 | 239 | // Get which side to resize from 240 | if (_resizingLocationsToCmd.ContainsKey((int)m.WParam)) 241 | bFlag = (byte)_resizingLocationsToCmd[(int)m.WParam]; 242 | 243 | if (bFlag != 0) 244 | SendMessage(Handle, WM_SYSCOMMAND, 0xF000 | bFlag, (int)m.LParam); 245 | } 246 | else if (m.Msg == WM_LBUTTONUP) 247 | { 248 | _headerMouseDown = false; 249 | } 250 | } 251 | 252 | protected override CreateParams CreateParams 253 | { 254 | get 255 | { 256 | var par = base.CreateParams; 257 | // WS_SYSMENU: Trigger the creation of the system menu 258 | // WS_MINIMIZEBOX: Allow minimizing from taskbar 259 | par.Style = par.Style | WS_MINIMIZEBOX | WS_SYSMENU; // Turn on the WS_MINIMIZEBOX style flag 260 | return par; 261 | } 262 | } 263 | 264 | protected override void OnMouseDown(MouseEventArgs e) 265 | { 266 | if (DesignMode) return; 267 | UpdateButtons(e); 268 | 269 | if (e.Button == MouseButtons.Left && !_maximized) 270 | ResizeForm(_resizeDir); 271 | base.OnMouseDown(e); 272 | } 273 | 274 | protected override void OnMouseLeave(EventArgs e) 275 | { 276 | base.OnMouseLeave(e); 277 | if (DesignMode) return; 278 | _buttonState = ButtonState.None; 279 | Invalidate(); 280 | } 281 | 282 | protected override void OnMouseMove(MouseEventArgs e) 283 | { 284 | base.OnMouseMove(e); 285 | 286 | if (DesignMode) return; 287 | 288 | if (Sizable) 289 | { 290 | //True if the mouse is hovering over a child control 291 | var isChildUnderMouse = GetChildAtPoint(e.Location) != null; 292 | 293 | if (e.Location.X < BORDER_WIDTH && e.Location.Y > Height - BORDER_WIDTH && !isChildUnderMouse && !_maximized) 294 | { 295 | _resizeDir = ResizeDirection.BottomLeft; 296 | Cursor = Cursors.SizeNESW; 297 | } 298 | else if (e.Location.X < BORDER_WIDTH && !isChildUnderMouse && !_maximized) 299 | { 300 | _resizeDir = ResizeDirection.Left; 301 | Cursor = Cursors.SizeWE; 302 | } 303 | else if (e.Location.X > Width - BORDER_WIDTH && e.Location.Y > Height - BORDER_WIDTH && !isChildUnderMouse && !_maximized) 304 | { 305 | _resizeDir = ResizeDirection.BottomRight; 306 | Cursor = Cursors.SizeNWSE; 307 | } 308 | else if (e.Location.X > Width - BORDER_WIDTH && !isChildUnderMouse && !_maximized) 309 | { 310 | _resizeDir = ResizeDirection.Right; 311 | Cursor = Cursors.SizeWE; 312 | } 313 | else if (e.Location.Y > Height - BORDER_WIDTH && !isChildUnderMouse && !_maximized) 314 | { 315 | _resizeDir = ResizeDirection.Bottom; 316 | Cursor = Cursors.SizeNS; 317 | } 318 | else 319 | { 320 | _resizeDir = ResizeDirection.None; 321 | 322 | //Only reset the cursor when needed, this prevents it from flickering when a child control changes the cursor to its own needs 323 | if (_resizeCursors.Contains(Cursor)) 324 | { 325 | Cursor = Cursors.Default; 326 | } 327 | } 328 | } 329 | 330 | UpdateButtons(e); 331 | } 332 | 333 | protected void OnGlobalMouseMove(object sender, MouseEventArgs e) 334 | { 335 | if (IsDisposed) return; 336 | // Convert to client position and pass to Form.MouseMove 337 | var clientCursorPos = PointToClient(e.Location); 338 | var newE = new MouseEventArgs(MouseButtons.None, 0, clientCursorPos.X, clientCursorPos.Y, 0); 339 | OnMouseMove(newE); 340 | } 341 | 342 | private void UpdateButtons(MouseEventArgs e, bool up = false) 343 | { 344 | if (DesignMode) return; 345 | var oldState = _buttonState; 346 | bool showMin = MinimizeBox && ControlBox; 347 | bool showMax = MaximizeBox && ControlBox; 348 | 349 | if (e.Button == MouseButtons.Left && !up) 350 | { 351 | if (showMin && !showMax && _maxButtonBounds.Contains(e.Location)) 352 | _buttonState = ButtonState.MinDown; 353 | else if (showMin && showMax && _minButtonBounds.Contains(e.Location)) 354 | _buttonState = ButtonState.MinDown; 355 | else if (showMax && _maxButtonBounds.Contains(e.Location)) 356 | _buttonState = ButtonState.MaxDown; 357 | else if (ControlBox && _xButtonBounds.Contains(e.Location)) 358 | _buttonState = ButtonState.XDown; 359 | else 360 | _buttonState = ButtonState.None; 361 | } 362 | else 363 | { 364 | if (showMin && !showMax && _maxButtonBounds.Contains(e.Location)) 365 | { 366 | _buttonState = ButtonState.MinOver; 367 | 368 | if (oldState == ButtonState.MinDown && up) 369 | WindowState = FormWindowState.Minimized; 370 | } 371 | else if (showMin && showMax && _minButtonBounds.Contains(e.Location)) 372 | { 373 | _buttonState = ButtonState.MinOver; 374 | 375 | if (oldState == ButtonState.MinDown && up) 376 | WindowState = FormWindowState.Minimized; 377 | } 378 | else if (MaximizeBox && ControlBox && _maxButtonBounds.Contains(e.Location)) 379 | { 380 | _buttonState = ButtonState.MaxOver; 381 | 382 | if (oldState == ButtonState.MaxDown && up) 383 | MaximizeWindow(!_maximized); 384 | 385 | } 386 | else if (ControlBox && _xButtonBounds.Contains(e.Location)) 387 | { 388 | _buttonState = ButtonState.XOver; 389 | 390 | if (oldState == ButtonState.XDown && up) 391 | Close(); 392 | } 393 | else _buttonState = ButtonState.None; 394 | } 395 | 396 | if (oldState != _buttonState) Invalidate(); 397 | } 398 | 399 | private void MaximizeWindow(bool maximize) 400 | { 401 | if (!MaximizeBox || !ControlBox) return; 402 | 403 | _maximized = maximize; 404 | 405 | if (maximize) 406 | { 407 | var monitorHandle = MonitorFromWindow(Handle, MONITOR_DEFAULTTONEAREST); 408 | var monitorInfo = new MONITORINFOEX(); 409 | GetMonitorInfo(new HandleRef(null, monitorHandle), monitorInfo); 410 | _previousSize = Size; 411 | _previousLocation = Location; 412 | Size = new Size(monitorInfo.rcWork.Width(), monitorInfo.rcWork.Height()); 413 | Location = new Point(monitorInfo.rcWork.left, monitorInfo.rcWork.top); 414 | } 415 | else 416 | { 417 | Size = _previousSize; 418 | Location = _previousLocation; 419 | } 420 | 421 | } 422 | 423 | protected override void OnMouseUp(MouseEventArgs e) 424 | { 425 | if (DesignMode) return; 426 | UpdateButtons(e, true); 427 | 428 | base.OnMouseUp(e); 429 | ReleaseCapture(); 430 | } 431 | 432 | private void ResizeForm(ResizeDirection direction) 433 | { 434 | if (DesignMode) return; 435 | var dir = -1; 436 | switch (direction) 437 | { 438 | case ResizeDirection.BottomLeft: 439 | dir = HTBOTTOMLEFT; 440 | break; 441 | case ResizeDirection.Left: 442 | dir = HTLEFT; 443 | break; 444 | case ResizeDirection.Right: 445 | dir = HTRIGHT; 446 | break; 447 | case ResizeDirection.BottomRight: 448 | dir = HTBOTTOMRIGHT; 449 | break; 450 | case ResizeDirection.Bottom: 451 | dir = HTBOTTOM; 452 | break; 453 | } 454 | 455 | ReleaseCapture(); 456 | if (dir != -1) 457 | { 458 | SendMessage(Handle, WM_NCLBUTTONDOWN, dir, 0); 459 | } 460 | } 461 | 462 | protected override void OnResize(EventArgs e) 463 | { 464 | base.OnResize(e); 465 | 466 | _minButtonBounds = new Rectangle((Width - SkinManager.FORM_PADDING / 2) - 3 * STATUS_BAR_BUTTON_WIDTH, 0, STATUS_BAR_BUTTON_WIDTH, STATUS_BAR_HEIGHT); 467 | _maxButtonBounds = new Rectangle((Width - SkinManager.FORM_PADDING / 2) - 2 * STATUS_BAR_BUTTON_WIDTH, 0, STATUS_BAR_BUTTON_WIDTH, STATUS_BAR_HEIGHT); 468 | _xButtonBounds = new Rectangle((Width - SkinManager.FORM_PADDING / 2) - STATUS_BAR_BUTTON_WIDTH, 0, STATUS_BAR_BUTTON_WIDTH, STATUS_BAR_HEIGHT); 469 | _statusBarBounds = new Rectangle(0, 0, Width, STATUS_BAR_HEIGHT); 470 | _actionBarBounds = new Rectangle(0, STATUS_BAR_HEIGHT, Width, ACTION_BAR_HEIGHT); 471 | } 472 | 473 | protected override void OnPaint(PaintEventArgs e) 474 | { 475 | var g = e.Graphics; 476 | g.TextRenderingHint = TextRenderingHint.AntiAlias; 477 | 478 | g.Clear(SkinManager.GetApplicationBackgroundColor()); 479 | g.FillRectangle(SkinManager.ColorScheme.DarkPrimaryBrush, _statusBarBounds); 480 | g.FillRectangle(SkinManager.ColorScheme.PrimaryBrush, _actionBarBounds); 481 | 482 | //Draw border 483 | using (var borderPen = new Pen(SkinManager.GetDividersColor(), 1)) 484 | { 485 | g.DrawLine(borderPen, new Point(0, _actionBarBounds.Bottom), new Point(0, Height - 2)); 486 | g.DrawLine(borderPen, new Point(Width - 1, _actionBarBounds.Bottom), new Point(Width - 1, Height - 2)); 487 | g.DrawLine(borderPen, new Point(0, Height - 1), new Point(Width - 1, Height - 1)); 488 | } 489 | 490 | // Determine whether or not we even should be drawing the buttons. 491 | bool showMin = MinimizeBox && ControlBox; 492 | bool showMax = MaximizeBox && ControlBox; 493 | var hoverBrush = SkinManager.GetFlatButtonHoverBackgroundBrush(); 494 | var downBrush = SkinManager.GetFlatButtonPressedBackgroundBrush(); 495 | 496 | // When MaximizeButton == false, the minimize button will be painted in its place 497 | if (_buttonState == ButtonState.MinOver && showMin) 498 | g.FillRectangle(hoverBrush, showMax ? _minButtonBounds : _maxButtonBounds); 499 | 500 | if (_buttonState == ButtonState.MinDown && showMin) 501 | g.FillRectangle(downBrush, showMax ? _minButtonBounds : _maxButtonBounds); 502 | 503 | if (_buttonState == ButtonState.MaxOver && showMax) 504 | g.FillRectangle(hoverBrush, _maxButtonBounds); 505 | 506 | if (_buttonState == ButtonState.MaxDown && showMax) 507 | g.FillRectangle(downBrush, _maxButtonBounds); 508 | 509 | if (_buttonState == ButtonState.XOver && ControlBox) 510 | g.FillRectangle(hoverBrush, _xButtonBounds); 511 | 512 | if (_buttonState == ButtonState.XDown && ControlBox) 513 | g.FillRectangle(downBrush, _xButtonBounds); 514 | 515 | using (var formButtonsPen = new Pen(SkinManager.ACTION_BAR_TEXT_SECONDARY, 2)) 516 | { 517 | // Minimize button. 518 | if (showMin) 519 | { 520 | int x = showMax ? _minButtonBounds.X : _maxButtonBounds.X; 521 | int y = showMax ? _minButtonBounds.Y : _maxButtonBounds.Y; 522 | 523 | g.DrawLine( 524 | formButtonsPen, 525 | x + (int)(_minButtonBounds.Width * 0.33), 526 | y + (int)(_minButtonBounds.Height * 0.66), 527 | x + (int)(_minButtonBounds.Width * 0.66), 528 | y + (int)(_minButtonBounds.Height * 0.66) 529 | ); 530 | } 531 | 532 | // Maximize button 533 | if (showMax) 534 | { 535 | g.DrawRectangle( 536 | formButtonsPen, 537 | _maxButtonBounds.X + (int)(_maxButtonBounds.Width * 0.33), 538 | _maxButtonBounds.Y + (int)(_maxButtonBounds.Height * 0.36), 539 | (int)(_maxButtonBounds.Width * 0.39), 540 | (int)(_maxButtonBounds.Height * 0.31) 541 | ); 542 | } 543 | 544 | // Close button 545 | if (ControlBox) 546 | { 547 | g.DrawLine( 548 | formButtonsPen, 549 | _xButtonBounds.X + (int)(_xButtonBounds.Width * 0.33), 550 | _xButtonBounds.Y + (int)(_xButtonBounds.Height * 0.33), 551 | _xButtonBounds.X + (int)(_xButtonBounds.Width * 0.66), 552 | _xButtonBounds.Y + (int)(_xButtonBounds.Height * 0.66) 553 | ); 554 | 555 | g.DrawLine( 556 | formButtonsPen, 557 | _xButtonBounds.X + (int)(_xButtonBounds.Width * 0.66), 558 | _xButtonBounds.Y + (int)(_xButtonBounds.Height * 0.33), 559 | _xButtonBounds.X + (int)(_xButtonBounds.Width * 0.33), 560 | _xButtonBounds.Y + (int)(_xButtonBounds.Height * 0.66)); 561 | } 562 | } 563 | 564 | //Form title 565 | g.DrawString(Text, SkinManager.ROBOTO_MEDIUM_12, SkinManager.ColorScheme.TextBrush, new Rectangle(SkinManager.FORM_PADDING, STATUS_BAR_HEIGHT, Width, ACTION_BAR_HEIGHT), new StringFormat { LineAlignment = StringAlignment.Center }); 566 | } 567 | } 568 | 569 | public class MouseMessageFilter : IMessageFilter 570 | { 571 | private const int WM_MOUSEMOVE = 0x0200; 572 | 573 | public static event MouseEventHandler MouseMove; 574 | 575 | public bool PreFilterMessage(ref Message m) 576 | { 577 | 578 | if (m.Msg == WM_MOUSEMOVE) 579 | { 580 | if (MouseMove != null) 581 | { 582 | int x = Control.MousePosition.X, y = Control.MousePosition.Y; 583 | 584 | MouseMove(null, new MouseEventArgs(MouseButtons.None, 0, x, y, 0)); 585 | } 586 | } 587 | return false; 588 | } 589 | } 590 | } 591 | --------------------------------------------------------------------------------