FRRichTextBox.cs 13 KB

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