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