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