nyctergatis.com

Contact

Projects
Sysquake Remote Live
NME
PDF
Hike
Sudoku
GifBuilder
jpeglib for Palm OS
MySQL Client
Cross-GCC for Mac OS
NMEMFC.cpp
Go to the documentation of this file.
00001 
00008 /* License: new BSD license (see file NME.h) */
00009 
00010 #include "NMEMFC.h"
00011 #include "NMEStyleCpp.h"
00012 
00014 #define isFirstUTF8Byte(c) \
00015     (((c) & 0x80) == 0 || ((c) & 0xe0) == 0xc0 || ((c) & 0xf0) == 0xe0)
00016 
00021 static CString utf8ToCString(char const *utf8, int len = -1)
00022 {
00023     int i, j, wlen;
00024     WCHAR *wstr;
00025     CString s;
00026     
00027     // count len
00028     if (len < 0)
00029         for (len = 0; utf8[len]; len++)
00030             ;
00031     
00032     // count characters
00033     for (i = wlen = 0; i < len; i++)
00034         if (isFirstUTF8Byte(utf8[i]))
00035             wlen++;
00036     
00037     // allocate room for null-terminated array of WCHAR
00038     wstr = (WCHAR *)malloc((len + 1) * sizeof(WCHAR));
00039 
00040     // convert string
00041     for (i = j = 0; j < len; i++)
00042     {
00043         if ((utf8[j] & 0x80) == 0)  // 7 bits
00044             wstr[i] = (WCHAR)utf8[j++];
00045         else if (j + 1 < len    // 11 bits
00046             && (utf8[j] & 0xe0) == 0xc0 && (utf8[j + 1] & 0xc0) == 0x80)
00047         {
00048             wstr[i] = ((WCHAR)utf8[j++] & 0x1f) << 6;
00049             wstr[i] |= utf8[j++] & 0x3f;
00050         }
00051         else if (j + 2 < len    // 16 bits
00052             && (utf8[j] & 0xf0) == 0xe0 && (utf8[j + 1] & 0xc0) == 0x80
00053             && (utf8[j + 2] & 0xc0) == 0x80)
00054         {
00055             wstr[i] = (WCHAR)utf8[j++] << 12;
00056             wstr[i] |= (utf8[j++] & 0x3f) << 6;
00057             wstr[i] |= utf8[j++] & 0x3f;
00058         }
00059         else
00060         {
00061             j++;    // ignore
00062             i--;
00063         }
00064     }
00065     wstr[i] = 0;
00066 
00067     // make CString
00068     s = wstr;
00069 
00070     // free array of WCHAR
00071     free((void *)wstr);
00072     
00073     return s;
00074 }
00075 
00082 static char *cStringToUtf8(WCHAR const *wstr, int len = -1)
00083 {
00084     int len8;   // number of UTF-8 bytes, excluding ending null
00085     int i, j;
00086     char *s;
00087     
00088     // count number of UTF-8 bytes
00089     for (i = len8 = 0; len < 0 ? wstr[i] : i < len; i++)
00090         if (!(wstr[i] & 0xff80))
00091             len8++;
00092         else if (!(wstr[i] & 0xf800))
00093             len8 += 2;
00094         else
00095             len8 += 3;
00096     
00097     // alloc output string
00098     s = new char [len8 + 1];
00099     if (!s)
00100         return s;
00101     
00102     // convert to UTF-8
00103     for (i = j = 0; len < 0 ? wstr[i] : i < len; i++)
00104         if (!(wstr[i] & 0xff80))
00105             s[j++] = (char)wstr[i];
00106         else if (!(wstr[i] & 0xf800))
00107         {
00108             s[j++] = 0xc0 | (wstr[i] >> 6);
00109             s[j++] = 0x80 | wstr[i] & 0x3f;
00110         }
00111         else
00112         {
00113             s[j++] = 0xe0 | (wstr[i] >> 12) & 0x0f;
00114             s[j++] = 0x80 | (wstr[i] >> 6) & 0x3f;
00115             s[j++] = 0x80 | wstr[i] & 0x3f;
00116         }
00117     
00118     // add ending null and return
00119     s[j] = '\0';
00120     return s;
00121 }
00122 
00123 void NMEMFCSetRichText(CRichEditCtrl &c,
00124         char const *input, int inputLength,
00125         bool replaceSel,
00126         CHARFORMAT const *plainTextCharFormat,
00127         bool links)
00128 {
00129     // convert input to text + style table
00130     NMEStyle nme(input, inputLength);
00131     NMEOutputFormat f = NMEOutputFormatBasicText;
00132     f.parHookFun = NMEStyleSpanHook;
00133     if (links)
00134         f.sepLink = "|";
00135     nme.setFormat(f);
00136 #if defined(_UNICODE)
00137     nme.setUnicodeStyleOffsets(TRUE);
00138 #endif
00139     NMEConstText output;
00140     NMEInt outputLength;
00141     if (nme.getOutput(&output, &outputLength) != kNMEErrOk)
00142         return;
00143     NMEStyleTable const *styleTable = nme.getStyleTable();
00144     
00145     // replace whole text or selection
00146     long offset = 0;
00147     long length = outputLength;
00148 #if defined(_UNICODE)
00149     CString str = utf8ToCString(output, outputLength);
00150     length = str.GetLength();
00151     if (replaceSel)
00152     {
00153         long endSel;    // ignored
00154         
00155         c.GetSel(offset, endSel);
00156         c.ReplaceSel(str);
00157     }
00158     else
00159         c.SetWindowText(str);
00160 #else
00161     length = outputLength;
00162     if (replaceSel)
00163     {
00164         long endSel;    // ignored
00165         
00166         c.GetSel(offset, endSel);
00167         c.ReplaceSel(CString(output, outputLength));
00168     }
00169     else
00170         c.SetWindowText(CString(output, outputLength));
00171 #endif
00172     
00173     // apply style
00174     CHARFORMAT cf;
00175     PARAFORMAT pf;
00176     if (plainTextCharFormat)
00177         cf = *plainTextCharFormat;
00178     else
00179         c.GetDefaultCharFormat(cf);
00180     c.SetSel(offset, offset + length);
00181     c.SetSelectionCharFormat(cf);
00182     cf.cbSize = sizeof(cf);
00183     pf.cbSize = sizeof(pf);
00184     for (int i = 0; i < styleTable->n; i++)
00185     {
00186         cf.dwMask = 0;
00187         pf.dwMask = 0;
00188         switch (styleTable->span[i].style)
00189         {
00190             case kNMEStyleCharBold:
00191             case kNMEStyleCharDT:
00192             case kNMEStyleCharTH:
00193                 cf.dwMask = CFM_BOLD;
00194                 cf.dwEffects = CFE_BOLD;
00195                 break;
00196             case kNMEStyleCharItalic:
00197                 cf.dwMask = CFM_ITALIC;
00198                 cf.dwEffects = CFE_ITALIC;
00199                 break;
00200             case kNMEStyleCharUnderline:
00201                 cf.dwMask = CFM_UNDERLINE;
00202                 cf.dwEffects = CFE_UNDERLINE;
00203                 break;
00204             case kNMEStyleCharSuperscript:
00205                 cf.dwMask = CFM_OFFSET;
00206                 cf.yOffset = 100;
00207                 break;
00208             case kNMEStyleCharSubscript:
00209                 cf.dwMask = CFM_OFFSET;
00210                 cf.yOffset = -100;
00211                 break;
00212             case kNMEStyleCharMonospace:
00213                 cf.dwMask = CFM_FACE;
00214 #if (_RICHEDIT_VER >= 0x0200)
00215                 _tcscpy(cf.szFaceName, _T("Courier"));
00216 #else
00217                 strcpy(cf.szFaceName, "Courier");
00218 #endif
00219                 break;
00220             case kNMEStyleCharLink:
00221                 if (links)
00222                 {
00223                     // hide target and set both target and link to CFM_LINK
00224                     CHARFORMAT2 c2;
00225                     int j;
00226 #if defined(_UNICODE)
00227                     for (j = 0; j < length && str.GetAt(styleTable->span[i].begin + j) != _T('|'); j++)
00228                         ;
00229 #else
00230                     for (j = 0; j < length && output[j] != '|'; j++)
00231                         ;
00232 #endif
00233                     if (j < length)
00234                         j++;
00235                     c2.cbSize = sizeof(c2);
00236                     c2.dwMask = CFM_HIDDEN;
00237                     c2.dwEffects = CFE_HIDDEN;
00238                     c.SetSel(offset + styleTable->span[i].begin, offset + styleTable->span[i].begin + j);
00239                     ::SendMessage(c.m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&c2);
00240                     cf.dwMask = CFM_LINK;
00241                     cf.dwEffects = CFE_LINK;
00242                     c.SetSel(offset + styleTable->span[i].begin, offset + styleTable->span[i].end);
00243                     c.SetSelectionCharFormat(cf);
00244                     cf.dwMask = 0;
00245                 }
00246                 break;
00247             case kNMEStyleParPlain:
00248                 pf.dwMask = PFM_OFFSETINDENT | PFM_OFFSET;
00249                 pf.dxStartIndent = 300;
00250                 pf.dxOffset = -300;
00251                 break;
00252             case kNMEStyleParIndentedPar:
00253                 pf.dwMask = PFM_OFFSETINDENT | PFM_OFFSET;
00254                 pf.dxStartIndent = 600 * styleTable->span[i].level + 300;
00255                 pf.dxOffset = -300;
00256                 break;
00257             case kNMEStyleParHeading:
00258                 cf.dwMask = CFM_SIZE;
00259                 cf.yHeight = 20 * (20 - 2 * styleTable->span[i].level);
00260                 if (styleTable->span[i].level == 1)
00261                 {
00262                     pf.dwMask = PFM_ALIGNMENT;
00263                     pf.wAlignment = PFA_CENTER;
00264                 }
00265                 break;
00266         }
00267         if (cf.dwMask != 0 || pf.dwMask != 0)
00268             c.SetSel(offset + styleTable->span[i].begin, offset + styleTable->span[i].end);
00269         if (cf.dwMask != 0)
00270             c.SetSelectionCharFormat(cf);
00271         if (pf.dwMask != 0)
00272             c.SetParaFormat(pf);
00273     }
00274     
00275     c.SetSel(0, 0); // don't leave the last span selected
00276 }
00277 
00278 void NMEMFCSetRichText(CRichEditCtrl &c,
00279         WCHAR const *input, int inputLength,
00280         bool replaceSel,
00281         CHARFORMAT const *plainTextCharFormat,
00282         bool links)
00283 {
00284     char *str8 = cStringToUtf8(input, inputLength);
00285     NMEMFCSetRichText(c, str8, -1, replaceSel, plainTextCharFormat, links);
00286     delete [] str8;
00287 }
00288 
00289 void NMEMFCEnLink(NMHDR const *pNMHDR, LRESULT *pResult,
00290         NMEMFCLinkFun linkFun, void *linkFunData)
00291 {
00292     ENLINK *event = (ENLINK *)pNMHDR;
00293     if (event->msg == WM_LBUTTONDOWN)
00294     {
00295         // extract link (8-bit char!)
00296         TEXTRANGE range;
00297         range.chrg = event->chrg;
00298 #if (_RICHEDIT_VER >= 0x0200)
00299         range.lpstrText = new TCHAR[range.chrg.cpMax - range.chrg.cpMin + 1];
00300 #else
00301         range.lpstrText = new char[range.chrg.cpMax - range.chrg.cpMin + 1];
00302 #endif
00303         ::SendMessage(pNMHDR->hwndFrom, EM_GETTEXTRANGE, 0 , (LPARAM)&range);
00304         CString s(range.lpstrText);
00305         if (s.Find('|') >= 0)
00306             s = s.Left(s.Find('|'));
00307 #if defined(_UNICODE)
00308         char *url = cStringToUtf8(s);
00309 #else
00310         char const *url = s;
00311 #endif
00312         if (url && linkFun)
00313             linkFun(url, linkFunData);
00314 #if defined(_UNICODE)
00315         if (url)
00316             delete [] url;
00317 #endif
00318         ShellExecute(NULL, _T("open"), s, NULL, NULL, SW_SHOWNORMAL);
00319         delete [] range.lpstrText;
00320     }
00321     *pResult = 0;
00322 }
00323 
00324 void NMEMFCLinkFunURL(NMEConstText link, void *data)
00325 {
00326     ShellExecute(NULL, _T("open"), utf8ToCString(link), NULL, NULL, SW_RESTORE);
00327 }
Generated by Doxygen.
Copyright 2007-2011, Yves Piguet.
All rights reserved.