SHOW:
|
|
- or go back to the newest paste.
1 | class UWindowHTMLTextArea expands UWindowDynamicTextArea; | |
2 | ||
3 | /* | |
4 | ||
5 | HTML Currently Supported | |
6 | ======================== | |
7 | ||
8 | Parsed on add | |
9 | ------------- | |
10 | <body bgcolor=#ffffff link=red alink=#yellow>...</body> | |
11 | <font color=#ffffff bgcolor=#ffffff>...</font> | |
12 | <br> | |
13 | <center>....</center> | |
14 | <p> | |
15 | <h1>...</h1> | |
16 | ||
17 | Parsed on add and display | |
18 | ------------------------- | |
19 | <nobr>...</nobr> | |
20 | <a href="...">...</a> | |
21 | <b>...</b> | |
22 | <u>...</u> | |
23 | <blink>...</blink> | |
24 | ||
25 | Parsed only on display | |
26 | ---------------------- | |
27 | > | |
28 | < | |
29 | & | |
30 | | |
31 | ||
32 | Planned improvements | |
33 | -------------------- | |
34 | <ul><li>item 1<li>item 2...</ul> | |
35 | <table>...</table> | |
36 | ||
37 | Bugs | |
38 | ---- | |
39 | The parsing is pretty slack! | |
40 | ||
41 | */ | |
42 | ||
43 | // default styles | |
44 | var Color TextColor; | |
45 | var Color BGColor; | |
46 | var Color LinkColor; | |
47 | var Color ALinkColor; | |
48 | var float LastBlinkTime; | |
49 | var bool bShowBlink; | |
50 | var bool bReleased; | |
51 | ||
52 | function SetHTML(string HTML) | |
53 | { | |
54 | Clear(); | |
55 | ReplaceText(HTML, Chr(13)$Chr(10), " "); | |
56 | ReplaceText(HTML, Chr(13), " "); | |
57 | ReplaceText(HTML, Chr(10), " "); | |
58 | AddText(HTML); | |
59 | } | |
60 | ||
61 | function BeforePaint(Canvas C, float X, float Y) | |
62 | { | |
63 | Super.BeforePaint(C, X, Y); | |
64 | Cursor = Root.NormalCursor; | |
65 | } | |
66 | ||
67 | function Paint(Canvas C, float X, float Y) | |
68 | { | |
69 | C.DrawColor = BGColor; | |
70 | DrawStretchedTexture(C, 0, 0, WinWidth, WinHeight, Texture'WhiteTexture'); | |
71 | Super.Paint(C, X, Y); | |
72 | bReleased = False; | |
73 | } | |
74 | ||
75 | function Click(float X, float Y) | |
76 | { | |
77 | Super.Click(X, Y); | |
78 | bReleased = True; | |
79 | } | |
80 | ||
81 | function ProcessURL(string URL) | |
82 | { | |
83 | Log("Clicked Link: >>"$URL$"<<"); | |
84 | ||
85 | if ( Left(URL, 7) ~= "mailto:" ) | |
86 | GetPlayerOwner().ConsoleCommand("start "$URL); | |
87 | if ( Left(URL, 7) ~= "http://" ) | |
88 | GetPlayerOwner().ConsoleCommand("start "$URL); | |
89 | if ( Left(URL, 8) ~= "https://" ) | |
90 | GetPlayerOwner().ConsoleCommand("start "$URL); | |
91 | if ( Left(URL, 6) ~= "ftp://" ) | |
92 | GetPlayerOwner().ConsoleCommand("start "$URL); | |
93 | if ( Left(URL, 9) ~= "telnet://" ) | |
94 | GetPlayerOwner().ConsoleCommand("start "$URL); | |
95 | if ( Left(URL, 9) ~= "gopher://" ) | |
96 | GetPlayerOwner().ConsoleCommand("start "$URL); | |
97 | if ( Left(URL, 4) ~= "www." ) | |
98 | GetPlayerOwner().ConsoleCommand("start http://"$URL); | |
99 | if ( Left(URL, 4) ~= "ftp." ) | |
100 | GetPlayerOwner().ConsoleCommand("start ftp://"$URL); | |
101 | else if ( Left(URL, 9) ~= "unreal://" ) | |
102 | LaunchUnrealURL(URL); | |
103 | } | |
104 | ||
105 | function OverURL(string URL) | |
106 | { | |
107 | } | |
108 | ||
109 | function LaunchUnrealURL(string URL) | |
110 | { | |
111 | GetPlayerOwner().ClientTravel(URL, TRAVEL_Absolute, false); | |
112 | } | |
113 | ||
114 | function TextAreaTextSize(Canvas C, string Text, out float W, out float H) | |
115 | { | |
116 | ReplaceText(Text, " ", " "); | |
117 | ReplaceText(Text, ">", ">"); | |
118 | ReplaceText(Text, "<", "<"); | |
119 | ReplaceText(Text, "&", "&"); | |
120 | ||
121 | TextSize(C, Text, W, H); | |
122 | } | |
123 | ||
124 | function TextAreaClipText(Canvas C, float DrawX, float DrawY, coerce string Text, optional bool bCheckHotkey, optional color Col ) | |
125 | { | |
126 | ReplaceText(Text, " ", " "); | |
127 | ReplaceText(Text, ">", ">"); | |
128 | ReplaceText(Text, "<", "<"); | |
129 | ReplaceText(Text, "&", "&"); | |
130 | ||
131 | ClipText(C, DrawX, DrawY, Text, bCheckHotKey); | |
132 | } | |
133 | ||
134 | /////////////////////////////////////////////////////// | |
135 | // Overloaded functions from UWindowDynamicTextArea | |
136 | /////////////////////////////////////////////////////// | |
137 | ||
138 | function WrapRow(Canvas C, UWindowDynamicTextRow L) | |
139 | { | |
140 | local HTMLStyle CurrentStyle; | |
141 | local UWindowHTMLTextRow R; | |
142 | local string Input, LeftText, HTML, RightText; | |
143 | ||
144 | Super.WrapRow(C, L); | |
145 | ||
146 | // Generate the DisplayString and StyleString lines for each row | |
147 | R = UWindowHTMLTextRow(L); | |
148 | while (R != None && (R == L || R.WrapParent == L)) | |
149 | { | |
150 | R.DisplayString = ""; | |
151 | R.StyleString = ""; | |
152 | ||
153 | CurrentStyle = R.StartStyle; | |
154 | ||
155 | Input = R.Text; | |
156 | while (Input != "") | |
157 | { | |
158 | ParseHTML(Input, LeftText, HTML, RightText); | |
159 | ||
160 | if (LeftText != "" || R.DisplayString == "") | |
161 | { | |
162 | R.DisplayString = R.DisplayString $ LeftText; | |
163 | R.StyleString = R.StyleString $ WriteStyleText(CurrentStyle, Len(LeftText)); | |
164 | } | |
165 | ||
166 | ProcessInlineHTML(HTML, CurrentStyle); | |
167 | SetCanvasStyle(C, CurrentStyle); | |
168 | ||
169 | Input = RightText; | |
170 | } | |
171 | ||
172 | R = UWindowHTMLTextRow(R.Next); | |
173 | } | |
174 | } | |
175 | ||
176 | function float DrawTextLine(Canvas C, UWindowDynamicTextRow L, float Y) | |
177 | { | |
178 | local float X, W, H, MouseX, MouseY; | |
179 | local HTMLStyle CurrentStyle; | |
180 | local float RowHeight; | |
181 | local Color OldColor; | |
182 | local int StylePos, DisplayPos, i; | |
183 | local string S; | |
184 | ||
185 | RowHeight = 0; | |
186 | ||
187 | CurrentStyle = UWindowHTMLTextRow(L).StartStyle; | |
188 | if (CurrentStyle.bCenter) | |
189 | { | |
190 | W = CalcHTMLTextWidth(C, L.Text, CurrentStyle); | |
191 | if (VertSB.bWindowVisible) | |
192 | X = int(((WinWidth - VertSB.WinWidth) - W) / 2); | |
193 | else | |
194 | X = int((WinWidth - W) / 2); | |
195 | } | |
196 | else | |
197 | X = 2; | |
198 | ||
199 | if (GetEntryLevel().TimeSeconds > LastBlinkTime + 0.5) | |
200 | { | |
201 | bShowBlink = !bShowBlink; | |
202 | LastBlinkTime = GetEntryLevel().TimeSeconds; | |
203 | } | |
204 | ||
205 | if (UWindowHTMLTextRow(L).DisplayString == "") | |
206 | SetCanvasStyle(C, CurrentStyle); | |
207 | else | |
208 | { | |
209 | while (DisplayPos < Len(UWindowHTMLTextRow(L).DisplayString)) | |
210 | { | |
211 | i = ReadStyleText(UWindowHTMLTextRow(L).StyleString, StylePos, CurrentStyle); | |
212 | S = Mid(UWindowHTMLTextRow(L).DisplayString, DisplayPos, i); | |
213 | DisplayPos += i; | |
214 | SetCanvasStyle(C, CurrentStyle); | |
215 | ||
216 | TextAreaTextSize(C, S, W, H); | |
217 | if (H > RowHeight) | |
218 | RowHeight = H; | |
219 | ||
220 | if (CurrentStyle.bLink) | |
221 | { | |
222 | GetMouseXY(MouseX, MouseY); | |
223 | if (X < MouseX && X + W > MouseX && Y < MouseY && Y + H > MouseY) | |
224 | { | |
225 | Cursor = Root.HandCursor; | |
226 | OverURL(CurrentStyle.LinkDestination); | |
227 | ||
228 | if (bMouseDown || bReleased) | |
229 | { | |
230 | if (bReleased) | |
231 | { | |
232 | ProcessURL(CurrentStyle.LinkDestination); | |
233 | bReleased = False; | |
234 | } | |
235 | else | |
236 | C.DrawColor = ALinkColor; | |
237 | } | |
238 | } | |
239 | } | |
240 | ||
241 | if (CurrentStyle.BGColor != BGColor) | |
242 | { | |
243 | OldColor = C.DrawColor; | |
244 | C.DrawColor = CurrentStyle.BGColor; | |
245 | DrawStretchedTexture(C, X, Y, W, H, Texture'WhiteTexture'); | |
246 | C.DrawColor = OldColor; | |
247 | } | |
248 | if (!CurrentStyle.bBlink || bShowBlink) | |
249 | TextAreaClipText(C, X, Y, S); | |
250 | if (CurrentStyle.bLink || CurrentStyle.bUnderline) | |
251 | DrawStretchedTexture(C, X, Y+H-1, W, 1, Texture'WhiteTexture'); | |
252 | ||
253 | X += W; | |
254 | } | |
255 | } | |
256 | if (RowHeight == 0) | |
257 | TextAreaTextSize(C, "A", W, RowHeight); | |
258 | ||
259 | return RowHeight; | |
260 | } | |
261 | ||
262 | function UWindowDynamicTextRow SplitRowAt(UWindowDynamicTextRow L, int SplitPos) | |
263 | { | |
264 | local UWindowDynamicTextRow N; | |
265 | local HTMLStyle CurrentStyle; | |
266 | ||
267 | N = Super.SplitRowAt(L, SplitPos); | |
268 | ||
269 | // update the style by processing from the start of L to the split position. | |
270 | UWindowHTMLTextRow(N).EndStyle = UWindowHTMLTextRow(L).EndStyle; | |
271 | CurrentStyle = UWindowHTMLTextRow(L).StartStyle; | |
272 | HTMLUpdateStyle(L.Text, CurrentStyle); | |
273 | UWindowHTMLTextRow(L).EndStyle = CurrentStyle; | |
274 | UWindowHTMLTextRow(N).StartStyle = CurrentStyle; | |
275 | ||
276 | return N; | |
277 | } | |
278 | ||
279 | function RemoveWrap(UWindowDynamicTextRow L) | |
280 | { | |
281 | local UWindowDynamicTextRow N; | |
282 | ||
283 | // copy final endstyle to current row | |
284 | N = UWindowDynamicTextRow(L.Next); | |
285 | while (N != None && N.WrapParent == L) | |
286 | { | |
287 | UWindowHTMLTextRow(L).EndStyle = UWindowHTMLTextRow(N).EndStyle; | |
288 | N = UWindowDynamicTextRow(N.Next); | |
289 | } | |
290 | ||
291 | Super.RemoveWrap(L); | |
292 | } | |
293 | ||
294 | function int GetWrapPos(Canvas C, UWindowDynamicTextRow L, float MaxWidth) | |
295 | { | |
296 | local float LineWidth, NextWordWidth; | |
297 | local string Input, NextWord; | |
298 | local int WordsThisRow, WrapPos; | |
299 | local HTMLStyle CurrentStyle; | |
300 | ||
301 | CurrentStyle = UWindowHTMLTextRow(L).StartStyle; | |
302 | ||
303 | // quick check | |
304 | if (CalcHTMLTextWidth(C, L.Text, CurrentStyle) <= MaxWidth) | |
305 | return -1; | |
306 | ||
307 | Input = L.Text; | |
308 | WordsThisRow = 0; | |
309 | LineWidth = 0; | |
310 | WrapPos = 0; | |
311 | NextWord = ""; | |
312 | CurrentStyle = UWindowHTMLTextRow(L).StartStyle; | |
313 | ||
314 | while (Input != "" || NextWord != "") | |
315 | { | |
316 | if (NextWord == "") | |
317 | { | |
318 | RemoveNextWord(Input, NextWord); | |
319 | NextWordWidth = CalcHTMLTextWidth(C, NextWord, CurrentStyle); | |
320 | } | |
321 | if (WordsThisRow > 0 && LineWidth + NextWordWidth > MaxWidth) | |
322 | { | |
323 | return WrapPos; | |
324 | } | |
325 | else | |
326 | { | |
327 | WrapPos += Len(NextWord); | |
328 | LineWidth += NextWordWidth; | |
329 | NextWord = ""; | |
330 | WordsThisRow++; | |
331 | } | |
332 | } | |
333 | return -1; | |
334 | } | |
335 | ||
336 | // Find the next word - but don't split up HTML tags. | |
337 | function RemoveNextWord(out string Text, out string NextWord) | |
338 | { | |
339 | local int i; | |
340 | local bool bInsideTag; | |
341 | local string Ch; | |
342 | ||
343 | bInsideTag = False; | |
344 | ||
345 | for (i=0; i<Len(Text); i++) | |
346 | { | |
347 | Ch = Mid(Text, i, 1); | |
348 | if (Ch == ">") | |
349 | bInsideTag = False; | |
350 | if (Ch == "<") | |
351 | bInsideTag = True; | |
352 | if (Ch == " " && !bInsideTag) | |
353 | break; | |
354 | } | |
355 | while (Mid(Text, i, 1) == " ") | |
356 | i++; | |
357 | NextWord = Left(Text, i); | |
358 | Text = Mid(Text, i); | |
359 | } | |
360 | ||
361 | function UWindowDynamicTextRow AddText(string NewLine, optional color TxtCol ) | |
362 | { | |
363 | local string Input, Output, LeftText, RightText, HTML, Temp; | |
364 | local int i; | |
365 | local UWindowDynamicTextRow L; | |
366 | local HTMLStyle CurrentStyle, StartStyle; | |
367 | ||
368 | if (List.Last == List) | |
369 | { | |
370 | CurrentStyle.BulletLevel = 0; | |
371 | CurrentStyle.LinkDestination = ""; | |
372 | CurrentStyle.TextColor = TextColor; | |
373 | CurrentStyle.BGColor = BGColor; | |
374 | CurrentStyle.bCenter = bHCenter; | |
375 | CurrentStyle.bLink = False; | |
376 | CurrentStyle.bUnderline = False; | |
377 | CurrentStyle.bNoBR = False; | |
378 | CurrentStyle.bHeading = False; | |
379 | CurrentStyle.bBold = False; | |
380 | CurrentStyle.bBlink = False; | |
381 | } | |
382 | else | |
383 | CurrentStyle = UWindowHTMLTextRow(List.Last).EndStyle; | |
384 | StartStyle = CurrentStyle; | |
385 | ||
386 | // convert \\n's -> <br>'s | |
387 | i = InStr(NewLine, "\\n"); | |
388 | while (i != -1) | |
389 | { | |
390 | NewLine = Left(NewLine, i) $ "<br>" $ Mid(NewLine, i + 2); | |
391 | i = InStr(NewLine, "\\n"); | |
392 | } | |
393 | ||
394 | Input = NewLine; | |
395 | Output = ""; | |
396 | while (Input != "") | |
397 | { | |
398 | ParseHTML(Input, LeftText, HTML, RightText); | |
399 | ||
400 | switch (GetTag(HTML)) | |
401 | { | |
402 | // multiline HTML tags | |
403 | case "P": | |
404 | if ((Output $ LeftText) != "") | |
405 | { | |
406 | L = Super.AddText(Output $ LeftText); | |
407 | Output = ""; | |
408 | UWindowHTMLTextRow(L).StartStyle = StartStyle; | |
409 | UWindowHTMLTextRow(L).EndStyle = CurrentStyle; | |
410 | } | |
411 | StartStyle = CurrentStyle; | |
412 | L = Super.AddText(""); | |
413 | UWindowHTMLTextRow(L).StartStyle = StartStyle; | |
414 | UWindowHTMLTextRow(L).EndStyle = CurrentStyle; | |
415 | break; | |
416 | case "BR": | |
417 | L = Super.AddText(Output $ LeftText); | |
418 | Output = ""; | |
419 | UWindowHTMLTextRow(L).StartStyle = StartStyle; | |
420 | UWindowHTMLTextRow(L).EndStyle = CurrentStyle; | |
421 | StartStyle = CurrentStyle; | |
422 | break; | |
423 | case "BODY": | |
424 | Temp = GetOption(HTML, "BGCOLOR="); | |
425 | if (Temp != "") | |
426 | { | |
427 | BGColor = ParseColor(Temp); | |
428 | CurrentStyle.BGColor = BGColor; | |
429 | StartStyle.BGColor = BGColor; | |
430 | } | |
431 | ||
432 | Temp = GetOption(HTML, "LINK="); | |
433 | if (Temp != "") | |
434 | LinkColor = ParseColor(Temp); | |
435 | ||
436 | Temp = GetOption(HTML, "ALINK="); | |
437 | if (Temp != "") | |
438 | ALinkColor = ParseColor(Temp); | |
439 | ||
440 | Temp = GetOption(HTML, "TEXT="); | |
441 | if (Temp != "") | |
442 | { | |
443 | TextColor = ParseColor(Temp); | |
444 | CurrentStyle.TextColor = TextColor; | |
445 | } | |
446 | Output = Output $ LeftText; | |
447 | break; | |
448 | case "CENTER": | |
449 | if ((Output $ LeftText) != "") | |
450 | { | |
451 | L = Super.AddText(Output $ LeftText); | |
452 | Output = ""; | |
453 | UWindowHTMLTextRow(L).StartStyle = StartStyle; | |
454 | UWindowHTMLTextRow(L).EndStyle = CurrentStyle; | |
455 | } | |
456 | CurrentStyle.bCenter = True; | |
457 | StartStyle = CurrentStyle; | |
458 | break; | |
459 | case "/CENTER": | |
460 | L = Super.AddText(Output $ LeftText); | |
461 | Output = ""; | |
462 | UWindowHTMLTextRow(L).StartStyle = StartStyle; | |
463 | UWindowHTMLTextRow(L).EndStyle = CurrentStyle; | |
464 | CurrentStyle.bCenter = False; | |
465 | StartStyle = CurrentStyle; | |
466 | break; | |
467 | // Inline HTML tags | |
468 | case "H1": | |
469 | if ((Output $ LeftText) != "") | |
470 | { | |
471 | L = Super.AddText(Output $ LeftText); | |
472 | Output = ""; | |
473 | UWindowHTMLTextRow(L).StartStyle = StartStyle; | |
474 | UWindowHTMLTextRow(L).EndStyle = CurrentStyle; | |
475 | } | |
476 | CurrentStyle.bHeading = True; | |
477 | StartStyle = CurrentStyle; | |
478 | break; | |
479 | case "/H1": | |
480 | L = Super.AddText(Output $ LeftText); | |
481 | Output = ""; | |
482 | UWindowHTMLTextRow(L).StartStyle = StartStyle; | |
483 | UWindowHTMLTextRow(L).EndStyle = CurrentStyle; | |
484 | CurrentStyle.bHeading = False; | |
485 | StartStyle = CurrentStyle; | |
486 | break; | |
487 | case "FONT": | |
488 | Output = Output $ LeftText $ HTML; | |
489 | Temp = GetOption(HTML, "COLOR="); | |
490 | if (Temp != "") | |
491 | CurrentStyle.TextColor = ParseColor(Temp); | |
492 | Temp = GetOption(HTML, "BGCOLOR="); | |
493 | if (Temp != "") | |
494 | CurrentStyle.BGColor = ParseColor(Temp); | |
495 | break; | |
496 | case "/FONT": | |
497 | Output = Output $ LeftText $ HTML; | |
498 | CurrentStyle.TextColor = TextColor; | |
499 | CurrentStyle.BGColor = BGColor; | |
500 | break; | |
501 | case "B": | |
502 | Output = Output $ LeftText $ HTML; | |
503 | CurrentStyle.bBold = True; | |
504 | break; | |
505 | case "/B": | |
506 | Output = Output $ LeftText $ HTML; | |
507 | CurrentStyle.bBold = False; | |
508 | break; | |
509 | case "U": | |
510 | Output = Output $ LeftText $ HTML; | |
511 | CurrentStyle.bUnderline = True; | |
512 | break; | |
513 | case "/U": | |
514 | Output = Output $ LeftText $ HTML; | |
515 | CurrentStyle.bUnderline = False; | |
516 | break; | |
517 | case "A": | |
518 | Output = Output $ LeftText $ HTML; | |
519 | CurrentStyle.bLink = True; | |
520 | CurrentStyle.LinkDestination = GetOption(HTML, "HREF="); | |
521 | break; | |
522 | case "/A": | |
523 | Output = Output $ LeftText $ HTML; | |
524 | CurrentStyle.bLink = False; | |
525 | CurrentStyle.LinkDestination = ""; | |
526 | break; | |
527 | case "NOBR": | |
528 | Output = Output $ LeftText $ HTML; | |
529 | CurrentStyle.bNoBR = True; | |
530 | break; | |
531 | case "/NOBR": | |
532 | Output = Output $ LeftText $ HTML; | |
533 | CurrentStyle.bNoBR = False; | |
534 | break; | |
535 | case "BLINK": | |
536 | Output = Output $ LeftText $ HTML; | |
537 | CurrentStyle.bBlink = True; | |
538 | break; | |
539 | case "/BLINK": | |
540 | Output = Output $ LeftText $ HTML; | |
541 | CurrentStyle.bBlink = False; | |
542 | break; | |
543 | default: | |
544 | Output = Output $ LeftText; | |
545 | break; | |
546 | } | |
547 | Input = RightText; | |
548 | } | |
549 | ||
550 | L = Super.AddText(Output); | |
551 | UWindowHTMLTextRow(L).StartStyle = StartStyle; | |
552 | UWindowHTMLTextRow(L).EndStyle = CurrentStyle; | |
553 | ||
554 | return L; | |
555 | } | |
556 | ||
557 | /////////////////////////////////////////////////// | |
558 | // HTML Text Processing | |
559 | /////////////////////////////////////////////////// | |
560 | ||
561 | // Get the next HTML tag, the text before it and everthing after it. | |
562 | function ParseHTML(string Input, out string LeftText, out string HTML, out string RightText) | |
563 | { | |
564 | local int i; | |
565 | ||
566 | i = InStr(Input, "<"); | |
567 | if (i == -1) | |
568 | { | |
569 | LeftText = Input; | |
570 | HTML = ""; | |
571 | RightText = ""; | |
572 | return; | |
573 | } | |
574 | ||
575 | LeftText = Left(Input, i); | |
576 | HTML = Mid(Input, i); | |
577 | ||
578 | i = InStr(HTML, ">"); | |
579 | if (i == -1) | |
580 | { | |
581 | RightText = ""; | |
582 | return; | |
583 | } | |
584 | ||
585 | RightText = Mid(HTML, i+1); | |
586 | HTML = Left(HTML, i+1); | |
587 | } | |
588 | ||
589 | function float CalcHTMLTextWidth(Canvas C, string Text, out HTMLStyle CurrentStyle) | |
590 | { | |
591 | local string Input, LeftText, HTML, RightText; | |
592 | local float W, H, Width; | |
593 | ||
594 | Width = 0; | |
595 | Input = Text; | |
596 | while (Input != "") | |
597 | { | |
598 | ParseHTML(Input, LeftText, HTML, RightText); | |
599 | ||
600 | SetCanvasStyle(C, CurrentStyle); | |
601 | TextAreaTextSize(C, LeftText, W, H); | |
602 | Width += W; | |
603 | ||
604 | ProcessInlineHTML(HTML, CurrentStyle); | |
605 | ||
606 | Input = RightText; | |
607 | } | |
608 | ||
609 | return Width; | |
610 | } | |
611 | ||
612 | // Update CurrentStyle based on the contents of the HTML tag provided | |
613 | function ProcessInlineHTML(string HTML, out HTMLStyle CurrentStyle) | |
614 | { | |
615 | local string Temp; | |
616 | ||
617 | if (HTML == "") | |
618 | return; | |
619 | ||
620 | switch (GetTag(HTML)) | |
621 | { | |
622 | case "H1": | |
623 | CurrentStyle.bHeading = True; | |
624 | break; | |
625 | case "/H1": | |
626 | CurrentStyle.bHeading = False; | |
627 | break; | |
628 | case "FONT": | |
629 | Temp = GetOption(HTML, "COLOR="); | |
630 | if (Temp != "") | |
631 | CurrentStyle.TextColor = ParseColor(Temp); | |
632 | Temp = GetOption(HTML, "BGCOLOR="); | |
633 | if (Temp != "") | |
634 | CurrentStyle.BGColor = ParseColor(Temp); | |
635 | break; | |
636 | case "/FONT": | |
637 | CurrentStyle.TextColor = TextColor; | |
638 | CurrentStyle.BGColor = BGColor; | |
639 | break; | |
640 | case "B": | |
641 | CurrentStyle.bBold = True; | |
642 | break; | |
643 | case "/B": | |
644 | CurrentStyle.bBold = False; | |
645 | break; | |
646 | case "U": | |
647 | CurrentStyle.bUnderline = True; | |
648 | break; | |
649 | case "/U": | |
650 | CurrentStyle.bUnderline = False; | |
651 | break; | |
652 | case "A": | |
653 | CurrentStyle.bLink = True; | |
654 | CurrentStyle.LinkDestination = GetOption(HTML, "HREF="); | |
655 | break; | |
656 | case "/A": | |
657 | CurrentStyle.bLink = False; | |
658 | CurrentStyle.LinkDestination = ""; | |
659 | break; | |
660 | case "NOBR": | |
661 | CurrentStyle.bNoBR = True; | |
662 | break; | |
663 | case "/NOBR": | |
664 | CurrentStyle.bNoBR = False; | |
665 | break; | |
666 | case "BLINK": | |
667 | CurrentStyle.bBlink = True; | |
668 | break; | |
669 | case "/BLINK": | |
670 | CurrentStyle.bBlink = False; | |
671 | break; | |
672 | } | |
673 | } | |
674 | ||
675 | // update the current style based on some text input | |
676 | function HTMLUpdateStyle(string Input, out HTMLStyle CurrentStyle) | |
677 | { | |
678 | local string LeftText, HTML, RightText; | |
679 | ||
680 | while (Input != "") | |
681 | { | |
682 | ParseHTML(Input, LeftText, HTML, RightText); | |
683 | ProcessInlineHTML(HTML, CurrentStyle); | |
684 | Input = RightText; | |
685 | } | |
686 | } | |
687 | ||
688 | final function string GetOption(string HTML, string Option) | |
689 | { | |
690 | local int i, j; | |
691 | local string s; | |
692 | ||
693 | i = InStr(Caps(HTML), Caps(Option)); | |
694 | ||
695 | if (i == 1 || Mid(HTML, i-1, 1) == " ") | |
696 | { | |
697 | s = Mid(HTML, i+Len(Option)); | |
698 | j = FirstMatching(InStr(s, ">"), InStr(s, " ")); | |
699 | s = Left(s, j); | |
700 | ||
701 | if (Left(s, 1) == "\"") | |
702 | s = Mid(s, 1); | |
703 | ||
704 | if (Right(s, 1) == "\"") | |
705 | s = Left(s, Len(s) - 1); | |
706 | ||
707 | return s; | |
708 | } | |
709 | return ""; | |
710 | } | |
711 | ||
712 | final function string GetTag(string HTML) | |
713 | { | |
714 | local int i; | |
715 | ||
716 | if (HTML == "") | |
717 | return ""; | |
718 | ||
719 | HTML = Mid(HTML, 1); // lose < | |
720 | ||
721 | i = FirstMatching(InStr(HTML, ">"), InStr(HTML, " ")); | |
722 | if (i == -1) | |
723 | return Caps(HTML); | |
724 | else | |
725 | return Caps(Left(HTML, i)); | |
726 | } | |
727 | ||
728 | function Color ParseColor(string S) | |
729 | { | |
730 | local Color C; | |
731 | ||
732 | if (Left(S, 1) == "#") | |
733 | S = Mid(S, 1); | |
734 | ||
735 | if ( S~="red" ) | |
736 | { | |
737 | C.R = 255; | |
738 | C.G = 0; | |
739 | C.B = 0; | |
740 | } | |
741 | else if ( S~="blue" ) | |
742 | { | |
743 | C.R = 0; | |
744 | C.G = 0; | |
745 | C.B = 255; | |
746 | } | |
747 | else if ( S~="green" ) | |
748 | { | |
749 | C.R = 0; | |
750 | C.G = 255; | |
751 | C.B = 0; | |
752 | } | |
753 | else if ( S~="yellow" ) | |
754 | { | |
755 | C.R = 255; | |
756 | C.G = 255; | |
757 | C.B = 0; | |
758 | } | |
759 | else if ( S~="white" ) | |
760 | { | |
761 | C.R = 255; | |
762 | C.G = 255; | |
763 | C.B = 255; | |
764 | } | |
765 | else if ( S~="black" ) | |
766 | { | |
767 | C.R = 0; | |
768 | C.G = 0; | |
769 | C.B = 0; | |
770 | } | |
771 | else | |
772 | { | |
773 | C.R = 16 * GetHexDigit(Mid(S, 0, 1)) + GetHexDigit(Mid(S, 1, 1)); | |
774 | C.G = 16 * GetHexDigit(Mid(S, 2, 1)) + GetHexDigit(Mid(S, 3, 1)); | |
775 | C.B = 16 * GetHexDigit(Mid(S, 4, 1)) + GetHexDigit(Mid(S, 5, 1)); | |
776 | } | |
777 | ||
778 | return C; | |
779 | } | |
780 | ||
781 | final function int GetHexDigit(string D) | |
782 | { | |
783 | switch (caps(D)) | |
784 | { | |
785 | case "0": | |
786 | return 0; | |
787 | case "1": | |
788 | return 1; | |
789 | case "2": | |
790 | return 2; | |
791 | case "3": | |
792 | return 3; | |
793 | case "4": | |
794 | return 4; | |
795 | case "5": | |
796 | return 5; | |
797 | case "6": | |
798 | return 6; | |
799 | case "7": | |
800 | return 7; | |
801 | case "8": | |
802 | return 8; | |
803 | case "9": | |
804 | return 9; | |
805 | case "A": | |
806 | return 10; | |
807 | case "B": | |
808 | return 11; | |
809 | case "C": | |
810 | return 12; | |
811 | case "D": | |
812 | return 13; | |
813 | case "E": | |
814 | return 14; | |
815 | case "F": | |
816 | return 15; | |
817 | } | |
818 | ||
819 | return 0; | |
820 | } | |
821 | ||
822 | function int FirstMatching(int i, int j) | |
823 | { | |
824 | if (i == -1) | |
825 | return j; | |
826 | ||
827 | if (j == -1) | |
828 | return i; | |
829 | else | |
830 | return Min(i, j); | |
831 | } | |
832 | ||
833 | function SetCanvasStyle(Canvas C, HTMLStyle CurrentStyle) | |
834 | { | |
835 | if (CurrentStyle.bLink) | |
836 | C.DrawColor = LinkColor; | |
837 | else | |
838 | C.DrawColor = CurrentStyle.TextColor; | |
839 | ||
840 | if (CurrentStyle.bHeading) | |
841 | C.Font = Root.Fonts[F_LargeBold]; | |
842 | else if (CurrentStyle.bBold) | |
843 | C.Font = Root.Fonts[F_Bold]; | |
844 | else | |
845 | C.Font = Root.Fonts[F_Normal]; | |
846 | } | |
847 | ||
848 | function string WriteStyleText(HTMLStyle CurrentStyle, int CharCount) | |
849 | { | |
850 | local string Pad; | |
851 | local string Temp; | |
852 | local string Output; | |
853 | ||
854 | Pad = "0000"; | |
855 | ||
856 | Temp = string(CharCount); | |
857 | Output = Left(Pad, 4 - Len(Temp)) $ Temp; | |
858 | ||
859 | Temp = string(Len(CurrentStyle.LinkDestination)); | |
860 | Output = Output $ Left(Pad, 4 - Len(Temp)) $ Temp $ CurrentStyle.LinkDestination; | |
861 | ||
862 | Temp = string(CurrentStyle.TextColor.R); | |
863 | Output = Output $ Left(Pad, 3 - Len(Temp)) $ Temp; | |
864 | Temp = string(CurrentStyle.TextColor.G); | |
865 | Output = Output $ Left(Pad, 3 - Len(Temp)) $ Temp; | |
866 | Temp = string(CurrentStyle.TextColor.B); | |
867 | Output = Output $ Left(Pad, 3 - Len(Temp)) $ Temp; | |
868 | ||
869 | Temp = string(CurrentStyle.BGColor.R); | |
870 | Output = Output $ Left(Pad, 3 - Len(Temp)) $ Temp; | |
871 | Temp = string(CurrentStyle.BGColor.G); | |
872 | Output = Output $ Left(Pad, 3 - Len(Temp)) $ Temp; | |
873 | Temp = string(CurrentStyle.BGColor.B); | |
874 | Output = Output $ Left(Pad, 3 - Len(Temp)) $ Temp; | |
875 | ||
876 | if (CurrentStyle.bCenter) | |
877 | Output = Output $ "T"; | |
878 | else | |
879 | Output = Output $ "F"; | |
880 | ||
881 | if (CurrentStyle.bLink) | |
882 | Output = Output $ "T"; | |
883 | else | |
884 | Output = Output $ "F"; | |
885 | ||
886 | if (CurrentStyle.bUnderline) | |
887 | Output = Output $ "T"; | |
888 | else | |
889 | Output = Output $ "F"; | |
890 | ||
891 | if (CurrentStyle.bNoBR) | |
892 | Output = Output $ "T"; | |
893 | else | |
894 | Output = Output $ "F"; | |
895 | ||
896 | if (CurrentStyle.bHeading) | |
897 | Output = Output $ "T"; | |
898 | else | |
899 | Output = Output $ "F"; | |
900 | ||
901 | if (CurrentStyle.bBold) | |
902 | Output = Output $ "T"; | |
903 | else | |
904 | Output = Output $ "F"; | |
905 | ||
906 | if (CurrentStyle.bBlink) | |
907 | Output = Output $ "T"; | |
908 | else | |
909 | Output = Output $ "F"; | |
910 | ||
911 | return Output; | |
912 | } | |
913 | ||
914 | function int ReadStyleText(string StyleString, out int StylePos, out HTMLStyle CurrentStyle) | |
915 | { | |
916 | local int CharCount; | |
917 | local int i; | |
918 | ||
919 | CharCount = Int(Mid(StyleString, StylePos, 4)); | |
920 | StylePos += 4; | |
921 | ||
922 | i = Int(Mid(StyleString, StylePos, 4)); | |
923 | StylePos += 4; | |
924 | ||
925 | CurrentStyle.LinkDestination = Mid(StyleString, StylePos, i); | |
926 | StylePos += i; | |
927 | ||
928 | CurrentStyle.TextColor.R = Int(Mid(StyleString, StylePos, 3)); | |
929 | StylePos += 3; | |
930 | CurrentStyle.TextColor.G = Int(Mid(StyleString, StylePos, 3)); | |
931 | StylePos += 3; | |
932 | CurrentStyle.TextColor.B = Int(Mid(StyleString, StylePos, 3)); | |
933 | StylePos += 3; | |
934 | ||
935 | CurrentStyle.BGColor.R = Int(Mid(StyleString, StylePos, 3)); | |
936 | StylePos += 3; | |
937 | CurrentStyle.BGColor.G = Int(Mid(StyleString, StylePos, 3)); | |
938 | StylePos += 3; | |
939 | CurrentStyle.BGColor.B = Int(Mid(StyleString, StylePos, 3)); | |
940 | StylePos += 3; | |
941 | ||
942 | CurrentStyle.bCenter = Mid(StyleString, StylePos++, 1) == "T"; | |
943 | CurrentStyle.bLink = Mid(StyleString, StylePos++, 1) == "T"; | |
944 | CurrentStyle.bUnderline = Mid(StyleString, StylePos++, 1) == "T"; | |
945 | CurrentStyle.bNoBR = Mid(StyleString, StylePos++, 1) == "T"; | |
946 | CurrentStyle.bHeading = Mid(StyleString, StylePos++, 1) == "T"; | |
947 | CurrentStyle.bBold = Mid(StyleString, StylePos++, 1) == "T"; | |
948 | CurrentStyle.bBlink = Mid(StyleString, StylePos++, 1) == "T"; | |
949 | ||
950 | return CharCount; | |
951 | } | |
952 | ||
953 | defaultproperties | |
954 | { | |
955 | TextColor=(R=255,G=255,B=255) | |
956 | LinkColor=(B=255) | |
957 | ALinkColor=(R=255) | |
958 | bTopCentric=True | |
959 | bAutoScrollbar=True | |
960 | bVariableRowHeight=True | |
961 | RowClass=Class'UWindow.UWindowHTMLTextRow' | |
962 | bIgnoreLDoubleClick=True | |
963 | } |