using System; using System.Collections.Generic; using System.Drawing; using System.Reflection; using System.Text; using System.Windows.Forms; namespace BismNormalizer.TabularCompare.UI { /// /// Utilities class for handling high DPI scenarios /// public class Utils { public static string AssemblyProduct { get { object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); if (attributes.Length == 0) { return ""; } return ((AssemblyProductAttribute)attributes[0]).Product; } } // Since the move to .Net4.5.2 we should use this const to scale context menus or they will be scaled twice public static Size ContextMenuDefaultImageScalingSize = new Size(16, 16); public static void ScaleByDpi(ref int height, ref int width) { float dpiFactor = GetDpiFactor(); height = (int)(height * dpiFactor); width = (int)(width * dpiFactor); } public static int ScaleByDpi(int size) { float dpiFactor = GetDpiFactor(); return (int)(size * dpiFactor); } public static Size ScaleByDpi(Size size) { float dpiFactorFudged = GetDpiFactor() * Utils.PrimaryFudgeFactor; return new Size((int)(size.Width * dpiFactorFudged), (int)(size.Height * dpiFactorFudged)); } /// /// Scales a Size object based on a given factor /// /// Size to scale /// Factor to scale with /// Scaked Size object public static Size ScaleByFactor(Size size, float factor) { return new Size( (int)(size.Width * factor), (int)(size.Height * factor)); } /// /// Scales an ImageList which is already populated with an ImageStream. Scaling occurs on the object iteself. /// /// Target ImageList public static void ScaleStreamedImageListByDpi(ImageList imageList) { // Need to store the images before setting ImageSize as this completely wipes the Images collection Dictionary originalImages = new Dictionary(); for (int i = 0; i < imageList.Images.Count; i++) { originalImages.Add(imageList.Images.Keys[i], imageList.Images[i]); } // According to MSDN, setting a new size resets the Images collection imageList.ImageSize = Utils.ScaleByDpi(imageList.ImageSize); foreach (KeyValuePair entry in originalImages) { imageList.Images.Add(entry.Key, entry.Value); } } /// /// Check whether a string with a preferred font fits a rectangle. If if does, return the preferred font. If it doesn't, scale down to fit. /// /// Graphics control used to draw /// String to draw /// Rectangle to draw the string on /// Preferred font to draw /// Minumum font size to be used if scaling is required /// public static Font ScaleFontToFit(System.Drawing.Graphics g, string str, RectangleF rectangle, Font preferredFont, float minFontSize) { SizeF actualSize = g.MeasureString(str, preferredFont); if (actualSize.Width <= rectangle.Width) { return preferredFont; } float scaleRatio = rectangle.Width / actualSize.Width; float scaledFontSize = preferredFont.Size * scaleRatio; scaledFontSize = Math.Max(scaledFontSize, minFontSize); return new Font(preferredFont.FontFamily, (float)Math.Floor(scaledFontSize)); } public static float PrimaryFudgeFactor = 0.72f; // 0.68f; // 0.54f; public static float SecondaryFudgeFactor = 1.6f; //1.2f; public static float GetDpiFactor() { float factor = 1.0F; try { using (Graphics graphics = Graphics.FromHwnd(IntPtr.Zero)) { factor = (float)graphics.DpiX / 96F; //96 is the default windows DPI if (factor > 1.3 && factor < 1.7) { Utils.PrimaryFudgeFactor = 0.66f; Utils.SecondaryFudgeFactor = 1.1f; } else if (factor >= 1.7) { if (!Settings.Default.OptionHighDpiLocal) { Utils.PrimaryFudgeFactor = 0.72f; Utils.SecondaryFudgeFactor = 1.6f; } else { Utils.PrimaryFudgeFactor = 0.54f; Utils.SecondaryFudgeFactor = 1.2f; } } } } catch (Exception) { // Swallow any exceptions related to system DPI and use the default } return factor; } public static float GetDpiWindowMonitor() { float dpi = 0; try { using (Graphics graphics = Graphics.FromHwnd(IntPtr.Zero)) { dpi = (float)graphics.DpiX; } } catch (Exception) { // Swallow any exceptions related to system DPI and use the default } return dpi; } public static Bitmap ScaleByDpi(Bitmap bmp) { int height = bmp.Height; int width = bmp.Width; ScaleByDpi(ref height, ref width); if (height == bmp.Height && width == bmp.Width) { // No scaling is done return bmp; } return new Bitmap(bmp, new Size(width, height)); } /// /// Scales an Image object if its of type Bitmap. Otherwise doesn't scale. /// /// /// Scaled Image public static Image ScaleByDpi(Image bmp) { if (bmp is Bitmap) { return ScaleByDpi((Bitmap)bmp); } // We can't scale if we don't know the type of Image sent return bmp; } // Get child Controls in a specified Control. internal static List GetChildInControl(Control parent) { List controlList = new List(); foreach (Control child in parent.Controls) { controlList.Add(child); controlList.AddRange(GetChildInControl(child)); } return controlList; } } }