]> git.vomp.tv Git - vompclient.git/blob - boxx.cc
Fix text corruption on channel list when returning from live TV
[vompclient.git] / boxx.cc
1 /*
2     Copyright 2007 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include <stdlib.h>
22
23 #include "defines.h"
24 #include "bitmap.h"
25 #include "log.h"
26 #include "osd.h"
27
28 #include "boxx.h"
29 #include "surfacevector.h"
30 char Boxx::numBoxxes = 0;
31
32 Boxx::Boxx()
33 {
34   // I want a parent box or a surface.
35   parent = NULL;
36   surface = NULL;
37
38   area.x = 0;
39   area.y = 0;
40   area.w = 0;
41   area.h = 0;
42
43   vdisplay.mode = None;
44
45   paraVSpace = 6; // default gap for drawPara
46
47   backgroundColourSet = false;
48   visible = true;
49
50   numBoxxes++;
51   Log::getInstance()->log("Boxx", Log::DEBUG, "Construct, now %u", numBoxxes);
52 }
53
54 Boxx::~Boxx()
55 {
56   if (surface) delete surface;
57   numBoxxes--;
58   Log::getInstance()->log("Boxx", Log::DEBUG, "Destruct, now %u", numBoxxes);
59 }
60 #include <typeinfo>
61 void Boxx::draw()
62 {
63   //Log::getInstance()->log("Boxx", Log::DEBUG, "Draw this %p surface %p", this, surface);
64   if (backgroundColourSet) fillColour(backgroundColour);
65
66   Boxx* currentBoxx;
67   vector<Boxx*>::iterator j;
68   //int count=0;
69   for (j = children.begin(); j != children.end(); j++)
70   {
71     currentBoxx = *j;
72    //Log::getInstance()->log("Boxx", Log::DEBUG, "Draw child %d %d %s", count,currentBoxx,typeid(*currentBoxx).name());
73     if (currentBoxx->getVisible()) currentBoxx->draw();
74    //Log::getInstance()->log("Boxx", Log::DEBUG, "Draw child %d %d end", count,currentBoxx);
75    // count++;
76   }  
77  // Log::getInstance()->log("Boxx", Log::DEBUG, "Draw this %p surface %p End", this, surface);
78 }
79
80 void Boxx::setSize(UINT w, UINT h)
81 {
82   area.w = w;
83   area.h = h;
84 }
85
86 void Boxx::setPosition(UINT x, UINT y)
87 {
88   area.x = x;
89   area.y = y;
90 }
91
92 void Boxx::createBuffer()
93 {
94   surface = Osd::getInstance()->createNewSurface();
95   surface->create(area.w, area.h);
96 }
97
98 void Boxx::add(Boxx* newChild)
99 {
100   newChild->setParent(this);
101   children.push_back(newChild);
102 }
103
104 void Boxx::remove(Boxx* oldChild)
105 {
106   for(vector<Boxx*>::iterator i = children.begin(); i != children.end(); i++)
107   {
108     if (*i == oldChild)
109     {
110       children.erase(i);
111       return;
112     }
113   }
114   Log::getInstance()->log("Boxx", Log::ERR, "Remove child box called, child %p not found", oldChild);
115 }
116
117 void Boxx::removeVisibleChilds(Region & r)
118 {
119         for(vector<Boxx*>::iterator i = children.begin(); i != children.end(); i++)
120         {
121                 if ((*i)->getVisible())
122                 {
123                         Region temp=(*i)->getRegionR();
124                         if (r.intersects(temp)) {
125                                 r=r.subtract(temp);
126                         }
127                 }
128         }
129 }
130
131 void Boxx::setParent(Boxx* newParent)
132 {
133   parent = newParent;
134 }
135
136 void Boxx::setBackgroundColour(const DrawStyle& Tcolour)
137 {
138   backgroundColour = Tcolour;
139   backgroundColourSet = true;
140 }
141
142 void Boxx::setVideoBackground()
143 {
144         vdisplay.mode=Window;
145         vdisplay.fallbackMode=Fullscreen;
146         vdisplay.x=getScreenX();
147         vdisplay.y=getScreenY();
148         vdisplay.width=getWidth();
149         vdisplay.height=getHeight();
150 }
151
152 void Boxx::setVisible(bool isVisible)
153 {
154   visible = isVisible;
155 }
156
157 bool Boxx::getVisible()
158 {
159   return visible;
160 }
161
162 void Boxx::setGap(UINT gap)
163 {
164   paraVSpace = gap;
165 }
166
167 void Boxx::blt(Region& r)
168 {
169   /* surface update to screen needs:
170   source x distance into this surface
171   source y distance into this surface
172   width of update
173   height of update
174   destination x on screen
175   destination y on screen
176   */
177
178   if (parent) abort(); // if (parent) then this is a child boxx. It can not blt.
179
180   // this shouldn't be here
181   r.x -= area.x;
182   r.y -= area.y;
183
184   surface->updateToScreen(r.x, r.y, r.w, r.h, area.x + r.x, area.y + r.y);
185
186 }
187
188 int Boxx::getScreenX()
189 {
190   if (parent) return area.x + parent->getScreenX();
191   return area.x;
192 }
193
194 int Boxx::getScreenY()
195 {
196   if (parent) return area.y + parent->getScreenY();
197   return area.y;
198 }
199
200 int Boxx::getRootBoxOffsetX() // convert this to be getX and silently do the parent/not thing? same for Y below?
201 {
202   if (parent) return area.x + parent->getRootBoxOffsetX();
203   return 0;
204 }
205
206 int Boxx::getRootBoxOffsetY()
207 {
208   if (parent) return area.y + parent->getRootBoxOffsetY();
209   return 0;
210 }
211
212 int Boxx::getX()
213 {
214   return area.x;
215 }
216
217 int Boxx::getY()
218 {
219   return area.y;
220 }
221
222 int Boxx::getX2()
223 {
224   return area.x + area.w;
225 }
226
227 int Boxx::getY2()
228 {
229   return area.y + area.h;
230 }
231
232 UINT Boxx::getWidth()
233 {
234   return area.w;
235 }
236
237 UINT Boxx::getHeight()
238 {
239   return area.h;
240 }
241
242 // FIXME Clean up the code to use just one of the following
243
244 Region* Boxx::getRegion()
245 {
246   return &area;
247 }
248
249 Region Boxx::getRegionR()
250 {
251   return area;
252 }
253
254 void Boxx::getRootBoxRegion(Region* r)
255 {
256   // Returns a region that describes the position of this box on the box with the surface
257   // To be used for boxstack->update calls
258
259   r->x = getRootBoxOffsetX();
260   r->y = getRootBoxOffsetY();
261   r->w = area.w;
262   r->h = area.h;  
263 }
264
265 bool Boxx::getVideoDisplay(VideoDisplay &vd)
266 {
267         for(vector<Boxx*>::iterator i = children.begin(); i != children.end(); i++)
268         {
269                 if ((*i)->getVideoDisplay(vd)) return true;
270         }
271
272         if (vdisplay.mode==None) return false;
273         vd=vdisplay;
274         return true;
275 }
276
277 // Level 1 drawing functions
278
279 void Boxx::fillColour(const DrawStyle& colour)
280 {
281   rectangle(0, 0, area.w, area.h, colour);
282 }
283
284 int Boxx::drawPara(const char* text, int x, int y, const DrawStyle& colour,unsigned int skiplines)
285 {
286   char line[256];
287   int lineHeight = getFontHeight() + paraVSpace;
288   float lineWidth;
289   float thisCharWidth;
290   int textPos;
291   int textLength;
292   int linePos;
293   int ypos;
294   int printLine;
295   int leftlines=0;
296
297 #if WIN32
298   // FIXME win pragma
299 #pragma warning(disable : 4146)
300 #endif
301
302   int drawLinePos=-skiplines;
303
304   textPos = 0;
305   textLength = strlen(text);
306   ypos = y;
307   Region tester;
308
309
310   bool haschildren = true;
311   if ( children.size() == 0) haschildren = false;
312   bool mchar=false;
313   Osd *osd=Osd::getInstance();
314   if (osd->charSet()!=1) mchar=true;
315   OsdVector *osdv=dynamic_cast<OsdVector*>(osd);
316   float *charwidtharray=NULL;
317   if (osdv) charwidtharray=osdv->getCharWidthArray();
318
319   mbstate_t state;
320   memset((void*)&state,0,sizeof(state));
321
322   while(1)
323   {
324     linePos = 0;
325     lineWidth = 0;
326     // tester reinit
327     tester.h = lineHeight;
328     tester.y=ypos;
329     tester.x = x;
330     tester.w = area.w - (2 * paraMargin);
331
332     if (haschildren) removeVisibleChilds(tester);
333
334     while(1)
335     {
336       printLine = 0;
337       int cur_length = 1;
338       wchar_t cur_char;
339       if (*(text + textPos) == '\0') break;
340       if (mchar) {
341           cur_length = mbrtowc(&cur_char, text + textPos, textLength-textPos, &state);
342           if (cur_length <= 0){
343                   cur_char='?';
344                   cur_length=1;
345           }
346       } else cur_char= *(text + textPos);
347
348
349       if (cur_char == '\0') break;
350
351       if (cur_char == '\n')
352       {
353         textPos += cur_length; // ignore the \n
354         printLine = 1;
355         break;
356       }
357       if (charwidtharray) {
358           thisCharWidth=charwidtharray[cur_char & 0xFF];
359           if (cur_char && 0xFFFFFF00) thisCharWidth=osdv->getCharWidth(cur_char);
360       } else  thisCharWidth = charWidth(cur_char);
361
362
363
364
365
366       if ((lineWidth + thisCharWidth + x) > tester.w)
367       {
368         // this character would break the right margin
369         if (cur_char == ' ')
370         {
371           // this char is a space, ignore and break
372           textPos += cur_length;
373           break;
374         }
375         else
376         {
377           // Need to go back to the last space in the line
378           while ((cur_char != ' ') && (linePos >= 0))
379           {
380             textPos -= cur_length;
381             if (mchar) {
382                   cur_length = mbrtowc(&cur_char, text + textPos, textLength-textPos, &state);
383                   if (cur_length <= 0){
384                         cur_char='?';
385                         cur_length=1;
386                   }
387             } else cur_char= *(text + textPos);
388             linePos--;
389           }
390           // Now take the space we just found
391           textPos += cur_length;
392           break;
393         }
394       }
395       for (int n = 0; n < cur_length; n++) line[linePos++] = text[textPos + n];
396       lineWidth += thisCharWidth;
397       textPos += cur_length;
398     }
399
400 //    line[linePos++] = '\0';
401     if (linePos >= 0) line[linePos++] = '\0'; //Here is the change
402
403     if (printLine || (linePos > 1)) // if some text was put in line
404     {
405         if (ypos <= (int)(area.h - lineHeight + paraVSpace)) {
406                 if (drawLinePos >= 0) {
407                         drawText(line, x, ypos, colour);
408                         ypos += lineHeight;
409                 }
410         } else {
411                 leftlines++;
412         }
413       drawLinePos++;
414     }
415     else
416     {
417       break;
418     }
419   }
420   return leftlines;
421 }
422
423 void Boxx::rectangle(Region& region, const DrawStyle& colour)
424 {
425   rectangle(region.x, region.y, region.w, region.h, colour);
426 }
427
428 // Level 0 drawing functions
429
430 void Boxx::rectangle(UINT x, UINT y, UINT w, UINT h, const DrawStyle& colour)
431 {
432   if (parent) parent->rectangle(area.x + x, area.y + y, w, h, colour);
433   else surface->fillblt(x, y, w, h, colour);
434 }
435
436 void Boxx::drawText(const char* text, int x, int y, const DrawStyle& colour)
437 {
438   if (parent) parent->drawText(text, area.x + x, area.y + y, colour);
439   else surface->drawText(text, x, y, colour);
440 }
441
442 void Boxx::drawText(const char* text, int x, int y, int width, const DrawStyle& colour)
443 {
444   if (parent) parent->drawText(text, area.x + x, area.y + y, width, colour);
445   else surface->drawText(text, x, y, width, colour);
446 }
447
448 void Boxx::drawTextRJ(const char* text, int x, int y, const DrawStyle& colour)
449 {
450   if (parent) parent->drawTextRJ(text, area.x + x, area.y + y, colour);
451   else surface->drawTextRJ(text, x, y, colour);
452 }
453
454 void Boxx::drawTextCentre(const char* text, int x, int y, const DrawStyle& colour)
455 {
456   if (parent) parent->drawTextCentre(text, area.x + x, area.y + y, colour);
457   else  surface->drawTextCentre(text, x, y, colour);
458 }
459 // Now deprecated
460 /*
461 void Boxx::drawPixelAlpha(UINT x, UINT y, const Colour& colour,bool fastdraw)
462 {
463   if (parent) parent->drawPixelAlpha(area.x + x, area.y + y, colour,fastdraw);
464   else
465   {
466     int c = (  (colour.alpha << 24 )
467              | (colour.red    << 16)
468              | (colour.green  <<  8)
469              | (colour.blue        ) );
470
471     surface->drawPixel(x, y, c,fastdraw);
472   }
473 }
474
475 void Boxx::drawPixel(UINT x, UINT y, const Colour& colour, bool fastdraw)
476 {
477   if (parent) parent->drawPixel(area.x + x, area.y + y, colour,fastdraw);
478   else
479   {
480     int c = (  (0xFF000000         )
481              | (colour.red    << 16)
482              | (colour.green  <<  8)
483              | (colour.blue        ) );
484
485     surface->drawPixel(x, y, c,fastdraw);
486   }
487 }
488 */
489
490 void Boxx::drawTTChar(int ox, int oy,int x, int y, cTeletextChar c)
491 {
492         if (parent) parent->drawTTChar(area.x + ox, area.y + oy, x,y,c);
493         else  if (surface) surface->drawTTChar(ox, oy,x,y,c);
494
495 }
496
497 void Boxx::drawBitmap(UINT x, UINT y, const Bitmap& bm, const DisplayRegion & region)
498 {
499   if (parent) parent->drawBitmap(area.x + x, area.y + y, bm, region);
500   else  if (surface) surface->drawBitmap(x, y, bm, region);
501 }
502
503 void Boxx::drawJpeg(const char *fileName, int x, int y, int *width, int *height)
504 {
505   if (parent) parent->drawJpeg(fileName, area.x + x, area.y + y, width, height);
506   else if (surface) surface->drawJpeg(fileName, x, y, width, height);
507 }
508
509 void Boxx::drawMonoBitmap(UCHAR*base, int dx, int dy, unsigned int height,unsigned int width, DrawStyle& nextColour)
510 {
511   if (parent) parent->drawMonoBitmap(base, area.x +dx, area.y + dy, height, width, nextColour);
512   else if (surface) surface->drawMonoBitmap(base, dx,dy, height, width, nextColour);
513 }
514
515 void Boxx::drawTVMedia(TVMediaInfo & tvmedia,float x, float y, float  width, float height, Corner corner)
516 {
517         if (parent) parent->drawTVMedia(tvmedia,area.x + x,area.y + y,width, height, corner);
518         else if (surface) {
519                 SurfaceVector * surfacevector=dynamic_cast<SurfaceVector*>(surface);
520                 if (surfacevector) surfacevector->drawTVMedia(tvmedia,x, y,width, height, corner);
521                 else surface->fillblt((int)x, (int)y, (int)width, (int)height, DrawStyle::RED); // Signal that something went wrong
522         }
523
524 }
525
526 void Boxx::drawClippingRectangle(float x, float y, float w, float h)
527 {
528         if (parent) parent->drawClippingRectangle(area.x + x, area.y + y, w, h);
529         else if (surface) {
530                 SurfaceVector * surfacevector=dynamic_cast<SurfaceVector*>(surface);
531                 if (surfacevector) surfacevector->drawClippingRectangle(x, y, w, h);
532
533         }
534 }
535
536 int Boxx::getFontHeight()
537 {
538   if (parent) return parent->getFontHeight();
539   else if (surface) return surface->getFontHeight();
540   else return 18;
541 }
542
543 void Boxx::startFastDraw()
544 {
545   if (parent)
546   {
547     parent->startFastDraw();
548   }
549   else
550   {
551     if (surface) surface->startFastDraw();
552   }
553 }
554
555 void Boxx::endFastDraw()
556 {
557   if (parent)
558   {
559     parent->endFastDraw();
560   }
561   else
562   {
563     if (surface) surface->endFastDraw();
564   }
565 }
566
567 float Boxx::charWidth(wchar_t c)
568 {
569   if (parent) return parent->charWidth(c);
570   else if (surface) return surface->getCharWidth(c);
571   else return 16.; //?
572 }
573
574
575 Surface* Boxx::getSurface()
576 {
577   if (parent) return parent->getSurface();
578   return surface;
579 }
580
581 bool Boxx::mouseMove(int x, int y)
582 {
583         if ((x >=  (int)area.x) && (x<(int)area.x2())
584                 && (y >= (int)area.y) && (y < (int)area.y2()))
585         {
586                 return true;
587         }
588         else 
589         {
590                 return false;
591         }
592 }
593
594 bool Boxx::mouseLBDOWN(int x, int y)
595 {
596         if ((x >= (int)area.x) && (x<(int)area.x2())
597                 && (y >= (int)area.y) && (y < (int)area.y2()))
598         {
599                 return true;
600         }
601         else
602         {
603                 return false;
604         }
605 }