7d09e8f654bfd95dab250dec55f1c0e16936d32f
[sdk] / extras / html / lines.ec
1 import "HTMLView"
2 import "tables"
3
4 Block GetNextBlock(Block block)
5 {
6    // Do we have children?
7    if(block.subBlocks.first)
8       block = block.subBlocks.first;
9    else
10    {
11       for(;block;)
12       {
13          // Do we have younger siblings?
14          if(block.next)
15          {
16             block = block.next;
17             break;
18          }
19          block = block.parent;
20       }
21    }
22    return block;
23 }
24
25 /*static */Block NextBlockUp(Surface surface, Block block, int * centered, RenderFlags flags)
26 {
27    for(;block;)
28    {
29       // Do we have younger siblings?
30       if(block.next)
31       {
32          if(block.type == FONT || block.type == ANCHOR)
33          {
34             surface.TextFont(block.prevFont.font.font);
35             if(flags.render)
36                surface.SetForeground(block.prevFont.textColor);
37          }
38          block = block.next;
39          break;
40       }
41
42       block = block.parent;
43
44       // Getting out of a block
45       if(block)
46       {
47          if(block.type == FONT || block.type == ANCHOR)
48          {
49             surface.TextFont(block.prevFont.font.font);
50             if(flags.render)
51                surface.SetForeground(block.prevFont.textColor);
52          }
53          else if(block.type == CENTER)
54          {
55             if(centered)
56                (*centered)--;
57          }
58       }
59    }
60    return block;
61 }
62
63 /*static */Block NextBlock(Surface surface, Block block, int * centered, uint flags)
64 {
65    // Do we have children?
66    if(block.subBlocks.first)
67       block = block.subBlocks.first;
68    else
69    {
70       block = NextBlockUp(surface, block, centered, flags);
71    }
72    return block;
73 }
74
75 int ComputeLine(Surface surface, Block startBlock, int startTextPos, Block * nextBlock, int * nextTextPos, int * centered, int * w, 
76    int maxW, int maxH, uint flags, int y, OldList leftObjects, OldList rightObjects, bool * changeLine, bool computeStartY, int sy, int sx)
77 {
78    int h = 0;
79    int x = 0;
80    bool lineComplete = false;
81    AlignedObject object;
82
83    Block block = startBlock;
84    int textPos = startTextPos;
85    int width = 0, height = 0;
86
87    int centeredBefore = *centered;
88
89    if(changeLine)
90       *changeLine = true;
91
92    *nextBlock = block;
93    *nextTextPos = textPos;
94
95    for(;!lineComplete && block;)
96    {
97       if(computeStartY && startTextPos == 0)
98       {
99          block.startX = x + sx;
100          block.startY = y + sy;
101       }
102       switch(block.type)
103       {
104          case INPUT:
105          {
106             if(block.window)
107             {
108                width += block.window.size.w;
109                height = Max(height, block.window.size.h);
110             }
111             break;
112          }
113          case IMAGE:
114          {
115             int bw = block.pWidth ? (maxW * block.pWidth / 100) : block.w;
116             int bh = block.pHeight ? (maxH * block.pHeight / 100) : block.h;
117
118             if(block.halign == left || block.halign == right)
119             {
120                height = Max(height, bh);
121                h = Max(h, height);
122                if(changeLine)
123                   *changeLine = false;
124                if(leftObjects && rightObjects)
125                {
126                   object = AlignedObject { w = bw, untilY = y + bh };
127                   if(block.halign == left)
128                      leftObjects.Add(object);
129                   else
130                      rightObjects.Add(object);
131                }
132                lineComplete = true;
133                *nextBlock = NextBlockUp(surface, block, centered, flags);
134                *nextTextPos = 0;
135             }
136             else
137             {
138                *nextBlock = block;
139                *nextTextPos = 0;
140                h = Max(h, height);
141                x += width;
142                width = 0;
143                if(x + width + bw > maxW && x > 0)
144                {
145                   lineComplete = true;
146                }
147                else
148                {
149                   width += bw;
150                   height = Max(height, bh);
151                }
152             }
153             break;
154          }
155          case TEXT:
156          {
157             char * text = block.text;
158             int th;
159
160             // TO FIX: THIS USED TO BE COMMENTED... PUT IT BACK FOR DOCUMENTOR
161             surface.TextExtent(" ", 1, null, &th);
162             height = Max(height, th);
163
164
165             for(; textPos<block.textLen && !lineComplete;)
166             {
167                int w;
168                int len;
169                char * nextSpace = strchr(text + textPos, ' ');
170
171                if(nextSpace)
172                   len = (nextSpace - (text + textPos)) + 1;
173                else
174                   len = block.textLen - textPos;
175                
176                surface.TextExtent(text + textPos, len, &w, &th);
177
178                if(x + width + w > maxW && x > 0)
179                {
180                   lineComplete = true;
181                   break;
182                }
183
184                textPos += len;
185
186                width += w;
187                height = Max(height, th);
188
189                if(nextSpace)
190                {
191                   *nextTextPos = textPos;
192                   *nextBlock = block;
193                   h = Max(h, height);
194                   x += width;
195                   width = 0;
196                }
197             }
198             block.height += height;
199             break;
200          }
201          case FONT:
202          case ANCHOR:
203             surface.TextFont(block.font.font);
204             break;
205          case BR:
206          {
207             int th;
208             surface.TextExtent(" ", 1, null, &th);
209
210             lineComplete = true;
211             *nextBlock = NextBlock(surface, block, null, flags);
212             *nextTextPos = 0;
213             height = Max(height, th);
214             h = Max(h, height);
215             x += width;
216             width = 0;
217             break;
218          }
219          case CENTER:
220             (*centered)++;
221             break;
222          case TABLE:
223             if(width || x)
224             {
225                lineComplete = true;
226                *nextBlock = block;
227                *nextTextPos = 0;
228                h = Max(h, height);
229                x += width;
230                width = 0;
231             }
232             else if(block.halign == left || block.halign == right)
233             {
234                ComputeTable(surface, block, textPos, &width, &height, maxW, maxH, flags, y + sy, x + sx);
235                x += width;
236             
237                *nextBlock = NextBlockUp(surface, block, centered, flags);
238                *nextTextPos = 0;
239                h = Max(h, height);
240                if(changeLine)
241                   *changeLine = false;
242
243                if(leftObjects && rightObjects)
244                {
245                   object = AlignedObject { w = block.w, untilY = y + block.h };
246                   if(block.halign == left)
247                      leftObjects.Add(object);
248                   else
249                      rightObjects.Add(object);
250                }
251                lineComplete = true;
252             }
253             else
254             {
255                ComputeTable(surface, block, textPos, &width, &height, maxW, maxH, flags, y + sy, x + sx);
256                lineComplete = true;
257                *nextBlock = NextBlockUp(surface, block, centered, flags);
258                *nextTextPos = 0;
259                h = Max(h, height);
260                x += width;
261                width = 0;
262             }
263             break;
264       }
265
266       if(lineComplete || !block)
267          break;
268
269       if(textPos >= block.textLen)
270       {
271          textPos = 0;
272          block = NextBlock(surface, block, centered, flags);
273          if(block && block.type == TEXT)
274             block.height = 0;
275          // Break line after </center>
276          if(centeredBefore != *centered)
277          {
278             lineComplete = true;
279             *nextBlock = block;
280             *nextTextPos = 0;
281             h = Max(h, height);
282             x += width;
283             width = 0;
284          }
285       }
286    }
287    if(!lineComplete)
288    {
289       *nextBlock = null;
290       *nextTextPos = 0;
291       h = Max(h, height);
292       x += width;
293       width = 0;
294    }
295    *w = x;
296    if(x > 1000000)
297    {
298       printf("bug");
299    }
300    return h;
301 }
302
303 void RenderLine(HTMLView browser, Surface surface, int x, int y, int w, int h, Block startBlock, int startTextPos, Block endBlock, int endTextPos, int left, int right)
304 {
305    int textPos = startTextPos;
306    Block block = startBlock;
307    bool lineComplete = false;
308    int startSel, endSel;
309    Block startSelBlock = null, endSelBlock = null;
310    if(browser.textBlock != browser.selBlock || browser.curPosition != browser.selPosition)
311       browser.NormalizeSelection(&startSelBlock, &startSel, &endSelBlock, &endSel);
312
313    for(;;)
314    {
315       Color fore = surface.foreground, back = surface.background;
316       if(block == endBlock && textPos >= endTextPos)
317          break;
318
319       switch(block.type)
320       {
321          case INPUT:
322          {
323             if(block.window)
324             {
325                x += block.window.size.w;
326             }
327             break;
328          }
329          case BODY:
330             surface.SetForeground(block.textColor);
331             break;
332          case IMAGE:
333          {
334             int bw = block.pWidth ? (w * block.pWidth / 100) : block.w;
335             int bh = block.pHeight ? (h * block.pHeight / 100) : block.h;
336
337             int dx, dy;
338
339             ColorAlpha fg = surface.GetForeground();
340             surface.SetForeground(white);
341
342             switch(block.halign)
343             {
344                case HorizontalAlignment::left:
345                   block.valign = top;
346                   dx = x;
347                   break;
348                case HorizontalAlignment::right:
349                   block.valign = top;
350                   dx = x + w - bw;
351                   dx = Max(x, dx);
352                   break;
353                case middle:
354                   dx = x;
355                   break;
356             }
357
358             switch(block.valign)
359             {
360                case bottom: dy = y + h - bh; break;
361                case top: dy = y; break;
362                case middle: dy = y + (h - bh) / 2; break;
363             }
364
365             if(block.bitmap)
366             {
367                if(bw == block.bitmap.width && bh == block.bitmap.height)
368                   surface.Blit(block.bitmap, dx,dy,0,0,bw,bh);
369                else
370                   surface.Stretch(block.bitmap, dx,dy,0,0,bw,bh,block.bitmap.width, block.bitmap.height);
371             }
372             else if(block.imageEntry && block.imageEntry.missing)
373             {
374                surface.Bevel(false, dx, dy, bw, bh);
375                if(browser.missing.bitmap)
376                   surface.Blit(browser.missing.bitmap, dx + 5, dy + 5, 0,0, 
377                      browser.missing.bitmap.width, browser.missing.bitmap.height);
378             }
379             surface.SetForeground(fg);
380             x += bw;
381             break;
382          }
383          case TEXT:
384          {
385             int tw, th;
386             int endPos = (block == endBlock) ? endTextPos : block.textLen;
387             int len = endPos - textPos;
388
389             if(startSelBlock && block == startSelBlock && startSel >= textPos && startSel <= textPos + len)
390             {
391                int l = startSel - textPos;
392                if(block.text)
393                {
394                   surface.TextExtent(block.text + textPos, l, &tw, &th);
395                   surface.WriteText(x, y + h - th, block.text + textPos, l);
396                   x += tw;
397                }
398                textPos += l;
399                browser.isSelected = true;
400                len -= l;
401             }
402
403             if(endSelBlock && block == endSelBlock && endPos > textPos && endSel >= textPos && endSel < textPos + len)
404                len = endSel - textPos;
405
406             if(block.text)
407             {
408                if(browser.isSelected)
409                {
410                   surface.background = Color { 10, 36, 106 };
411                   surface.foreground = white;
412                   surface.textOpacity = true;
413                }
414                surface.TextExtent(block.text + textPos, len, &tw, &th);
415                surface.WriteText(x, y + h - th, block.text + textPos, len);
416                x += tw;
417                if(browser.isSelected)
418                {
419                   surface.background = back;
420                   surface.foreground = fore;
421                   surface.textOpacity = false;
422                }
423             }
424             textPos += len;
425             if(block == endSelBlock && textPos >= endSel)
426                browser.isSelected = false;
427
428             if(endPos > textPos)
429             {
430                int l = endPos - textPos;
431                if(block.text)
432                {
433                   surface.TextExtent(block.text + textPos, l, &tw, &th);
434                   surface.WriteText(x, y + h - th, block.text + textPos, l);
435                   x += tw;
436                }
437                textPos += l;
438             }
439             break;
440          }
441          case FONT:
442          case ANCHOR:
443             surface.TextFont(block.font.font);
444             surface.SetForeground(block.textColor);
445             break;
446         case TABLE:
447             RenderTable(browser, surface, x, y, w, h, left, right, block);
448             lineComplete = true;
449             block = NextBlockUp(surface, block, null, RenderFlags { render = true });
450             textPos = 0;
451             break;
452       }
453
454       if(block == endBlock && textPos >= endTextPos)
455          break;
456
457       if(textPos >= block.textLen)
458       {
459          block = NextBlock(surface, block, null, RenderFlags { render = true });
460          textPos = 0;
461       }
462    }
463 }
464
465 bool PickLine(HTMLView browser, Surface surface, int x, int y, int w, int h, Block startBlock, int startTextPos, 
466               Block endBlock, int endTextPos, int left, int right, int pickX, int pickY, Block* pickBlock, int * pickTextPos)
467 {
468    bool result = false;
469    int textPos = startTextPos;
470    Block block = startBlock;
471    bool lineComplete = false;
472
473    for(;!result;)
474    {
475       if(block == endBlock && textPos >= endTextPos)
476          break;
477
478       switch(block.type)
479       {
480          case INPUT:
481          {
482             if(block.window)
483             {
484                x += block.window.size.w;
485             }
486             break;
487          }
488          case IMAGE:
489          {
490             int bw = block.pWidth ? (w * block.pWidth / 100) : block.w;
491             int bh = block.pHeight ? (h * block.pHeight / 100) : block.h;
492             int dx, dy;
493
494             switch(block.halign)
495             {
496                case HorizontalAlignment::left:
497                   block.valign = top;
498                   dx = x;
499                   break;
500                case HorizontalAlignment::right:
501                   block.valign = top;
502                   dx = x + w - bw;
503                   dx = Max(x, dx);
504                   break;
505                case middle:
506                   dx = x;
507                   break;
508             }
509
510             switch(block.valign)
511             {
512                case bottom: dy = y + h - bh; break;
513                case top: dy = y; break;
514                case middle: dy = y + (h - bh) / 2; break;
515             }
516
517             if(block.bitmap || block.src)
518             {
519                if(pickX >= dx && pickY >= dy && pickX < dx + bw && pickY < dy + bh)
520                {
521                   *pickBlock = block;
522                   *pickTextPos = 0;
523                   result = true;
524                }
525             }
526             x += bw;
527             break;
528          }
529          case TEXT:
530          {
531             int len, tw, th;
532             if(block == endBlock)
533                len = endTextPos - textPos;
534             else
535                len = block.textLen - textPos;
536             surface.TextExtent(block.text + textPos, len, &tw, &th);
537             // eSurface_WriteText(surface, x, y + h - th, block.text + textPos, len);
538
539             if(pickX >= x && pickY >= y+h-th && pickX < x + tw && pickY < y+h)
540             {
541                result = true;
542                *pickBlock = block;
543                // Have to properly compute this
544                *pickTextPos = 0;
545             }
546             textPos += len;
547             x += tw;
548             break;
549          }
550          case FONT:
551          case ANCHOR:
552             surface.TextFont(block.font.font);
553             break;
554         case TABLE:
555             result = PickTable(browser, surface, x, y, w, h, left, right, block, pickX, pickY, pickBlock, pickTextPos);
556             lineComplete = true;
557             block = NextBlockUp(surface, block, null, RenderFlags { render = true });
558             textPos = 0;
559             break;
560       }
561
562       if(block == endBlock && textPos >= endTextPos)
563          break;
564
565       if(textPos >= block.textLen)
566       {
567          block = NextBlock(surface, block, null, RenderFlags { render = true });
568          textPos = 0;
569       }
570    }
571    return result;
572 }
573
574               
575 void PositionLine(HTMLView browser, Surface surface, int x, int y, int w, int h, Block startBlock, int startTextPos, 
576                   Block endBlock, int endTextPos, int left, int right)
577 {
578    int textPos = startTextPos;
579    Block block = startBlock;
580    bool lineComplete = false;
581
582    for(;;)
583    {
584       if(block == endBlock && textPos >= endTextPos)
585          break;
586
587       switch(block.type)
588       {
589          case INPUT:
590          {
591             if(block.window)
592             {
593                Window parent = block.window.parent;
594                block.window.Move(
595                   x + parent.scroll.x, y + parent.scroll.y, 
596                   block.window.size.w, block.window.size.h);
597                //block.window.visible = false;
598                x += block.window.size.w;
599                if(block.inputType == text)
600                {
601                   printf("");
602                }
603             }
604             break;
605          }
606          case IMAGE:
607          {
608             int bw = block.pWidth ? (w * block.pWidth / 100) : block.w;
609             int bh = block.pHeight ? (h * block.pHeight / 100) : block.h;
610             int dx, dy;
611
612             switch(block.halign)
613             {
614                case HorizontalAlignment::left:
615                   block.valign = top;
616                   dx = x;
617                   break;
618                case HorizontalAlignment::right:
619                   block.valign = top;
620                   dx = x + w - bw;
621                   dx = Max(x, dx);
622                   break;
623                case middle:
624                   dx = x;
625                   break;
626             }
627
628             switch(block.valign)
629             {
630                case bottom: dy = y + h - bh; break;
631                case top: dy = y; break;
632                case middle: dy = y + (h - bh) / 2; break;
633             }
634
635             x += bw;
636             break;
637          }
638          case TEXT:
639          {
640             int len, tw, th;
641             if(block == endBlock)
642                len = endTextPos - textPos;
643             else
644                len = block.textLen - textPos;
645             surface.TextExtent(block.text + textPos, len, &tw, &th);
646             // eSurface_WriteText(surface, x, y + h - th, block.text + textPos, len);
647
648             textPos += len;
649             x += tw;
650             break;
651          }
652          case FONT:
653          case ANCHOR:
654             surface.TextFont(block.font.font);
655             break;
656         case TABLE:
657             PositionTable(browser, surface, x, y, w, h, left, right, block);
658             lineComplete = true;
659             block = NextBlockUp(surface, block, null, RenderFlags { render = true });
660             textPos = 0;
661             break;
662       }
663
664       if(block == endBlock && textPos >= endTextPos)
665          break;
666
667       if(textPos >= block.textLen)
668       {
669          block = NextBlock(surface, block, null, RenderFlags { render = true });
670          textPos = 0;
671       }
672    }
673 }