1 /* WINGsP.h should NEVER be included from user applications */
17 void Close(WMWidget
*self
, void *client
)
24 /* =============== a rudimentary HTML parser ======================= */
26 /* due to the WMSetTextParser stuff, it should not
27 be too hard to add parsers. like dis :-] */
31 * A hack to speed up caseless_equal. Thanks to Quincey Koziol for
32 * developing it for the "chimera" folks so I could use it 7 years later ;-)
33 * Constraint: nothing but '\0' may map to 0
35 unsigned char map_table
[256] =
37 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
38 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
39 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
40 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
41 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
42 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92,
43 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
44 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
45 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
46 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
47 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163,
48 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
49 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
50 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205,
51 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
52 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233,
53 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247,
54 248, 249, 250, 251, 252, 253, 254, 255};
56 #define TOLOWER(x) (map_table[(int)x])
58 mystrcasecmp(const unsigned char *s1
, const unsigned char *s2
)
60 if (!*s1
|| !*s2
) return 0;
62 if (TOLOWER (*s1
) != TOLOWER (*s2
)) /* true if *s1 == 0 ! */
67 return (*s1
=='\0' ||!isalnum(*s1
))?1:0;
71 typedef struct _currentFormat
{
77 WMParserActions actions
;
78 //WMBag *aligns; // for tables...
79 /* the following are "nested"
80 i.e.: <b><b><i></b><b></i>
81 1 2 1 1 2 0 get it? */
89 short ul
:3; /* how "nested"... up to 8 levels deep */
90 short comment
:1; /* ignore text till --> */
98 getArg(char *t
, short type
, void *arg
)
101 while(*(++t
) && !d
) {
103 if(*t
>='0' && *t
<='9') {
104 sscanf(t
, "%d", arg
);
105 while(*t
&& (*t
<'0' || *t
>'9'))
114 void parseToken(WMText
*tPtr
, char *token
, short tk
)
116 short mode
=0; /* 0 starts, 1 closes */
117 WMScreen
*scr
= (W_VIEW(tPtr
))->screen
;
119 while(*token
&& isspace(*(token
))) token
++;
123 while(isspace(*(token
))) token
++;
126 if(strlen(token
)==1) {
127 /* nice and fast for small tokens... no need for too much brain
129 switch(TOLOWER(*token
)) {
132 cfmt
.cfont
= WMGetFontItalic(scr
, cfmt
.cfont
);
133 WMPutInBag(cfmt
.fonts
, (void *)cfmt
.cfont
);
134 } else { /*dun wanna remove the baseFont eh? */
135 int count
= WMGetBagItemCount(cfmt
.fonts
);
137 WMDeleteFromBag(cfmt
.fonts
, count
-1);
138 cfmt
.cfont
= (WMFont
*)WMGetFromBag(cfmt
.fonts
,
139 WMGetBagItemCount(cfmt
.fonts
)-1);
143 cfmt
.cfont
= WMGetFontBold(scr
, cfmt
.cfont
);
144 WMPutInBag(cfmt
.fonts
, (void *)cfmt
.cfont
);
145 } else { /*dun wanna remove the baseFont eh? */
146 int count
= WMGetBagItemCount(cfmt
.fonts
);
148 WMDeleteFromBag(cfmt
.fonts
, count
-1);
149 cfmt
.cfont
= (WMFont
*)WMGetFromBag(cfmt
.fonts
,
150 WMGetBagItemCount(cfmt
.fonts
)-1);
153 cfmt
.para
= (cfmt
.actions
.createParagraph
) (cfmt
.fmargin
, cfmt
.bmargin
,
154 WMWidgetWidth(tPtr
)-30, NULL
, 0, cfmt
.align
);
155 (cfmt
.actions
.insertParagraph
) (tPtr
, cfmt
.para
, cfmt
.type
);
156 cfmt
.para
= (cfmt
.actions
.createParagraph
) (cfmt
.fmargin
, cfmt
.bmargin
,
157 WMWidgetWidth(tPtr
)-30, NULL
, 0, cfmt
.align
);
158 (cfmt
.actions
.insertParagraph
) (tPtr
, cfmt
.para
, cfmt
.type
);
160 case 'u': cfmt
.u
= !mode
; break;
162 } else { /* the <HTML> tag is, as far as I'm concerned, useless */
163 if(mystrcasecmp(token
, "br")) {
164 cfmt
.para
= (cfmt
.actions
.createParagraph
) (cfmt
.fmargin
, cfmt
.bmargin
,
165 WMWidgetWidth(tPtr
)-30, NULL
, 0, cfmt
.align
);
166 (cfmt
.actions
.insertParagraph
) (tPtr
, cfmt
.para
, cfmt
.type
);
168 else if(mystrcasecmp(token
, "ul")) {
170 if(cfmt
.ul
>1) cfmt
.ul
--;
173 cfmt
.bmargin
= cfmt
.ul
*30;
174 cfmt
.fmargin
= cfmt
.bmargin
-10;
175 } else cfmt
.fmargin
= cfmt
.bmargin
= 0;
176 } else if(mystrcasecmp(token
, "li")) {
177 cfmt
.para
= (cfmt
.actions
.createParagraph
) (cfmt
.fmargin
, cfmt
.bmargin
,
178 WMWidgetWidth(tPtr
)-30, NULL
, 0, cfmt
.align
);
179 (cfmt
.actions
.insertParagraph
) (tPtr
, cfmt
.para
, cfmt
.type
);
180 } else if(mystrcasecmp(token
, "align"))
182 else if(mystrcasecmp(token
, "img")) {
188 while(isspace(*(token
))) token
++;
190 switch(TOLOWER(*token
)) {
192 if(TOLOWER(*(1+token
)) == 'r' && TOLOWER(*(2+token
)) == 'c') {
193 mark
= strchr(token
, '=');
195 char img
[256], *iptr
;
198 sscanf(token
, "%s", img
);
200 if(*img
== '\"') { img
[strlen(img
)-1] = 0; iptr
++;}
201 pixmap
= WMCreatePixmapFromFile(scr
, iptr
);
202 chunk
= (cfmt
.actions
.createPChunk
)(pixmap
, 0, False
);
203 (cfmt
.actions
.insertChunk
) (tPtr
, chunk
, False
);
204 printf("[%s]\n", iptr
);
205 } } break; } } while(*(token
++));
207 } else if(mystrcasecmp(token
, "font")) {
210 cfmt
.cfont
= (WMFont
*)WMGetFromBag(cfmt
.fonts
,
211 WMGetBagItemCount(cfmt
.fonts
)-1);
213 (WMColor
*)WMGetFromBag(cfmt
.colors
,
214 WMGetBagItemCount(cfmt
.colors
)-1),
217 else if(mystrcasecmp(token
, "center")) {
219 if(mode
) cfmt
.align
= WALeft
;
220 else cfmt
.align
= WACenter
;
221 cfmt
.para
= (cfmt
.actions
.createParagraph
) (cfmt
.fmargin
, cfmt
.bmargin
,
222 WMWidgetWidth(tPtr
)-30, NULL
, 0, cfmt
.align
);
223 (cfmt
.actions
.insertParagraph
) (tPtr
, cfmt
.para
, cfmt
.type
);
230 //printf("parse token (%s)[%s]\n", mode?"close":"open", token);
233 //while(*token && !isspace(*(token))) token++;
234 //printf("A:%d a:%d z%d Z%d\n", '1', 'a', 'Z', 'z');
237 if(c
>=65 && c
<=122) { major
[i
++] = c
;
238 } else if(c
==' ' || c
=='='){ major
[i
] = 0; i
=0; mm
=1;
239 printf("\nmajor: [%s]", major
);}
243 } else { minor
[i
] = 0; i
=0; printf(" minor: [%s] ", minor
);}
245 }while((c
= *(++token
)));
249 //printf("parse token (%s)[%s]\n", mode?"close":"open", token);
252 void HTMLParser(WMWidget
*w
, void *clientData
, short type
)
254 static short init
=1; /* have we been here at least once before? */
255 char *stream
= (char *) clientData
;
256 WMText
*tPtr
= (WMText
*)w
;
260 #define MAX_TOKEN_SIZE 255
261 char token
[MAX_TOKEN_SIZE
+1];
262 #define MAX_TEXT_SIZE 1023
263 char text
[MAX_TEXT_SIZE
+1];
271 scr
= (W_VIEW(tPtr
))->screen
;
274 cfmt
.actions
= WMGetTextParserActions(tPtr
);
275 cfmt
.fonts
= WMCreateBag(4); /* there sould always be at least 1 font... */
276 cfmt
.cfont
= WMSystemFontOfSize(scr
, 12);
277 WMPutInBag(cfmt
.fonts
, (void *)cfmt
.cfont
);
278 cfmt
.colors
= WMCreateBag(4);
279 cfmt
.ccolor
= WMBlackColor(scr
);
280 WMPutInBag(cfmt
.colors
, (void *)cfmt
.ccolor
);
281 cfmt
.i
= cfmt
.b
= cfmt
.u
= cfmt
.ul
= 0;
283 cfmt
.fmargin
= cfmt
.bmargin
= 0;
284 cfmt
.para
= (cfmt
.actions
.createParagraph
) (cfmt
.fmargin
, cfmt
.bmargin
,
285 WMWidgetWidth(tPtr
)-30, NULL
, 0, cfmt
.align
);
286 (cfmt
.actions
.insertParagraph
) (tPtr
, cfmt
.para
, cfmt
.type
);
291 if(strlen(stream
) == 1 && stream
[0] == '\n') {
292 /* sometimes if the text entered is a single char AND is a newline,
293 the user prolly typed it */
294 cfmt
.para
= (cfmt
.actions
.createParagraph
) (cfmt
.fmargin
, cfmt
.bmargin
,
295 WMWidgetWidth(tPtr
)-30, NULL
, 0, cfmt
.align
);
296 (cfmt
.actions
.insertParagraph
) (tPtr
, cfmt
.para
, cfmt
.type
);
305 while( (c
=*(stream
++))) {
307 if(c
== '\n' || c
=='\t')
308 //c = ' '; //continue;
316 if(c
== '<' && !mode
) {
320 chunk
= (cfmt
.actions
.createTChunk
)(text
, txt
, cfmt
.cfont
,
321 cfmt
.ccolor
, 0, (cfmt
.u
?1:0));
322 (cfmt
.actions
.insertChunk
) (tPtr
, chunk
, cfmt
.type
);
323 //printf("%s\n", text);
326 } else if(c
== '>' && mode
) {
328 if(tk
>0) parseToken(tPtr
, token
, tk
);
333 if(tk
< MAX_TOKEN_SIZE
) token
[tk
++] = c
;
334 } else if(txt
< MAX_TEXT_SIZE
) text
[txt
++] = c
;
338 if(tk
>0) { token
[tk
] = 0; parseToken(tPtr
, token
, tk
);}
341 //printf("%s\n", text);
342 chunk
= (cfmt
.actions
.createTChunk
)(text
, txt
,
343 (WMFont
*)WMGetFromBag(cfmt
.fonts
,
344 WMGetBagItemCount(cfmt
.fonts
)-1),
345 (WMColor
*)WMGetFromBag(cfmt
.colors
,
346 WMGetBagItemCount(cfmt
.colors
)-1),
348 (cfmt
.actions
.insertChunk
) (tPtr
, chunk
, cfmt
.type
);
354 /* ================= the driver ================== */
359 void NotificationObserver(void *self
, WMNotification
*notif
)
361 void *object
= WMGetNotificationObject(notif
);
362 unsigned short w
= WMWidgetWidth(win
);
363 unsigned short h
= WMWidgetHeight(win
);
365 if (WMGetNotificationName(notif
) == WMViewSizeDidChangeNotification
) {
366 if (object
== WMWidgetView(win
)) {
367 WMResizeWidget(text
, w
-20, h
-20);
373 case 0: WMSetTextHasHorizontalScroller(text
, False
); break;
374 case 1: WMSetTextHasVerticalScroller(text
, False
); break;
375 case 2: WMSetTextHasVerticalScroller(text
, True
); break;
376 case 3: WMSetTextHasHorizontalScroller(text
, True
); break;
383 main(int argc
, char **argv
)
389 WMInitializeApplication("WMText", &argc
, argv
);
390 dpy
= XOpenDisplay(NULL
);
393 scr
= WMCreateSimpleApplicationScreen(dpy
);
395 win
= WMCreateWindow(scr
, "WMText Test");
396 WMRealizeWidget(win
);
397 WMResizeWidget(win
, 500, 300);
398 //WMResizeWidget(win, 900, 600);
399 WMSetWindowTitle(win
,"WMText Test");
400 WMSetWindowCloseAction(win
, Close
, NULL
);
402 text
= WMCreateText(win
);
403 WMRealizeWidget(text
);
404 WMResizeWidget(text
, 480, 280);
405 WMMoveWidget(text
, 10, 10);
406 WMSetTextUseFixedPitchFont(text
, False
);
407 WMSetTextMonoFont(text
, False
);
408 WMSetTextParser(text
, HTMLParser
);
409 WMSetTextEditable(text
, True
);
412 FILE *f
= fopen("./wm.html", "r");
415 while(fgets(data
, 1022,f
))
416 WMAppendTextStream(text
, data
);
419 WMAppendTextStream(text
, "<i>can't</i> open the <u>wm.html</u> file, but here's a <B>text <I>stream <img src=foo.bar></I><BR>that</B> <U>needs</U> parsing");
424 //WMPrependTextStream(text, "this is prepended\n");
425 //WMAppendTextStream(text, "blueplanet.rtf");
429 WMRefreshText(text
, 0, 0);
432 WMAddNotificationObserver(NotificationObserver, win,
433 WMViewSizeDidChangeNotification, WMWidgetView(win));
435 WMSetViewNotifySizeChanges(WMWidgetView(win
), True
);
436 WMMapSubwidgets(win
);
439 WMScreenMainLoop(scr
);