using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; namespace Payroll.Controls { public partial class HtmlRichTextBox : RichTextBox { public HtmlRichTextBox() { InitializeComponent(); } private int updating = 0; private int oldEventMask = 0; /// /// Maintains performance while updating. /// /// /// /// It is recommended to call this method before doing /// any major updates that you do not wish the user to /// see. Remember to call EndUpdate when you are finished /// with the update. Nested calls are supported. /// /// /// Calling this method will prevent redrawing. It will /// also setup the event mask of the underlying richedit /// control so that no events are sent. /// /// public void BeginUpdate() { // Deal with nested calls. ++updating; if (updating > 1) return; // Prevent the control from raising any events. oldEventMask = SendMessage(new HandleRef(this, Handle), EM_SETEVENTMASK, 0, 0); // Prevent the control from redrawing itself. SendMessage(new HandleRef(this, Handle), WM_SETREDRAW, 0, 0); } /// /// Resumes drawing and event handling. /// /// /// This method should be called every time a call is made /// made to BeginUpdate. It resets the event mask to it's /// original value and enables redrawing of the control. /// public void EndUpdate() { // Deal with nested calls. --updating; if (updating > 0) return; // Allow the control to redraw itself. SendMessage(new HandleRef(this, Handle), WM_SETREDRAW, 1, 0); // Allow the control to raise event messages. SendMessage(new HandleRef(this, Handle), EM_SETEVENTMASK, 0, oldEventMask); } /// /// Returns true when the control is performing some /// internal updates, specially when is reading or writing /// HTML text /// public bool InternalUpdating { get { return (updating != 0); } } #region Win32 Apis // Constants from the Platform SDK. private const int EM_FORMATRANGE = 1081; private const int WM_USER = 0x0400; private const int EM_GETCHARFORMAT = WM_USER + 58; private const int EM_SETCHARFORMAT = WM_USER + 68; private const int EM_SETEVENTMASK = 1073; private const int EM_GETPARAFORMAT = 1085; private const int EM_SETPARAFORMAT = 1095; private const int EM_SETTYPOGRAPHYOPTIONS = 1226; private const int WM_SETREDRAW = 11; private const int TO_ADVANCEDTYPOGRAPHY = 1; // Defines for EM_SETCHARFORMAT/EM_GETCHARFORMAT private const Int32 SCF_SELECTION = 0x0001; private const Int32 SCF_WORD = 0x0002; private const Int32 SCF_ALL = 0x0004; public const int LF_FACESIZE = 32; // Defines for STRUCT_CHARFORMAT member dwMask public const UInt32 CFM_BOLD = 0x00000001; public const UInt32 CFM_ITALIC = 0x00000002; public const UInt32 CFM_UNDERLINE = 0x00000004; public const UInt32 CFM_STRIKEOUT = 0x00000008; public const UInt32 CFM_PROTECTED = 0x00000010; public const UInt32 CFM_LINK = 0x00000020; public const UInt32 CFM_SIZE = 0x80000000; public const UInt32 CFM_COLOR = 0x40000000; public const UInt32 CFM_FACE = 0x20000000; public const UInt32 CFM_OFFSET = 0x10000000; public const UInt32 CFM_CHARSET = 0x08000000; public const UInt32 CFM_SUBSCRIPT = CFE_SUBSCRIPT | CFE_SUPERSCRIPT; public const UInt32 CFM_SUPERSCRIPT = CFM_SUBSCRIPT; // Defines for STRUCT_CHARFORMAT member dwEffects public const UInt32 CFE_BOLD = 0x00000001; public const UInt32 CFE_ITALIC = 0x00000002; public const UInt32 CFE_UNDERLINE = 0x00000004; public const UInt32 CFE_STRIKEOUT = 0x00000008; public const UInt32 CFE_PROTECTED = 0x00000010; public const UInt32 CFE_LINK = 0x00000020; public const UInt32 CFE_AUTOCOLOR = 0x40000000; public const UInt32 CFE_SUBSCRIPT = 0x00010000; /* Superscript and subscript are */ public const UInt32 CFE_SUPERSCRIPT = 0x00020000; /* mutually exclusive */ public const byte CFU_UNDERLINENONE = 0x00; public const byte CFU_UNDERLINE = 0x01; public const byte CFU_UNDERLINEWORD = 0x02; /* (*) displayed as ordinary underline */ public const byte CFU_UNDERLINEDOUBLE = 0x03; /* (*) displayed as ordinary underline */ public const byte CFU_UNDERLINEDOTTED = 0x04; public const byte CFU_UNDERLINEDASH = 0x05; public const byte CFU_UNDERLINEDASHDOT = 0x06; public const byte CFU_UNDERLINEDASHDOTDOT = 0x07; public const byte CFU_UNDERLINEWAVE = 0x08; public const byte CFU_UNDERLINETHICK = 0x09; public const byte CFU_UNDERLINEHAIRLINE = 0x0A; /* (*) displayed as ordinary underline */ public const int CFM_SMALLCAPS = 0x0040; /* (*) */ public const int CFM_ALLCAPS = 0x0080; /* Displayed by 3.0 */ public const int CFM_HIDDEN = 0x0100; /* Hidden by 3.0 */ public const int CFM_OUTLINE = 0x0200; /* (*) */ public const int CFM_SHADOW = 0x0400; /* (*) */ public const int CFM_EMBOSS = 0x0800; /* (*) */ public const int CFM_IMPRINT = 0x1000; /* (*) */ public const int CFM_DISABLED = 0x2000; public const int CFM_REVISED = 0x4000; public const int CFM_BACKCOLOR = 0x04000000; public const int CFM_LCID = 0x02000000; public const int CFM_UNDERLINETYPE = 0x00800000; /* Many displayed by 3.0 */ public const int CFM_WEIGHT = 0x00400000; public const int CFM_SPACING = 0x00200000; /* Displayed by 3.0 */ public const int CFM_KERNING = 0x00100000; /* (*) */ public const int CFM_STYLE = 0x00080000; /* (*) */ public const int CFM_ANIMATION = 0x00040000; /* (*) */ public const int CFM_REVAUTHOR = 0x00008000; // Font Weights public const short FW_DONTCARE = 0; public const short FW_THIN = 100; public const short FW_EXTRALIGHT = 200; public const short FW_LIGHT = 300; public const short FW_NORMAL = 400; public const short FW_MEDIUM = 500; public const short FW_SEMIBOLD = 600; public const short FW_BOLD = 700; public const short FW_EXTRABOLD = 800; public const short FW_HEAVY = 900; public const short FW_ULTRALIGHT = FW_EXTRALIGHT; public const short FW_REGULAR = FW_NORMAL; public const short FW_DEMIBOLD = FW_SEMIBOLD; public const short FW_ULTRABOLD = FW_EXTRABOLD; public const short FW_BLACK = FW_HEAVY; // PARAFORMAT mask values public const UInt32 PFM_STARTINDENT = 0x00000001; public const UInt32 PFM_RIGHTINDENT = 0x00000002; public const UInt32 PFM_OFFSET = 0x00000004; public const UInt32 PFM_ALIGNMENT = 0x00000008; public const UInt32 PFM_TABSTOPS = 0x00000010; public const UInt32 PFM_NUMBERING = 0x00000020; public const UInt32 PFM_OFFSETINDENT = 0x80000000; // PARAFORMAT numbering options public const UInt16 PFN_BULLET = 0x0001; // PARAFORMAT alignment options public const UInt16 PFA_LEFT = 0x0001; public const UInt16 PFA_RIGHT = 0x0002; public const UInt16 PFA_CENTER = 0x0003; // It makes no difference if we use PARAFORMAT or // PARAFORMAT2 here, so I have opted for PARAFORMAT2. [StructLayout(LayoutKind.Sequential)] public 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)] public struct CHARFORMAT { public int cbSize; public UInt32 dwMask; public UInt32 dwEffects; public Int32 yHeight; public Int32 yOffset; public Int32 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 Int32 crBackColor; public uint lcid; public uint dwReserved; public short sStyle; public short wKerning; public byte bUnderlineType; public byte bAnimation; public byte bRevAuthor; public byte bReserved1; } [DllImport("user32", CharSet = CharSet.Auto)] private static extern int SendMessage(HandleRef hWnd, int msg, int wParam, int lParam); [DllImport("user32", CharSet = CharSet.Auto)] private static extern int SendMessage(HandleRef hWnd, int msg, int wParam, ref PARAFORMAT lp); [DllImport("user32", CharSet = CharSet.Auto)] private static extern int SendMessage(HandleRef hWnd, int msg, int wParam, ref CHARFORMAT lp); #endregion //---------------------------- // New, version 1.1 public void SetSuperScript(bool bSet) { CHARFORMAT cf = this.CharFormat; if (bSet) { cf.dwMask |= CFM_SUPERSCRIPT; cf.dwEffects |= CFE_SUPERSCRIPT; } else { cf.dwEffects &= ~CFE_SUPERSCRIPT; } this.CharFormat = cf; } public void SetSubScript(bool bSet) { CHARFORMAT cf = this.CharFormat; if (bSet) { cf.dwMask |= CFM_SUBSCRIPT; cf.dwEffects |= CFE_SUBSCRIPT; } else { cf.dwEffects &= ~CFE_SUBSCRIPT; } this.CharFormat = cf; } public bool IsSuperScript() { CHARFORMAT cf = this.CharFormat; return ((cf.dwEffects & CFE_SUPERSCRIPT) == CFE_SUPERSCRIPT); } public bool IsSubScript() { CHARFORMAT cf = this.CharFormat; return ((cf.dwEffects & CFE_SUBSCRIPT) == CFE_SUBSCRIPT); } //---------------------------- public PARAFORMAT ParaFormat { get { PARAFORMAT pf = new PARAFORMAT(); pf.cbSize = Marshal.SizeOf(pf); // Get the alignment. SendMessage(new HandleRef(this, Handle), EM_GETPARAFORMAT, SCF_SELECTION, ref pf); return pf; } set { PARAFORMAT pf = value; pf.cbSize = Marshal.SizeOf(pf); // Set the alignment. SendMessage(new HandleRef(this, Handle), EM_SETPARAFORMAT, SCF_SELECTION, ref pf); } } public PARAFORMAT DefaultParaFormat { get { PARAFORMAT pf = new PARAFORMAT(); pf.cbSize = Marshal.SizeOf(pf); // Get the alignment. SendMessage(new HandleRef(this, Handle), EM_GETPARAFORMAT, SCF_ALL, ref pf); return pf; } set { PARAFORMAT pf = value; pf.cbSize = Marshal.SizeOf(pf); // Set the alignment. SendMessage(new HandleRef(this, Handle), EM_SETPARAFORMAT, SCF_ALL, ref pf); } } public CHARFORMAT CharFormat { get { CHARFORMAT cf = new CHARFORMAT(); cf.cbSize = Marshal.SizeOf(cf); // Get the alignment. SendMessage(new HandleRef(this, Handle), EM_GETCHARFORMAT, SCF_SELECTION, ref cf); return cf; } set { CHARFORMAT cf = value; cf.cbSize = Marshal.SizeOf(cf); // Set the alignment. SendMessage(new HandleRef(this, Handle), EM_SETCHARFORMAT, SCF_SELECTION, ref cf); } } public CHARFORMAT DefaultCharFormat { get { CHARFORMAT cf = new CHARFORMAT(); cf.cbSize = Marshal.SizeOf(cf); // Get the alignment. SendMessage(new HandleRef(this, Handle), EM_GETCHARFORMAT, SCF_ALL, ref cf); return cf; } set { CHARFORMAT cf = value; cf.cbSize = Marshal.SizeOf(cf); // Set the alignment. SendMessage(new HandleRef(this, Handle), EM_SETCHARFORMAT, SCF_ALL, ref cf); } } #region COLORREF helper functions // convert COLORREF to Color private Color GetColor(int crColor) { byte r = (byte)(crColor); byte g = (byte)(crColor >> 8); byte b = (byte)(crColor >> 16); return Color.FromArgb(r, g, b); } // convert COLORREF to Color private int GetCOLORREF(int r, int g, int b) { int r2 = r; int g2 = (g << 8); int b2 = (b << 16); int result = r2 | g2 | b2; return result; } private int GetCOLORREF(Color color) { int r = color.R; int g = color.G; int b = color.B; return GetCOLORREF(r, g, b); } #endregion #region "Get HTML text" // format states private enum ctformatStates { nctNone = 0, // none format applied nctNew = 1, // new format nctContinue = 2, // continue with previous format nctReset = 3 // reset format (close this tag) } private enum uMyREType { U_MYRE_TYPE_TAG, U_MYRE_TYPE_EMO, U_MYRE_TYPE_ENTITY, } private struct cMyREFormat { public uMyREType nType; public int nLen; public int nPos; public string strValue; } public string GetHTML(bool bHTML, bool bParaFormat) { //------------------------ // working variables CHARFORMAT cf; PARAFORMAT pf; ctformatStates bold = ctformatStates.nctNone; ctformatStates bitalic = ctformatStates.nctNone; ctformatStates bstrikeout = ctformatStates.nctNone; ctformatStates bunderline = ctformatStates.nctNone; ctformatStates super = ctformatStates.nctNone; ctformatStates sub = ctformatStates.nctNone; ctformatStates bacenter = ctformatStates.nctNone; ctformatStates baleft = ctformatStates.nctNone; ctformatStates baright = ctformatStates.nctNone; ctformatStates bnumbering = ctformatStates.nctNone; string strFont = ""; Int32 crFont = 0; Color color = new Color(); int yHeight = 0; int i = 0; //------------------------- //------------------------- // to store formatting ArrayList colFormat = new ArrayList(); cMyREFormat mfr; //------------------------- //------------------------- // ok, lets go int nStart, nEnd; string strHTML = ""; this.HideSelection = true; this.BeginUpdate(); nStart = this.SelectionStart; nEnd = this.SelectionLength; try { //-------------------------------- // replace entities if (bHTML) { char[] ch = { '&', '<', '>', '"', '\'' }; string[] strreplace = { "&", "<", ">", """, "'" }; for (i = 0; i < ch.Length; i++) { char[] ch2 = { ch[i] }; int n = this.Find(ch2, 0); while (n != -1) { mfr = new cMyREFormat(); mfr.nPos = n; mfr.nLen = 1; mfr.nType = uMyREType.U_MYRE_TYPE_ENTITY; mfr.strValue = strreplace[i]; colFormat.Add(mfr); n = this.Find(ch2, n + 1); } } } //-------------------------------- string strT = ""; int k = this.TextLength; char[] chtrim = { ' ', '\x0000' }; //-------------------------------- // this is an inefficient method to get text format // but RichTextBox doesn't provide another method to // get something like an array of charformat and paraformat //-------------------------------- for (i = 0; i < k; i++) { // select one character this.Select(i, 1); string strChar = this.SelectedText; if (bHTML) { //------------------------- // get format for this character cf = this.CharFormat; pf = this.ParaFormat; string strfname = new string(cf.szFaceName); strfname = strfname.Trim(chtrim); //------------------------- //------------------------- // new font format ? if ((strFont != strfname) || (crFont != cf.crTextColor) || (yHeight != cf.yHeight)) { if (strFont != "") { // close previous tag mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); } //------------------------- // save this for cache strFont = strfname; crFont = cf.crTextColor; yHeight = cf.yHeight; //------------------------- //------------------------- // font size should be translate to // html size (Approximately) double fsize = (double)yHeight / (double)(20 * 5); //------------------------- //------------------------- // color object from COLORREF color = GetColor(crFont); //------------------------- //------------------------- // add tag mfr = new cMyREFormat(); string strcolor = string.Concat("#", (color.ToArgb() & 0x00FFFFFF).ToString("X6")); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); //------------------------- } //------------------------- // are we in another line ? if ((strChar == "\r") || (strChar == "\n")) { // yes? // then, we need to reset paragraph format // and character format if (bParaFormat) { bnumbering = ctformatStates.nctNone; baleft = ctformatStates.nctNone; baright = ctformatStates.nctNone; bacenter = ctformatStates.nctNone; } // close previous tags // is italic? => close it if (bitalic != ctformatStates.nctNone) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); bitalic = ctformatStates.nctNone; } // is bold? => close it if (bold != ctformatStates.nctNone) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); bold = ctformatStates.nctNone; } // is underline? => close it if (bunderline != ctformatStates.nctNone) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); bunderline = ctformatStates.nctNone; } // is strikeout? => close it if (bstrikeout != ctformatStates.nctNone) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); bstrikeout = ctformatStates.nctNone; } // is super? => close it if (super != ctformatStates.nctNone) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); super = ctformatStates.nctNone; } // is sub? => close it if (sub != ctformatStates.nctNone) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); sub = ctformatStates.nctNone; } } // now, process the paragraph format, // managing states: none, new, continue {with previous}, reset if (bParaFormat) { // align to center? if (pf.wAlignment == PFA_CENTER) { if (bacenter == ctformatStates.nctNone) bacenter = ctformatStates.nctNew; else bacenter = ctformatStates.nctContinue; } else { if (bacenter != ctformatStates.nctNone) bacenter = ctformatStates.nctReset; } if (bacenter == ctformatStates.nctNew) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = "

"; colFormat.Add(mfr); } else if (bacenter == ctformatStates.nctReset) bacenter = ctformatStates.nctNone; //--------------------- //--------------------- // align to left ? if (pf.wAlignment == PFA_LEFT) { if (baleft == ctformatStates.nctNone) baleft = ctformatStates.nctNew; else baleft = ctformatStates.nctContinue; } else { if (baleft != ctformatStates.nctNone) baleft = ctformatStates.nctReset; } if (baleft == ctformatStates.nctNew) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = "

"; colFormat.Add(mfr); } else if (baleft == ctformatStates.nctReset) baleft = ctformatStates.nctNone; //--------------------- //--------------------- // align to right ? if (pf.wAlignment == PFA_RIGHT) { if (baright == ctformatStates.nctNone) baright = ctformatStates.nctNew; else baright = ctformatStates.nctContinue; } else { if (baright != ctformatStates.nctNone) baright = ctformatStates.nctReset; } if (baright == ctformatStates.nctNew) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = "

"; colFormat.Add(mfr); } else if (baright == ctformatStates.nctReset) baright = ctformatStates.nctNone; //--------------------- //--------------------- // bullet ? if (pf.wNumbering == PFN_BULLET) { if (bnumbering == ctformatStates.nctNone) bnumbering = ctformatStates.nctNew; else bnumbering = ctformatStates.nctContinue; } else { if (bnumbering != ctformatStates.nctNone) bnumbering = ctformatStates.nctReset; } if (bnumbering == ctformatStates.nctNew) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = "

  • "; colFormat.Add(mfr); } else if (bnumbering == ctformatStates.nctReset) bnumbering = ctformatStates.nctNone; //--------------------- } //--------------------- // bold ? if ((cf.dwEffects & CFE_BOLD) == CFE_BOLD) { if (bold == ctformatStates.nctNone) bold = ctformatStates.nctNew; else bold = ctformatStates.nctContinue; } else { if (bold != ctformatStates.nctNone) bold = ctformatStates.nctReset; } if (bold == ctformatStates.nctNew) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); } else if (bold == ctformatStates.nctReset) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); bold = ctformatStates.nctNone; } //--------------------- //--------------------- // Italic if ((cf.dwEffects & CFE_ITALIC) == CFE_ITALIC) { if (bitalic == ctformatStates.nctNone) bitalic = ctformatStates.nctNew; else bitalic = ctformatStates.nctContinue; } else { if (bitalic != ctformatStates.nctNone) bitalic = ctformatStates.nctReset; } if (bitalic == ctformatStates.nctNew) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); } else if (bitalic == ctformatStates.nctReset) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); bitalic = ctformatStates.nctNone; } //--------------------- //--------------------- // strikeout if ((cf.dwEffects & CFM_STRIKEOUT) == CFM_STRIKEOUT) { if (bstrikeout == ctformatStates.nctNone) bstrikeout = ctformatStates.nctNew; else bstrikeout = ctformatStates.nctContinue; } else { if (bstrikeout != ctformatStates.nctNone) bstrikeout = ctformatStates.nctReset; } if (bstrikeout == ctformatStates.nctNew) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); } else if (bstrikeout == ctformatStates.nctReset) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); bstrikeout = ctformatStates.nctNone; } //--------------------- //--------------------- // underline ? if ((cf.dwEffects & CFE_UNDERLINE) == CFE_UNDERLINE) { if (bunderline == ctformatStates.nctNone) bunderline = ctformatStates.nctNew; else bunderline = ctformatStates.nctContinue; } else { if (bunderline != ctformatStates.nctNone) bunderline = ctformatStates.nctReset; } if (bunderline == ctformatStates.nctNew) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); } else if (bunderline == ctformatStates.nctReset) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); bunderline = ctformatStates.nctNone; } //--------------------- //--------------------- // superscript ? if ((cf.dwEffects & CFE_SUPERSCRIPT) == CFE_SUPERSCRIPT) { if (super == ctformatStates.nctNone) super = ctformatStates.nctNew; else super = ctformatStates.nctContinue; } else { if (super != ctformatStates.nctNone) super = ctformatStates.nctReset; } if (super == ctformatStates.nctNew) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); } else if (super == ctformatStates.nctReset) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); super = ctformatStates.nctNone; } //--------------------- //--------------------- // subscript ? if ((cf.dwEffects & CFE_SUBSCRIPT) == CFE_SUBSCRIPT) { if (sub == ctformatStates.nctNone) sub = ctformatStates.nctNew; else sub = ctformatStates.nctContinue; } else { if (sub != ctformatStates.nctNone) sub = ctformatStates.nctReset; } if (sub == ctformatStates.nctNew) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); } else if (sub == ctformatStates.nctReset) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); sub = ctformatStates.nctNone; } //--------------------- } strT += strChar; } if (bHTML) { // close pending tags if (bold != ctformatStates.nctNone) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); //strT += ""; } if (bitalic != ctformatStates.nctNone) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); //strT += ""; } if (bstrikeout != ctformatStates.nctNone) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); //strT += ""; } if (bunderline != ctformatStates.nctNone) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); //strT += ""; } if (super != ctformatStates.nctNone) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); //strT += ""; } if (sub != ctformatStates.nctNone) { mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); //strT += ""; } if (strFont != "") { // close pending font format mfr = new cMyREFormat(); mfr.nPos = i; mfr.nLen = 0; mfr.nType = uMyREType.U_MYRE_TYPE_TAG; mfr.strValue = ""; colFormat.Add(mfr); } } //-------------------------- // now, reorder the formatting array k = colFormat.Count; for (i = 0; i < k - 1; i++) { for (int j = i + 1; j < k; j++) { mfr = (cMyREFormat)colFormat[i]; cMyREFormat mfr2 = (cMyREFormat)colFormat[j]; if (mfr2.nPos < mfr.nPos) { colFormat.RemoveAt(j); colFormat.Insert(i, mfr2); j--; } else if ((mfr2.nPos == mfr.nPos) && (mfr2.nLen < mfr.nLen)) { colFormat.RemoveAt(j); colFormat.Insert(i, mfr2); j--; } } } //-------------------------- //-------------------------- // apply format by replacing and inserting HTML tags // stored in the Format Array int nAcum = 0; for (i = 0; i < k; i++) { mfr = (cMyREFormat)colFormat[i]; strHTML += strT.Substring(nAcum, mfr.nPos - nAcum) + mfr.strValue; nAcum = mfr.nPos + mfr.nLen; } if (nAcum < strT.Length) strHTML += strT.Substring(nAcum); //-------------------------- } catch { //MessageBox.Show(ex.Message); } finally { //-------------------------- // finish, restore this.SelectionStart = nStart; this.SelectionLength = nEnd; this.EndUpdate(); this.HideSelection = false; //-------------------------- } return strHTML; } #endregion #region "Add HTML text" public void AddHTML(string strHTML) { CHARFORMAT cf; PARAFORMAT pf; cf = this.DefaultCharFormat; // to apply character formatting pf = this.DefaultParaFormat; // to apply paragraph formatting char[] chtrim = { ' ', '\x0000' }; this.HideSelection = true; this.BeginUpdate(); try { // process text while (strHTML.Length > 0) { string strData = strHTML; reinit: // looking for start tags int nStart = strHTML.IndexOf('<'); if (nStart >= 0) { if (nStart > 0) { // tag is not the first character, so // we need to add text to control and continue // looking for tags at the begining of the text strData = strHTML.Substring(0, nStart); strHTML = strHTML.Substring(nStart); } else { // ok, get tag value int nEnd = strHTML.IndexOf('>', nStart); if (nEnd > nStart) { if ((nEnd - nStart) > 0) { string strTag = strHTML.Substring(nStart, nEnd - nStart + 1); strTag = strTag.ToLower(); if (strTag == "") { cf.dwMask |= CFM_WEIGHT | CFM_BOLD; cf.dwEffects |= CFE_BOLD; cf.wWeight = FW_BOLD; } else if (strTag == "") { cf.dwMask |= CFM_ITALIC; cf.dwEffects |= CFE_ITALIC; } else if (strTag == "") { cf.dwMask |= CFM_UNDERLINE | CFM_UNDERLINETYPE; cf.dwEffects |= CFE_UNDERLINE; cf.bUnderlineType = CFU_UNDERLINE; } else if (strTag == "") { cf.dwMask |= CFM_STRIKEOUT; cf.dwEffects |= CFE_STRIKEOUT; } else if (strTag == "") { cf.dwMask |= CFM_SUPERSCRIPT; cf.dwEffects |= CFE_SUPERSCRIPT; } else if (strTag == "") { cf.dwMask |= CFM_SUBSCRIPT; cf.dwEffects |= CFE_SUBSCRIPT; } else if ((strTag.Length > 2) && (strTag.Substring(0, 2) == " 0) { pf.dwMask |= PFM_ALIGNMENT; pf.wAlignment = (short)PFA_LEFT; } else if (strTag.IndexOf("align=\"right\"") > 0) { pf.dwMask |= PFM_ALIGNMENT; pf.wAlignment = (short)PFA_RIGHT; } else if (strTag.IndexOf("align=\"center\"") > 0) { pf.dwMask |= PFM_ALIGNMENT; pf.wAlignment = (short)PFA_CENTER; } } else if ((strTag.Length > 5) && (strTag.Substring(0, 5) == " 0) { int nFaceEnd = strTag.IndexOf('\"', nFace + 6); if (nFaceEnd > nFace) strFont = strTag.Substring(nFace + 6, nFaceEnd - nFace - 6); } int nSize = strTag.IndexOf("size="); if (nSize > 0) { int nSizeEnd = strTag.IndexOf('\"', nSize + 6); if (nSizeEnd > nSize) { dHeight = double.Parse(strTag.Substring(nSize + 6, nSizeEnd - nSize - 6)); dHeight *= (double)(20 * 5); yHeight = (int)dHeight; } } int nColor = strTag.IndexOf("color="); if (nColor > 0) { int nColorEnd = strTag.IndexOf('\"', nColor + 7); if (nColorEnd > nColor) { if (strTag.Substring(nColor + 7, 1) == "#") { string strCr = strTag.Substring(nColor + 8, nColorEnd - nColor - 8); int nCr = Convert.ToInt32(strCr, 16); Color color = Color.FromArgb(nCr); crFont = GetCOLORREF(color); } else { crFont = int.Parse(strTag.Substring(nColor + 7, nColorEnd - nColor - 7)); } } } cf.szFaceName = new char[LF_FACESIZE]; strFont.CopyTo(0, cf.szFaceName, 0, Math.Min(LF_FACESIZE - 1, strFont.Length)); //cf.szFaceName = strFont.ToCharArray(0, Math.Min(strFont.Length, LF_FACESIZE)); cf.crTextColor = crFont; cf.yHeight = yHeight; cf.dwMask |= CFM_COLOR | CFM_SIZE | CFM_FACE; cf.dwEffects &= ~CFE_AUTOCOLOR; } else if (strTag == "
  • ") { if (pf.wNumbering != PFN_BULLET) { pf.dwMask |= PFM_NUMBERING; pf.wNumbering = (short)PFN_BULLET; } } else if (strTag == "") { cf.dwEffects &= ~CFE_BOLD; cf.wWeight = FW_NORMAL; } else if (strTag == "") { cf.dwEffects &= ~CFE_ITALIC; } else if (strTag == "") { cf.dwEffects &= ~CFE_UNDERLINE; } else if (strTag == "") { cf.dwEffects &= ~CFM_STRIKEOUT; } else if (strTag == "") { cf.dwEffects &= ~CFE_SUPERSCRIPT; } else if (strTag == "") { cf.dwEffects &= ~CFE_SUBSCRIPT; } else if (strTag == "") { } else if (strTag == "

    ") { } else if (strTag == "
  • ") { } //------------------------------- // now, remove tag from HTML int nStart2 = strHTML.IndexOf("<", nEnd + 1); if (nStart2 > 0) { // extract partial data strData = strHTML.Substring(nEnd + 1, nStart2 - nEnd - 1); strHTML = strHTML.Substring(nStart2); } else { // get remain text and finish if ((nEnd + 1) < strHTML.Length) strData = strHTML.Substring(nEnd + 1); else strData = ""; strHTML = ""; } //-------------------------------s //------------------------------- // have we any continuos tag ? if (strData.Length > 0) { // yes, ok, goto to reinit if (strData[0] == '<') goto reinit; } //------------------------------- } else { // we have not found any valid tag strHTML = ""; } } else { // we have not found any valid tag strHTML = ""; } } } else { // we have not found any tag strHTML = ""; } if (strData.Length > 0) { //------------------------------- // replace entities strData = strData.Replace("&", "&"); strData = strData.Replace("<", "<"); strData = strData.Replace(">", ">"); strData = strData.Replace("'", "'"); strData = strData.Replace(""", "\""); //------------------------------- string strAux = strData; // use another copy while (strAux.Length > 0) { //----------------------- int nLen = strAux.Length; //----------------------- //------------------------------- // now, add text to control int nStartCache = this.SelectionStart; string strt = strAux.Substring(0, nLen); this.SelectedText = strt; strAux = strAux.Remove(0, nLen); this.SelectionStart = nStartCache; this.SelectionLength = strt.Length; //------------------------------- //------------------------------- // apply format this.ParaFormat = pf; this.CharFormat = cf; //------------------------------- // reposition to final this.SelectionStart = this.TextLength + 1; this.SelectionLength = 0; } // reposition to final this.SelectionStart = this.TextLength + 1; this.SelectionLength = 0; //------------------------------- // new paragraph requires to reset alignment if ((strData.IndexOf("\r\n", 0) >= 0) || (strData.IndexOf("\n", 0) >= 0)) { pf.dwMask = PFM_ALIGNMENT | PFM_NUMBERING; pf.wAlignment = (short)PFA_LEFT; pf.wNumbering = 0; } //------------------------------- } } // while (strHTML.Length > 0) } catch (Exception ex) { MessageBox.Show(ex.Message); } finally { // reposition to final this.SelectionStart = this.TextLength + 1; this.SelectionLength = 0; this.EndUpdate(); this.HideSelection = false; } } #endregion } }