diff --git a/Demo/App.config b/Demo/App.config new file mode 100644 index 0000000..56efbc7 --- /dev/null +++ b/Demo/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Demo/Demo.csproj b/Demo/Demo.csproj new file mode 100644 index 0000000..6e9d440 --- /dev/null +++ b/Demo/Demo.csproj @@ -0,0 +1,110 @@ + + + + + Debug + AnyCPU + {B8318FEF-8FC2-44CF-A490-F4AFB70745E8} + WinExe + Demo + Demo + v4.7.2 + 512 + true + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + Form + + + FormDemo.cs + + + + + FormDemo.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + {7c49620c-5f61-4a4e-a6ca-166b18e4daa6} + SwitchWinForms + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + \ No newline at end of file diff --git a/Demo/FormDemo.Designer.cs b/Demo/FormDemo.Designer.cs new file mode 100644 index 0000000..2f8431e --- /dev/null +++ b/Demo/FormDemo.Designer.cs @@ -0,0 +1,183 @@ +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; +using SwitchWinForms; //Primary object for custom Titlebars, Body, Buttons, etc.. + +namespace Demo +{ + partial class FormDemo + { + /// + /// Required designer variable. + /// + private IContainer components = null; + private readonly Font DefaultButtonFont = new Font("Verdana", 12, FontStyle.Regular, GraphicsUnit.Pixel); + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(770, 488); + this.Name = "Form1"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Form1"; + this.Load += new System.EventHandler(this.Form1_Load); + this.ResumeLayout(false); + + } + #endregion + + #region Added User code + /// + /// In use of SwitchWinForms.dll + /// + private void LoadSwitchWinForms() + { + _tbOptions = new SWFTitlebarOptions() + { + RoundedCorners = SWF_ARC_CORNERS.TopLeft | SWF_ARC_CORNERS.TopRight, + Icon = this.Icon.ToBitmap(), + RoundedRadius = 15, + Height = 30, + Padding = new Padding(2, 2, 2, 2), + BackColor = Color.FromArgb(255, 30, 30, 30),// SystemColors.ActiveCaption, + BorderColor = Color.Black, + BorderSize = 2, + ButtonsEnabled = SWF_TITLE_BUTTON.All, + Close = new SWFTitlebarOptions.ButtonsState() //customizing only the close and defaults for Min and Max/Norm + { + RoundedCorners = SWF_ARC_CORNERS.TopRight, + RoundedRadius = 5, + BorderColor = Color.Transparent, + BorderSize = 1, + BackColor = Color.Wheat, + TextSetup = new TextUtil.TextOptions() + { + Color = Color.Black, + Text = SWFUnicodeChars.CLOSE.ToString(), + Font = DefaultButtonFont, + HorizonalAlign = StringAlignment.Center, + VerticalAlign = StringAlignment.Center, + } + }, + Minimized = new SWFTitlebarOptions.ButtonsState() //customizing only the close and defaults for Min and Max/Norm + { + RoundedCorners = SWF_ARC_CORNERS.None, + RoundedRadius = 15, + BorderColor = Color.Transparent, + BorderSize = 1, + BackColor = Color.Wheat, + TextSetup = new TextUtil.TextOptions() + { + Color = Color.Black, + Text = SWFUnicodeChars.MIN.ToString(), + Font = DefaultButtonFont, + HorizonalAlign = StringAlignment.Center, + VerticalAlign = StringAlignment.Center, + } + }, + Maximize = new SWFTitlebarOptions.ButtonsState() //customizing only the close and defaults for Min and Max/Norm + { + RoundedCorners = SWF_ARC_CORNERS.None, + RoundedRadius = 15, + BorderColor = Color.Transparent, + BorderSize = 1, + BackColor = Color.Wheat, + TextSetup = new TextUtil.TextOptions() + { + Color = Color.Black, + Text = SWFUnicodeChars.MAX.ToString(), + Font = DefaultButtonFont, + HorizonalAlign = StringAlignment.Center, + VerticalAlign = StringAlignment.Center, + } + }, + Normal = new SWFTitlebarOptions.ButtonsState() //customizing only the close and defaults for Min and Max/Norm + { + RoundedCorners = SWF_ARC_CORNERS.None, + RoundedRadius = 15, + BorderColor = Color.Transparent, + BorderSize = 1, + BackColor = Color.Wheat, + TextSetup = new TextUtil.TextOptions() + { + Color = Color.Black, + Text = SWFUnicodeChars.NORM.ToString(), + Font = DefaultButtonFont, + HorizonalAlign = StringAlignment.Center, + VerticalAlign = StringAlignment.Center, + } + }, + TextSetup = new TextUtil.TextOptions() + { + //BackgroundImage = (Image)SWFBoxing.ImageFromFile(@"imgs\test.png"), + //BackgroundImageLayout = SWF_BG_IMG_LAYOUT.Tile, + //ReplaceImageColor = new List() { new ReplaceColor(Color.FromArgb(241, 81, 27), Color.Transparent, 100) }, + Text = $"Demo v1", + Color = Color.Wheat, + Font = new Font("Verdana", 10, FontStyle.Bold), + HorizonalAlign = StringAlignment.Near, + VerticalAlign = StringAlignment.Center + }, + }; + _frmOptions = new SWFBoxingOptions() + { + Name = "FrmBody", + Type = SWF_BOX_TYPE.FormBody, + TitleBarHeight = _tbOptions.Height, //default is 30, if not set for SWF_BOX_TYPE.FormBody + RoundedCorners = SWF_ARC_CORNERS.BottomLeft | SWF_ARC_CORNERS.BottomRight, + RoundedRadius = 15, + BackColor = Color.FromArgb(255, 62, 62, 66), + BorderColor = Color.Black, + BorderSize = 2, + Location = new Point(0, 0), + Padding = new Padding(2), + Size = new Size(this.Width, this.Height), + TextSetup = new TextUtil.TextOptions() + { + Color = Color.Wheat, + Text = "Gavin", + Font = new Font("Verdana", 24, FontStyle.Bold, GraphicsUnit.Pixel), + HorizonalAlign = StringAlignment.Center, + VerticalAlign = StringAlignment.Center + }, + }; + + _frmMain = new SWFBoxing(this, _frmOptions); + _titleBar = new SWFTitlebar(this, _tbOptions); + } + + private SWFTitlebarOptions _tbOptions; + private SWFBoxingOptions _frmOptions; + private SWFTitlebar _titleBar; + private SWFBoxing _frmMain; + private SWFBoxing _btn1TileImg; + private SWFBoxing _btn2StretchImg; + private SWFBoxing _lblDisplay; + private SWFBoxing _txtInput; + #endregion + } +} + diff --git a/Demo/FormDemo.cs b/Demo/FormDemo.cs new file mode 100644 index 0000000..4775e99 --- /dev/null +++ b/Demo/FormDemo.cs @@ -0,0 +1,223 @@ +using System; //EventArgs - required by Form Events +using System.Collections.Generic; //List +using System.Drawing; //Color, SystemColors, Font, FrontStyle, GraphicsUnit, StringAlignment, Point, Size +using System.Windows.Forms; //Form +using SwitchWinForms; //Primary object for custom Titlebars, Body, Buttons, etc.. + +namespace Demo +{ + public partial class FormDemo : Form + { + /* + //pre-set unicode characters. + string close_Text_Example1 = SWFUnicodeChars.CLOSE; + //custom unicode characters can be passed here.. + string close_Text_Example2 = new SWFUnicodeChars(10062).ToString(); + */ + public FormDemo() + { + InitializeComponent(); + this.Icon = (Icon)SWFBoxing.ImageFromFile(@"imgs\test.png"); + this.LoadSwitchWinForms(); + } + + private void Form1_Load(object sender, EventArgs e) + { + //example of callback for form resize. Do this on or after load. + //anything prior can cause errors, because the form isn't ready yet. + _frmMain.Resize += Form1_Resize; + + SetupButtons(); + } + private void Form1_Resize(object sender, EventArgs e) + { + ResetSizes(); + } + private void SetupButtons() + { + _btn2StretchImg = new SWFBoxing(this, new SWFBoxingOptions() + { + Name = "BtnStretchedButton", + RoundedCorners = SWF_ARC_CORNERS.TopLeft | SWF_ARC_CORNERS.BottomRight, + RoundedRadius = 80, + BackColor = Color.DarkGray, + BorderColor = Color.Black, + BorderSize = 1, + Location = new Point(100, 100), + Padding = new Padding(2), + Size = new Size(200, 200), + IsAnimatedButton = true, + Type = SWF_BOX_TYPE.Button, + Cursors = new SWFCursors(Cursors.Hand, Cursors.Default), + Shadowing = new ShadowingSetup() + { + Visibilty = SWF_TRANSPARENT_PERCENTAGE.Forty, + Color = Color.Black, + Depth = 20 + }, + TextSetup = new TextUtil.TextOptions() + { + BackgroundImage = (Image)SWFBoxing.ImageFromFile(@"imgs\test.png"), + BackgroundImageLayout = SWF_BG_IMG_LAYOUT.Stretch, + ReplaceImageColor = new List() { + new ReplaceColor(Color.FromArgb(104, 104, 25), Color.Transparent, 100), + new ReplaceColor(Color.White, Color.Transparent, 90) + }, + Color = Color.Black, + Text = "Click Stretched Button", + Font = new Font("Verdana", 10, FontStyle.Bold, GraphicsUnit.Pixel), + HorizonalAlign = StringAlignment.Center, + VerticalAlign = StringAlignment.Center + }, + }); + + _btn2StretchImg.MouseUp += (sender, e) => + { + lock (_lblDisplay.BoxingOptions.TextSetup) + { + SWFBoxing box = (SWFBoxing)sender; + _lblDisplay.BoxingOptions.TextSetup.Text = $"Name: \"{box.BoxingOptions.Name}\" - Text:\"{box.BoxingOptions.TextSetup.Text}\""; + } + }; + + _btn1TileImg = new SWFBoxing(this, new SWFBoxingOptions() + { + Name = "BtnTiledButton", + RoundedCorners = SWF_ARC_CORNERS.TopRight, + RoundedRadius = 40, + //BackColor = Color.Red, + BackColor = Color.Wheat, + BorderColor = Color.Black, + BorderSize = 1, + Location = new Point(_btn2StretchImg.BoxingOptions.Location.X + _btn2StretchImg.BoxingOptions.Size.Width + 30 + , _btn2StretchImg.BoxingOptions.Location.Y), + Padding = new Padding(2), + Size = new Size(200, 200), + IsAnimatedButton = true, + Cursors = new SWFCursors(Cursors.Hand, Cursors.Default), + Type = SWF_BOX_TYPE.Button, + Shadowing = new ShadowingSetup() + { + Visibilty = SWF_TRANSPARENT_PERCENTAGE.Ten, + Color = Color.Black, + Depth = 5 + }, + TextSetup = new TextUtil.TextOptions() + { + BackgroundImage = (Image)SWFBoxing.ImageFromFile(@"imgs\test.png"), + BackgroundImageLayout = SWF_BG_IMG_LAYOUT.Tile, + ReplaceImageColor = new List() { + new ReplaceColor(Color.FromArgb(251, 188, 9), Color.Transparent, 90), + new ReplaceColor(Color.FromArgb(104, 104, 25), Color.Transparent) }, + Color = Color.Black, + Text = "Click Tiled Button", + Font = new Font("Verdana", 10, FontStyle.Bold, GraphicsUnit.Pixel), + HorizonalAlign = StringAlignment.Center, + VerticalAlign = StringAlignment.Center + }, + }); + + _btn1TileImg.MouseUp += (sender, e) => + { + lock (_lblDisplay.BoxingOptions.TextSetup) + { + SWFBoxing box = (SWFBoxing)sender; + _lblDisplay.BoxingOptions.TextSetup.Text = $"Name: \"{box.BoxingOptions.Name}\" - Text:\"{box.BoxingOptions.TextSetup.Text}\""; + } + }; + + _lblDisplay = new SWFBoxing(this, new SWFBoxingOptions() + { + Name = "LblDisplay", + BackColor = Color.FromArgb(60, 255, 255, 255), + BorderColor = Color.Black, + BorderSize = 1, + Padding = new Padding(2), + //Location = new Point(0, _frmMain.BoxingOptions.Size.Height), //handled at resize + //Size = new Size(_frmMain.BoxingOptions.Size.Width, 30), //handled at resize + Type = SWF_BOX_TYPE.Label, + TextSetup = new TextUtil.TextOptions() + { + Color = Color.Black, + Text = "Waiting for click", + Font = new Font("Verdana", 10, FontStyle.Bold, GraphicsUnit.Pixel), + HorizonalAlign = StringAlignment.Near, + VerticalAlign = StringAlignment.Center + }, + }); + + _txtInput = new SWFBoxing(this, new SWFBoxingOptions() + { + Name = "TxtInput", + BackColor = Color.White, + BorderColor = Color.Black, + BorderSize = 1, + Padding = new Padding(2), + Cursors = new SWFCursors(Cursors.IBeam, Cursors.Default), + //Location = new Point(30, _lblDisplay.BoxingOptions.Location.Y - 40), //handled at resize + //Size = new Size(_frmMain.BoxingOptions.Size.Width - 60, 30), //handled at resize + Type = SWF_BOX_TYPE.TextBox, + TextSetup = new TextUtil.TextOptions() + { + Color = Color.Black, + Text = "[Email Here]", + ValidInputExpression = @"^((\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*)\s*[;]{0,1}\s*)+$", + Font = new Font("Courier New", 12, FontStyle.Bold, GraphicsUnit.Pixel), + HorizonalAlign = StringAlignment.Near, + VerticalAlign = StringAlignment.Center + }, + }); + + _txtInput.Exception += (sender, e) => + { + lock (_txtInput.BoxingOptions.TextSetup) + { + SWFBoxing box = (SWFBoxing)sender; + + string msg = $"{box.BoxingOptions.Name}: {e.Exception.Message}"; + _lblDisplay.BoxingOptions.TextSetup.Text = msg; + MessageBox.Show(msg, "Exception"); + this.Invalidate(); + } + }; + + _txtInput.Success += (sender, e) => + { + lock (_txtInput.BoxingOptions.TextSetup) + { + SWFBoxing box = (SWFBoxing)sender; + + string msg = $"{box.BoxingOptions.Name}: {e.Message}"; + _lblDisplay.BoxingOptions.TextSetup.Text = msg; + this.Invalidate(); + } + }; + + ResetSizes(); + } + private void ResetSizes() + { + Size reSize = new Size(this.ClientSize.Width, this.ClientSize.Height - _tbOptions.Height); + + int w = (int)((double)reSize.Width * .3); + int h = (int)((double)reSize.Height * .3); + _btn1TileImg.BoxingOptions.Size = new Size(w, h); + + w = (int)((double)reSize.Width); + h = (int)((double)reSize.Height); + + int brd = _lblDisplay.BoxingOptions.BorderSize + 5; + _lblDisplay.BoxingOptions.Location = new Point(brd, h - 40); + _lblDisplay.BoxingOptions.Size = new Size(w - (brd * 2), 30); + + _txtInput.BoxingOptions.Location = new Point(brd, _lblDisplay.BoxingOptions.Location.Y - 40); + _txtInput.BoxingOptions.Size = _lblDisplay.BoxingOptions.Size; + } + protected override void WndProc(ref Message m) + { + //this handles all form edges and button mouse overs for title. + if (_titleBar == null || !_titleBar.WndProc(ref m)) + base.WndProc(ref m); + } + } +} diff --git a/Demo/FormDemo.resx b/Demo/FormDemo.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Demo/FormDemo.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Demo/Program.cs b/Demo/Program.cs new file mode 100644 index 0000000..0c07285 --- /dev/null +++ b/Demo/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Demo +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new FormDemo()); + } + } +} diff --git a/Demo/Properties/AssemblyInfo.cs b/Demo/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..eff49af --- /dev/null +++ b/Demo/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Demo")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Demo")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b8318fef-8fc2-44cf-a490-f4afb70745e8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Demo/Properties/Resources.Designer.cs b/Demo/Properties/Resources.Designer.cs new file mode 100644 index 0000000..8b245d3 --- /dev/null +++ b/Demo/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Demo.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Demo.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/Demo/Properties/Resources.resx b/Demo/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/Demo/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Demo/Properties/Settings.Designer.cs b/Demo/Properties/Settings.Designer.cs new file mode 100644 index 0000000..d196517 --- /dev/null +++ b/Demo/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Demo.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/Demo/Properties/Settings.settings b/Demo/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/Demo/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Demo/imgs/test.bmp b/Demo/imgs/test.bmp new file mode 100644 index 0000000..793b541 Binary files /dev/null and b/Demo/imgs/test.bmp differ diff --git a/Demo/imgs/test.gif b/Demo/imgs/test.gif new file mode 100644 index 0000000..7a97f73 Binary files /dev/null and b/Demo/imgs/test.gif differ diff --git a/Demo/imgs/test.ico b/Demo/imgs/test.ico new file mode 100644 index 0000000..5906cf7 Binary files /dev/null and b/Demo/imgs/test.ico differ diff --git a/Demo/imgs/test.jpg b/Demo/imgs/test.jpg new file mode 100644 index 0000000..9c86e93 Binary files /dev/null and b/Demo/imgs/test.jpg differ diff --git a/Demo/imgs/test.png b/Demo/imgs/test.png new file mode 100644 index 0000000..a8d30bc Binary files /dev/null and b/Demo/imgs/test.png differ diff --git a/Demo/imgs/test.tif b/Demo/imgs/test.tif new file mode 100644 index 0000000..4f01408 Binary files /dev/null and b/Demo/imgs/test.tif differ diff --git a/SwitchWinForms.sln b/SwitchWinForms.sln new file mode 100644 index 0000000..8cb7661 --- /dev/null +++ b/SwitchWinForms.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SwitchWinForms", "SwitchWinForms\SwitchWinForms.csproj", "{7C49620C-5F61-4A4E-A6CA-166B18E4DAA6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo", "Demo\Demo.csproj", "{B8318FEF-8FC2-44CF-A490-F4AFB70745E8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7C49620C-5F61-4A4E-A6CA-166B18E4DAA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7C49620C-5F61-4A4E-A6CA-166B18E4DAA6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7C49620C-5F61-4A4E-A6CA-166B18E4DAA6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7C49620C-5F61-4A4E-A6CA-166B18E4DAA6}.Release|Any CPU.Build.0 = Release|Any CPU + {B8318FEF-8FC2-44CF-A490-F4AFB70745E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B8318FEF-8FC2-44CF-A490-F4AFB70745E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B8318FEF-8FC2-44CF-A490-F4AFB70745E8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B8318FEF-8FC2-44CF-A490-F4AFB70745E8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DEBD63DC-842D-4950-8765-4C5C196429CF} + EndGlobalSection +EndGlobal diff --git a/SwitchWinForms/Handler/SWFBoxing.cs b/SwitchWinForms/Handler/SWFBoxing.cs new file mode 100644 index 0000000..5c7fcac --- /dev/null +++ b/SwitchWinForms/Handler/SWFBoxing.cs @@ -0,0 +1,485 @@ +using System; +using System.Drawing; +using System.Text.RegularExpressions; +using System.Windows.Forms; + +namespace SwitchWinForms +{ + /// + /// Building custom boxes on your form. + /// + public class SWFBoxing : BoxMethods + { + #region Public Form Events and Delegates + //public delegate void SWFExceptionEventHandler(object sender, SWFMessageEventArgs e); + public delegate void SWFMessageHandler(object sender, SWFMessageEventArgs e); + public event MouseEventHandler MouseDown; + public event MouseEventHandler MouseUp; + public event MouseEventHandler MouseMove; + public event EventHandler MouseLeave; + public event EventHandler Resize; + public event PaintEventHandler Paint; + public event KeyEventHandler KeyUp; + public event KeyEventHandler KeyDown; + public event KeyPressEventHandler KeyPress; + public event SWFMessageHandler Exception; + public event SWFMessageHandler Success; + #endregion + + #region Constructor + /// + /// Building custom boxes on your form. + /// + /// Form Handle => new SWFBoxing(this, ...) + /// + /// + public SWFBoxing(Form frm, SWFBoxingOptions options) + { + if (options == null) + throw new ArgumentNullException("Options is required."); + if (string.IsNullOrWhiteSpace(options.Name)) + throw new ArgumentNullException($"Name property for this box is required.\nType: {options.Type}\nText: {options.TextSetup.Text}"); + + if (GetZIndex(ref options, out int z)) + throw new ArgumentNullException($"'{options.Name}' already exists."); + + options.TextSetup.TextCursor = options.TextSetup.Text.Length; + + this.SetBoxOptions = options; + this.BoxingOptions.Parent = frm; + this.BoxingOptions.ZIndex = z; + + BoxingLoc = new Rectangle(this.BoxingOptions.Location, this.BoxingOptions.Size); + + SetupOptions(); + } + #endregion + + #region Private Properties + private Rectangle BoxingLoc { get; set; } = new Rectangle(); + private bool IgnoreKeyPress { get; set; } = false; + private bool ButtonClicked { get; set; } = false; + private bool InputStart { get; set; } = false; + private bool IsInBounds { get; set; } = false; + private bool CursorChanged { get; set; } = false; + private string DefaultTip { get; set; } = string.Empty; + private SWFBoxingOptions SetBoxOptions { get; set; } = new SWFBoxingOptions(); + #endregion + + #region Public Properties + + /// + /// All setup options for the object your creating. Can be passed in with Constructor or this property. + /// + public SWFBoxingOptions BoxingOptions { get { return SetBoxOptions; } } + + /// + /// Get bounderies for this object. + /// + public Rectangle Rectangle { get { return BoxingLoc; } } + + /// + /// Get location for this object. + /// + public Point Location { get { return BoxingLoc.Location; } } + + /// + /// Get size for this object. + /// + public Size Size { get { return BoxingLoc.Size; } } + + /// + /// Get left boundary for this object. + /// + public int Left { get { return BoxingLoc.X; } } + + /// + /// Get top boundary for this object. + /// + public int Top { get { return BoxingLoc.Y; } } + + /// + /// Get right boundary for this object. + /// + public int Right { get { return BoxingLoc.X + BoxingLoc.Width; } } + + /// + /// Get bottom boundary for this object. + /// + public int Bottom { get { return BoxingLoc.Y + BoxingLoc.Height; } } + #endregion + + #region Private Keyboard Events + private void MR_KeyUp(object sender, KeyEventArgs e) + { + KeyUp?.Invoke(this, e); + } + private void MR_KeyDown(object sender, KeyEventArgs e) + { + if (this.BoxingOptions != null && this.InputStart) + { + bool changes = false; + string text = this.BoxingOptions.TextSetup.Text; + + //KeyPress doesn't capture some keys. We must handle them here. + if (e.KeyCode == Keys.Right) + { + this.BoxingOptions.TextSetup.TextCursor++; + changes = true; + } + else if (e.KeyCode == Keys.Left) + { + this.BoxingOptions.TextSetup.TextCursor--; + changes = true; + } + else if (e.KeyCode == Keys.Delete) + { + Console.WriteLine($"KeyDown: {e.KeyCode}"); + //only used for Delete at the moment. + if (!string.IsNullOrEmpty(text)) + { + int textCursor = this.BoxingOptions.TextSetup.TextCursor; + if (text.Length - (textCursor) > 0) + { + string newText = text.Substring(0, textCursor); + newText += text.Substring(textCursor + 1, text.Length - (textCursor + 1)); + text = newText; + changes = true; + + if (textCursor - 1 > text.Length) + this.BoxingOptions.TextSetup.TextCursor--; + } + } + else + Console.WriteLine($"KeyDown: Nothing to {Keys.Delete}"); + } + else if (e.KeyCode == Keys.Enter) + { + bool valid = true; + string validMessage = "No expression found"; + + lock (SetBoxOptions) + this.IgnoreKeyPress = true; + + Console.WriteLine($"KeyDown: {e.KeyCode}"); + if (this.BoxingOptions.TextSetup.ValidInputExpression != null) + { + string pattern = this.BoxingOptions.TextSetup.ValidInputExpression; + valid = Regex.Match(text, pattern, RegexOptions.IgnoreCase).Success; + if (valid) + validMessage = "Expression is valid"; + } + + if (valid) + { + changes = true; + this.InputStart = false; + this.BoxingOptions.TextSetup.TextCursor = text.Length; + Success?.Invoke(this, + new SWFMessageEventArgs( + validMessage + )); + } + else + { + Exception?.Invoke(this, + new SWFMessageEventArgs( + new Exception("Failed regex expression.") + )); + } + } + else if (e.KeyCode == Keys.Escape) + { + lock (SetBoxOptions) + { + this.IgnoreKeyPress = true; + this.InputStart = false; + } + + Console.WriteLine($"KeyDown: {e.KeyCode}"); + changes = true; + text = this.DefaultTip; + this.BoxingOptions.TextSetup.TextCursor = text.Length; + } + else if (e.KeyCode == Keys.Back) + { + Console.WriteLine($"KeyDown: {e.KeyCode}"); + int textCursor = this.BoxingOptions.TextSetup.TextCursor; + if (!string.IsNullOrEmpty(text) && textCursor > 0) + { + string newText = text.Substring(0, textCursor - 1); + int size = text.Length > textCursor ? text.Length - textCursor : textCursor - text.Length; + newText += text.Substring(textCursor, size); + text = newText; + + changes = true; + this.BoxingOptions.TextSetup.TextCursor--; + } + else + Console.WriteLine($"Nothing to {e.KeyCode}"); + + lock (SetBoxOptions) + this.IgnoreKeyPress = true; + } + + if (this.BoxingOptions.TextSetup.TextCursor < 0) + this.BoxingOptions.TextSetup.TextCursor = 0; + else if (this.BoxingOptions.TextSetup.TextCursor > text.Length) + this.BoxingOptions.TextSetup.TextCursor = text.Length; + + if (changes) + { + this.BoxingOptions.TextSetup.Text = text; + this.BoxingOptions.Parent.Invalidate(); + } + } + + KeyDown?.Invoke(this, e); + } + private void MR_KeyPress(object sender, KeyPressEventArgs e) + { + if (this.BoxingOptions != null && this.InputStart) + { + lock (SetBoxOptions) + { + if (!this.IgnoreKeyPress) + { + Console.WriteLine($"KeyPress: {e.KeyChar}"); + + string text = this.BoxingOptions.TextSetup.Text; + int textCursor = this.BoxingOptions.TextSetup.TextCursor; + + string newText = string.IsNullOrEmpty(text) || textCursor == 0 ? "" : + text.Substring(0, textCursor); + string subText = string.IsNullOrEmpty(text) || textCursor == 0 ? "" : + text.Substring(textCursor, text.Length - textCursor); + + this.BoxingOptions.TextSetup.TextCursor++; + + text = newText; + text += e.KeyChar.ToString(); + text += subText; + + this.BoxingOptions.TextSetup.Text = text; + this.BoxingOptions.Parent.Invalidate(); + + if (this.BoxingOptions.TextSetup.TextCursor < 0) + this.BoxingOptions.TextSetup.TextCursor = 0; + else if (this.BoxingOptions.TextSetup.TextCursor > text.Length) + this.BoxingOptions.TextSetup.TextCursor = text.Length; + } + else + Console.WriteLine($"KeyPress: Ignoring {e.KeyChar}"); + + this.IgnoreKeyPress = false; + } + } + + KeyPress?.Invoke(this, e); + } + #endregion + + #region Private Mouse Events + private void MR_MouseLeave(object sender, EventArgs e) + { + if (CursorChanged && this.BoxingOptions != null) + { + CursorChanged = false; + this.BoxingOptions.Parent.Cursor = Cursors.Default; + } + this.MouseLeave?.Invoke(this, e); + } + private void MR_MouseUp(object sender, MouseEventArgs e) + { + if (this.BoxingOptions != null && this.ButtonClicked && this.IsInBounds) + { + this.ButtonClicked = false; + this.BoxingOptions.Location = new Point(this.BoxingOptions.Location.X - this.BoxingOptions.Shadowing.Depth, + this.BoxingOptions.Location.Y - this.BoxingOptions.Shadowing.Depth); + this.BoxingOptions.Parent.Invalidate(); + } + + if (this.IsInBounds) + MouseUp?.Invoke(this, e); + } + private void MR_MouseDown(object sender, MouseEventArgs e) + { + if (this.BoxingOptions == null) + return; + + if (IsClickable() && this.IsInBounds) + { + if (ImOnTop(this.BoxingOptions)) + { + if (this.BoxingOptions.Type == SWF_BOX_TYPE.TextBox) + { + this.InputStart = true; + string text = this.BoxingOptions.TextSetup.Text; + this.DefaultTip = text; + + if (text.StartsWith("[") && text.EndsWith("]")) + this.BoxingOptions.TextSetup.Text = ""; + this.BoxingOptions.Parent.Invalidate(); + } + else if (this.BoxingOptions.Type == SWF_BOX_TYPE.Button && this.BoxingOptions.Shadowing.Depth > 0) + { + this.ButtonClicked = true; + this.BoxingOptions.Location = new Point(this.BoxingOptions.Location.X + this.BoxingOptions.Shadowing.Depth, + this.BoxingOptions.Location.Y + this.BoxingOptions.Shadowing.Depth); + this.BoxingOptions.Parent.Invalidate(); + } + + this.MouseDown?.Invoke(this, e); + } + } + } + private void MR_MouseMove(object sender, MouseEventArgs e) + { + if (this.BoxingOptions == null) + return; + + if(Global.IsInBounds(this.BoxingOptions.Parent, e.Location, this.BoxingLoc)) + { + if (ImOnTop(this.BoxingOptions)) + { + this.IsInBounds = true; + bool isClickable = IsClickable(); + Cursor cursor = GetCursorByType(this.BoxingOptions.Parent, this.BoxingOptions.Cursors.OnMove, out bool cursorChanged); + + if (isClickable && cursorChanged) + { + this.BoxingOptions.Parent.Cursor = cursor; + this.CursorChanged = cursorChanged; + } + + this.MouseMove?.Invoke(this, e); + } + } + else + { + //check to see if this object was in bounds, if not, then ignore.. + if (this.IsInBounds) + { + this.IsInBounds = false; + this.BoxingOptions.Parent.Cursor = Cursors.Default; + this.CursorChanged = true; + this.MouseLeave?.Invoke(this, e); + } + + if (this.ButtonClicked) + { + this.ButtonClicked = false; + this.BoxingOptions.Location = new Point(this.BoxingOptions.Location.X - this.BoxingOptions.Shadowing.Depth, + this.BoxingOptions.Location.Y - this.BoxingOptions.Shadowing.Depth); + this.BoxingOptions.Parent.Invalidate(); + } + } + } + #endregion + + #region Private Form Events + private void MR_Resize(object sender, EventArgs e) + { + this.BoxingLoc = new Rectangle(this.BoxingOptions.Location, this.BoxingOptions.Size); + this.BoxingOptions.Parent.Invalidate(); + this.Resize?.Invoke(this, e); + } + private void MR_Paint(object sender, PaintEventArgs e) + { + Rectangle rec = e.ClipRectangle; + Graphics g = e.Graphics; + if (g != null && + this.BoxingOptions.Location.X < this.BoxingOptions.Parent.Width && + this.BoxingOptions.Location.Y < this.BoxingOptions.Parent.Height) + { + if (this.BoxingOptions.Type == SWF_BOX_TYPE.FormBody) + { + this.BoxingOptions.Location = new Point(0, this.BoxingOptions.TitleBarHeight - this.BoxingOptions.BorderSize); + this.BoxingOptions.Size = new Size(this.BoxingOptions.Parent.Width, + this.BoxingOptions.Parent.Height - this.BoxingOptions.TitleBarHeight); + + //cannot do shadowing on the form, as it's not able to draw off the form. + //possibly in the future, sizing of the form instead so shadow shows up, + //however, since the real form is pink, it might not work. + this.BoxingOptions.Shadowing = null; + } + + Rectangle titleBG = new Rectangle(this.BoxingOptions.Location, this.BoxingOptions.Size); + + BoxInfo bi = Global.CreateBox(g, new BoxInfo() + { + BackColor = this.BoxingOptions.BackColor, + ForeColor = this.BoxingOptions.TextSetup.Color, + BorderColor = this.BoxingOptions.BorderColor, + BorderSize = this.BoxingOptions.BorderSize, + Rectangle = titleBG, + HAlign = this.BoxingOptions.TextSetup.HorizonalAlign, + VAlign = this.BoxingOptions.TextSetup.VerticalAlign, + Font = this.BoxingOptions.TextSetup.Font, + Text = this.BoxingOptions.TextSetup.Text, + Padding = this.BoxingOptions.Padding, + Shadowing = this.BoxingOptions.Shadowing, + BackgroundImage = this.BoxingOptions.TextSetup.BackgroundImage, + RoundedCorners = this.BoxingOptions.RoundedCorners, + RoundedRadius = this.BoxingOptions.RoundedRadius, + BackgroundImageLayout = this.BoxingOptions.TextSetup.BackgroundImageLayout, + ReplaceImageColor = this.BoxingOptions.TextSetup.ReplaceImageColor, + ButtonClicked = this.ButtonClicked, + TextCursor = this.BoxingOptions.TextSetup.TextCursor, + Type = this.BoxingOptions.Type, + InputStart = this.InputStart, + }); + + if (bi.BackgroundImageModified) + { + this.BoxingOptions.TextSetup.BackgroundImage = bi.BackgroundImage; + this.BoxingOptions.TextSetup.ReplaceImageColor = bi.ReplaceImageColor; + } + + BoxingLoc = new Rectangle(this.BoxingOptions.Location, this.BoxingOptions.Size); + } + this.Paint?.Invoke(this, e); + } + #endregion + + #region Private Methods + private bool IsClickable() + { + if (this.MouseDown != null || + this.MouseUp != null || + this.BoxingOptions.Type == SWF_BOX_TYPE.Button || + this.BoxingOptions.Type == SWF_BOX_TYPE.TextBox) + return true; + else + return false; + } + private void SetupOptions() + { + this.BoxingOptions.Parent.MouseMove += MR_MouseMove; + this.BoxingOptions.Parent.MouseLeave += MR_MouseLeave; + this.BoxingOptions.Parent.MouseUp += MR_MouseUp; + this.BoxingOptions.Parent.MouseDown += MR_MouseDown; + this.BoxingOptions.Parent.Paint += MR_Paint; + this.BoxingOptions.Parent.Resize += MR_Resize; + this.BoxingOptions.Parent.KeyPress += MR_KeyPress; + this.BoxingOptions.Parent.KeyUp += MR_KeyUp; + this.BoxingOptions.Parent.KeyDown += MR_KeyDown; + } + #endregion + + #region Public Static Methods + /// + /// Load image from file. Supported files types are (gif,bmp,ico,tif,jpg,png). + /// + public static object ImageFromFile(string path) + { + if (typeof(T).Name.ToLower() == "image") + return (object)Global.GetImage(path); + else if (typeof(T).Name.ToLower() == "icon") + return (object)Global.GetIcon(path); + else + return null; + } + #endregion + } +} diff --git a/SwitchWinForms/Handler/SWFTitlebar.cs b/SwitchWinForms/Handler/SWFTitlebar.cs new file mode 100644 index 0000000..1d31bd4 --- /dev/null +++ b/SwitchWinForms/Handler/SWFTitlebar.cs @@ -0,0 +1,378 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using System.Reflection; +using System.IO; + +namespace SwitchWinForms +{ + /// + /// Creating a custome Titlebar, this replaces your exists. Do not use more that one instnace per project. + /// + public partial class SWFTitlebar : BoxMethods + { + #region Constructor + public SWFTitlebar(Form frm, SWFTitlebarOptions options = null) + { + if (frm == null) + { + SetLastError = new ArgumentNullException("Missing Form Object"); + throw SetLastError; + } + + if (frm.FormBorderStyle != FormBorderStyle.None) + frm.FormBorderStyle = FormBorderStyle.None; + + //Ensure doublebuffered set on form. + //This stops major flickering. + SetDoubleBuffered(frm); + + frm.BackColor = Color.FromArgb(192, 0, 191); + frm.TransparencyKey = frm.BackColor; + + if (frm.MinimumSize.Width == 0 && + frm.MinimumSize.Height == 0) + frm.MinimumSize = new Size(100, 100); + + TitleOptions = options ?? new SWFTitlebarOptions(); + TitleOptions.GetSetParent = frm; + + if (TitleOptions.TextSetup != null && !TitleOptions.TextSetup.Empty) + TitleOptions.Parent.Text = TitleOptions.TextSetup?.Text; + + SetupOptions(); + } + #endregion + + #region Private Form Events + private void Form_MouseUp(object sender, MouseEventArgs e) + { + this.Drag = false; + } + private void Form_MouseDown(object sender, MouseEventArgs e) + { + if ((TitleOptions.ButtonsEnabled & SWF_TITLE_BUTTON.Close) == SWF_TITLE_BUTTON.Close + && Global.IsInBounds(TitleOptions.Parent, e.Location, this.BtnCloseRec, Cursors.Hand)) + { + TitleOptions.Parent.Close(); + } + else if ((TitleOptions.ButtonsEnabled & SWF_TITLE_BUTTON.Minimize) == SWF_TITLE_BUTTON.Minimize + && Global.IsInBounds(TitleOptions.Parent, e.Location, this.BtnMinRec, Cursors.Hand)) + { + TitleOptions.Parent.WindowState = FormWindowState.Minimized; + } + else if ((TitleOptions.ButtonsEnabled & SWF_TITLE_BUTTON.Maximize_Normal) == SWF_TITLE_BUTTON.Maximize_Normal + && Global.IsInBounds(TitleOptions.Parent, e.Location, this.BtnMaxRec, Cursors.Hand)) + { + + if (TitleOptions.Parent.WindowState == FormWindowState.Maximized) + TitleOptions.Parent.WindowState = FormWindowState.Normal; + else + TitleOptions.Parent.WindowState = FormWindowState.Maximized; + } + else if (TitleOptions.Height > e.Location.Y) + { + this.StartPoint = e.Location; + this.Drag = true; + } + } + private void Form_MouseMove(object sender, MouseEventArgs e) + { + if (this.Drag) + { + // if we should be dragging it, we need to figure out some movement + Point p1 = new Point(e.X, e.Y); + Point p2 = TitleOptions.Parent.PointToScreen(p1); + Point p3 = new Point(p2.X - this.StartPoint.X, + p2.Y - this.StartPoint.Y); + + TitleOptions.Parent.Location = p3; + } + else + { + if (Global.IsInBounds(TitleOptions.Parent, e.Location, TitleOptions.Rectangle) + && TitleOptions.Parent.Cursor != Cursors.Default) + { + int x = 0; + int t = 0; + int b = 0; + + if ((TitleOptions.ButtonsEnabled & SWF_TITLE_BUTTON.Minimize) == SWF_TITLE_BUTTON.Minimize) + { + x = this.BtnMinRec.Left; + t = this.BtnMinRec.Top; + b = this.BtnMinRec.Top + this.BtnMinRec.Height; + } + else if ((TitleOptions.ButtonsEnabled & SWF_TITLE_BUTTON.Maximize_Normal) == SWF_TITLE_BUTTON.Maximize_Normal) + { + x = this.BtnMaxRec.Left; + t = this.BtnMaxRec.Top; + b = this.BtnMaxRec.Top + this.BtnMaxRec.Height; + } + else if ((TitleOptions.ButtonsEnabled & SWF_TITLE_BUTTON.Close) == SWF_TITLE_BUTTON.Close) + { + x = this.BtnCloseRec.Left; + t = this.BtnCloseRec.Top; + b = this.BtnCloseRec.Top + this.BtnCloseRec.Height; + } + + if (e.X < x || e.Y < t || e.Y > b) + TitleOptions.Parent.Cursor = Cursors.Default; + } + } + } + private void Form_Resize(object sender, EventArgs e) + { + if ((TitleOptions.Parent.MinimumSize.Width == 0 && + TitleOptions.Parent.MinimumSize.Height == 0) || + (TitleOptions.Parent.MinimumSize.Width == 100 && + TitleOptions.Parent.MinimumSize.Height == 100)) + { + int w = 0; + int fWidth = TitleOptions.Parent.Width + (this.BtnMinRec.Width / 2); + + if ((TitleOptions.ButtonsEnabled & SWF_TITLE_BUTTON.Minimize) == SWF_TITLE_BUTTON.Minimize && this.BtnMinRec.Height > 0) + w = fWidth - this.BtnMinRec.Left; + else if ((TitleOptions.ButtonsEnabled & SWF_TITLE_BUTTON.Maximize_Normal) == SWF_TITLE_BUTTON.Maximize_Normal && this.BtnMaxRec.Height > 0) + w = fWidth - this.BtnMaxRec.Left; + else if ((TitleOptions.ButtonsEnabled & SWF_TITLE_BUTTON.Close) == SWF_TITLE_BUTTON.Close && this.BtnCloseRec.Height > 0) + w = fWidth - this.BtnCloseRec.Left; + + if (w > 0) + TitleOptions.Parent.MinimumSize = new Size(w, 100); + } + + TitleOptions.Parent.Invalidate(); + } + private void Form_Paint(object sender, PaintEventArgs e) + { + Graphics g = e.Graphics; + if (g != null) + { + TitleOptions.Location = new Point(0, 0); + TitleOptions.Size = new Size(TitleOptions.Parent.Width, TitleOptions.Height); + + /*if ((TitleOptions.RoundedCorners & SWF_ARC_CORNERS.TopLeft) > 0 && TitleOptions.TextSetup.HorizonalAlign == StringAlignment.Near) + { + float f = ((float)TitleOptions.RoundedRadius) * 0.5F; + int extra = (int)Math.Floor(f); + TitleOptions.Padding = new Padding(TitleOptions.Padding.Left + extra, TitleOptions.Padding.Top, TitleOptions.Padding.Right, TitleOptions.Padding.Bottom); + }*/ + + BoxInfo boxInfo = new BoxInfo() + { + BackColor = TitleOptions.BackColor, + ForeColor = TitleOptions.TextSetup.Color, + BorderColor = TitleOptions.BorderColor, + BorderSize = TitleOptions.BorderSize, + Rectangle = TitleOptions.Rectangle, + HAlign = TitleOptions.TextSetup.HorizonalAlign, + VAlign = TitleOptions.TextSetup.VerticalAlign, + Font = TitleOptions.TextSetup.Font, + Text = TitleOptions.TextSetup.Text, + Padding = TitleOptions.Padding, + BackgroundImage = TitleOptions.TextSetup.BackgroundImage, + RoundedCorners = TitleOptions.RoundedCorners, + RoundedRadius = TitleOptions.RoundedRadius, + BackgroundImageLayout = TitleOptions.TextSetup.BackgroundImageLayout, + ReplaceImageColor = TitleOptions.TextSetup.ReplaceImageColor, + Type = SWF_BOX_TYPE.Titlebar, + Icon = TitleOptions.Icon + }; + + BoxInfo bi = Global.CreateBox(g, boxInfo); //title + + if (bi.BackgroundImageModified) + { + TitleOptions.TextSetup.BackgroundImage = bi.BackgroundImage; + TitleOptions.TextSetup.ReplaceImageColor = bi.ReplaceImageColor; + } + + CreateButtons(g, boxInfo); //title buttons + } + } + #endregion + + #region Private Methods + private bool SetDoubleBuffered(Form frm) + { + bool retVal = false; + if (SystemInformation.TerminalServerSession) + { + SetLastError = new Exception("## WARN ##, Flicking may occur, because your in a terminal session."); + return retVal; + } + + if (frm != null) + { + try + { + PropertyInfo aProp = + typeof(Control).GetProperty("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance); + + aProp.SetValue(frm, true, null); + retVal = true; + } + catch (Exception ex) + { + SetLastError = ex; + } + } + else + SetLastError = new Exception("## WARN ##, Missing Form object."); + + return retVal; + } + private void CreateButtons(Graphics g, BoxInfo boxInfo) + { + int buttonPadding = 2; + Rectangle titleRect = boxInfo.Rectangle; + Rectangle btnRect = boxInfo.Rectangle; + BoxInfo newBtnSetup; + + btnRect.Height = titleRect.Height - (TitleOptions.Padding.Top + TitleOptions.Padding.Bottom) - (boxInfo.BorderSize * 2); + btnRect.Width = btnRect.Height; + + float f = ((float)TitleOptions.RoundedRadius) * 0.5F; + int extra = (int)Math.Floor(f); + + if (TitleOptions.Icon != null) + { + btnRect.X = TitleOptions.Padding.Left + TitleOptions.BorderSize; + btnRect.Y = TitleOptions.Padding.Top + TitleOptions.BorderSize; + + if ((TitleOptions.RoundedCorners & SWF_ARC_CORNERS.TopLeft) > 0) + btnRect.X += extra; + + newBtnSetup = new BoxInfo() + { + Rectangle = btnRect, + BackgroundImageLayout = SWF_BG_IMG_LAYOUT.Normal, + BorderSize = TitleOptions.Close.BorderSize, + BorderColor = TitleOptions.Close.BorderColor, + RoundedCorners = TitleOptions.Close.RoundedCorners, + RoundedRadius = TitleOptions.Close.RoundedRadius, + BackgroundImage = TitleOptions.Icon, + }; + //newBtnSetup.Rectangle = new Rectangle(new Point(30, 0), new Size(200, 200)); + + Global.CreateBox(g, newBtnSetup); + } + + btnRect.X = titleRect.Width - btnRect.Width - TitleOptions.Padding.Right - TitleOptions.BorderSize; + btnRect.Y = boxInfo.Rectangle.Y + TitleOptions.Padding.Top + TitleOptions.BorderSize; + + if ((TitleOptions.RoundedCorners & SWF_ARC_CORNERS.TopRight) > 0) + btnRect.X -= extra; + + if ((TitleOptions.ButtonsEnabled & SWF_TITLE_BUTTON.Close) > 0) + { + newBtnSetup = new BoxInfo() + { + BackColor = TitleOptions.Close.BackColor, + ForeColor = TitleOptions.Close.TextSetup.Color, + BorderSize = TitleOptions.Close.BorderSize, + BorderColor = TitleOptions.Close.BorderColor, + Font = TitleOptions.Close.TextSetup.Font, + Padding = TitleOptions.Close.Padding, + HAlign = TitleOptions.Close.TextSetup.HorizonalAlign, + VAlign = TitleOptions.Close.TextSetup.VerticalAlign, + Rectangle = btnRect, + Text = TitleOptions.Close.TextSetup.Text, + RoundedCorners = TitleOptions.Close.RoundedCorners, + RoundedRadius = TitleOptions.Close.RoundedRadius + }; + + this.BtnCloseRec = newBtnSetup.Rectangle; + Global.CreateBox(g, newBtnSetup); + btnRect.X -= (btnRect.Width + buttonPadding + boxInfo.BorderSize); + newBtnSetup.Rectangle = btnRect; + } + else + this.BtnCloseRec = new Rectangle(); + + if ((TitleOptions.ButtonsEnabled & SWF_TITLE_BUTTON.Maximize_Normal) > 0) + { + if (TitleOptions.Parent.WindowState == FormWindowState.Maximized) + { + newBtnSetup = new BoxInfo() + { + BackColor = TitleOptions.Maximize.BackColor, + ForeColor = TitleOptions.Maximize.TextSetup.Color, + BorderSize = TitleOptions.Maximize.BorderSize, + BorderColor = TitleOptions.Maximize.BorderColor, + Font = TitleOptions.Maximize.TextSetup.Font, + Padding = TitleOptions.Maximize.Padding, + HAlign = TitleOptions.Maximize.TextSetup.HorizonalAlign, + VAlign = TitleOptions.Maximize.TextSetup.VerticalAlign, + Rectangle = btnRect, + Text = TitleOptions.Maximize.TextSetup.Text, + RoundedCorners = TitleOptions.Maximize.RoundedCorners, + RoundedRadius = TitleOptions.Maximize.RoundedRadius + }; + } + else + { + newBtnSetup = new BoxInfo() + { + BackColor = TitleOptions.Normal.BackColor, + ForeColor = TitleOptions.Normal.TextSetup.Color, + BorderSize = TitleOptions.Normal.BorderSize, + BorderColor = TitleOptions.Normal.BorderColor, + Font = TitleOptions.Normal.TextSetup.Font, + Padding = TitleOptions.Normal.Padding, + HAlign = TitleOptions.Normal.TextSetup.HorizonalAlign, + VAlign = TitleOptions.Normal.TextSetup.VerticalAlign, + Rectangle = btnRect, + Text = TitleOptions.Normal.TextSetup.Text, + RoundedCorners = TitleOptions.Normal.RoundedCorners, + RoundedRadius = TitleOptions.Normal.RoundedRadius + }; + } + + this.BtnMaxRec = newBtnSetup.Rectangle; + Global.CreateBox(g, newBtnSetup); + btnRect.X -= (btnRect.Width + buttonPadding + boxInfo.BorderSize); + newBtnSetup.Rectangle = btnRect; + } + else + this.BtnMaxRec = new Rectangle(); + + if ((TitleOptions.ButtonsEnabled & SWF_TITLE_BUTTON.Minimize) > 0) + { + newBtnSetup = new BoxInfo() + { + BackColor = TitleOptions.Minimized.BackColor, + ForeColor = TitleOptions.Minimized.TextSetup.Color, + BorderSize = TitleOptions.Minimized.BorderSize, + BorderColor = TitleOptions.Minimized.BorderColor, + Font = TitleOptions.Minimized.TextSetup.Font, + Padding = TitleOptions.Minimized.Padding, + HAlign = TitleOptions.Minimized.TextSetup.HorizonalAlign, + VAlign = TitleOptions.Minimized.TextSetup.VerticalAlign, + Rectangle = btnRect, + Text = TitleOptions.Minimized.TextSetup.Text, + RoundedCorners = TitleOptions.Minimized.RoundedCorners, + RoundedRadius = TitleOptions.Minimized.RoundedRadius + }; + + this.BtnMinRec = newBtnSetup.Rectangle; + Global.CreateBox(g, newBtnSetup); + btnRect.X -= (btnRect.Width + buttonPadding + boxInfo.BorderSize); + newBtnSetup.Rectangle = btnRect; + } + else + this.BtnMinRec = new Rectangle(); + } + private void SetupOptions() + { + TitleOptions.Parent.MouseMove += Form_MouseMove; + TitleOptions.Parent.MouseUp += Form_MouseUp; + TitleOptions.Parent.MouseDown += Form_MouseDown; + TitleOptions.Parent.Paint += Form_Paint; + TitleOptions.Parent.Resize += Form_Resize; + } + #endregion + } +} diff --git a/SwitchWinForms/Helper/BoxMethods.cs b/SwitchWinForms/Helper/BoxMethods.cs new file mode 100644 index 0000000..16e06e3 --- /dev/null +++ b/SwitchWinForms/Helper/BoxMethods.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Security.Permissions; +using System.Windows.Forms; + +namespace SwitchWinForms +{ + public abstract class BoxMethods + { + private static SWFTitlebarOptions _titleOptions = null; + + const int cursorFormEdge = 5; + const int WM_NCHITTEST = 0x0084; + + private SWF_RESIZEABLE _resizeable = SWF_RESIZEABLE.None; + + + #region Internal Properties + internal static Dictionary ZIndex { get; } = new Dictionary(); + internal static int LatestZIndex { get; set; } = 0; + internal Rectangle BtnCloseRec { get; set; } = new Rectangle(); + internal Rectangle BtnMinRec { get; set; } = new Rectangle(); + internal Rectangle BtnMaxRec { get; set; } = new Rectangle(); + internal Point StartPoint { get; set; } = new Point(0, 0); // also for the moving + internal bool Drag { get; set; } = false; // determine if we should be moving the form + internal Exception SetLastError { get; set; } + #endregion + + #region Public Methods + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + public bool WndProc(ref Message m) + { + bool retVal = false; + + if (m.Msg == WM_NCHITTEST && IsFormResizeable()) + { + int x = (int)(m.LParam.ToInt64() & 0xFFFF); + int y = (int)((m.LParam.ToInt64() & 0xFFFF0000) >> 16); + Point pt = SWFTitlebar.TitleOptions.Parent.PointToClient(new Point(x, y)); + Size clientSize = SWFTitlebar.TitleOptions.Parent.ClientSize; + + if (Global.IsInBounds(SWFTitlebar.TitleOptions.Parent, pt, this.BtnCloseRec, Cursors.Hand) || + Global.IsInBounds(SWFTitlebar.TitleOptions.Parent, pt, this.BtnMinRec, Cursors.Hand) || + Global.IsInBounds(SWFTitlebar.TitleOptions.Parent, pt, this.BtnMaxRec, Cursors.Hand)) + { + retVal = false; + } + else if (pt.X <= cursorFormEdge && pt.Y >= clientSize.Height - cursorFormEdge && clientSize.Height >= cursorFormEdge) + { + m.Result = (IntPtr)(SWFTitlebar.TitleOptions.Parent.IsMirrored ? SWF_HITTEST.HT_BOTTOMRIGHT : SWF_HITTEST.HT_BOTTOMLEFT); + retVal = true; + } + else if (pt.X >= clientSize.Width - cursorFormEdge && pt.Y >= clientSize.Height - cursorFormEdge && clientSize.Width >= cursorFormEdge) + { + m.Result = (IntPtr)(SWFTitlebar.TitleOptions.Parent.IsMirrored ? SWF_HITTEST.HT_BOTTOMLEFT : SWF_HITTEST.HT_BOTTOMRIGHT); + retVal = true; + } + else if (pt.X <= cursorFormEdge && pt.Y <= cursorFormEdge && clientSize.Height >= cursorFormEdge) + { + m.Result = (IntPtr)(SWFTitlebar.TitleOptions.Parent.IsMirrored ? SWF_HITTEST.HT_TOPRIGHT : SWF_HITTEST.HT_TOPLEFT); + retVal = true; + } + else if (pt.X >= clientSize.Width - cursorFormEdge && pt.Y <= cursorFormEdge && clientSize.Height >= cursorFormEdge) + { + m.Result = (IntPtr)(SWFTitlebar.TitleOptions.Parent.IsMirrored ? SWF_HITTEST.HT_TOPLEFT : SWF_HITTEST.HT_TOPRIGHT); + retVal = true; + } + else if (pt.Y <= cursorFormEdge && clientSize.Height >= cursorFormEdge) + { + m.Result = (IntPtr)(SWF_HITTEST.HT_TOP); + retVal = true; + } + else if (pt.Y >= clientSize.Height - cursorFormEdge && clientSize.Height >= cursorFormEdge) + { + m.Result = (IntPtr)(SWF_HITTEST.HT_BOTTOM); + retVal = true; + } + else if (pt.X <= cursorFormEdge && clientSize.Height >= cursorFormEdge) + { + m.Result = (IntPtr)(SWF_HITTEST.HT_LEFT); + retVal = true; + } + else if (pt.X >= clientSize.Width - cursorFormEdge && clientSize.Height >= cursorFormEdge) + { + m.Result = (IntPtr)(SWF_HITTEST.HT_RIGHT); + retVal = true; + } + else + { + //SWFTitlebar.TitleOptions.Parent.Cursor = Cursors.Default; + retVal = false; + } + } + + return retVal; + } + public static SWFTitlebarOptions TitleOptions + { + get { return _titleOptions; } + set + { + _titleOptions = value; + if (TitleOptions.Parent != null && !string.IsNullOrWhiteSpace(TitleOptions.TextSetup?.Text)) + TitleOptions.Parent.Text = TitleOptions.TextSetup.Text; + } + } + public Exception LastError { get { return SetLastError; } } + #endregion + + #region Private/Internal Methods + internal bool GetZIndex(ref SWFBoxingOptions options, out int idx) + { + bool retVal = false; + + lock (ZIndex) + { + if (ZIndex.TryGetValue(options.Name, out SWFBoxingOptions foundOpt)) + { + idx = foundOpt.ZIndex; + retVal = true; + } + else + { + idx = ++LatestZIndex; + options.ZIndex = idx; + ZIndex.Add(options.Name, options); + } + } + + return retVal; + } + internal bool ImOnTop(SWFBoxingOptions options) + { + bool retVal = true; + + foreach (SWFBoxingOptions bopt in ZIndex.Values) + { + if (options.Name == bopt.Name) + continue; + + if (bopt.ZIndex > options.ZIndex) + { + if (options.Rectangle.Contains(bopt.Rectangle)) + { + retVal = false; + break; + } + } + } + + return retVal; + } + private bool IsFormResizeable() + { + if (this._resizeable == SWF_RESIZEABLE.None) + { + if ((TitleOptions.ButtonsEnabled & SWF_TITLE_BUTTON.Maximize_Normal) > 0) + this._resizeable = SWF_RESIZEABLE.Yes; + else + this._resizeable = SWF_RESIZEABLE.No; + } + + return this._resizeable == SWF_RESIZEABLE.Yes; + } + internal Cursor GetCursorByType(Form frm, Cursor defaultCursor, out bool cursorChanged) + { + Cursor retVal = frm.Cursor; + cursorChanged = false; + + if (retVal != defaultCursor) + { + cursorChanged = true; + retVal = defaultCursor; + } + return retVal; + } + #endregion + } +} diff --git a/SwitchWinForms/Models/BoxInfo.cs b/SwitchWinForms/Models/BoxInfo.cs new file mode 100644 index 0000000..096f204 --- /dev/null +++ b/SwitchWinForms/Models/BoxInfo.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; +//test +namespace SwitchWinForms +{ + internal class BoxInfo + { + public int BorderSize { get; set; } + public Padding Padding { get; set; } + public Rectangle Rectangle { get; set; } + public SWF_BOX_TYPE Type { get; set; } + public int TextCursor { get; set; } + public string Text { get; set; } + public Image Icon { get; set; } + public Font Font { get; set; } + public StringAlignment VAlign { get; set; } + public StringAlignment HAlign { get; set; } + public Color BackColor { get; set; } + public Color BorderColor { get; set; } + public Color ForeColor { get; set; } + public Image BackgroundImage { get; set; } = null; + public List ReplaceImageColor { get; set; } = new List() { }; + public ShadowingSetup Shadowing { get; set; } = new ShadowingSetup(); + public SWF_BG_IMG_LAYOUT BackgroundImageLayout { get; set; } = SWF_BG_IMG_LAYOUT.Stretch; + public SWF_ARC_CORNERS RoundedCorners { get; set; } = SWF_ARC_CORNERS.None; + public int RoundedRadius { get; set; } = 0; + public bool Empty { get { return (this == new BoxInfo()); } } + + internal bool ButtonClicked { get; set; } = false; + internal bool InputStart { get; set; } = false; + internal Image BackgroundImageOrg { get; set; } = null; + internal bool BackgroundImageModified { get; set; } = false; + /// + /// Deprecated Method. + /// + /// + [Obsolete("IsTextEmpty() is deprecated, please use 'Empty' property instead.")] + public bool IsTextEmpty() + { + return Empty; + } + } +} diff --git a/SwitchWinForms/Models/ReplaceColor.cs b/SwitchWinForms/Models/ReplaceColor.cs new file mode 100644 index 0000000..bd0686b --- /dev/null +++ b/SwitchWinForms/Models/ReplaceColor.cs @@ -0,0 +1,31 @@ +using System; +using System.Drawing; + +namespace SwitchWinForms +{ + public class ReplaceColor + { + private int _defaultImageColorTolerance = 10; + public ReplaceColor() { } + public ReplaceColor(Color delete, Color add, int clrTol = 100) + { + Delete = delete; + Add = add; + ImageColorTolerance = clrTol; + } + public Color Delete { get; set; } = Color.Empty; + public Color Add { get; set; } = Color.Empty; + public int ImageColorTolerance + { + get => this._defaultImageColorTolerance; + set + { + if (value > 100 || value < 0) + throw new Exception("Invalid image color tolerance.\nValid range: 0 - 100"); + + this._defaultImageColorTolerance = value; + } + } + public bool Empty { get { return this == new ReplaceColor(); } } + } +} diff --git a/SwitchWinForms/Models/SWFBoxingOptions.cs b/SwitchWinForms/Models/SWFBoxingOptions.cs new file mode 100644 index 0000000..338e7d5 --- /dev/null +++ b/SwitchWinForms/Models/SWFBoxingOptions.cs @@ -0,0 +1,115 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace SwitchWinForms +{ + public class SWFBoxingOptions : TextUtil + { + private SWF_BOX_TYPE _type = SWF_BOX_TYPE.Frame; + private int _titleBarHeight = -1; + /// + /// To access the box it's easier with a name. + /// + public string Name { get; set; } = string.Empty; + /// + /// Required to be setup, as different types of objects work differently based on type. + /// + public SWF_BOX_TYPE Type + { + get { return _type; } + set { + _type = value; + if (_type != SWF_BOX_TYPE.FormBody) + _titleBarHeight = -1; + else if (_titleBarHeight == -1) + _titleBarHeight = 30; //default + } + } + /// + /// On mouse over or click, cursor changes. + /// + public SWFCursors Cursors { get; set; } = new SWFCursors(); + /// + /// Parent allows zindex. + /// + public Form Parent { get; set; } = null; + /// + /// Select corners to round off. Default None. + /// + public SWF_ARC_CORNERS RoundedCorners { get; set; } = SWF_ARC_CORNERS.None; + /// + /// Arc of the corners. 0 = Square. + /// + public int RoundedRadius { get; set; } = 0; + /// + /// Pixle size of the border for all 4 sides. + /// + public int BorderSize { get; set; } = 2; + /// + /// Padding for each size. Example: new Padding(5,2,2,2) + /// + public Padding Padding { get; set; } = new Padding(0); + /// + /// Get or Set the Location of the box. + /// + public Point Location { get; set; } = new Point(0, 0); + /// + /// Get or Set the Bounderies of the box. + /// + public Size Size { get; set; } = new Size(0, 0); + /// + /// Get or Set the Location and Bounderies of the box. + /// + public Rectangle Rectangle + { + get { return new Rectangle(Location, Size); } + set + { + Location = value == null ? Point.Empty : value.Location; + Size = value == null ? Size.Empty : value.Size; + } + } + /// + /// If there is a custom titlebar and if this this box type is
+ /// a SWF_BOX_TYPE.FormBody, auto-sizing requires to know how tall the titlebar is.
+ /// This setting will be ignored if this object type is not a SWF_BOX_TYPE.FormBody. + ///
+ public int TitleBarHeight + { + get { return _titleBarHeight; } + set + { + _titleBarHeight = value; + } + } + /// + /// Text location, value, font, etc.. + /// + public TextOptions TextSetup { get; set; } = new TextOptions(); + /// + /// Back ground color + /// + public Color BackColor { get; set; } = SystemColors.Control; + /// + /// Border color, if exists. + /// + public Color BorderColor { get; set; } = SystemColors.ActiveCaption; + /// + /// Setup shadowing color, opacity and depth + /// + public ShadowingSetup Shadowing { get; set; } = new ShadowingSetup(); + /// + /// If setup as a button, if has a shadow, when clicked, should button look like it's clicked on move down and mouse up + /// + public bool IsAnimatedButton { get; set; } = false; + /// + /// Internal tracking for mouse up and down, if animation on. + /// + internal bool ButtonClicked { get; set; } = false; + /// + /// Since everyting is painted on a form, mouse over icons and clicks need to ver reviewd based on zindex + /// + internal int ZIndex { get; set; } = 0; + } +} diff --git a/SwitchWinForms/Models/SWFCursors.cs b/SwitchWinForms/Models/SWFCursors.cs new file mode 100644 index 0000000..2ed54b0 --- /dev/null +++ b/SwitchWinForms/Models/SWFCursors.cs @@ -0,0 +1,23 @@ +using System.Windows.Forms; + +/* CursorConverter cConverter = new CursorConverter(); + Cursor hand = (Cursor)cConverter.ConvertFromString("Hand"); + string hhh = this.BoxingOptions.Parent.Cursor.cu.ToString(); + string iii =Cursor.Current.ToString(); +*/ +namespace SwitchWinForms +{ + public class SWFCursors + { + internal Cursor OnMove { get; set; } = Cursors.Default; + internal Cursor OnClick { get; set; } = Cursors.Default; + public SWFCursors(Cursor onMove = null, Cursor onClick = null) + { + if (onMove != null) + this.OnMove = onMove; + + if (onClick != null) + this.OnClick = onClick; + } + } +} diff --git a/SwitchWinForms/Models/SWFMessageEventArgs.cs b/SwitchWinForms/Models/SWFMessageEventArgs.cs new file mode 100644 index 0000000..bda0207 --- /dev/null +++ b/SwitchWinForms/Models/SWFMessageEventArgs.cs @@ -0,0 +1,23 @@ +using System; + +namespace SwitchWinForms +{ + public class SWFMessageEventArgs : EventArgs + { + private Exception _exception = null; + private string _message = string.Empty; + + public SWFMessageEventArgs(Exception exception) + { + this._exception = exception; + this._message = exception.Message; + } + + public SWFMessageEventArgs(string message) => + this._message = message; + + public Exception Exception { get { return this._exception; } } + public string Message { get { return this._message; } } + public bool Success { get { return this._exception == null; } } + } +} diff --git a/SwitchWinForms/Models/SWFTitlebarOptions.cs b/SwitchWinForms/Models/SWFTitlebarOptions.cs new file mode 100644 index 0000000..f3bd006 --- /dev/null +++ b/SwitchWinForms/Models/SWFTitlebarOptions.cs @@ -0,0 +1,266 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace SwitchWinForms +{ + public class SWFTitlebarOptions : TextUtil + { + private int _borderSize = 2; + /// + /// Name of Titlebar Option + /// + public string Name { get; set; } = string.Empty; + /// + /// Parent Form + /// + internal Form GetSetParent { get; set; } + /// + /// titlebar is always location 0,0 + /// + internal Point Location { get; set; } = new Point(0, 0); + /// + /// Size is updated by paint. + /// + internal Size Size { get; set; } = new Size(0, 0); + public Image Icon { get; set; } + /// + /// The primary form. + /// + public Form Parent { get { return GetSetParent; } } + /// + /// Get Location and Size of titlebar. + /// + public Rectangle Rectangle { get { return new Rectangle(this.Location, this.Size); } } + /// + /// Border size. + /// Valid alues (0-5). + /// Default: 2 + /// + public int BorderSize + { + get { return _borderSize; } + set + { + if (value < 0 || value > 5) + throw new Exception("BorderSize must be between 0-5"); + + _borderSize = value; + } + } + /// + /// Rounding corners specified. + /// + /// + /// Default: None + /// + public SWF_ARC_CORNERS RoundedCorners { get; set; } = SWF_ARC_CORNERS.None; + /// + /// Radius of the arc for the rounded corners. + /// Will be ignored if RoundedCorners is set to None. + /// Default: 0 + /// + public int RoundedRadius { get; set; } = 0; + /// + /// All text and buttons will be adjusted based on padding. + /// Usage: Padding(Left, Top, Right, Bottom) + /// Default: 0 + /// + public Padding Padding { get; set; } = new Padding(0); + /// + /// Height of titlebar. + /// Default: 30 + /// + public int Height { get; set; } = 30; + /// + /// Enable the Minimize, Maximum/Normal, and Close buttons for titlebar. + /// Usage: SWF_TITLE_BUTTON.Minimize | SWF_TITLE_BUTTON.Close + /// Default: SWF_TITLE_BUTTON.All + /// + public SWF_TITLE_BUTTON ButtonsEnabled { get; set; } = SWF_TITLE_BUTTON.All; + /// + /// Setup or use defaults for Minimized button. + /// + /// + /// Default:
+ /// BackColor = SystemColors.Window,
+ /// BorderColor = SystemColors.WindowFrame,
+ /// TextSetup = new TextOptions()
+ /// {
+ /// Color = SystemColors.WindowText,
+ /// Text = SWFUnicodeChars.MIN,
+ /// Font = Global.DefaultButtonFont,
+ /// HorizonalAlign = StringAlignment.Center,
+ /// VerticalAlign = StringAlignment.Center,
+ /// }
+ ///
+ public ButtonsState Minimized { get; set; } = new ButtonsState() + { + BackColor = SystemColors.Window, + BorderColor = SystemColors.WindowFrame, + TextSetup = new TextOptions() + { + Color = SystemColors.WindowText, + Text = SWFUnicodeChars.MIN, + Font = Global.DefaultButtonFont, + HorizonalAlign = StringAlignment.Center, + VerticalAlign = StringAlignment.Center, + } + }; + /// + /// Setup or use defaults for Maximize button. + /// + /// + /// Default:
+ /// BackColor = SystemColors.Window,
+ /// BorderColor = SystemColors.WindowFrame,
+ /// TextSetup = new TextOptions()
+ /// {
+ /// Color = SystemColors.WindowText,
+ /// Text = SWFUnicodeChars.MAX,
+ /// Font = Global.DefaultButtonFont,
+ /// HorizonalAlign = StringAlignment.Center,
+ /// VerticalAlign = StringAlignment.Center,
+ /// }
+ ///
+ public ButtonsState Maximize { get; set; } = new ButtonsState() + { + BackColor = SystemColors.Window, + BorderColor = SystemColors.WindowFrame, + TextSetup = new TextOptions() + { + Color = SystemColors.WindowText, + Text = SWFUnicodeChars.MAX, + Font = Global.DefaultButtonFont, + HorizonalAlign = StringAlignment.Center, + VerticalAlign = StringAlignment.Center, + } + }; + /// + /// Setup or use defaults for Normal button. + /// + /// + /// Default: + /// BackColor = SystemColors.Window,
+ /// BorderColor = SystemColors.WindowFrame,
+ /// TextSetup = new TextOptions()
+ /// {
+ /// Color = SystemColors.WindowText,
+ /// Text = SWFUnicodeChars.NORM,
+ /// Font = Global.DefaultButtonFont,
+ /// HorizonalAlign = StringAlignment.Center,
+ /// VerticalAlign = StringAlignment.Center,
+ /// }
+ ///
+ public ButtonsState Normal { get; set; } = new ButtonsState() + { + BackColor = SystemColors.Window, + BorderColor = SystemColors.WindowFrame, + TextSetup = new TextOptions() + { + Color = SystemColors.WindowText, + Text = SWFUnicodeChars.NORM, + Font = Global.DefaultButtonFont, + HorizonalAlign = StringAlignment.Center, + VerticalAlign = StringAlignment.Center, + } + }; + /// + /// Setup or use defaults for Close button. + /// + /// + /// Default: + /// BackColor = SystemColors.Window,
+ /// BorderColor = SystemColors.WindowFrame,
+ /// TextSetup = new TextOptions()
+ /// {
+ /// Color = SystemColors.WindowText,
+ /// Text = Global.GetUnicode(SWF_UNICODE_BUTTONS.CLOSE),
+ /// Font = Global.DefaultButtonFont,
+ /// HorizonalAlign = StringAlignment.Center,
+ /// VerticalAlign = StringAlignment.Center,
+ /// }
+ ///
+ public ButtonsState Close { get; set; } = new ButtonsState() + { + BackColor = SystemColors.Window, + BorderColor = SystemColors.WindowFrame, + TextSetup = new TextOptions() + { + Color = SystemColors.WindowText, + Text = SWFUnicodeChars.CLOSE, + Font = Global.DefaultButtonFont, + HorizonalAlign = StringAlignment.Center, + VerticalAlign = StringAlignment.Center, + } + }; + /// + /// Titlebar caption information + /// + public TextOptions TextSetup { get; set; } = new TextOptions(); + /// + /// Titlebar background color. + /// Default: SystemColors.GradientActiveCaption + /// + public Color BackColor { get; set; } = SystemColors.GradientActiveCaption; + /// + /// Titlebar border color. + /// Default: SystemColors.ActiveBorder + /// + public Color BorderColor { get; set; } = SystemColors.ActiveBorder; + /// + /// All button setup shown on the title bar. This includes, Minimum, Normal/Maximum, Close buttons. + /// + public class ButtonsState : TextUtil + { + /// + /// Border size around buttons.
+ /// Default: 1 + ///
+ public int BorderSize { get; set; } = 1; + /// + /// Seperations between buttons. + /// Default: 2 + /// + public int MarginRight { get; set; } = 2; + /// + /// Buttons border color
+ /// Default: SystemColors.ActiveBorder + ///
+ public Color BorderColor { get; set; } = SystemColors.ActiveBorder; + /// + /// Button Background Color
+ /// Default: SystemColors.ActiveCaption + ///
+ public Color BackColor { get; set; } = SystemColors.ActiveCaption; + /// + /// Button's text configuration + /// + public TextOptions TextSetup { get; set; } = new TextOptions(); + /// + /// Button's padding + /// Default: 0 + /// + public Padding Padding { get; set; } = new Padding(0); + /// + /// Which corners to be rounded for this button.
+ /// Default: None + ///
+ public SWF_ARC_CORNERS RoundedCorners { get; set; } = SWF_ARC_CORNERS.None; + /// + /// Radius of the arc for each corner.
+ /// Default: 0
+ /// Suggest: 2-10 + ///
+ public int RoundedRadius { get; set; } = 0; + /// + /// Is default ButtonsState class without any settings. + /// + public bool Empty { get { return this == new ButtonsState(); } } + } + /// + /// Is default SWFTitlebarOptions class without any settings. + /// + public bool Empty { get { return this == new SWFTitlebarOptions(); } } + } +} diff --git a/SwitchWinForms/Models/SWFUnicodeChars.cs b/SwitchWinForms/Models/SWFUnicodeChars.cs new file mode 100644 index 0000000..fda3a11 --- /dev/null +++ b/SwitchWinForms/Models/SWFUnicodeChars.cs @@ -0,0 +1,80 @@ +using System.Globalization; + +namespace SwitchWinForms +{ + /// + /// Unicode for special characters. + /// + public class SWFUnicodeChars + { + private const int min = 10134; + private const int max = 11026; + private const int norm = 11027; + private const int close = 10062; //10060-X; + private const int txtCursor = 10626; //10070-❖ 10626-⦂ + private int ucode = 0; + /// + /// You can pass any unicode number and use + /// .ToString() to get the local string value. + /// + /// + public SWFUnicodeChars(int ucode) => + this.ucode = ucode; + /// + /// Internal method to convert unicode to current culture string value. + /// + /// + /// + private static string MakeString(int unicode) + { + return ((char)unicode) + .ToString(new CultureInfo(CultureInfo.CurrentCulture.Name)); + } + /// + /// Returns the default value for Minimum button text. + /// + public static string MIN + { + get { return MakeString(min); } + } + /// + /// Returns the default value for Text Cursor text. + /// + public static string TXT_CURSOR + { + get { return MakeString(txtCursor); } + } + /// + /// Returns the default value for Maximum button text. + /// + public static string MAX + { + get { return MakeString(max); } + } + /// + /// Returns the default value for Normal button text. + /// + public static string NORM + { + get { return MakeString(norm); } + } + /// + /// Returns the default value for Close button text. + /// + public static string CLOSE + { + get { return MakeString(close); } + } + /// + /// Converts the unicode value passed in to the curent culture string value. + /// + public override string ToString() + { + return MakeString(this.ucode); + } + /// + /// Has class been called. + /// + public bool Empty { get { return this.ucode == 0; } } + } +} diff --git a/SwitchWinForms/Models/ShadowingSetup.cs b/SwitchWinForms/Models/ShadowingSetup.cs new file mode 100644 index 0000000..0c58ec1 --- /dev/null +++ b/SwitchWinForms/Models/ShadowingSetup.cs @@ -0,0 +1,14 @@ + +using System.Drawing; + +namespace SwitchWinForms +{ + public class ShadowingSetup + { + public Color Color { get; set; } = Color.Black; + public SWF_TRANSPARENT_PERCENTAGE Visibilty { get; set; } = SWF_TRANSPARENT_PERCENTAGE.Empty; + public int Depth { get; set; } = 5; + internal int getVisibilty { get { return (int)Visibilty; } } + public bool Empty { get { return this == new ShadowingSetup(); } } + } +} diff --git a/SwitchWinForms/Models/TextUtil.cs b/SwitchWinForms/Models/TextUtil.cs new file mode 100644 index 0000000..8da2330 --- /dev/null +++ b/SwitchWinForms/Models/TextUtil.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Text.RegularExpressions; +using System.Windows.Forms; + +namespace SwitchWinForms +{ + public abstract class TextUtil + { + public class TextOptions + { + internal int TextCursor { get; set; } = 0; + public string Text { get; set; } = string.Empty; + /// + /// Only used for SWF_BOX_TYPE.TextBox + /// + public string ValidInputExpression { get; set; } = null; + public Image BackgroundImage { get; set; } = null; + public SWF_BG_IMG_LAYOUT BackgroundImageLayout { get; set; } = SWF_BG_IMG_LAYOUT.Stretch; + public List ReplaceImageColor { get; set; } = new List() { }; + public Font Font { get; set; } = Global.DefaultFont; + public Color Color { get; set; } = Global.DefaultFontColor; + public StringAlignment VerticalAlign { get; set; } = StringAlignment.Near; + public StringAlignment HorizonalAlign { get; set; } = StringAlignment.Near; + public bool Empty { get { return this == new TextOptions(); } } + /// + /// Deprecated Method + /// + /// + [Obsolete("IsEmpty() is deprecated, please use 'Empty' property instead.")] + public bool IsEmpty() { + return Empty; + } + } + } +} \ No newline at end of file diff --git a/SwitchWinForms/Properties/AssemblyInfo.cs b/SwitchWinForms/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..fe7aa53 --- /dev/null +++ b/SwitchWinForms/Properties/AssemblyInfo.cs @@ -0,0 +1,37 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SwitchWinForms")] +[assembly: AssemblyDescription("Create new forms with flare or use it for certain components.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("chizl.com")] +[assembly: AssemblyProduct("SwitchWinForms")] +[assembly: AssemblyCopyright("copyright (c) chizl.com 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7c49620c-5f61-4a4e-a6ca-166b18e4daa6")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("2.1.0.0")] +[assembly: AssemblyFileVersion("2.1.0.317")] +[assembly: AssemblyInformationalVersion("2.1.0.0")] \ No newline at end of file diff --git a/SwitchWinForms/Static/Constants.cs b/SwitchWinForms/Static/Constants.cs new file mode 100644 index 0000000..24bf991 --- /dev/null +++ b/SwitchWinForms/Static/Constants.cs @@ -0,0 +1,97 @@ +namespace SwitchWinForms +{ + public enum SWF_BG_IMG_LAYOUT + { + Normal, + Center, + Stretch, + Tile + } + public enum SWF_BOX_TYPE + { + Empty, + Titlebar, + FormBody, + Button, + Frame, + Label, + TextBox + } + public enum SWF_ARC_CORNERS + { + None = 0, + TopLeft = 1, + TopRight = 2, + BottomLeft = 4, + BottomRight = 8, + Left = TopLeft | BottomLeft, + Right = TopRight | BottomRight, + Top = TopLeft | TopRight, + Bottom = BottomLeft | BottomRight, + All = TopLeft | TopRight | BottomLeft | BottomRight, + } + public enum SWF_TRANSPARENT_PERCENTAGE + { + Empty = 0, + Five = 13, + Ten = 26, + Fifteen = 38, + Twenty = 51, + TwentyFive = 64, + Thirty = 77, + ThirtyFive = 89, + Forty = 102, + FortyFive = 115, + Fifty = 127, + FiftyFive = 140, + Sixty = 153, + SixtyFive = 166, + Seventy = 179, + SeventyFive = 191, + Eighty = 204, + EightyFive = 217, + Ninty = 230, + NintyFive = 242, + Hundered = 255 + } + public enum SWF_TITLE_BUTTON + { + Minimize = 1, + Maximize_Normal = 2, + Close = 4, + All = Minimize | Maximize_Normal | Close + } + internal enum SWF_RESIZEABLE + { + None = 0, + Yes = 1, + No = 2 + } + internal enum SWF_HITTEST + { + HT_ERROR = -2, + HT_TRANSPARENT = -1, + HT_NOWHERE = 0, + HT_CLIENT = 1, + HT_CAPTION = 2, + HT_SYSMENU = 3, + HT_GROWBOX = 4, + HT_MENU = 5, + HT_HSCROLL = 6, + HT_VSCROLL = 7, + HT_MINBUTTON = 8, + HT_MAXBUTTON = 9, + HT_LEFT = 10, + HT_RIGHT = 11, + HT_TOP = 12, + HT_TOPLEFT = 13, + HT_TOPRIGHT = 14, + HT_BOTTOM = 15, + HT_BOTTOMLEFT = 16, + HT_BOTTOMRIGHT = 17, + HT_BORDER = 18, + HT_OBJECT = 19, + HT_CLOSE = 20, + HT_HELP = 21 + } +} \ No newline at end of file diff --git a/SwitchWinForms/Static/Global.cs b/SwitchWinForms/Static/Global.cs new file mode 100644 index 0000000..aac1890 --- /dev/null +++ b/SwitchWinForms/Static/Global.cs @@ -0,0 +1,487 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace SwitchWinForms +{ + internal class Global + { + [DllImport("user32.dll", CharSet = CharSet.Auto)] + extern static bool DestroyIcon(IntPtr handle); + + private const string DefaultTextFont = "Courier New"; + internal static List IgnoreKeys { get; } = new List() { Keys.Right, Keys.Left, Keys.Home, Keys.End, + Keys.Enter, Keys.Return, Keys.Back, Keys.Delete, + Keys.Escape, Keys.Shift, Keys.ShiftKey, Keys.Capital, + Keys.Alt, Keys.Control, Keys.ControlKey, + Keys.CapsLock, Keys.Snapshot, Keys.Print, Keys.PrintScreen, + Keys.Menu, Keys.Apps, Keys.Up, Keys.Down, Keys.PageDown, + Keys.PageUp, Keys.VolumeDown, + Keys.VolumeUp, Keys.VolumeMute }; + internal static Dictionary ConvertKey { get; } = new Dictionary() + { + { Keys.Enter, '\n' }, + { Keys.Tab, '\t' }, + { Keys.OemPeriod, '.' }, + { Keys.Decimal, '.' }, + { Keys.NumPad1, '1' }, + { Keys.NumPad2, '2' }, + { Keys.NumPad3, '3' }, + { Keys.NumPad4, '4' }, + { Keys.NumPad5, '5' }, + { Keys.NumPad6, '6' }, + { Keys.NumPad7, '7' }, + { Keys.NumPad8, '8' }, + { Keys.NumPad9, '9' }, + { Keys.NumPad0, '0' }, + { Keys.D1, '1' }, + { Keys.D2, '2' }, + { Keys.D3, '3' }, + { Keys.D4, '4' }, + { Keys.D5, '5' }, + { Keys.D6, '6' }, + { Keys.D7, '7' }, + { Keys.D8, '8' }, + { Keys.D9, '9' }, + { Keys.D0, '0' }, + }; + internal static Font DefaultFont { get; } = new Font("Verdana", 12, FontStyle.Regular, GraphicsUnit.Pixel); + internal static Font DefaultButtonFont { get; } = new Font("Verdana", 12, FontStyle.Regular, GraphicsUnit.Pixel); + internal static Color DefaultFontColor { get; } = Color.Black; + internal static bool IsInBounds(Form frm, Point pt, Rectangle rect, Cursor cursorType = null) + { + bool retVal = false; + + if (pt.X >= rect.Left && + pt.Y >= rect.Top && + pt.X <= rect.Left + rect.Width && + pt.Y <= rect.Top + rect.Height) + { + if (frm != null && cursorType != null) + frm.Cursor = cursorType; + + retVal = true; + } + + return retVal; + } + internal static bool MouseIsClose(Point pt, Rectangle rect) + { + int count = 0; + int closeBy = 2; + bool[] hasBool = new bool[4]; + + hasBool[0] = pt.X < rect.X && (rect.X - pt.X <= closeBy) ? true : false; + hasBool[1] = pt.Y < rect.Y && (rect.Y - pt.Y <= closeBy) ? true : false; + hasBool[2] = pt.X > (rect.X + rect.Width) && (pt.X - (rect.X + rect.Width) <= closeBy) ? true : false; + hasBool[3] = pt.Y > (rect.Y + rect.Height) && (pt.Y - (rect.Y + rect.Height) <= closeBy) ? true : false; + + for(int i= 0; i < 4; i++) + { + if (hasBool[i]) + count++; + } + + return count >= 1; + } + internal static BoxInfo CreateBox(Graphics g, BoxInfo boxInfo) + { + int buffer = 1; + Size maxSize = boxInfo.Rectangle.Size; + Rectangle innerBoxRect = boxInfo.Rectangle; + + if (innerBoxRect.Width < 1 || innerBoxRect.Height < 1) + return boxInfo; + + //create the shadow first. + if (boxInfo.Shadowing != null && + boxInfo.Shadowing.Visibilty != SWF_TRANSPARENT_PERCENTAGE.Empty && + !boxInfo.ButtonClicked) + { + Color shaColor = Color.FromArgb( + boxInfo.Shadowing.getVisibilty, + boxInfo.Shadowing.Color.R, + boxInfo.Shadowing.Color.G, + boxInfo.Shadowing.Color.B); + + Brush shadowBrush = new SolidBrush(shaColor); + + Rectangle shadowBox = new Rectangle( + boxInfo.Rectangle.X + boxInfo.Shadowing.Depth, + boxInfo.Rectangle.Y + boxInfo.Shadowing.Depth, + boxInfo.Rectangle.Width, + boxInfo.Rectangle.Height); + + FillRoundedRectangle(g, shadowBrush, boxInfo, shadowBox, true); + } + + //&& !boxInfo.BackgroundImageModified + if (boxInfo.BackgroundImage != null ) + { + Image newImg = boxInfo.BackgroundImage; + if (boxInfo.ReplaceImageColor.Count > 0) + { + //we dont want to call MakeTransparent each roll, this + //will cause jumping excuted mutliple times. + foreach (ReplaceColor rc in boxInfo.ReplaceImageColor) + newImg = MakeTransparent(newImg, rc, rc.ImageColorTolerance); + + boxInfo.ReplaceImageColor = new List(); + //This makes it perminate until next restart. + + boxInfo.BackgroundImage = newImg; + boxInfo.BackgroundImageModified = true; + } + + if (boxInfo.BackgroundImageLayout != SWF_BG_IMG_LAYOUT.Tile && + (boxInfo.BackgroundImage.Width > boxInfo.Rectangle.Width || + boxInfo.BackgroundImage.Height > boxInfo.Rectangle.Height)) + { + newImg = ResizeBitmap(new Bitmap(newImg), boxInfo.Rectangle.Size); + boxInfo.BackgroundImage = newImg; + boxInfo.BackgroundImageModified = true; + } + } + + //create the background. + SolidBrush bgColor = new SolidBrush(boxInfo.BackColor); + FillRoundedRectangle(g, bgColor, boxInfo, boxInfo.Rectangle, false); + + //if border, then draw border ontop of background. + if (boxInfo.BorderSize > 0) + { + for (int i = 0; i < boxInfo.BorderSize; i++) + { + Rectangle borderRect = new Rectangle() + { + Location = new Point(boxInfo.Rectangle.Location.X + i, boxInfo.Rectangle.Location.Y + i), + Size = new Size((maxSize.Width - (i * 2)) - buffer, (maxSize.Height - (i * 2)) - buffer) + }; + + //create the border + Pen titlePen = new Pen(boxInfo.BorderColor, boxInfo.BorderSize); + DrawRoundedRectangle(g, titlePen, boxInfo, borderRect); + + innerBoxRect = borderRect; + } + } + + if (!string.IsNullOrWhiteSpace(boxInfo.Text)) + { + StringFormat stringFormat = new StringFormat() + { + Alignment = boxInfo.HAlign, + LineAlignment = boxInfo.VAlign + }; + + innerBoxRect = new Rectangle(innerBoxRect.Left + boxInfo.Padding.Left, + innerBoxRect.Top + boxInfo.Padding.Top, + innerBoxRect.Width - boxInfo.Padding.Right, + innerBoxRect.Height - boxInfo.Padding.Bottom); + + if (boxInfo.Type == SWF_BOX_TYPE.Titlebar && boxInfo.Icon != null) + innerBoxRect.Location = new Point((innerBoxRect.X * 2) + innerBoxRect.Height + (boxInfo.Padding.Left * 2), innerBoxRect.Y); + else if (boxInfo.Type == SWF_BOX_TYPE.Titlebar) + innerBoxRect.Location = new Point((innerBoxRect.X * 2) + (boxInfo.Padding.Left * 2), innerBoxRect.Y); + + Font ft = boxInfo.Font; + if (boxInfo.Type == SWF_BOX_TYPE.TextBox && boxInfo.InputStart) + { + //We have to change the font to "Courier New", since I"m overlaying so I can add the * at the cursor spot. + //An asterisk can be a differnt size than a letter for example if not using a squared font letter. + ft = new Font(DefaultTextFont, boxInfo.Font.Size, boxInfo.Font.Style, GraphicsUnit.Pixel); + int cursor = boxInfo.TextCursor; + string text; + + if (cursor > 0) + text = boxInfo.Text.Substring(0, cursor) + "*"; + else + text = "*"; + + g.DrawString(text, ft, new SolidBrush(Color.Gray), innerBoxRect, stringFormat); + } + + g.DrawString(boxInfo.Text, ft, new SolidBrush(boxInfo.ForeColor), innerBoxRect, stringFormat); + } + + return boxInfo; + } + internal static bool IsValidGraphic(Graphics g) + { + bool retVal = true; + + try + { + if (!g.IsClipEmpty) + retVal = false; + } + catch + { + retVal = false; + } + + return retVal; + } + internal static Image GetImage(string path) + { + if (!File.Exists(path)) + throw new IOException($"File not found.\n${path}"); + + Image retVal; + FileInfo fi = new FileInfo(path); + try + { + switch (fi.Extension.ToLower()) + { + case ".exe": + case ".ico": + retVal = (Image)GetEXEImage(path); + break; + default: + retVal = Image.FromFile(path); + break; + } + } + catch + { + throw new IOException("Invalid filetype."); + } + + return retVal; + } + internal static Icon GetIcon(string path) + { + if (!File.Exists(path)) + throw new IOException($"File not found.\n${path}"); + + FileInfo fi = new FileInfo(path); + Icon retVal; + try + { + switch (fi.Extension.ToLower()) + { + case ".exe": + case ".ico": + retVal = (Icon)GetEXEImage(path); + break; + default: + Bitmap bmp = (Bitmap)Image.FromFile(path); + if (bmp.Width > 128 || bmp.Height > 128) //max icon size: 128x128 .ico + bmp = ResizeBitmap(bmp, new Size(128, 128)); + IntPtr Hicon = bmp.GetHicon(); + retVal = (Icon)Icon.FromHandle(Hicon).Clone(); + //Required cleanup or creates memory leak. + DestroyIcon(Hicon); + break; + } + } + catch + { + throw new IOException("Invalid filetype."); + } + + return retVal; + } + private static Bitmap ResizeBitmap(Bitmap img, Size sz) + { + float width = sz.Width; + float height = sz.Height; + var brush = new SolidBrush(Color.Transparent); + float scale = Math.Min(width / ((float)img.Width), height / ((float)img.Height)); + var bmp = new Bitmap(sz.Width, sz.Height); + var graph = Graphics.FromImage(bmp); + var scaleWidth = (int)(img.Width * scale); + var scaleHeight = (int)(img.Height * scale); + RectangleF rec = new RectangleF(((int)width - scaleWidth) / 2, ((int)height - scaleHeight) / 2, scaleWidth, scaleHeight); + graph.FillRectangle(brush, rec); + graph.DrawImage(img, rec); + + return bmp; + } + internal static void DrawRoundedRectangle(Graphics graphics, Pen pen, BoxInfo boxInfo, Rectangle bounds) + { + if (graphics == null) + throw new ArgumentNullException("graphics"); + if (pen == null) + throw new ArgumentNullException("pen"); + + using (GraphicsPath path = RoundedRect(bounds, boxInfo)) + { + graphics.DrawPath(pen, path); + } + } + internal static void FillRoundedRectangle(Graphics graphics, Brush brush, BoxInfo boxInfo, Rectangle bounds, bool isShadow = false) + { + if (graphics == null) + throw new ArgumentNullException("graphics"); + if (brush == null) + throw new ArgumentNullException("brush"); + + using (GraphicsPath path = RoundedRect(bounds, boxInfo)) + { + graphics.FillPath(brush, path); + if (boxInfo.BackgroundImage != null && !isShadow) + { + if (boxInfo.BackgroundImageLayout == SWF_BG_IMG_LAYOUT.Normal) + graphics.DrawImage(boxInfo.BackgroundImage, bounds.Location); + //if (boxInfo.BackgroundImageLayout == SWF_BG_IMG_LAYOUT.Tile) + else + { + Brush gbrush = new TextureBrush(boxInfo.BackgroundImage); + graphics.FillPath(gbrush, path); + } + /*else if (boxInfo.BackgroundImageLayout == SWF_BG_IMG_LAYOUT.Stretch) + { + graphics.DrawImage(boxInfo.BackgroundImage, bounds.Location); + } + else if (boxInfo.BackgroundImageLayout == SWF_BG_IMG_LAYOUT.Center) + { + graphics.DrawImage(boxInfo.BackgroundImage, bounds.Location); + }*/ + } + } + } + internal static GraphicsPath PointsToGraphicsPath(List points) + { + GraphicsPath gp = new GraphicsPath(); + gp.AddLines(points.ToArray()); + return gp; + } + internal static List GraphicsPathToPoints(GraphicsPath gp) + { + return gp.PathPoints.ToList(); + } + internal static bool DeleteFile(string path) + { + bool retVal = true; + + try + { + if (File.Exists(path)) + File.Delete(path); + } + catch + { + retVal = false; + } + + return retVal; + } + private static GraphicsPath RoundedRect(Rectangle bounds, BoxInfo boxInfo) + { + int radiusTopLeft = 0; + int radiusTopRight = 0; + int radiusBottomRight = 0; + int radiusBottomLeft = 0; + + if ((boxInfo.RoundedCorners & SWF_ARC_CORNERS.TopLeft) > 0) + radiusTopLeft = boxInfo.RoundedRadius; + if ((boxInfo.RoundedCorners & SWF_ARC_CORNERS.TopRight) > 0) + radiusTopRight = boxInfo.RoundedRadius; + if ((boxInfo.RoundedCorners & SWF_ARC_CORNERS.BottomRight) > 0) + radiusBottomRight = boxInfo.RoundedRadius; + if ((boxInfo.RoundedCorners & SWF_ARC_CORNERS.BottomLeft) > 0) + radiusBottomLeft = boxInfo.RoundedRadius; + + var size = new Size(radiusTopLeft << 1, radiusTopLeft << 1); + var arc = new Rectangle(bounds.Location, size); + var path = new GraphicsPath(); + + // top left arc + if (radiusTopLeft == 0) + path.AddLine(arc.Location, arc.Location); + else + path.AddArc(arc, 180, 90); + + // top right arc + if (radiusTopRight != radiusTopLeft) + { + size = new Size(radiusTopRight << 1, radiusTopRight << 1); + arc.Size = size; + } + + arc.X = bounds.Right - size.Width; + if (radiusTopRight == 0) + path.AddLine(arc.Location, arc.Location); + else + path.AddArc(arc, 270, 90); + + // bottom right arc + if (radiusTopRight != radiusBottomRight) + { + size = new Size(radiusBottomRight << 1, radiusBottomRight << 1); + arc.X = bounds.Right - size.Width; + arc.Size = size; + } + + arc.Y = bounds.Bottom - size.Height; + if (radiusBottomRight == 0) + path.AddLine(arc.Location, arc.Location); + else + path.AddArc(arc, 0, 90); + + // bottom left arc + if (radiusBottomRight != radiusBottomLeft) + { + arc.Size = new Size(radiusBottomLeft << 1, radiusBottomLeft << 1); + arc.Y = bounds.Bottom - arc.Height; + } + + arc.X = bounds.Left; + if (radiusBottomLeft == 0) + path.AddLine(arc.Location, arc.Location); + else + path.AddArc(arc, 90, 90); + + path.CloseFigure(); + return path; + } + private static object GetEXEImage(string path) + { + object retVal; + string typeofName = typeof(T).Name.ToLower(); + try + { + Icon IEIcon = Icon.ExtractAssociatedIcon(path); + if (typeofName == "icon") + retVal = (object)IEIcon; + else + retVal = IEIcon.ToBitmap(); + } + catch + { + retVal = null; + } + + return retVal; + } + private static Image MakeTransparent(Image image, ReplaceColor color, int tolerance) + { + return MakeTransparent(new Bitmap(image), color, tolerance); + } + private static Bitmap MakeTransparent(Bitmap bitmap, ReplaceColor color, int tolerance) + { + Bitmap transparentImage = new Bitmap(bitmap); + + for (int i = transparentImage.Size.Width - 1; i >= 0; i--) + { + for (int j = transparentImage.Size.Height - 1; j >= 0; j--) + { + var currentColor = transparentImage.GetPixel(i, j); + if (Math.Abs(color.Delete.R - currentColor.R) < tolerance && + Math.Abs(color.Delete.G - currentColor.G) < tolerance && + Math.Abs(color.Delete.B - currentColor.B) < tolerance) + transparentImage.SetPixel(i, j, color.Add); + } + } + + //transparentImage.MakeTransparent(color.Delete); + return transparentImage; + } + } +} diff --git a/SwitchWinForms/SwitchWinForms.csproj b/SwitchWinForms/SwitchWinForms.csproj new file mode 100644 index 0000000..ba6a0c2 --- /dev/null +++ b/SwitchWinForms/SwitchWinForms.csproj @@ -0,0 +1,68 @@ + + + + + Debug + AnyCPU + {7C49620C-5F61-4A4E-A6CA-166B18E4DAA6} + Library + Properties + SwitchWinForms + SwitchWinForms + v4.7.2 + 512 + true + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + C:\Code\~VBS\setVersion.vbs "$(ProjectDir)" + + \ No newline at end of file