diff --git a/src/modules/Projects/ProjectsEditor/Models/Project.cs b/src/modules/Projects/ProjectsEditor/Models/Project.cs index 7cc0b3e1bc..0fc07d6953 100644 --- a/src/modules/Projects/ProjectsEditor/Models/Project.cs +++ b/src/modules/Projects/ProjectsEditor/Models/Project.cs @@ -271,27 +271,5 @@ namespace ProjectsEditor.Models return new Rectangle((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY)); } - - internal string GetShortcutChars() - { - if (string.IsNullOrEmpty(Name)) - { - return "PR"; - } - - string[] words = Name.Trim().ToUpperInvariant().Split(' '); - if (words.Length > 2) - { - return $"{words[0][0]}{words[1][0]}{words[2][0]}"; - } - else if (words.Length == 2) - { - return $"{words[0][0]}{words[1][0]}"; - } - else - { - return words[0].Substring(0, Math.Min(3, words[0].Length)); - } - } } } diff --git a/src/modules/Projects/ProjectsEditor/Utils/DrawHelper.cs b/src/modules/Projects/ProjectsEditor/Utils/DrawHelper.cs index f6300b4a3b..c951dd1c55 100644 --- a/src/modules/Projects/ProjectsEditor/Utils/DrawHelper.cs +++ b/src/modules/Projects/ProjectsEditor/Utils/DrawHelper.cs @@ -19,34 +19,7 @@ namespace ProjectsEditor.Utils { public class DrawHelper { - private const int IconSize = 128; private static Font font = new("Tahoma", 24); - private static List iconBrushes = new List - { - ////Brushes.Gold, - ////Brushes.SteelBlue, - ////Brushes.SkyBlue, - ////Brushes.DarkGoldenrod, - ////Brushes.ForestGreen, - ////Brushes.Peru, - ////Brushes.Chartreuse, - ////Brushes.LightPink, - ////Brushes.CadetBlue, - ////Brushes.DarkSalmon, - ////Brushes.Orange, - ////Brushes.DarkSeaGreen, - ////Brushes.Yellow, - ////Brushes.Green, - ////Brushes.Orange, - ////Brushes.White, - new SolidBrush(Color.FromArgb(255, 40, 101, 120)), - new SolidBrush(Color.FromArgb(255, 58, 91, 153)), - new SolidBrush(Color.FromArgb(255, 87, 88, 163)), - new SolidBrush(Color.FromArgb(255, 116, 87, 160)), - new SolidBrush(Color.FromArgb(255, 139, 82, 145)), - }; - - private static int iconBrushIndex; public static BitmapImage DrawPreview(Project project, Rectangle bounds) { @@ -239,164 +212,7 @@ namespace ProjectsEditor.Utils } } - public static GraphicsPath RoundedRect(Rectangle bounds) - { - int minorSize = Math.Min(bounds.Width, bounds.Height); - int radius = (int)(minorSize / 8); - - int diameter = radius * 2; - Size size = new Size(diameter, diameter); - Rectangle arc = new Rectangle(bounds.Location, size); - GraphicsPath path = new GraphicsPath(); - - if (radius == 0) - { - path.AddRectangle(bounds); - return path; - } - - // top left arc - path.AddArc(arc, 180, 90); - - // top right arc - arc.X = bounds.Right - diameter; - path.AddArc(arc, 270, 90); - - // bottom right arc - arc.Y = bounds.Bottom - diameter; - path.AddArc(arc, 0, 90); - - // bottom left arc - arc.X = bounds.Left; - path.AddArc(arc, 90, 90); - - path.CloseFigure(); - return path; - } - - internal static string CreateShortcutIcon(Project project, out Bitmap bitmap) - { - object shDesktop = (object)"Desktop"; - IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShell(); - string shortcutIconFilename = (string)shell.SpecialFolders.Item(ref shDesktop) + $"\\{project.Name}.ico"; - bitmap = new Bitmap(IconSize, IconSize); - using (Graphics graphics = Graphics.FromImage(bitmap)) - { - graphics.SmoothingMode = SmoothingMode.AntiAlias; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - - // if (project != null) - // { - // List selectedApps = project.Applications.Where(x => x.IsSelected).ToList(); - // if (selectedApps.Count > 0) - // { - // graphics.DrawIcon(selectedApps[0].Icon, new Rectangle(0, 0, IconSize / 2, IconSize / 2)); - // } - // if (selectedApps.Count > 1) - // { - // graphics.DrawIcon(selectedApps[1].Icon, new Rectangle(IconSize / 2, 0, IconSize / 2, IconSize / 2)); - // } - // if (selectedApps.Count > 2) - // { - // graphics.DrawIcon(selectedApps[2].Icon, new Rectangle(0, IconSize / 2, IconSize / 2, IconSize / 2)); - // } - // if (selectedApps.Count > 3) - // { - // graphics.DrawIcon(selectedApps[3].Icon, new Rectangle(IconSize / 2, IconSize / 2, IconSize / 2, IconSize / 2)); - // } - // } - // graphics.FillRectangle(new System.Drawing.SolidBrush(Color.FromArgb(128, 32, 32, 32)), 0, 0, IconSize, IconSize); - graphics.FillEllipse(iconBrushes[iconBrushIndex], 0, 0, IconSize, IconSize); - - string shortcutChars = "PR"; - - if (project != null) - { - shortcutChars = project.GetShortcutChars(); - } - - Rectangle indexBounds; - if (shortcutChars.Length > 1) - { - indexBounds = new Rectangle(0, 0, IconSize, IconSize); - } - else - { - indexBounds = new Rectangle(IconSize / 4, 0, IconSize / 2, IconSize); - } - - var textSize = graphics.MeasureString(shortcutChars, font); - var state = graphics.Save(); - graphics.TranslateTransform(indexBounds.Left, indexBounds.Top); - graphics.ScaleTransform(indexBounds.Width / textSize.Width, indexBounds.Height / textSize.Height); - graphics.DrawString(shortcutChars, font, Brushes.White, PointF.Empty); - graphics.Restore(state); - iconBrushIndex++; - if (iconBrushIndex >= iconBrushes.Count) - { - iconBrushIndex = 0; - } - } - - FileStream fileStream = new FileStream(shortcutIconFilename, FileMode.OpenOrCreate); - - using (var memoryStream = new MemoryStream()) - { - bitmap.Save(memoryStream, ImageFormat.Png); - - BinaryWriter iconWriter = new BinaryWriter(fileStream); - if (fileStream != null && iconWriter != null) - { - // 0-1 reserved, 0 - iconWriter.Write((byte)0); - iconWriter.Write((byte)0); - - // 2-3 image type, 1 = icon, 2 = cursor - iconWriter.Write((short)1); - - // 4-5 number of images - iconWriter.Write((short)1); - - // image entry 1 - // 0 image width - iconWriter.Write((byte)IconSize); - - // 1 image height - iconWriter.Write((byte)IconSize); - - // 2 number of colors - iconWriter.Write((byte)0); - - // 3 reserved - iconWriter.Write((byte)0); - - // 4-5 color planes - iconWriter.Write((short)0); - - // 6-7 bits per pixel - iconWriter.Write((short)32); - - // 8-11 size of image data - iconWriter.Write((int)memoryStream.Length); - - // 12-15 offset of image data - iconWriter.Write((int)(6 + 16)); - - // write image data - // png data must contain the whole png data file - iconWriter.Write(memoryStream.ToArray()); - - iconWriter.Flush(); - } - } - - fileStream.Flush(); - fileStream.Close(); - return shortcutIconFilename; - } - - internal static BitmapImage DrawPreviewIcons(Project project) + public static BitmapImage DrawPreviewIcons(Project project) { var selectedApps = project.Applications.Where(x => x.IsSelected); int appsCount = selectedApps.Count(); @@ -443,46 +259,39 @@ namespace ProjectsEditor.Utils } } - private static void CreateExamples(Project project) + private static GraphicsPath RoundedRect(Rectangle bounds) { - Bitmap bitmap = new Bitmap(IconSize + 1000, IconSize * iconBrushes.Count); - using (Graphics graphics = Graphics.FromImage(bitmap)) + int minorSize = Math.Min(bounds.Width, bounds.Height); + int radius = (int)(minorSize / 8); + + int diameter = radius * 2; + Size size = new Size(diameter, diameter); + Rectangle arc = new Rectangle(bounds.Location, size); + GraphicsPath path = new GraphicsPath(); + + if (radius == 0) { - for (int brushIndex = 0; brushIndex < iconBrushes.Count; brushIndex++) - { - graphics.SmoothingMode = SmoothingMode.AntiAlias; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - - graphics.FillEllipse(iconBrushes[brushIndex], 0, IconSize * brushIndex, IconSize, IconSize); - - string shortcutChars = "PR"; - - Rectangle indexBounds; - indexBounds = new Rectangle(0, IconSize * brushIndex, IconSize, IconSize); - - var textSize = graphics.MeasureString(shortcutChars, font); - var state = graphics.Save(); - graphics.TranslateTransform(indexBounds.Left, indexBounds.Top); - graphics.ScaleTransform(indexBounds.Width / textSize.Width, indexBounds.Height / textSize.Height); - graphics.DrawString(shortcutChars, font, Brushes.Black, 0, 0); - graphics.Restore(state); - - var b = (SolidBrush)iconBrushes[brushIndex]; - var colorName = (from p in typeof(System.Drawing.Color).GetProperties() - where p.PropertyType.Equals(typeof(System.Drawing.Color)) - let value = (System.Drawing.Color)p.GetValue(null, null) - where value.R == b.Color.R && - value.G == b.Color.G && - value.B == b.Color.B && - value.A == b.Color.A - select p.Name).DefaultIfEmpty("unknown").First(); - - graphics.DrawString(colorName, font, Brushes.White, IconSize, IconSize * brushIndex); - } + path.AddRectangle(bounds); + return path; } - bitmap.Save(@"C:\temp\shortcutIcons.png"); + // top left arc + path.AddArc(arc, 180, 90); + + // top right arc + arc.X = bounds.Right - diameter; + path.AddArc(arc, 270, 90); + + // bottom right arc + arc.Y = bounds.Bottom - diameter; + path.AddArc(arc, 0, 90); + + // bottom left arc + arc.X = bounds.Left; + path.AddArc(arc, 90, 90); + + path.CloseFigure(); + return path; } } } diff --git a/src/modules/Projects/ProjectsEditor/Utils/ProjectIcon.cs b/src/modules/Projects/ProjectsEditor/Utils/ProjectIcon.cs new file mode 100644 index 0000000000..ca752d3075 --- /dev/null +++ b/src/modules/Projects/ProjectsEditor/Utils/ProjectIcon.cs @@ -0,0 +1,147 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; + +namespace ProjectsEditor.Utils +{ + public class ProjectIcon : IDisposable + { + private const int IconSize = 128; + + public static readonly Brush LightThemeIconBackground = new SolidBrush(Color.FromArgb(255, 239, 243, 251)); + public static readonly Brush LightThemeIconForeground = new SolidBrush(Color.FromArgb(255, 47, 50, 56)); + public static readonly Brush DarkThemeIconBackground = new SolidBrush(Color.FromArgb(255, 55, 55, 55)); + public static readonly Brush DarkThemeIconForeground = new SolidBrush(Color.FromArgb(255, 228, 228, 228)); + + public static readonly Font IconFont = new("Aptos", 24, FontStyle.Bold); + + public static string IconTextFromProjectName(string projectName) + { + string result = string.Empty; + char[] delimiterChars = { ' ', ',', '.', ':', '-', '\t' }; + string[] words = projectName.Split(delimiterChars); + + foreach (string word in words) + { + if (string.IsNullOrEmpty(word)) + { + continue; + } + + if (word.All(char.IsDigit)) + { + result += word; + } + else + { + result += word.ToUpper(System.Globalization.CultureInfo.CurrentCulture).ToCharArray()[0]; + } + } + + return result; + } + + public static Bitmap DrawIcon(string text) + { + Brush background = Common.ThemeManager.GetCurrentTheme() == Common.Theme.Dark ? DarkThemeIconBackground : LightThemeIconBackground; + Brush foreground = Common.ThemeManager.GetCurrentTheme() == Common.Theme.Dark ? DarkThemeIconForeground : LightThemeIconForeground; + Bitmap bitmap = new Bitmap(IconSize, IconSize); + + using (Graphics graphics = Graphics.FromImage(bitmap)) + { + graphics.SmoothingMode = SmoothingMode.AntiAlias; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.FillEllipse(background, 0, 0, IconSize, IconSize); + + var textSize = graphics.MeasureString(text, IconFont); + var state = graphics.Save(); + + // Calculate scaling factors + float scaleX = (float)IconSize / textSize.Width; + float scaleY = (float)IconSize / textSize.Height; + float scale = Math.Min(scaleX, scaleY) * 0.8f; // Use the smaller scale factor to maintain aspect ratio + + // Calculate the position to center the text + float textX = (IconSize - (textSize.Width * scale)) / 2; + float textY = ((IconSize - (textSize.Height * scale)) / 2) + 6; + + graphics.TranslateTransform(textX, textY); + graphics.ScaleTransform(scale, scale); + graphics.DrawString(text, IconFont, foreground, 0, 0); + graphics.Restore(state); + } + + return bitmap; + } + + public static void SaveIcon(Bitmap icon, string path) + { + FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate); + using (var memoryStream = new MemoryStream()) + { + icon.Save(memoryStream, ImageFormat.Png); + + BinaryWriter iconWriter = new BinaryWriter(fileStream); + if (fileStream != null && iconWriter != null) + { + // 0-1 reserved, 0 + iconWriter.Write((byte)0); + iconWriter.Write((byte)0); + + // 2-3 image type, 1 = icon, 2 = cursor + iconWriter.Write((short)1); + + // 4-5 number of images + iconWriter.Write((short)1); + + // image entry 1 + // 0 image width + iconWriter.Write((byte)IconSize); + + // 1 image height + iconWriter.Write((byte)IconSize); + + // 2 number of colors + iconWriter.Write((byte)0); + + // 3 reserved + iconWriter.Write((byte)0); + + // 4-5 color planes + iconWriter.Write((short)0); + + // 6-7 bits per pixel + iconWriter.Write((short)32); + + // 8-11 size of image data + iconWriter.Write((int)memoryStream.Length); + + // 12-15 offset of image data + iconWriter.Write((int)(6 + 16)); + + // write image data + // png data must contain the whole png data file + iconWriter.Write(memoryStream.ToArray()); + + iconWriter.Flush(); + } + } + + fileStream.Flush(); + fileStream.Close(); + } + + public void Dispose() + { + GC.SuppressFinalize(this); + } + } +} diff --git a/src/modules/Projects/ProjectsEditor/ViewModels/MainViewModel.cs b/src/modules/Projects/ProjectsEditor/ViewModels/MainViewModel.cs index 17713257b3..0c1a5c44b4 100644 --- a/src/modules/Projects/ProjectsEditor/ViewModels/MainViewModel.cs +++ b/src/modules/Projects/ProjectsEditor/ViewModels/MainViewModel.cs @@ -145,8 +145,12 @@ namespace ProjectsEditor.ViewModels shortcut.TargetPath = Path.Combine(basePath, "ProjectsLauncher.exe"); shortcut.Arguments = '"' + project.Id + '"'; shortcut.WorkingDirectory = basePath; - string iconFilename = DrawHelper.CreateShortcutIcon(project, out Bitmap bitmap); - shortcut.IconLocation = iconFilename; + + string shortcutIconFilename = (string)shell.SpecialFolders.Item(ref shDesktop) + $"\\{project.Name}.ico"; + Bitmap icon = ProjectIcon.DrawIcon(ProjectIcon.IconTextFromProjectName(project.Name)); + ProjectIcon.SaveIcon(icon, shortcutIconFilename); + + shortcut.IconLocation = shortcutIconFilename; shortcut.Save(); }