ide/Project: (#241) Seeing GCC warnings when building from IDE
[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    int startSel, endSel;
320    Block startSelBlock = null, endSelBlock = null;
321    if(browser.textBlock != browser.selBlock || browser.curPosition != browser.selPosition)
322       browser.NormalizeSelection(&startSelBlock, &startSel, &endSelBlock, &endSel);
323
324    for(;;)
325    {
326       Color fore = surface.foreground, back = surface.background;
327       if(block == endBlock && textPos >= endTextPos)
328          break;
329
330       switch(block.type)
331       {
332          case INPUT:
333          {
334             if(block.window)
335             {
336                x += block.window.size.w;
337             }
338             break;
339          }
340          case BODY:
341             surface.SetForeground(block.textColor);
342             break;
343          case IMAGE:
344          {
345             int bw = block.pWidth ? (w * block.pWidth / 100) : block.w;
346             int bh = block.pHeight ? (h * block.pHeight / 100) : block.h;
347
348             int dx, dy;
349
350             ColorAlpha fg = surface.GetForeground();
351             surface.SetForeground(white);
352
353             switch(block.halign)
354             {
355                case HorizontalAlignment::left:
356                   block.valign = top;
357                   dx = x;
358                   break;
359                case HorizontalAlignment::right:
360                   block.valign = top;
361                   dx = x + w - bw;
362                   dx = Max(x, dx);
363                   break;
364                case middle:
365                   dx = x;
366                   break;
367             }
368
369             switch(block.valign)
370             {
371                case bottom: dy = y + h - bh; break;
372                case top: dy = y; break;
373                case middle: dy = y + (h - bh) / 2; break;
374             }
375
376             if(block.bitmap)
377             {
378                if(bw == block.bitmap.width && bh == block.bitmap.height)
379                   surface.Blit(block.bitmap, dx,dy,0,0,bw,bh);
380                else
381                   surface.Stretch(block.bitmap, dx,dy,0,0,bw,bh,block.bitmap.width, block.bitmap.height);
382             }
383             else if(block.imageEntry && block.imageEntry.missing)
384             {
385                surface.Bevel(false, dx, dy, bw, bh);
386                if(browser.missing.bitmap)
387                   surface.Blit(browser.missing.bitmap, dx + 5, dy + 5, 0,0,
388                      browser.missing.bitmap.width, browser.missing.bitmap.height);
389             }
390             surface.SetForeground(fg);
391             x += bw;
392             break;
393          }
394          case TEXT:
395          {
396             int tw, th;
397             int endPos = (block == endBlock) ? endTextPos : block.textLen;
398             int len = endPos - textPos;
399
400             if(startSelBlock && block == startSelBlock && startSel >= textPos && startSel <= textPos + len)
401             {
402                int l = startSel - textPos;
403                if(block.text)
404                {
405                   surface.TextExtent(block.text + textPos, l, &tw, &th);
406                   surface.WriteText(x, y + h - th, block.text + textPos, l);
407                   x += tw;
408                }
409                textPos += l;
410                browser.isSelected = true;
411                len -= l;
412             }
413
414             if(endSelBlock && block == endSelBlock && endPos > textPos && endSel >= textPos && endSel < textPos + len)
415                len = endSel - textPos;
416
417             if(block.text)
418             {
419                if(browser.isSelected)
420                {
421                   surface.background = Color { 10, 36, 106 };
422                   surface.foreground = white;
423                   surface.textOpacity = true;
424                }
425                surface.TextExtent(block.text + textPos, len, &tw, &th);
426                surface.WriteText(x, y + h - th, block.text + textPos, len);
427                x += tw;
428                if(browser.isSelected)
429                {
430                   surface.background = back;
431                   surface.foreground = fore;
432                   surface.textOpacity = false;
433                }
434             }
435             textPos += len;
436             if(block == endSelBlock && textPos >= endSel)
437                browser.isSelected = false;
438
439             if(endPos > textPos)
440             {
441                int l = endPos - textPos;
442                if(block.text)
443                {
444                   surface.TextExtent(block.text + textPos, l, &tw, &th);
445                   surface.WriteText(x, y + h - th, block.text + textPos, l);
446                   x += tw;
447                }
448                textPos += l;
449             }
450             break;
451          }
452          case FONT:
453          case ANCHOR:
454             surface.TextFont(block.font.font);
455             surface.SetForeground(block.textColor);
456             break;
457         case TABLE:
458             RenderTable(browser, surface, x, y, w, h, left, right, block);
459             block = NextBlockUp(surface, block, null, RenderFlags { render = true });
460             textPos = 0;
461             break;
462       }
463
464       if(block == endBlock && textPos >= endTextPos)
465          break;
466
467       if(textPos >= block.textLen)
468       {
469          block = NextBlock(surface, block, null, RenderFlags { render = true });
470          textPos = 0;
471       }
472    }
473 }
474
475 bool PickLine(HTMLView browser, Surface surface, int x, int y, int w, int h, Block startBlock, int startTextPos,
476               Block endBlock, int endTextPos, int left, int right, int pickX, int pickY, Block* pickBlock, int * pickTextPos)
477 {
478    bool result = false;
479    int textPos = startTextPos;
480    Block block = startBlock;
481
482    for(;!result;)
483    {
484       if(block == endBlock && textPos >= endTextPos)
485          break;
486
487       switch(block.type)
488       {
489          case INPUT:
490          {
491             if(block.window)
492             {
493                x += block.window.size.w;
494             }
495             break;
496          }
497          case IMAGE:
498          {
499             int bw = block.pWidth ? (w * block.pWidth / 100) : block.w;
500             int bh = block.pHeight ? (h * block.pHeight / 100) : block.h;
501             int dx, dy;
502
503             switch(block.halign)
504             {
505                case HorizontalAlignment::left:
506                   block.valign = top;
507                   dx = x;
508                   break;
509                case HorizontalAlignment::right:
510                   block.valign = top;
511                   dx = x + w - bw;
512                   dx = Max(x, dx);
513                   break;
514                case middle:
515                   dx = x;
516                   break;
517             }
518
519             switch(block.valign)
520             {
521                case bottom: dy = y + h - bh; break;
522                case top: dy = y; break;
523                case middle: dy = y + (h - bh) / 2; break;
524             }
525
526             if(block.bitmap || block.src)
527             {
528                if(pickX >= dx && pickY >= dy && pickX < dx + bw && pickY < dy + bh)
529                {
530                   *pickBlock = block;
531                   *pickTextPos = 0;
532                   result = true;
533                }
534             }
535             x += bw;
536             break;
537          }
538          case TEXT:
539          {
540             int len, tw, th;
541             if(block == endBlock)
542                len = endTextPos - textPos;
543             else
544                len = block.textLen - textPos;
545             surface.TextExtent(block.text + textPos, len, &tw, &th);
546             // eSurface_WriteText(surface, x, y + h - th, block.text + textPos, len);
547
548             if(pickX >= x && pickY >= y+h-th && pickX < x + tw && pickY < y+h)
549             {
550                result = true;
551                *pickBlock = block;
552                // Have to properly compute this
553                *pickTextPos = 0;
554             }
555             textPos += len;
556             x += tw;
557             break;
558          }
559          case FONT:
560          case ANCHOR:
561             surface.TextFont(block.font.font);
562             break;
563         case TABLE:
564             result = PickTable(browser, surface, x, y, w, h, left, right, block, pickX, pickY, pickBlock, pickTextPos);
565             block = NextBlockUp(surface, block, null, RenderFlags { render = true });
566             textPos = 0;
567             break;
568       }
569
570       if(block == endBlock && textPos >= endTextPos)
571          break;
572
573       if(textPos >= block.textLen)
574       {
575          block = NextBlock(surface, block, null, RenderFlags { render = true });
576          textPos = 0;
577       }
578    }
579    return result;
580 }
581
582
583 void PositionLine(HTMLView browser, Surface surface, int x, int y, int w, int h, Block startBlock, int startTextPos,
584                   Block endBlock, int endTextPos, int left, int right)
585 {
586    int textPos = startTextPos;
587    Block block = startBlock;
588
589    for(;;)
590    {
591       if(block == endBlock && textPos >= endTextPos)
592          break;
593
594       switch(block.type)
595       {
596          case INPUT:
597          {
598             if(block.window)
599             {
600                Window parent = block.window.parent;
601                block.window.Move(
602                   x + parent.scroll.x, y + parent.scroll.y,
603                   block.window.size.w, block.window.size.h);
604                //block.window.visible = false;
605                x += block.window.size.w;
606             }
607             break;
608          }
609          case IMAGE:
610          {
611             int bw = block.pWidth ? (w * block.pWidth / 100) : block.w;
612             //int bh = block.pHeight ? (h * block.pHeight / 100) : block.h;
613             int dx;//, dy;
614
615             switch(block.halign)
616             {
617                case HorizontalAlignment::left:
618                   block.valign = top;
619                   dx = x;
620                   break;
621                case HorizontalAlignment::right:
622                   block.valign = top;
623                   dx = x + w - bw;
624                   dx = Max(x, dx);
625                   break;
626                case middle:
627                   dx = x;
628                   break;
629             }
630
631             /*
632             switch(block.valign)
633             {
634                case bottom: dy = y + h - bh; break;
635                case top: dy = y; break;
636                case middle: dy = y + (h - bh) / 2; break;
637             }
638             */
639
640             x += bw;
641             break;
642          }
643          case TEXT:
644          {
645             int len, tw, th;
646             if(block == endBlock)
647                len = endTextPos - textPos;
648             else
649                len = block.textLen - textPos;
650             surface.TextExtent(block.text + textPos, len, &tw, &th);
651             // eSurface_WriteText(surface, x, y + h - th, block.text + textPos, len);
652
653             textPos += len;
654             x += tw;
655             break;
656          }
657          case FONT:
658          case ANCHOR:
659             surface.TextFont(block.font.font);
660             break;
661         case TABLE:
662             PositionTable(browser, surface, x, y, w, h, left, right, block);
663             block = NextBlockUp(surface, block, null, RenderFlags { render = true });
664             textPos = 0;
665             break;
666       }
667
668       if(block == endBlock && textPos >= endTextPos)
669          break;
670
671       if(textPos >= block.textLen)
672       {
673          block = NextBlock(surface, block, null, RenderFlags { render = true });
674          textPos = 0;
675       }
676    }
677 }