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