using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Drawing; using System.ComponentModel; namespace FastReport.Controls { /// /// Specifies how text in a is horizontally aligned. /// internal enum TextAlign { /// /// The text is aligned to the left. /// Left = 1, /// /// The text is aligned to the right. /// Right = 2, /// /// The text is aligned in the center. /// Center = 3, /// /// The text is justified. /// Justify = 4 } #if !DEBUG [DesignTimeVisible(false)] #endif internal class FRRichTextBox : RichTextBox { #region Fields, Structures private bool editor = false; // Constants from the Platform SDK. private const int EM_GETPARAFORMAT = 1085; private const int EM_SETPARAFORMAT = 1095; private const int EM_SETCHARFORMAT = 1092; private const int EM_SETTYPOGRAPHYOPTIONS = 1226; private const int EM_FORMATRANGE = 1081; private const int EM_SETTARGETDEVICE = 1096; private const int TO_ADVANCEDTYPOGRAPHY = 1; private const int PFM_ALIGNMENT = 8; private const int SCF_SELECTION = 1; private const int CFM_BOLD = 1; private const int CFM_ITALIC = 2; private const int CFM_UNDERLINE = 4; private const uint CFM_SIZE = 0x80000000; private const uint CFM_FACE = 0x20000000; private const int GWL_EXSTYLE = -20; private const int WS_EX_TRANSPARENT = 0x20; [StructLayout(LayoutKind.Sequential)] private struct PARAFORMAT { public int cbSize; public uint dwMask; public short wNumbering; public short wReserved; public int dxStartIndent; public int dxRightIndent; public int dxOffset; public short wAlignment; public short cTabCount; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public int[] rgxTabs; // PARAFORMAT2 from here onwards. public int dySpaceBefore; public int dySpaceAfter; public int dyLineSpacing; public short sStyle; public byte bLineSpacingRule; public byte bOutlineLevel; public short wShadingWeight; public short wShadingStyle; public short wNumberingStart; public short wNumberingStyle; public short wNumberingTab; public short wBorderSpace; public short wBorderWidth; public short wBorders; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct CHARFORMAT { public int cbSize; public uint dwMask; public uint dwEffects; public int yHeight; public int yOffset; public int crTextColor; public byte bCharSet; public byte bPitchAndFamily; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public char[] szFaceName; // CHARFORMAT2 from here onwards. public short wWeight; public short sSpacing; public int crBackColor; #pragma warning disable FR0005 // Field must be texted in lowerCamelCase. public int LCID; #pragma warning restore FR0005 // Field must be texted in lowerCamelCase. public uint dwReserved; public short sStyle; public short wKerning; public byte bUnderlineType; public byte bAnimation; public byte bRevAuthor; public byte bReserved1; } [StructLayout(LayoutKind.Sequential)] private struct STRUCT_CHARRANGE { public int cpMin; public int cpMax; } #pragma warning disable FR0006 // Field name of struct must be longer than 2 characters. [StructLayout(LayoutKind.Sequential)] private struct STRUCT_FORMATRANGE { public IntPtr hdc; public IntPtr hdcTarget; public STRUCT_RECT rc; public STRUCT_RECT rcPage; public STRUCT_CHARRANGE chrg; } #pragma warning restore FR0006 // Field name of struct must be longer than 2 characters. [StructLayout(LayoutKind.Sequential)] private struct STRUCT_RECT { public int left; public int top; public int right; public int bottom; } [DllImport("user32", CharSet = CharSet.Auto)] private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam); [DllImport("user32", CharSet = CharSet.Auto)] private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam); [DllImport("user32", CharSet = CharSet.Auto)] private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, ref PARAFORMAT fmt); [DllImport("user32", CharSet = CharSet.Auto)] private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, ref CHARFORMAT fmt); [DllImport("kernel32.dll", CharSet=CharSet.Auto)] static extern IntPtr LoadLibrary(string lpFileName); #endregion #region Properties /// /// Gets or sets the alignment to apply to the current /// selection or insertion point. /// /// /// Replaces the SelectionAlignment from . /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new TextAlign SelectionAlignment { get { PARAFORMAT fmt = new PARAFORMAT(); fmt.cbSize = Marshal.SizeOf(fmt); // Get the alignment. SendMessage(Handle, EM_GETPARAFORMAT, SCF_SELECTION, ref fmt); // Default to Left align. if ((fmt.dwMask & PFM_ALIGNMENT) == 0) return TextAlign.Left; return (TextAlign)fmt.wAlignment; } set { PARAFORMAT fmt = new PARAFORMAT(); fmt.cbSize = Marshal.SizeOf(fmt); fmt.dwMask = PFM_ALIGNMENT; fmt.wAlignment = (short)value; // Set the alignment. SendMessage(Handle, EM_SETPARAFORMAT, SCF_SELECTION, ref fmt); } } #endregion #region Private Methods /// /// Convert between screen pixels and twips (1/1440 inch, used by Win32 API calls) /// /// Value in screen pixels /// Value in twips private int PixelsToTwips(float n) { return (int)(n / 96 * 1440); } /// /// Convert between screen pixels and twips (1/1440 inch, used by Win32 API calls) /// /// Value in twips /// Value in screen pixels private float TwipsToPixels(int twips) { return twips / 1440f * 96f; } private void SetCharFormatMessage(ref CHARFORMAT fmt) { SendMessage(Handle, EM_SETCHARFORMAT, SCF_SELECTION, ref fmt); } private void ApplyStyle(uint style, bool on) { CHARFORMAT fmt = new CHARFORMAT(); fmt.cbSize = Marshal.SizeOf(fmt); fmt.dwMask = style; if (on) fmt.dwEffects = style; SetCharFormatMessage(ref fmt); } #endregion #region Protected Methods protected override CreateParams CreateParams { get { CreateParams prams = base.CreateParams; if (LoadLibrary("msftedit.dll") != IntPtr.Zero) { if(editor) prams.ExStyle |= WS_EX_TRANSPARENT; // transparent prams.ClassName = "RICHEDIT50W"; } return prams; } } protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); // Enable support for justification. SendMessage(Handle, EM_SETTYPOGRAPHYOPTIONS, TO_ADVANCEDTYPOGRAPHY, TO_ADVANCEDTYPOGRAPHY); } #endregion #region Public Methods /// /// Calculate or render the contents of RichTextBox for printing /// /// Graphics object /// Graphics object to measure richtext for /// Bonding rectangle of the RichTextBox /// Index of first character to be printed /// Index of last character to be printed /// If true, only the calculation is performed, /// otherwise the text is rendered as well /// (Index of last character that fitted on the page) + 1 public int FormatRange(Graphics g, Graphics measureGraphics, RectangleF displayRect, int charFrom, int charTo, bool measureOnly) { int i; return FormatRange(g, measureGraphics, displayRect, charFrom, charTo, measureOnly, out i); } /// /// Calculate or render the contents of RichTextBox for printing /// /// Graphics object /// Graphics object to measure richtext for /// Bonding rectangle of the RichTextBox /// Index of first character to be printed /// Index of last character to be printed /// If true, only the calculation is performed, /// otherwise the text is rendered as well /// The calculated text height /// (Index of last character that fitted on the page) + 1 public int FormatRange(Graphics g, Graphics measureGraphics, RectangleF displayRect, int charFrom, int charTo, bool measureOnly, out int height) { // Specify which characters to print STRUCT_CHARRANGE cr; cr.cpMin = charFrom; cr.cpMax = charTo; // Specify the area inside page margins STRUCT_RECT rc; rc.left = PixelsToTwips(displayRect.Left); rc.top = PixelsToTwips(displayRect.Top); rc.right = PixelsToTwips(displayRect.Right); rc.bottom = PixelsToTwips(displayRect.Bottom); // Specify the page area STRUCT_RECT rcPage; rcPage.left = rc.left; rcPage.top = rc.top; rcPage.right = rc.right; rcPage.bottom = rc.bottom; // Get device context of output device IntPtr hdc = g.GetHdc(); IntPtr measureHdc = g == measureGraphics ? hdc : measureGraphics.GetHdc(); // Fill in the FORMATRANGE struct STRUCT_FORMATRANGE fr; fr.chrg = cr; fr.hdc = hdc; fr.hdcTarget = measureHdc; fr.rc = rc; fr.rcPage = rcPage; // Non-Zero wParam means render, Zero means measure int wParam = measureOnly ? 0 : 1; // Allocate memory for the FORMATRANGE struct and // copy the contents of our struct to this memory IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fr)); Marshal.StructureToPtr(fr, lParam, false); // Send the actual Win32 message int res = SendMessage(Handle, EM_FORMATRANGE, wParam, lParam); height = 0; if (measureOnly) { fr = (STRUCT_FORMATRANGE)Marshal.PtrToStructure(lParam, typeof(STRUCT_FORMATRANGE)); height = (int)Math.Round(fr.rc.bottom / (1440f / 96f)); } // Free allocated memory Marshal.FreeCoTaskMem(lParam); // and release the device context g.ReleaseHdc(hdc); if (g != measureGraphics) measureGraphics.ReleaseHdc(measureHdc); // finish the formatting SendMessage(Handle, EM_FORMATRANGE, 0, 0); return res; } public void SetSelectionFont(string face) { CHARFORMAT fmt = new CHARFORMAT(); fmt.cbSize = Marshal.SizeOf(fmt); fmt.dwMask = CFM_FACE; fmt.szFaceName = new char[32]; face.CopyTo(0, fmt.szFaceName, 0, Math.Min(face.Length, 31)); SetCharFormatMessage(ref fmt); } public void SetSelectionSize(int size) { CHARFORMAT fmt = new CHARFORMAT(); fmt.cbSize = Marshal.SizeOf(fmt); fmt.dwMask = CFM_SIZE; fmt.yHeight = size * 20; SetCharFormatMessage(ref fmt); } public void SetSelectionBold(bool value) { ApplyStyle(CFM_BOLD, value); } public void SetSelectionItalic(bool value) { ApplyStyle(CFM_ITALIC, value); } public void SetSelectionUnderline(bool value) { ApplyStyle(CFM_UNDERLINE, value); } public FRRichTextBox(bool editor) : base() { this.editor = editor; } public FRRichTextBox() : base() { } #endregion } /// /// Contener for better work FRRichTextBox /// #if !DEBUG [DesignTimeVisible(false)] #endif public class ContainerFRRichTextBox : Control { /// /// /// protected override CreateParams CreateParams { get { CreateParams prams = base.CreateParams; prams.ExStyle |= 0x02000000; // WS_EX_COMPOSITED return prams; } } } }