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 
00216                 _tcscpy(cf.szFaceName, _T("Courier"));
00217 
00218 #else
00219 
00220                 strcpy(cf.szFaceName, "Courier");
00221 
00222 #endif
00223                 break;
00224             case kNMEStyleCharLink:
00225                 if (links)
00226                 {
00227                     // hide target and set both target and link to CFM_LINK
00228                     CHARFORMAT2 c2;
00229                     int j;
00230 #if defined(_UNICODE)
00231                     for (j = 0; j < length && str.GetAt(styleTable->span[i].begin + j) != _T('|'); j++)
00232                         ;
00233 #else
00234                     for (j = 0; j < length && output[j] != '|'; j++)
00235                         ;
00236 #endif
00237                     if (j < length)
00238                         j++;
00239                     c2.cbSize = sizeof(c2);
00240                     c2.dwMask = CFM_HIDDEN;
00241                     c2.dwEffects = CFE_HIDDEN;
00242                     c.SetSel(offset + styleTable->span[i].begin, offset + styleTable->span[i].begin + j);
00243                     ::SendMessage(c.m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&c2);
00244                     cf.dwMask = CFM_LINK;
00245                     cf.dwEffects = CFE_LINK;
00246                     c.SetSel(offset + styleTable->span[i].begin, offset + styleTable->span[i].end);
00247                     c.SetSelectionCharFormat(cf);
00248                     cf.dwMask = 0;
00249                 }
00250                 break;
00251             case kNMEStyleParPlain:
00252                 pf.dwMask = PFM_OFFSETINDENT | PFM_OFFSET;
00253                 pf.dxStartIndent = 300;
00254                 pf.dxOffset = -300;
00255                 break;
00256             case kNMEStyleParIndentedPar:
00257                 pf.dwMask = PFM_OFFSETINDENT | PFM_OFFSET;
00258                 pf.dxStartIndent = 600 * styleTable->span[i].level + 300;
00259                 pf.dxOffset = -300;
00260                 break;
00261             case kNMEStyleParHeading:
00262                 cf.dwMask = CFM_SIZE;
00263                 cf.yHeight = 20 * (20 - 2 * styleTable->span[i].level);
00264                 if (styleTable->span[i].level == 1)
00265                 {
00266                     pf.dwMask = PFM_ALIGNMENT;
00267                     pf.wAlignment = PFA_CENTER;
00268                 }
00269                 break;
00270         }
00271         if (cf.dwMask != 0 || pf.dwMask != 0)
00272             c.SetSel(offset + styleTable->span[i].begin, offset + styleTable->span[i].end);
00273         if (cf.dwMask != 0)
00274             c.SetSelectionCharFormat(cf);
00275         if (pf.dwMask != 0)
00276             c.SetParaFormat(pf);
00277     }
00278     
00279     c.SetSel(0, 0); // don't leave the last span selected
00280 }
00281 
00282 void NMEMFCSetRichText(CRichEditCtrl &c,
00283         WCHAR const *input, int inputLength,
00284         bool replaceSel,
00285         CHARFORMAT const *plainTextCharFormat,
00286         bool links)
00287 {
00288     char *str8 = cStringToUtf8(input, inputLength);
00289     NMEMFCSetRichText(c, str8, -1, replaceSel, plainTextCharFormat, links);
00290     delete [] str8;
00291 }
00292 
00293 void NMEMFCEnLink(NMHDR const *pNMHDR, LRESULT *pResult,
00294         NMEMFCLinkFun linkFun, void *linkFunData)
00295 {
00296     ENLINK *event = (ENLINK *)pNMHDR;
00297     if (event->msg == WM_LBUTTONDOWN)
00298     {
00299         // extract link (8-bit char!)
00300         TEXTRANGE range;
00301         range.chrg = event->chrg;
00302 #if (_RICHEDIT_VER >= 0x0200)
00303 
00304         range.lpstrText = new TCHAR[range.chrg.cpMax - range.chrg.cpMin + 1];
00305 
00306 #else
00307 
00308         range.lpstrText = new char[range.chrg.cpMax - range.chrg.cpMin + 1];
00309 
00310 #endif
00311         ::SendMessage(pNMHDR->hwndFrom, EM_GETTEXTRANGE, 0 , (LPARAM)&range);
00312         CString s(range.lpstrText);
00313         if (s.Find('|') >= 0)
00314             s = s.Left(s.Find('|'));
00315 #if defined(_UNICODE)
00316         char *url = cStringToUtf8(s);
00317 #else
00318         char const *url = s;
00319 #endif
00320         if (url && linkFun)
00321             linkFun(url, linkFunData);
00322 #if defined(_UNICODE)
00323         if (url)
00324             delete [] url;
00325 #endif
00326         ShellExecute(NULL, _T("open"), s, NULL, NULL, SW_SHOWNORMAL);
00327         delete [] range.lpstrText;
00328     }
00329     *pResult = 0;
00330 }
00331 
00332 void NMEMFCLinkFunURL(NMEConstText link, void *data)
00333 {
00334     ShellExecute(NULL, _T("open"), utf8ToCString(link), NULL, NULL, SW_RESTORE);
00335 }
Generated by Doxygen.
Copyright 2007-2013, Yves Piguet.
All rights reserved.