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;
}
}
}