UIUtils.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. using System;
  2. using System.Windows.Forms;
  3. using System.Drawing;
  4. using System.Reflection;
  5. namespace FastReport.Utils
  6. {
  7. /// <summary>
  8. /// A static class that contains methods to auto-convert rtl layout.
  9. /// </summary>
  10. public static class UIUtils
  11. {
  12. #region RTL support methods
  13. /// <summary>
  14. /// Changes control's layout to rtl.
  15. /// </summary>
  16. /// <param name="parent"></param>
  17. public static void CheckRTL(Control parent)
  18. {
  19. if (!Config.RightToLeft)
  20. return;
  21. parent.RightToLeft = RightToLeft.Yes;
  22. parent.SuspendLayout();
  23. foreach (Control item in parent.Controls)
  24. {
  25. try
  26. {
  27. AnchorStyles anchor = AnchorStyles.None;
  28. if ((item.Anchor & AnchorStyles.Left) != 0)
  29. anchor |= AnchorStyles.Right;
  30. if ((item.Anchor & AnchorStyles.Right) != 0)
  31. anchor |= AnchorStyles.Left;
  32. if ((item.Anchor & AnchorStyles.Top) != 0)
  33. anchor |= AnchorStyles.Top;
  34. if ((item.Anchor & AnchorStyles.Bottom) != 0)
  35. anchor |= AnchorStyles.Bottom;
  36. DockStyle dock = item.Dock;
  37. if (item.Dock == DockStyle.Left)
  38. dock = DockStyle.Right;
  39. if (item.Dock == DockStyle.Right)
  40. dock = DockStyle.Left;
  41. int width = parent is Form ? (parent as Form).ClientSize.Width : parent.Width;
  42. if (!(item is SplitterPanel))
  43. {
  44. item.Location = new Point(width - item.Size.Width - item.Location.X, item.Location.Y);
  45. item.Anchor = anchor;
  46. item.Dock = dock;
  47. }
  48. if (item is TreeView)
  49. {
  50. (item as TreeView).RightToLeftLayout = true;
  51. }
  52. CheckRTL(item);
  53. }
  54. catch
  55. {
  56. }
  57. }
  58. parent.ResumeLayout();
  59. }
  60. #endregion
  61. #region Draw extension methods
  62. /// <summary>
  63. /// Draws an image and a text.
  64. /// </summary>
  65. /// <param name="control">The control which is used to determine RTL and DPI settings.</param>
  66. /// <param name="e">The draw event args.</param>
  67. /// <param name="img">The image.</param>
  68. /// <param name="text">The text.</param>
  69. /// <remarks>This method is used to draw items in an owner-drawn listboxes and comboboxes. It respects RTL and DPI settings of a control.</remarks>
  70. public static void DrawImageAndText(this Control control, DrawItemEventArgs e, Image img, string text)
  71. {
  72. Graphics g = e.Graphics;
  73. int offsX = 2;
  74. if (img != null)
  75. {
  76. Rectangle imgRect = new Rectangle(
  77. control.RightToLeft == RightToLeft.Yes ? e.Bounds.Right - img.Width - control.LogicalToDevice(4) : e.Bounds.X + control.LogicalToDevice(4),
  78. e.Bounds.Y + (e.Bounds.Height - img.Height) / 2,
  79. img.Width,
  80. img.Height);
  81. g.DrawImage(img, imgRect);
  82. offsX = img.Width + control.LogicalToDevice(8);
  83. }
  84. Rectangle textRect = new Rectangle(
  85. control.RightToLeft == RightToLeft.Yes ? e.Bounds.X : e.Bounds.X + offsX,
  86. e.Bounds.Y,
  87. e.Bounds.Width - offsX,
  88. e.Bounds.Height);
  89. TextFormatFlags flags = TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis;
  90. if (control.RightToLeft == RightToLeft.Yes)
  91. flags |= TextFormatFlags.RightToLeft | TextFormatFlags.Right;
  92. TextRenderer.DrawText(g, text, e.Font, textRect, e.ForeColor, flags);
  93. }
  94. #endregion
  95. #region DPI Extension methods
  96. // Per-monitor DPI support extension methods.
  97. // In .Net 4.7 MS introduced new properties and methods such as Control.DeviceDpi and Control.LogicalToDeviceUnits.
  98. // Since we are targeting .Net 4.0, emulate these methods in earlier versions of fw (also on Mono),
  99. // and use reflection to call these methods if they exist.
  100. /// <summary>
  101. /// Gets current dpi value for the control.
  102. /// </summary>
  103. /// <param name="control">The control.</param>
  104. /// <returns>The dpi value.</returns>
  105. public static int Dpi(this Control control)
  106. {
  107. try
  108. {
  109. // the reason why we use a form instead of a control: the control may not be updated yet
  110. // if we call this code from WM_DPICHANGED handler
  111. Form form = control.FindForm();
  112. if (form != null)
  113. control = form;
  114. // introduced in .Net 4.7
  115. PropertyInfo p = control.GetType().GetProperty("DeviceDpi");
  116. if (p != null)
  117. return (int)(p.GetValue(control, null));
  118. }
  119. catch
  120. { }
  121. return DrawUtils.ScreenDpi;
  122. }
  123. /// <summary>
  124. /// Gets current dpi multiplier for the control (1.0 for 96dpi).
  125. /// </summary>
  126. /// <param name="control">The control.</param>
  127. /// <returns>The dpi multiplier.</returns>
  128. public static float DpiMultiplier(this Control control)
  129. {
  130. return control.Dpi() / 96f;
  131. }
  132. /// <summary>
  133. /// Gets current font dpi multiplier for the control (1.0 for 96dpi).
  134. /// </summary>
  135. /// <remarks>The return value depends on the base resolution of the main screen.</remarks>
  136. /// <param name="control">The control.</param>
  137. /// <returns>The font dpi multiplier.</returns>
  138. public static float FontDpiMultiplier(this Control control)
  139. {
  140. return (float)control.Dpi() / DrawUtils.ScreenDpi;
  141. }
  142. /// <summary>
  143. /// Converts logical units to device units (pixels).
  144. /// </summary>
  145. /// <param name="control">The control.</param>
  146. /// <param name="value">Logical units.</param>
  147. /// <returns>Device units.</returns>
  148. public static int LogicalToDevice(this Control control, int value)
  149. {
  150. return (int)(value * control.DpiMultiplier());
  151. }
  152. /// <summary>
  153. /// Converts logical units to device units (pixels).
  154. /// </summary>
  155. /// <param name="control">The control.</param>
  156. /// <param name="value">Logical units.</param>
  157. /// <returns>Device units.</returns>
  158. public static float LogicalToDevice(this Control control, float value)
  159. {
  160. return value * control.DpiMultiplier();
  161. }
  162. /// <summary>
  163. /// Converts logical units to device units (pixels).
  164. /// </summary>
  165. /// <param name="control">The control.</param>
  166. /// <param name="value">Logical units.</param>
  167. /// <returns>Device units.</returns>
  168. public static Rectangle LogicalToDevice(this Control control, Rectangle value)
  169. {
  170. return new Rectangle(
  171. control.LogicalToDevice(value.Left),
  172. control.LogicalToDevice(value.Top),
  173. control.LogicalToDevice(value.Width),
  174. control.LogicalToDevice(value.Height));
  175. }
  176. /// <summary>
  177. /// Converts logical units to device units (pixels).
  178. /// </summary>
  179. /// <param name="control">The control.</param>
  180. /// <param name="value">Logical units.</param>
  181. /// <returns>Device units.</returns>
  182. public static Point LogicalToDevice(this Control control, Point value)
  183. {
  184. return new Point(
  185. control.LogicalToDevice(value.X),
  186. control.LogicalToDevice(value.Y));
  187. }
  188. /// <summary>
  189. /// Converts logical units to device units (pixels).
  190. /// </summary>
  191. /// <param name="control">The control.</param>
  192. /// <param name="value">Logical units.</param>
  193. /// <returns>Device units.</returns>
  194. public static Size LogicalToDevice(this Control control, Size value)
  195. {
  196. return new Size(
  197. control.LogicalToDevice(value.Width),
  198. control.LogicalToDevice(value.Height));
  199. }
  200. /// <summary>
  201. /// Converts logical font to device font.
  202. /// </summary>
  203. /// <param name="control">The control.</param>
  204. /// <param name="value">Logical font.</param>
  205. /// <param name="disposeOriginal">Determines whether to dispose the original font or not.</param>
  206. /// <returns>Device font.</returns>
  207. public static Font LogicalToDevice(this Control control, Font value, bool disposeOriginal = false)
  208. {
  209. float mult = (float)control.Dpi() / DrawUtils.ScreenDpi;
  210. Font result = new Font(value.Name, value.Size * mult, value.Style);
  211. if (disposeOriginal)
  212. value.Dispose();
  213. return result;
  214. }
  215. #endregion
  216. #region Image helper extension methods
  217. /// <summary>
  218. /// Returns an image from resources using control's dpi value.
  219. /// </summary>
  220. /// <param name="control">The control.</param>
  221. /// <param name="index">Image index.</param>
  222. /// <returns>An image with specified index from "buttons.png" resource.</returns>
  223. public static Image GetImage(this Control control, int index)
  224. {
  225. return Res.GetImage(index, control.Dpi());
  226. }
  227. /// <summary>
  228. /// Returns an image from resources using control's dpi value.
  229. /// </summary>
  230. /// <param name="control">The control.</param>
  231. /// <param name="name">Image name.</param>
  232. /// <returns>An image with specified index from "buttons.png" resource.</returns>
  233. public static Image GetImage(this Control control, string name)
  234. {
  235. return Res.GetImage(name, control.Dpi());
  236. }
  237. /// <summary>
  238. /// Returns an imagelist from resources using control's dpi value.
  239. /// </summary>
  240. /// <param name="control">The control.</param>
  241. /// <returns>An imagelist from "buttons.png" resource.</returns>
  242. public static ImageList GetImages(this Control control)
  243. {
  244. return Res.GetImages(control.Dpi());
  245. }
  246. #endregion
  247. }
  248. }