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