| File: System\Drawing\Design\IconEditor.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms.Design\src\System.Windows.Forms.Design.csproj (System.Windows.Forms.Design) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; using System.Windows.Forms; using System.Windows.Forms.Design; namespace System.Drawing.Design; // NOTE: this class should be almost identical to ImageEditor. The main exception is PaintValue, which has logic // that should probably be copied into ImageEditor. /// <summary> /// Provides an editor for visually picking an icon. /// </summary> public class IconEditor : UITypeEditor { private static readonly List<string> s_iconExtensions = ["ico"]; private static readonly Type[] s_imageExtenders = []; private FileDialog? _fileDialog; protected static string? CreateExtensionsString(string?[]? extensions, string sep) { if (extensions is null || extensions.Length == 0) { return null; } string text = string.Empty; for (int i = 0; i < extensions.Length; i++) { if (string.IsNullOrWhiteSpace(extensions[i])) { continue; } text = $"{text}*.{extensions[i]}"; if (i < extensions.Length - 1) { text += sep; } } return text; } protected static string CreateFilterEntry(IconEditor editor) { string description = editor.GetFileDialogDescription(); string? extensions = CreateExtensionsString(editor.GetExtensions(), ","); string? extensionsWithSemicolons = CreateExtensionsString(editor.GetExtensions(), ";"); return $"{description}({extensions})|{extensionsWithSemicolons}"; } public override object? EditValue(ITypeDescriptorContext? context, IServiceProvider provider, object? value) { // Even though we don't use the editor service this is historically what we did. if (!provider.TryGetService(out IWindowsFormsEditorService? _)) { return value; } if (_fileDialog is null) { _fileDialog = new OpenFileDialog(); string filter = CreateFilterEntry(this); Debug.Assert(s_imageExtenders.Length <= 0, "Why does IconEditor have subclasses if Icon doesn't?"); _fileDialog.Filter = filter; } HWND hwndFocus = PInvoke.GetFocus(); try { if (_fileDialog.ShowDialog() == DialogResult.OK) { using FileStream stream = new(_fileDialog.FileName, FileMode.Open, FileAccess.Read, FileShare.Read); value = LoadFromStream(stream); } } finally { if (!hwndFocus.IsNull) { PInvoke.SetFocus(hwndFocus); } } return value; } /// <summary> /// Retrieves the editing style of the Edit method. If the method /// is not supported, this will return None. /// </summary> public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext? context) => UITypeEditorEditStyle.Modal; protected virtual string GetFileDialogDescription() => SR.iconFileDescription; protected virtual string[] GetExtensions() => [.. s_iconExtensions]; /// <inheritdoc /> public override bool GetPaintValueSupported(ITypeDescriptorContext? context) => true; protected virtual Icon LoadFromStream(Stream stream) => new(stream); /// <inheritdoc /> public override void PaintValue(PaintValueEventArgs e) { if (e?.Value is not Icon icon) { return; } // If icon is smaller than rectangle, just center it unscaled in the rectangle. Rectangle rectangle = e.Bounds; if (icon.Width < rectangle.Width) { rectangle.X += (rectangle.Width - icon.Width) / 2; rectangle.Width = icon.Width; } if (icon.Height < rectangle.Height) { rectangle.Y += (rectangle.Height - icon.Height) / 2; rectangle.Height = icon.Height; } e.Graphics.DrawIcon(icon, rectangle); } }