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