using System;
using System.Windows.Forms;
using System.Drawing;
using System.Reflection;
namespace FastReport.Utils
{
///
/// A static class that contains methods to auto-convert rtl layout.
///
public static class UIUtils
{
#region RTL support methods
///
/// Changes control's layout to rtl.
///
///
public static void CheckRTL(Control parent)
{
if (!Config.RightToLeft)
return;
parent.RightToLeft = RightToLeft.Yes;
parent.SuspendLayout();
foreach (Control item in parent.Controls)
{
try
{
AnchorStyles anchor = AnchorStyles.None;
if ((item.Anchor & AnchorStyles.Left) != 0)
anchor |= AnchorStyles.Right;
if ((item.Anchor & AnchorStyles.Right) != 0)
anchor |= AnchorStyles.Left;
if ((item.Anchor & AnchorStyles.Top) != 0)
anchor |= AnchorStyles.Top;
if ((item.Anchor & AnchorStyles.Bottom) != 0)
anchor |= AnchorStyles.Bottom;
DockStyle dock = item.Dock;
if (item.Dock == DockStyle.Left)
dock = DockStyle.Right;
if (item.Dock == DockStyle.Right)
dock = DockStyle.Left;
int width = parent is Form ? (parent as Form).ClientSize.Width : parent.Width;
if (!(item is SplitterPanel))
{
item.Location = new Point(width - item.Size.Width - item.Location.X, item.Location.Y);
item.Anchor = anchor;
item.Dock = dock;
}
if (item is TreeView)
{
(item as TreeView).RightToLeftLayout = true;
}
CheckRTL(item);
}
catch
{
}
}
parent.ResumeLayout();
}
#endregion
#region Draw extension methods
///
/// Draws an image and a text.
///
/// The control which is used to determine RTL and DPI settings.
/// The draw event args.
/// The image.
/// The text.
/// This method is used to draw items in an owner-drawn listboxes and comboboxes. It respects RTL and DPI settings of a control.
public static void DrawImageAndText(this Control control, DrawItemEventArgs e, Image img, string text)
{
Graphics g = e.Graphics;
int offsX = 2;
if (img != null)
{
Rectangle imgRect = new Rectangle(
control.RightToLeft == RightToLeft.Yes ? e.Bounds.Right - img.Width - control.LogicalToDevice(4) : e.Bounds.X + control.LogicalToDevice(4),
e.Bounds.Y + (e.Bounds.Height - img.Height) / 2,
img.Width,
img.Height);
g.DrawImage(img, imgRect);
offsX = img.Width + control.LogicalToDevice(8);
}
Rectangle textRect = new Rectangle(
control.RightToLeft == RightToLeft.Yes ? e.Bounds.X : e.Bounds.X + offsX,
e.Bounds.Y,
e.Bounds.Width - offsX,
e.Bounds.Height);
TextFormatFlags flags = TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis;
if (control.RightToLeft == RightToLeft.Yes)
flags |= TextFormatFlags.RightToLeft | TextFormatFlags.Right;
TextRenderer.DrawText(g, text, e.Font, textRect, e.ForeColor, flags);
}
#endregion
#region DPI Extension methods
// Per-monitor DPI support extension methods.
// In .Net 4.7 MS introduced new properties and methods such as Control.DeviceDpi and Control.LogicalToDeviceUnits.
// Since we are targeting .Net 4.0, emulate these methods in earlier versions of fw (also on Mono),
// and use reflection to call these methods if they exist.
///
/// Gets current dpi value for the control.
///
/// The control.
/// The dpi value.
public static int Dpi(this Control control)
{
try
{
// the reason why we use a form instead of a control: the control may not be updated yet
// if we call this code from WM_DPICHANGED handler
Form form = control.FindForm();
if (form != null)
control = form;
// introduced in .Net 4.7
PropertyInfo p = control.GetType().GetProperty("DeviceDpi");
if (p != null)
return (int)(p.GetValue(control, null));
}
catch
{ }
return DrawUtils.ScreenDpi;
}
///
/// Gets current dpi multiplier for the control (1.0 for 96dpi).
///
/// The control.
/// The dpi multiplier.
public static float DpiMultiplier(this Control control)
{
return control.Dpi() / 96f;
}
///
/// Gets current font dpi multiplier for the control (1.0 for 96dpi).
///
/// The return value depends on the base resolution of the main screen.
/// The control.
/// The font dpi multiplier.
public static float FontDpiMultiplier(this Control control)
{
return (float)control.Dpi() / DrawUtils.ScreenDpi;
}
///
/// Converts logical units to device units (pixels).
///
/// The control.
/// Logical units.
/// Device units.
public static int LogicalToDevice(this Control control, int value)
{
return (int)(value * control.DpiMultiplier());
}
///
/// Converts logical units to device units (pixels).
///
/// The control.
/// Logical units.
/// Device units.
public static float LogicalToDevice(this Control control, float value)
{
return value * control.DpiMultiplier();
}
///
/// Converts logical units to device units (pixels).
///
/// The control.
/// Logical units.
/// Device units.
public static Rectangle LogicalToDevice(this Control control, Rectangle value)
{
return new Rectangle(
control.LogicalToDevice(value.Left),
control.LogicalToDevice(value.Top),
control.LogicalToDevice(value.Width),
control.LogicalToDevice(value.Height));
}
///
/// Converts logical units to device units (pixels).
///
/// The control.
/// Logical units.
/// Device units.
public static Point LogicalToDevice(this Control control, Point value)
{
return new Point(
control.LogicalToDevice(value.X),
control.LogicalToDevice(value.Y));
}
///
/// Converts logical units to device units (pixels).
///
/// The control.
/// Logical units.
/// Device units.
public static Size LogicalToDevice(this Control control, Size value)
{
return new Size(
control.LogicalToDevice(value.Width),
control.LogicalToDevice(value.Height));
}
///
/// Converts logical font to device font.
///
/// The control.
/// Logical font.
/// Determines whether to dispose the original font or not.
/// Device font.
public static Font LogicalToDevice(this Control control, Font value, bool disposeOriginal = false)
{
float mult = (float)control.Dpi() / DrawUtils.ScreenDpi;
Font result = new Font(value.Name, value.Size * mult, value.Style);
if (disposeOriginal)
value.Dispose();
return result;
}
#endregion
#region Image helper extension methods
///
/// Returns an image from resources using control's dpi value.
///
/// The control.
/// Image index.
/// An image with specified index from "buttons.png" resource.
public static Image GetImage(this Control control, int index)
{
return Res.GetImage(index, control.Dpi());
}
///
/// Returns an image from resources using control's dpi value.
///
/// The control.
/// Image name.
/// An image with specified index from "buttons.png" resource.
public static Image GetImage(this Control control, string name)
{
return Res.GetImage(name, control.Dpi());
}
///
/// Returns an imagelist from resources using control's dpi value.
///
/// The control.
/// An imagelist from "buttons.png" resource.
public static ImageList GetImages(this Control control)
{
return Res.GetImages(control.Dpi());
}
#endregion
}
}