nyctergatis.com

Contact

Projects
Sysquake Remote Live
NME
PDF
Hike
Sudoku
GifBuilder
jpeglib for Palm OS
MySQL Client
Cross-GCC for Mac OS
NMEGtk.c
Go to the documentation of this file.
00001 
00008 /* License: new BSD license (see file NME.h) */
00009 
00010 #include "NMEGtk.h"
00011 #include <stdio.h>
00012 #include <stdlib.h>
00013 #include <string.h>
00014 
00015 static GdkCursor *textCursor = NULL;    
00016 static GdkCursor *linkCursor = NULL;    
00017 
00018 void NMEGtkInit(NMEGtk *nmegtk, GtkTextBuffer *textBuffer,
00019         int charSize)
00020 {
00021     int i;
00022     
00023     nmegtk->textBuffer = textBuffer;
00024     nmegtk->linkCB = NULL;
00025     
00026     nmegtk->plainTag = gtk_text_buffer_create_tag(textBuffer, "plain", NULL);
00027     g_object_set(G_OBJECT(nmegtk->plainTag), "font", "serif", NULL);
00028     nmegtk->boldTag = gtk_text_buffer_create_tag(textBuffer, "bold", NULL);
00029     g_object_set(G_OBJECT(nmegtk->boldTag), "weight", PANGO_WEIGHT_BOLD, NULL);
00030     nmegtk->italicTag = gtk_text_buffer_create_tag(textBuffer, "italic", NULL);
00031     g_object_set(G_OBJECT(nmegtk->italicTag), "style", PANGO_STYLE_ITALIC, NULL);
00032     nmegtk->underlineTag = gtk_text_buffer_create_tag(textBuffer, "underline", NULL);
00033     g_object_set(G_OBJECT(nmegtk->underlineTag), "underline", PANGO_UNDERLINE_SINGLE, NULL);
00034     nmegtk->superTag = gtk_text_buffer_create_tag(textBuffer, "superscript", NULL);
00035     g_object_set(G_OBJECT(nmegtk->superTag), "rise", charSize / 2, NULL);
00036     nmegtk->subTag = gtk_text_buffer_create_tag(textBuffer, "subscript", NULL);
00037     g_object_set(G_OBJECT(nmegtk->subTag), "rise", -charSize / 3, NULL);
00038     nmegtk->monoTag = gtk_text_buffer_create_tag(textBuffer, "monospace", NULL);
00039     g_object_set(G_OBJECT(nmegtk->monoTag), "font", "monospace", NULL);
00040     nmegtk->headingTag[0] = gtk_text_buffer_create_tag(textBuffer, "h1", NULL);
00041     g_object_set(G_OBJECT(nmegtk->headingTag[0]),
00042             "weight", PANGO_WEIGHT_BOLD,
00043             "scale", PANGO_SCALE_XX_LARGE,
00044             "pixels-above-lines", charSize / PANGO_SCALE,
00045             "justification", GTK_JUSTIFY_CENTER,
00046             NULL);
00047     nmegtk->headingTag[1] = gtk_text_buffer_create_tag(textBuffer, "h2", NULL);
00048     g_object_set(G_OBJECT(nmegtk->headingTag[1]),
00049             "weight", PANGO_WEIGHT_BOLD,
00050             "scale", PANGO_SCALE_X_LARGE,
00051             "pixels-above-lines", 2 * charSize / 3 / PANGO_SCALE,
00052             NULL);
00053     nmegtk->headingTag[2] = gtk_text_buffer_create_tag(textBuffer, "h3", NULL);
00054     g_object_set(G_OBJECT(nmegtk->headingTag[2]),
00055             "weight", PANGO_WEIGHT_BOLD,
00056             "scale", PANGO_SCALE_LARGE,
00057             "pixels-above-lines", charSize / 2 / PANGO_SCALE,
00058             NULL);
00059     nmegtk->headingTag[3] = gtk_text_buffer_create_tag(textBuffer, "h4", NULL);
00060     g_object_set(G_OBJECT(nmegtk->headingTag[3]), "weight", PANGO_WEIGHT_BOLD,
00061             "pixels-above-lines", charSize / 3 / PANGO_SCALE,
00062             NULL);
00063     nmegtk->parTag = gtk_text_buffer_create_tag(textBuffer, "plainpar", NULL);
00064     g_object_set(G_OBJECT(nmegtk->parTag), "indent", 2 * charSize / PANGO_SCALE, NULL);
00065     for (i = 0; i < kMaxListLevel; i++)
00066     {
00067         char name[16];
00068         
00069         sprintf(name, "indent%d", i + 1);
00070         nmegtk->indentTag[i] = gtk_text_buffer_create_tag(textBuffer, name, NULL);
00071         g_object_set(G_OBJECT(nmegtk->indentTag[i]),
00072                 "left-margin", (3 * i + 1) * charSize / PANGO_SCALE,
00073                 "indent", -charSize / PANGO_SCALE,
00074                 NULL);
00075     }
00076     
00077     // initialize cursors
00078     if (!linkCursor)
00079         linkCursor = gdk_cursor_new(GDK_LEFT_PTR);
00080     if (!textCursor)
00081         textCursor = gdk_cursor_new(GDK_XTERM);
00082 }
00083 
00084 void NMEGtkSetLinkFun(NMEGtk *nmegtk, NMEGtkLinkFun linkFun, void *linkFunData)
00085 {
00086     nmegtk->linkCB = g_malloc(sizeof(NMEGtkLinkCB));
00087     nmegtk->linkCB->fun = linkFun;
00088     nmegtk->linkCB->data = linkFunData;
00089     g_object_set_data_full(G_OBJECT(nmegtk->textBuffer), "link_cb",
00090             nmegtk->linkCB, g_free);
00091 }
00092 
00100 static gboolean linkEvent(GtkTextTag *tag, GtkWidget *w,
00101         GdkEventButton *event, GtkTextIter *iter,
00102         gpointer d)
00103 {
00104     NMEGtkLinkCB *l = (NMEGtkLinkCB *)d;
00105     
00106     switch (event->type)
00107     {
00108         case GDK_BUTTON_RELEASE:
00109             if (l)
00110             {
00111                 l->fun(g_object_get_data(G_OBJECT(tag), "link_url"),
00112                         l->data);
00113                 return TRUE;
00114             }
00115             break;
00116 // what follows doesn't work...
00117         case GDK_ENTER_NOTIFY:
00118             if (linkCursor)
00119                 gdk_window_set_cursor(gtk_widget_get_parent_window(w), linkCursor);
00120             return TRUE;
00121         case GDK_LEAVE_NOTIFY:
00122             if (textCursor)
00123                 gdk_window_set_cursor(gtk_widget_get_parent_window(w), textCursor);
00124             return TRUE;
00125     }
00126     
00127     return TRUE;    // FALSE; (TRUE to avoid assertion error)
00128 }
00129 
00130 void NMEGtkApplyStyle(NMEGtk const *nmegtk,
00131         NMEStyleTable const *spanTable,
00132         NMEInt offset, NMEInt length,
00133         NMEConstText nmeTextForLinks)
00134 {
00135     GtkTextIter start, end;
00136     GtkTextTag *tag;
00137     int i;
00138     
00139     gtk_text_buffer_get_iter_at_offset(nmegtk->textBuffer, &start,
00140             offset);
00141     gtk_text_buffer_get_iter_at_offset(nmegtk->textBuffer, &end,
00142             offset + length);
00143     gtk_text_buffer_apply_tag(nmegtk->textBuffer, nmegtk->plainTag, &start, &end);
00144     
00145     for (i = 0; i < spanTable->n; i++)
00146     {
00147         switch (spanTable->span[i].style)
00148         {
00149             case kNMEStyleCharBold:
00150             case kNMEStyleCharDT:
00151             case kNMEStyleCharTH:
00152                 tag = nmegtk->boldTag;
00153                 break;
00154             case kNMEStyleCharItalic:
00155                 tag = nmegtk->italicTag;
00156                 break;
00157             case kNMEStyleCharUnderline:
00158                 tag = nmegtk->underlineTag;
00159                 break;
00160             case kNMEStyleCharSuperscript:
00161                 tag = nmegtk->superTag;
00162                 break;
00163             case kNMEStyleCharSubscript:
00164                 tag = nmegtk->subTag;
00165                 break;
00166             case kNMEStyleCharMonospace:
00167                 tag = nmegtk->monoTag;
00168                 break;
00169             case kNMEStyleParHeading:
00170                 if (spanTable->span[i].level <= kMaxHeadingLevel)
00171                     tag = nmegtk->headingTag[spanTable->span[i].level - 1];
00172                 else
00173                     tag = nmegtk->headingTag[kMaxHeadingLevel - 1];
00174                 break;
00175             case kNMEStyleParPlain:
00176                 tag = nmegtk->parTag;
00177                 break;
00178             case kNMEStyleParUL:
00179             case kNMEStyleParOL:
00180             case kNMEStyleParDL:
00181             case kNMEStyleParDT:
00182             case kNMEStyleParIndentedPar:
00183                 if (spanTable->span[i].level <= kMaxListLevel)
00184                     tag = nmegtk->indentTag[spanTable->span[i].level - 1];
00185                 else
00186                     tag = nmegtk->indentTag[kMaxHeadingLevel - 1];
00187                 break;
00188             case kNMEStyleCharLink:
00189                 if (nmeTextForLinks)
00190                 {
00191                     tag = gtk_text_buffer_create_tag(nmegtk->textBuffer, NULL,
00192                             "foreground", "blue",
00193                             "underline", PANGO_UNDERLINE_SINGLE,
00194                             NULL);
00195                     g_object_set_data_full(G_OBJECT(tag),
00196                             "link_url",
00197                             g_strndup(nmeTextForLinks + spanTable->span[i].linkOffset,
00198                                     spanTable->span[i].linkLength),
00199                             g_free);
00200                     g_signal_connect(G_OBJECT(tag), "event",
00201                             G_CALLBACK(linkEvent), (gpointer)nmegtk->linkCB);
00202                     break;
00203                 }
00204                 // else no hyperlink
00205             default:
00206                 tag = NULL;
00207                 break;
00208         }
00209         
00210         if (tag)
00211         {
00212             gtk_text_buffer_get_iter_at_offset(nmegtk->textBuffer, &start,
00213                     spanTable->span[i].begin + offset);
00214             gtk_text_buffer_get_iter_at_offset(nmegtk->textBuffer, &end,
00215                     spanTable->span[i].end + offset);
00216             gtk_text_buffer_apply_tag(nmegtk->textBuffer, tag, &start, &end);
00217         }
00218     }
00219 }
00220 
00221 NMEErr NMEGtkInsert(GtkTextBuffer *textBuffer,
00222         NMEGtk const *nmegtk,
00223         NMEConstText str, NMEInt len,
00224         NMEBoolean replaceSel,
00225         NMEBoolean links)
00226 {
00227     NMEText buf, dest;
00228     NMEInt bufSize, destLen, destLenUCS16;
00229     NMEOutputFormat f;
00230     NMEErr err;
00231     int length;
00232     GtkTextIter iter;
00233     
00234     if (len < 0)
00235         len = strlen(str);
00236     
00237     bufSize = 1024 + 2 * len;
00238     f = NMEOutputFormatBasicText;
00239     f.spanHookFun = NMEStyleSpanHook;
00240     f.parHookFun = NMEStyleSpanHook;
00241     
00242 tryAgain:
00243     buf = malloc(bufSize);
00244     if (!buf)
00245         return kNMEErrNotEnoughMemory;
00246     f.hookData = malloc(bufSize);
00247     if (!f.hookData)
00248     {
00249         free((void *)buf);
00250         return kNMEErrNotEnoughMemory;
00251     }
00252     NMEStyleInit((NMEStyleTable *)f.hookData, bufSize, TRUE);
00253     
00254     err = NMEProcess(str, len, buf, bufSize,
00255             kNMEProcessOptDefault, "\n", &f, 0,
00256             &dest, &destLen, &destLenUCS16);
00257     if (err == kNMEErrNotEnoughMemory || err == kNMEErrStyleTableTooSmall)
00258     {
00259         free((void *)buf);
00260         free((void *)f.hookData);
00261         if (bufSize < 65536 + 10 * len)
00262         {
00263             bufSize *= 2;
00264             goto tryAgain;
00265         }
00266         else
00267             return kNMEErrNotEnoughMemory;
00268     }
00269     
00270     if (replaceSel)
00271     {
00272         length = gtk_text_buffer_get_char_count(textBuffer);
00273         gtk_text_buffer_get_iter_at_offset(textBuffer, &iter, length);
00274         gtk_text_buffer_insert(textBuffer, &iter, dest, destLen);
00275         NMEGtkApplyStyle(nmegtk, (NMEStyleTable *)f.hookData,
00276                 length, destLenUCS16, links ? str : NULL);
00277     }
00278     else
00279     {
00280         gtk_text_buffer_set_text(textBuffer, dest, destLen);
00281         NMEGtkApplyStyle(nmegtk, (NMEStyleTable *)f.hookData,
00282                 0, destLenUCS16, links ? str : NULL);
00283     }
00284     
00285     free((void *)buf);
00286     free((void *)f.hookData);
00287     
00288     return kNMEErrOk;
00289 }
Generated by Doxygen.
Copyright 2007-2013, Yves Piguet.
All rights reserved.