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