FRRichTextBox.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. using System;
  2. using System.Windows.Forms;
  3. using System.Runtime.InteropServices;
  4. using System.Drawing;
  5. using System.ComponentModel;
  6. namespace FastReport.Controls
  7. {
  8. /// <summary>
  9. /// Specifies how text in a <see cref="FRRichTextBox"/> is horizontally aligned.
  10. /// </summary>
  11. internal enum TextAlign
  12. {
  13. /// <summary>
  14. /// The text is aligned to the left.
  15. /// </summary>
  16. Left = 1,
  17. /// <summary>
  18. /// The text is aligned to the right.
  19. /// </summary>
  20. Right = 2,
  21. /// <summary>
  22. /// The text is aligned in the center.
  23. /// </summary>
  24. Center = 3,
  25. /// <summary>
  26. /// The text is justified.
  27. /// </summary>
  28. Justify = 4
  29. }
  30. internal class FRRichTextBox : RichTextBox
  31. {
  32. #region Fields, Structures
  33. private bool editor = false;
  34. // Constants from the Platform SDK.
  35. private const int EM_GETPARAFORMAT = 1085;
  36. private const int EM_SETPARAFORMAT = 1095;
  37. private const int EM_SETCHARFORMAT = 1092;
  38. private const int EM_SETTYPOGRAPHYOPTIONS = 1226;
  39. private const int EM_FORMATRANGE = 1081;
  40. private const int EM_SETTARGETDEVICE = 1096;
  41. private const int TO_ADVANCEDTYPOGRAPHY = 1;
  42. private const int PFM_ALIGNMENT = 8;
  43. private const int SCF_SELECTION = 1;
  44. private const int CFM_BOLD = 1;
  45. private const int CFM_ITALIC = 2;
  46. private const int CFM_UNDERLINE = 4;
  47. private const uint CFM_SIZE = 0x80000000;
  48. private const uint CFM_FACE = 0x20000000;
  49. private const int GWL_EXSTYLE = -20;
  50. private const int WS_EX_TRANSPARENT = 0x20;
  51. [StructLayout(LayoutKind.Sequential)]
  52. private struct PARAFORMAT
  53. {
  54. public int cbSize;
  55. public uint dwMask;
  56. public short wNumbering;
  57. public short wReserved;
  58. public int dxStartIndent;
  59. public int dxRightIndent;
  60. public int dxOffset;
  61. public short wAlignment;
  62. public short cTabCount;
  63. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  64. public int[] rgxTabs;
  65. // PARAFORMAT2 from here onwards.
  66. public int dySpaceBefore;
  67. public int dySpaceAfter;
  68. public int dyLineSpacing;
  69. public short sStyle;
  70. public byte bLineSpacingRule;
  71. public byte bOutlineLevel;
  72. public short wShadingWeight;
  73. public short wShadingStyle;
  74. public short wNumberingStart;
  75. public short wNumberingStyle;
  76. public short wNumberingTab;
  77. public short wBorderSpace;
  78. public short wBorderWidth;
  79. public short wBorders;
  80. }
  81. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
  82. private struct CHARFORMAT
  83. {
  84. public int cbSize;
  85. public uint dwMask;
  86. public uint dwEffects;
  87. public int yHeight;
  88. public int yOffset;
  89. public int crTextColor;
  90. public byte bCharSet;
  91. public byte bPitchAndFamily;
  92. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  93. public char[] szFaceName;
  94. // CHARFORMAT2 from here onwards.
  95. public short wWeight;
  96. public short sSpacing;
  97. public int crBackColor;
  98. #pragma warning disable FR0005 // Field must be texted in lowerCamelCase.
  99. public int LCID;
  100. #pragma warning restore FR0005 // Field must be texted in lowerCamelCase.
  101. public uint dwReserved;
  102. public short sStyle;
  103. public short wKerning;
  104. public byte bUnderlineType;
  105. public byte bAnimation;
  106. public byte bRevAuthor;
  107. public byte bReserved1;
  108. }
  109. [StructLayout(LayoutKind.Sequential)]
  110. private struct STRUCT_CHARRANGE
  111. {
  112. public int cpMin;
  113. public int cpMax;
  114. }
  115. #pragma warning disable FR0006 // Field name of struct must be longer than 2 characters.
  116. [StructLayout(LayoutKind.Sequential)]
  117. private struct STRUCT_FORMATRANGE
  118. {
  119. public IntPtr hdc;
  120. public IntPtr hdcTarget;
  121. public STRUCT_RECT rc;
  122. public STRUCT_RECT rcPage;
  123. public STRUCT_CHARRANGE chrg;
  124. }
  125. #pragma warning restore FR0006 // Field name of struct must be longer than 2 characters.
  126. [StructLayout(LayoutKind.Sequential)]
  127. private struct STRUCT_RECT
  128. {
  129. public int left;
  130. public int top;
  131. public int right;
  132. public int bottom;
  133. }
  134. [DllImport("user32", CharSet = CharSet.Auto)]
  135. private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
  136. [DllImport("user32", CharSet = CharSet.Auto)]
  137. private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
  138. [DllImport("user32", CharSet = CharSet.Auto)]
  139. private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, ref PARAFORMAT fmt);
  140. [DllImport("user32", CharSet = CharSet.Auto)]
  141. private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, ref CHARFORMAT fmt);
  142. [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
  143. static extern IntPtr LoadLibrary(string lpFileName);
  144. #endregion
  145. #region Properties
  146. /// <summary>
  147. /// Gets or sets the alignment to apply to the current
  148. /// selection or insertion point.
  149. /// </summary>
  150. /// <remarks>
  151. /// Replaces the SelectionAlignment from <see cref="RichTextBox"/>.
  152. /// </remarks>
  153. [Browsable(false)]
  154. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  155. public new TextAlign SelectionAlignment
  156. {
  157. get
  158. {
  159. PARAFORMAT fmt = new PARAFORMAT();
  160. fmt.cbSize = Marshal.SizeOf(fmt);
  161. // Get the alignment.
  162. SendMessage(Handle, EM_GETPARAFORMAT, SCF_SELECTION, ref fmt);
  163. // Default to Left align.
  164. if ((fmt.dwMask & PFM_ALIGNMENT) == 0)
  165. return TextAlign.Left;
  166. return (TextAlign)fmt.wAlignment;
  167. }
  168. set
  169. {
  170. PARAFORMAT fmt = new PARAFORMAT();
  171. fmt.cbSize = Marshal.SizeOf(fmt);
  172. fmt.dwMask = PFM_ALIGNMENT;
  173. fmt.wAlignment = (short)value;
  174. // Set the alignment.
  175. SendMessage(Handle, EM_SETPARAFORMAT, SCF_SELECTION, ref fmt);
  176. }
  177. }
  178. #endregion
  179. #region Private Methods
  180. /// <summary>
  181. /// Convert between screen pixels and twips (1/1440 inch, used by Win32 API calls)
  182. /// </summary>
  183. /// <param name="n">Value in screen pixels</param>
  184. /// <returns>Value in twips</returns>
  185. private int PixelsToTwips(float n)
  186. {
  187. return (int)(n / 96 * 1440);
  188. }
  189. /// <summary>
  190. /// Convert between screen pixels and twips (1/1440 inch, used by Win32 API calls)
  191. /// </summary>
  192. /// <param name="twips">Value in twips</param>
  193. /// <returns>Value in screen pixels</returns>
  194. private float TwipsToPixels(int twips)
  195. {
  196. return twips / 1440f * 96f;
  197. }
  198. private void SetCharFormatMessage(ref CHARFORMAT fmt)
  199. {
  200. SendMessage(Handle, EM_SETCHARFORMAT, SCF_SELECTION, ref fmt);
  201. }
  202. private void ApplyStyle(uint style, bool on)
  203. {
  204. CHARFORMAT fmt = new CHARFORMAT();
  205. fmt.cbSize = Marshal.SizeOf(fmt);
  206. fmt.dwMask = style;
  207. if (on)
  208. fmt.dwEffects = style;
  209. SetCharFormatMessage(ref fmt);
  210. }
  211. #endregion
  212. #region Protected Methods
  213. protected override CreateParams CreateParams
  214. {
  215. get
  216. {
  217. CreateParams prams = base.CreateParams;
  218. if (LoadLibrary("msftedit.dll") != IntPtr.Zero)
  219. {
  220. if (editor)
  221. prams.ExStyle |= WS_EX_TRANSPARENT; // transparent
  222. prams.ClassName = "RICHEDIT50W";
  223. }
  224. return prams;
  225. }
  226. }
  227. protected override void OnHandleCreated(EventArgs e)
  228. {
  229. base.OnHandleCreated(e);
  230. // Enable support for justification.
  231. SendMessage(Handle, EM_SETTYPOGRAPHYOPTIONS, TO_ADVANCEDTYPOGRAPHY, TO_ADVANCEDTYPOGRAPHY);
  232. }
  233. #endregion
  234. #region Public Methods
  235. /// <summary>
  236. /// Calculate or render the contents of RichTextBox for printing
  237. /// </summary>
  238. /// <param name="g">Graphics object</param>
  239. /// <param name="measureGraphics">Graphics object to measure richtext for</param>
  240. /// <param name="displayRect">Bonding rectangle of the RichTextBox</param>
  241. /// <param name="charFrom">Index of first character to be printed</param>
  242. /// <param name="charTo">Index of last character to be printed</param>
  243. /// <param name="measureOnly">If true, only the calculation is performed,
  244. /// otherwise the text is rendered as well</param>
  245. /// <returns>(Index of last character that fitted on the page) + 1</returns>
  246. public int FormatRange(Graphics g, Graphics measureGraphics, RectangleF displayRect,
  247. int charFrom, int charTo, bool measureOnly)
  248. {
  249. int i;
  250. return FormatRange(g, measureGraphics, displayRect, charFrom, charTo, measureOnly, out i);
  251. }
  252. /// <summary>
  253. /// Calculate or render the contents of RichTextBox for printing
  254. /// </summary>
  255. /// <param name="g">Graphics object</param>
  256. /// <param name="measureGraphics">Graphics object to measure richtext for</param>
  257. /// <param name="displayRect">Bonding rectangle of the RichTextBox</param>
  258. /// <param name="charFrom">Index of first character to be printed</param>
  259. /// <param name="charTo">Index of last character to be printed</param>
  260. /// <param name="measureOnly">If true, only the calculation is performed,
  261. /// otherwise the text is rendered as well</param>
  262. /// <param name="height">The calculated text height</param>
  263. /// <returns>(Index of last character that fitted on the page) + 1</returns>
  264. public int FormatRange(Graphics g, Graphics measureGraphics, RectangleF displayRect,
  265. int charFrom, int charTo, bool measureOnly, out int height)
  266. {
  267. // Specify which characters to print
  268. STRUCT_CHARRANGE cr;
  269. cr.cpMin = charFrom;
  270. cr.cpMax = charTo;
  271. // Specify the area inside page margins
  272. STRUCT_RECT rc;
  273. rc.left = PixelsToTwips(displayRect.Left);
  274. rc.top = PixelsToTwips(displayRect.Top);
  275. rc.right = PixelsToTwips(displayRect.Right);
  276. rc.bottom = PixelsToTwips(displayRect.Bottom);
  277. // Specify the page area
  278. STRUCT_RECT rcPage;
  279. rcPage.left = rc.left;
  280. rcPage.top = rc.top;
  281. rcPage.right = rc.right;
  282. rcPage.bottom = rc.bottom;
  283. // Get device context of output device
  284. IntPtr hdc = g.GetHdc();
  285. IntPtr measureHdc = g == measureGraphics ? hdc : measureGraphics.GetHdc();
  286. // Fill in the FORMATRANGE struct
  287. STRUCT_FORMATRANGE fr;
  288. fr.chrg = cr;
  289. fr.hdc = hdc;
  290. fr.hdcTarget = measureHdc;
  291. fr.rc = rc;
  292. fr.rcPage = rcPage;
  293. // Non-Zero wParam means render, Zero means measure
  294. int wParam = measureOnly ? 0 : 1;
  295. // Allocate memory for the FORMATRANGE struct and
  296. // copy the contents of our struct to this memory
  297. IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fr));
  298. Marshal.StructureToPtr(fr, lParam, false);
  299. // Send the actual Win32 message
  300. int res = SendMessage(Handle, EM_FORMATRANGE, wParam, lParam);
  301. height = 0;
  302. if (measureOnly)
  303. {
  304. fr = (STRUCT_FORMATRANGE)Marshal.PtrToStructure(lParam, typeof(STRUCT_FORMATRANGE));
  305. height = (int)Math.Round(fr.rc.bottom / (1440f / 96f));
  306. }
  307. // Free allocated memory
  308. Marshal.FreeCoTaskMem(lParam);
  309. // and release the device context
  310. g.ReleaseHdc(hdc);
  311. if (g != measureGraphics)
  312. measureGraphics.ReleaseHdc(measureHdc);
  313. // finish the formatting
  314. SendMessage(Handle, EM_FORMATRANGE, 0, 0);
  315. return res;
  316. }
  317. public void SetSelectionFont(string face)
  318. {
  319. CHARFORMAT fmt = new CHARFORMAT();
  320. fmt.cbSize = Marshal.SizeOf(fmt);
  321. fmt.dwMask = CFM_FACE;
  322. fmt.szFaceName = new char[32];
  323. face.CopyTo(0, fmt.szFaceName, 0, Math.Min(face.Length, 31));
  324. SetCharFormatMessage(ref fmt);
  325. }
  326. public void SetSelectionSize(int size)
  327. {
  328. CHARFORMAT fmt = new CHARFORMAT();
  329. fmt.cbSize = Marshal.SizeOf(fmt);
  330. fmt.dwMask = CFM_SIZE;
  331. fmt.yHeight = size * 20;
  332. SetCharFormatMessage(ref fmt);
  333. }
  334. public void SetSelectionBold(bool value)
  335. {
  336. ApplyStyle(CFM_BOLD, value);
  337. }
  338. public void SetSelectionItalic(bool value)
  339. {
  340. ApplyStyle(CFM_ITALIC, value);
  341. }
  342. public void SetSelectionUnderline(bool value)
  343. {
  344. ApplyStyle(CFM_UNDERLINE, value);
  345. }
  346. public FRRichTextBox(bool editor) : base()
  347. {
  348. this.editor = editor;
  349. }
  350. public FRRichTextBox() : base() { }
  351. #endregion
  352. }
  353. /// <summary>
  354. /// Contener for better work FRRichTextBox
  355. /// </summary>
  356. #if !DEBUG
  357. [DesignTimeVisible(false)]
  358. #endif
  359. public class ContainerFRRichTextBox : Control
  360. {
  361. /// <summary>
  362. /// <inheritdoc/>
  363. /// </summary>
  364. protected override CreateParams CreateParams
  365. {
  366. get
  367. {
  368. CreateParams prams = base.CreateParams;
  369. prams.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
  370. return prams;
  371. }
  372. }
  373. }
  374. }