vdr-1.4.7/osd.c

Go to the documentation of this file.
00001 /*
00002  * osd.c: Abstract On Screen Display layer
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: osd.c 1.68 2007/02/17 16:05:52 kls Exp $
00008  */
00009 
00010 #include "osd.h"
00011 #include <math.h>
00012 #include <stdlib.h>
00013 #include <sys/ioctl.h>
00014 #include <sys/stat.h>
00015 #include <sys/unistd.h>
00016 #include "tools.h"
00017 
00018 // --- cPalette --------------------------------------------------------------
00019 
00020 cPalette::cPalette(int Bpp)
00021 {
00022   SetBpp(Bpp);
00023 }
00024 
00025 void cPalette::Reset(void)
00026 {
00027   numColors = 0;
00028   modified = false;
00029 }
00030 
00031 int cPalette::Index(tColor Color)
00032 {
00033   for (int i = 0; i < numColors; i++) {
00034       if (color[i] == Color)
00035          return i;
00036       }
00037   if (numColors < maxColors) {
00038      color[numColors++] = Color;
00039      modified = true;
00040      return numColors - 1;
00041      }
00042   dsyslog("too many different colors used in palette");
00043   //TODO: return the index of the "closest" color?
00044   return 0;
00045 }
00046 
00047 void cPalette::SetBpp(int Bpp)
00048 {
00049   bpp = Bpp;
00050   maxColors = 1 << bpp;
00051   Reset();
00052 }
00053 
00054 void cPalette::SetColor(int Index, tColor Color)
00055 {
00056   if (Index < maxColors) {
00057      if (numColors <= Index) {
00058         numColors = Index + 1;
00059         modified = true;
00060         }
00061      else
00062         modified |= color[Index] != Color;
00063      color[Index] = Color;
00064      }
00065 }
00066 
00067 const tColor *cPalette::Colors(int &NumColors)
00068 {
00069   NumColors = numColors;
00070   return numColors ? color : NULL;
00071 }
00072 
00073 void cPalette::Take(const cPalette &Palette, tIndexes *Indexes, tColor ColorFg, tColor ColorBg)
00074 {
00075   for (int i = 0; i < Palette.numColors; i++) {
00076       tColor Color = Palette.color[i];
00077       if (ColorFg || ColorBg) {
00078          switch (i) {
00079            case 0: Color = ColorBg; break;
00080            case 1: Color = ColorFg; break;
00081            }
00082          }
00083       int n = Index(Color);
00084       if (Indexes)
00085          (*Indexes)[i] = n;
00086       }
00087 }
00088 
00089 void cPalette::Replace(const cPalette &Palette)
00090 {
00091   for (int i = 0; i < Palette.numColors; i++)
00092       SetColor(i, Palette.color[i]);
00093   numColors = Palette.numColors;
00094 }
00095 
00096 // --- cBitmap ---------------------------------------------------------------
00097 
00098 cBitmap::cBitmap(int Width, int Height, int Bpp, int X0, int Y0)
00099 :cPalette(Bpp)
00100 {
00101   bitmap = NULL;
00102   x0 = X0;
00103   y0 = Y0;
00104   SetSize(Width, Height);
00105 }
00106 
00107 cBitmap::cBitmap(const char *FileName)
00108 {
00109   bitmap = NULL;
00110   x0 = 0;
00111   y0 = 0;
00112   LoadXpm(FileName);
00113 }
00114 
00115 cBitmap::cBitmap(const char *const Xpm[])
00116 {
00117   bitmap = NULL;
00118   x0 = 0;
00119   y0 = 0;
00120   SetXpm(Xpm);
00121 }
00122 
00123 cBitmap::~cBitmap()
00124 {
00125   free(bitmap);
00126 }
00127 
00128 void cBitmap::SetSize(int Width, int Height)
00129 {
00130   if (bitmap && Width == width && Height == height)
00131      return;
00132   width = Width;
00133   height = Height;
00134   free(bitmap);
00135   bitmap = NULL;
00136   dirtyX1 = 0;
00137   dirtyY1 = 0;
00138   dirtyX2 = width - 1;
00139   dirtyY2 = height - 1;
00140   if (width > 0 && height > 0) {
00141      bitmap = MALLOC(tIndex, width * height);
00142      if (bitmap)
00143         memset(bitmap, 0x00, width * height);
00144      else
00145         esyslog("ERROR: can't allocate bitmap!");
00146      }
00147   else
00148      esyslog("ERROR: invalid bitmap parameters (%d, %d)!", width, height);
00149 }
00150 
00151 bool cBitmap::Contains(int x, int y) const
00152 {
00153   x -= x0;
00154   y -= y0;
00155   return 0 <= x && x < width && 0 <= y && y < height;
00156 }
00157 
00158 bool cBitmap::Covers(int x1, int y1, int x2, int y2) const
00159 {
00160   x1 -= x0;
00161   y1 -= y0;
00162   x2 -= x0;
00163   y2 -= y0;
00164   return x1 <= 0 && y1 <= 0 && x2 >= width - 1 && y2 >= height - 1;
00165 }
00166 
00167 bool cBitmap::Intersects(int x1, int y1, int x2, int y2) const
00168 {
00169   x1 -= x0;
00170   y1 -= y0;
00171   x2 -= x0;
00172   y2 -= y0;
00173   return !(x2 < 0 || x1 >= width || y2 < 0 || y1 >= height);
00174 }
00175 
00176 bool cBitmap::Dirty(int &x1, int &y1, int &x2, int &y2)
00177 {
00178   if (dirtyX2 >= 0) {
00179      x1 = dirtyX1;
00180      y1 = dirtyY1;
00181      x2 = dirtyX2;
00182      y2 = dirtyY2;
00183      return true;
00184      }
00185   return false;
00186 }
00187 
00188 void cBitmap::Clean(void)
00189 {
00190   dirtyX1 = width;
00191   dirtyY1 = height;
00192   dirtyX2 = -1;
00193   dirtyY2 = -1;
00194 }
00195 
00196 bool cBitmap::LoadXpm(const char *FileName)
00197 {
00198   bool Result = false;
00199   FILE *f = fopen(FileName, "r");
00200   if (f) {
00201      char **Xpm = NULL;
00202      bool isXpm = false;
00203      int lines = 0;
00204      int index = 0;
00205      char *s;
00206      cReadLine ReadLine;
00207      while ((s = ReadLine.Read(f)) != NULL) {
00208            s = skipspace(s);
00209            if (!isXpm) {
00210               if (strcmp(s, "/* XPM */") != 0) {
00211                  esyslog("ERROR: invalid header in XPM file '%s'", FileName);
00212                  break;
00213                  }
00214               isXpm = true;
00215               }
00216            else if (*s++ == '"') {
00217               if (!lines) {
00218                  int w, h, n, c;
00219                  if (4 != sscanf(s, "%d %d %d %d", &w, &h, &n, &c)) {
00220                     esyslog("ERROR: faulty 'values' line in XPM file '%s'", FileName);
00221                     isXpm = false;
00222                     break;
00223                     }
00224                  lines = h + n + 1;
00225                  Xpm = MALLOC(char *, lines);
00226                  memset(Xpm, 0, lines * sizeof(char*));
00227                  }
00228               char *q = strchr(s, '"');
00229               if (!q) {
00230                  esyslog("ERROR: missing quotes in XPM file '%s'", FileName);
00231                  isXpm = false;
00232                  break;
00233                  }
00234               *q = 0;
00235               if (index < lines)
00236                  Xpm[index++] = strdup(s);
00237               else {
00238                  esyslog("ERROR: too many lines in XPM file '%s'", FileName);
00239                  isXpm = false;
00240                  break;
00241                  }
00242               }
00243            }
00244      if (isXpm) {
00245         if (index == lines)
00246            Result = SetXpm(Xpm);
00247         else
00248            esyslog("ERROR: too few lines in XPM file '%s'", FileName);
00249         }
00250      if (Xpm) {
00251         for (int i = 0; i < index; i++)
00252             free(Xpm[i]);
00253         }
00254      free(Xpm);
00255      fclose(f);
00256      }
00257   else
00258      esyslog("ERROR: can't open XPM file '%s'", FileName);
00259   return Result;
00260 }
00261 
00262 bool cBitmap::SetXpm(const char *const Xpm[], bool IgnoreNone)
00263 {
00264   const char *const *p = Xpm;
00265   int w, h, n, c;
00266   if (4 != sscanf(*p, "%d %d %d %d", &w, &h, &n, &c)) {
00267      esyslog("ERROR: faulty 'values' line in XPM: '%s'", *p);
00268      return false;
00269      }
00270   if (n > MAXNUMCOLORS) {
00271      esyslog("ERROR: too many colors in XPM: %d", n);
00272      return false;
00273      }
00274   int b = 0;
00275   while (1 << (1 << b) < (IgnoreNone ? n - 1 : n))
00276         b++;
00277   SetBpp(1 << b);
00278   SetSize(w, h);
00279   int NoneColorIndex = MAXNUMCOLORS;
00280   for (int i = 0; i < n; i++) {
00281       const char *s = *++p;
00282       if (int(strlen(s)) < c) {
00283          esyslog("ERROR: faulty 'colors' line in XPM: '%s'", s);
00284          return false;
00285          }
00286       s = skipspace(s + c);
00287       if (*s != 'c') {
00288          esyslog("ERROR: unknown color key in XPM: '%c'", *s);
00289          return false;
00290          }
00291       s = skipspace(s + 1);
00292       if (strcasecmp(s, "none") == 0) {
00293          s = "#00000000";
00294          NoneColorIndex = i;
00295          if (IgnoreNone)
00296             continue;
00297          }
00298       if (*s != '#') {
00299          esyslog("ERROR: unknown color code in XPM: '%c'", *s);
00300          return false;
00301          }
00302       tColor color = strtoul(++s, NULL, 16) | 0xFF000000;
00303       SetColor((IgnoreNone && i > NoneColorIndex) ? i - 1 : i, color);
00304       }
00305   for (int y = 0; y < h; y++) {
00306       const char *s = *++p;
00307       if (int(strlen(s)) != w * c) {
00308          esyslog("ERROR: faulty pixel line in XPM: %d '%s'", y, s);
00309          return false;
00310          }
00311       for (int x = 0; x < w; x++) {
00312           for (int i = 0; i <= n; i++) {
00313               if (i == n) {
00314                  esyslog("ERROR: undefined pixel color in XPM: %d %d '%s'", x, y, s);
00315                  return false;
00316                  }
00317               if (strncmp(Xpm[i + 1], s, c) == 0) {
00318                  if (i == NoneColorIndex)
00319                     NoneColorIndex = MAXNUMCOLORS;
00320                  SetIndex(x, y, (IgnoreNone && i > NoneColorIndex) ? i - 1 : i);
00321                  break;
00322                  }
00323               }
00324           s += c;
00325           }
00326       }
00327   if (NoneColorIndex < MAXNUMCOLORS && !IgnoreNone)
00328      return SetXpm(Xpm, true);
00329   return true;
00330 }
00331 
00332 void cBitmap::SetIndex(int x, int y, tIndex Index)
00333 {
00334   if (bitmap) {
00335      if (0 <= x && x < width && 0 <= y && y < height) {
00336         if (bitmap[width * y + x] != Index) {
00337            bitmap[width * y + x] = Index;
00338            if (dirtyX1 > x)  dirtyX1 = x;
00339            if (dirtyY1 > y)  dirtyY1 = y;
00340            if (dirtyX2 < x)  dirtyX2 = x;
00341            if (dirtyY2 < y)  dirtyY2 = y;
00342            }
00343         }
00344      }
00345 }
00346 
00347 void cBitmap::DrawPixel(int x, int y, tColor Color)
00348 {
00349   x -= x0;
00350   y -= y0;
00351   if (0 <= x && x < width && 0 <= y && y < height)
00352      SetIndex(x, y, Index(Color));
00353 }
00354 
00355 void cBitmap::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
00356 {
00357   if (bitmap && Bitmap.bitmap && Intersects(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1)) {
00358      if (Covers(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1))
00359         Reset();
00360      x -= x0;
00361      y -= y0;
00362      if (ReplacePalette && Covers(x + x0, y + y0, x + x0 + Bitmap.Width() - 1, y + y0 + Bitmap.Height() - 1)) {
00363         Replace(Bitmap);
00364         for (int ix = 0; ix < Bitmap.width; ix++) {
00365             for (int iy = 0; iy < Bitmap.height; iy++) {
00366                 if (!Overlay || Bitmap.bitmap[Bitmap.width * iy + ix] != 0)
00367                    SetIndex(x + ix, y + iy, Bitmap.bitmap[Bitmap.width * iy + ix]);
00368                 }
00369             }
00370         }
00371      else {
00372         tIndexes Indexes;
00373         Take(Bitmap, &Indexes, ColorFg, ColorBg);
00374         for (int ix = 0; ix < Bitmap.width; ix++) {
00375             for (int iy = 0; iy < Bitmap.height; iy++) {
00376                 if (!Overlay || Bitmap.bitmap[Bitmap.width * iy + ix] != 0)
00377                    SetIndex(x + ix, y + iy, Indexes[int(Bitmap.bitmap[Bitmap.width * iy + ix])]);
00378                 }
00379             }
00380         }
00381      }
00382 }
00383 
00384 void cBitmap::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
00385 {
00386   if (bitmap) {
00387      int w = Font->Width(s);
00388      int h = Font->Height();
00389      int limit = 0;
00390      if (Width || Height) {
00391         int cw = Width ? Width : w;
00392         int ch = Height ? Height : h;
00393         if (!Intersects(x, y, x + cw - 1, y + ch - 1))
00394            return;
00395         if (ColorBg != clrTransparent)
00396            DrawRectangle(x, y, x + cw - 1, y + ch - 1, ColorBg);
00397         limit = x + cw - x0;
00398         if (Width) {
00399            if ((Alignment & taLeft) != 0)
00400               ;
00401            else if ((Alignment & taRight) != 0) {
00402               if (w < Width)
00403                  x += Width - w;
00404               }
00405            else { // taCentered
00406               if (w < Width)
00407                  x += (Width - w) / 2;
00408               }
00409            }
00410         if (Height) {
00411            if ((Alignment & taTop) != 0)
00412               ;
00413            else if ((Alignment & taBottom) != 0) {
00414               if (h < Height)
00415                  y += Height - h;
00416               }
00417            else { // taCentered
00418               if (h < Height)
00419                  y += (Height - h) / 2;
00420               }
00421            }
00422         }
00423      else if (!Intersects(x, y, x + w - 1, y + h - 1))
00424         return;
00425      x -= x0;
00426      y -= y0;
00427      tIndex fg = Index(ColorFg);
00428      tIndex bg = (ColorBg != clrTransparent) ? Index(ColorBg) : 0;
00429      while (s && *s) {
00430            const cFont::tCharData *CharData = Font->CharData(*s++);
00431            if (limit && int(x + CharData->width) > limit)
00432               break; // we don't draw partial characters
00433            if (int(x + CharData->width) > 0) {
00434               for (int row = 0; row < h; row++) {
00435                   cFont::tPixelData PixelData = CharData->lines[row];
00436                   for (int col = CharData->width; col-- > 0; ) {
00437                       if (ColorBg != clrTransparent || (PixelData & 1))
00438                          SetIndex(x + col, y + row, (PixelData & 1) ? fg : bg);
00439                       PixelData >>= 1;
00440                       }
00441                   }
00442               }
00443            x += CharData->width;
00444            if (x > width - 1)
00445               break;
00446            }
00447      }
00448 }
00449 
00450 void cBitmap::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
00451 {
00452   if (bitmap && Intersects(x1, y1, x2, y2)) {
00453      if (Covers(x1, y1, x2, y2))
00454         Reset();
00455      x1 -= x0;
00456      y1 -= y0;
00457      x2 -= x0;
00458      y2 -= y0;
00459      x1 = max(x1, 0);
00460      y1 = max(y1, 0);
00461      x2 = min(x2, width - 1);
00462      y2 = min(y2, height - 1);
00463      tIndex c = Index(Color);
00464      for (int y = y1; y <= y2; y++)
00465          for (int x = x1; x <= x2; x++)
00466              SetIndex(x, y, c);
00467      }
00468 }
00469 
00470 void cBitmap::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants)
00471 {
00472   if (!Intersects(x1, y1, x2, y2))
00473      return;
00474   // Algorithm based on http://homepage.smc.edu/kennedy_john/BELIPSE.PDF
00475   int rx = x2 - x1;
00476   int ry = y2 - y1;
00477   int cx = (x1 + x2) / 2;
00478   int cy = (y1 + y2) / 2;
00479   switch (abs(Quadrants)) {
00480     case 0: rx /= 2; ry /= 2; break;
00481     case 1: cx = x1; cy = y2; break;
00482     case 2: cx = x2; cy = y2; break;
00483     case 3: cx = x2; cy = y1; break;
00484     case 4: cx = x1; cy = y1; break;
00485     case 5: cx = x1;          ry /= 2; break;
00486     case 6:          cy = y2; rx /= 2; break;
00487     case 7: cx = x2;          ry /= 2; break;
00488     case 8:          cy = y1; rx /= 2; break;
00489     }
00490   int TwoASquare = 2 * rx * rx;
00491   int TwoBSquare = 2 * ry * ry;
00492   int x = rx;
00493   int y = 0;
00494   int XChange = ry * ry * (1 - 2 * rx);
00495   int YChange = rx * rx;
00496   int EllipseError = 0;
00497   int StoppingX = TwoBSquare * rx;
00498   int StoppingY = 0;
00499   while (StoppingX >= StoppingY) {
00500         switch (Quadrants) {
00501           case  5: DrawRectangle(cx,     cy + y, cx + x, cy + y, Color); // no break
00502           case  1: DrawRectangle(cx,     cy - y, cx + x, cy - y, Color); break;
00503           case  7: DrawRectangle(cx - x, cy + y, cx,     cy + y, Color); // no break
00504           case  2: DrawRectangle(cx - x, cy - y, cx,     cy - y, Color); break;
00505           case  3: DrawRectangle(cx - x, cy + y, cx,     cy + y, Color); break;
00506           case  4: DrawRectangle(cx,     cy + y, cx + x, cy + y, Color); break;
00507           case  0:
00508           case  6: DrawRectangle(cx - x, cy - y, cx + x, cy - y, Color); if (Quadrants == 6) break;
00509           case  8: DrawRectangle(cx - x, cy + y, cx + x, cy + y, Color); break;
00510           case -1: DrawRectangle(cx + x, cy - y, x2,     cy - y, Color); break;
00511           case -2: DrawRectangle(x1,     cy - y, cx - x, cy - y, Color); break;
00512           case -3: DrawRectangle(x1,     cy + y, cx - x, cy + y, Color); break;
00513           case -4: DrawRectangle(cx + x, cy + y, x2,     cy + y, Color); break;
00514           }
00515         y++;
00516         StoppingY += TwoASquare;
00517         EllipseError += YChange;
00518         YChange += TwoASquare;
00519         if (2 * EllipseError + XChange > 0) {
00520            x--;
00521            StoppingX -= TwoBSquare;
00522            EllipseError += XChange;
00523            XChange += TwoBSquare;
00524            }
00525         }
00526   x = 0;
00527   y = ry;
00528   XChange = ry * ry;
00529   YChange = rx * rx * (1 - 2 * ry);
00530   EllipseError = 0;
00531   StoppingX = 0;
00532   StoppingY = TwoASquare * ry;
00533   while (StoppingX <= StoppingY) {
00534         switch (Quadrants) {
00535           case  5: DrawRectangle(cx,     cy + y, cx + x, cy + y, Color); // no break
00536           case  1: DrawRectangle(cx,     cy - y, cx + x, cy - y, Color); break;
00537           case  7: DrawRectangle(cx - x, cy + y, cx,     cy + y, Color); // no break
00538           case  2: DrawRectangle(cx - x, cy - y, cx,     cy - y, Color); break;
00539           case  3: DrawRectangle(cx - x, cy + y, cx,     cy + y, Color); break;
00540           case  4: DrawRectangle(cx,     cy + y, cx + x, cy + y, Color); break;
00541           case  0:
00542           case  6: DrawRectangle(cx - x, cy - y, cx + x, cy - y, Color); if (Quadrants == 6) break;
00543           case  8: DrawRectangle(cx - x, cy + y, cx + x, cy + y, Color); break;
00544           case -1: DrawRectangle(cx + x, cy - y, x2,     cy - y, Color); break;
00545           case -2: DrawRectangle(x1,     cy - y, cx - x, cy - y, Color); break;
00546           case -3: DrawRectangle(x1,     cy + y, cx - x, cy + y, Color); break;
00547           case -4: DrawRectangle(cx + x, cy + y, x2,     cy + y, Color); break;
00548           }
00549         x++;
00550         StoppingX += TwoBSquare;
00551         EllipseError += XChange;
00552         XChange += TwoBSquare;
00553         if (2 * EllipseError + YChange > 0) {
00554            y--;
00555            StoppingY -= TwoASquare;
00556            EllipseError += YChange;
00557            YChange += TwoASquare;
00558            }
00559         }
00560 }
00561 
00562 void cBitmap::DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type)
00563 {
00564   // TODO This is just a quick and dirty implementation of a slope drawing
00565   // machanism. If somebody can come up with a better solution, let's have it!
00566   if (!Intersects(x1, y1, x2, y2))
00567      return;
00568   bool upper    = Type & 0x01;
00569   bool falling  = Type & 0x02;
00570   bool vertical = Type & 0x04;
00571   if (vertical) {
00572      for (int y = y1; y <= y2; y++) {
00573          double c = cos((y - y1) * M_PI / (y2 - y1 + 1));
00574          if (falling)
00575             c = -c;
00576          int x = int((x2 - x1 + 1) * c / 2);
00577          if (upper && !falling || !upper && falling)
00578             DrawRectangle(x1, y, (x1 + x2) / 2 + x, y, Color);
00579          else
00580             DrawRectangle((x1 + x2) / 2 + x, y, x2, y, Color);
00581          }
00582      }
00583   else {
00584      for (int x = x1; x <= x2; x++) {
00585          double c = cos((x - x1) * M_PI / (x2 - x1 + 1));
00586          if (falling)
00587             c = -c;
00588          int y = int((y2 - y1 + 1) * c / 2);
00589          if (upper)
00590             DrawRectangle(x, y1, x, (y1 + y2) / 2 + y, Color);
00591          else
00592             DrawRectangle(x, (y1 + y2) / 2 + y, x, y2, Color);
00593          }
00594      }
00595 }
00596 
00597 const tIndex *cBitmap::Data(int x, int y)
00598 {
00599   return &bitmap[y * width + x];
00600 }
00601 
00602 // --- cOsd ------------------------------------------------------------------
00603 
00604 int cOsd::isOpen = 0;
00605 
00606 cOsd::cOsd(int Left, int Top)
00607 {
00608   if (isOpen)
00609      esyslog("ERROR: OSD opened without closing previous OSD!");
00610   savedRegion = NULL;
00611   numBitmaps = 0;
00612   left = Left;
00613   top = Top;
00614   width = height = 0;
00615   isOpen++;
00616 }
00617 
00618 cOsd::~cOsd()
00619 {
00620   for (int i = 0; i < numBitmaps; i++)
00621       delete bitmaps[i];
00622   delete savedRegion;
00623   isOpen--;
00624 }
00625 
00626 cBitmap *cOsd::GetBitmap(int Area)
00627 {
00628   return Area < numBitmaps ? bitmaps[Area] : NULL;
00629 }
00630 
00631 eOsdError cOsd::CanHandleAreas(const tArea *Areas, int NumAreas)
00632 {
00633   if (NumAreas > MAXOSDAREAS)
00634      return oeTooManyAreas;
00635   eOsdError Result = oeOk;
00636   for (int i = 0; i < NumAreas; i++) {
00637       if (Areas[i].x1 > Areas[i].x2 || Areas[i].y1 > Areas[i].y2 || Areas[i].x1 < 0 || Areas[i].y1 < 0)
00638          return oeWrongAlignment;
00639       for (int j = i + 1; j < NumAreas; j++) {
00640           if (Areas[i].Intersects(Areas[j])) {
00641              Result = oeAreasOverlap;
00642              break;
00643              }
00644           }
00645       }
00646   return Result;
00647 }
00648 
00649 eOsdError cOsd::SetAreas(const tArea *Areas, int NumAreas)
00650 {
00651   eOsdError Result = oeUnknown;
00652   if (numBitmaps == 0) {
00653      Result = CanHandleAreas(Areas, NumAreas);
00654      if (Result == oeOk) {
00655         width = height = 0;
00656         for (int i = 0; i < NumAreas; i++) {
00657             bitmaps[numBitmaps++] = new cBitmap(Areas[i].Width(), Areas[i].Height(), Areas[i].bpp, Areas[i].x1, Areas[i].y1);
00658             width = max(width, Areas[i].x2 + 1);
00659             height = max(height, Areas[i].y2 + 1);
00660             }
00661         }
00662      }
00663   if (Result != oeOk)
00664      esyslog("ERROR: cOsd::SetAreas returned %d", Result);
00665   return Result;
00666 }
00667 
00668 void cOsd::SaveRegion(int x1, int y1, int x2, int y2)
00669 {
00670   delete savedRegion;
00671   savedRegion = new cBitmap(x2 - x1 + 1, y2 - y1 + 1, 8, x1, y1);
00672   for (int i = 0; i < numBitmaps; i++)
00673       savedRegion->DrawBitmap(bitmaps[i]->X0(), bitmaps[i]->Y0(), *bitmaps[i]);
00674 }
00675 
00676 void cOsd::RestoreRegion(void)
00677 {
00678   if (savedRegion) {
00679      DrawBitmap(savedRegion->X0(), savedRegion->Y0(), *savedRegion);
00680      delete savedRegion;
00681      savedRegion = NULL;
00682      }
00683 }
00684 
00685 eOsdError cOsd::SetPalette(const cPalette &Palette, int Area)
00686 {
00687   if (Area < numBitmaps)
00688      bitmaps[Area]->Take(Palette);
00689   return oeUnknown;
00690 }
00691 
00692 void cOsd::DrawPixel(int x, int y, tColor Color)
00693 {
00694   for (int i = 0; i < numBitmaps; i++)
00695       bitmaps[i]->DrawPixel(x, y, Color);
00696 }
00697 
00698 void cOsd::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
00699 {
00700   for (int i = 0; i < numBitmaps; i++)
00701       bitmaps[i]->DrawBitmap(x, y, Bitmap, ColorFg, ColorBg, ReplacePalette, Overlay);
00702 }
00703 
00704 void cOsd::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
00705 {
00706   for (int i = 0; i < numBitmaps; i++)
00707       bitmaps[i]->DrawText(x, y, s, ColorFg, ColorBg, Font, Width, Height, Alignment);
00708 }
00709 
00710 void cOsd::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
00711 {
00712   for (int i = 0; i < numBitmaps; i++)
00713       bitmaps[i]->DrawRectangle(x1, y1, x2, y2, Color);
00714 }
00715 
00716 void cOsd::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants)
00717 {
00718   for (int i = 0; i < numBitmaps; i++)
00719       bitmaps[i]->DrawEllipse(x1, y1, x2, y2, Color, Quadrants);
00720 }
00721 
00722 void cOsd::DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type)
00723 {
00724   for (int i = 0; i < numBitmaps; i++)
00725       bitmaps[i]->DrawSlope(x1, y1, x2, y2, Color, Type);
00726 }
00727 
00728 void cOsd::Flush(void)
00729 {
00730 }
00731 
00732 // --- cOsdProvider ----------------------------------------------------------
00733 
00734 cOsdProvider *cOsdProvider::osdProvider = NULL;
00735 
00736 cOsdProvider::cOsdProvider(void)
00737 {
00738   delete osdProvider;
00739   osdProvider = this;
00740 }
00741 
00742 cOsdProvider::~cOsdProvider()
00743 {
00744   osdProvider = NULL;
00745 }
00746 
00747 cOsd *cOsdProvider::NewOsd(int Left, int Top)
00748 {
00749   if (cOsd::IsOpen())
00750      esyslog("ERROR: attempt to open OSD while it is already open - using dummy OSD!");
00751   else if (osdProvider)
00752      return osdProvider->CreateOsd(Left, Top);
00753   else
00754      esyslog("ERROR: no OSD provider available - using dummy OSD!");
00755   return new cOsd(Left, Top); // create a dummy cOsd, so that access won't result in a segfault
00756 }
00757 
00758 void cOsdProvider::Shutdown(void)
00759 {
00760   delete osdProvider;
00761   osdProvider = NULL;
00762 }
00763 
00764 // --- cTextScroller ---------------------------------------------------------
00765 
00766 cTextScroller::cTextScroller(void)
00767 {
00768   osd = NULL;
00769   left = top = width = height = 0;
00770   font = NULL;
00771   colorFg = 0;
00772   colorBg = 0;
00773   offset = 0;
00774   shown = 0;
00775 }
00776 
00777 cTextScroller::cTextScroller(cOsd *Osd, int Left, int Top, int Width, int Height, const char *Text, const cFont *Font, tColor ColorFg, tColor ColorBg)
00778 {
00779   Set(Osd, Left, Top, Width, Height, Text, Font, ColorFg, ColorBg);
00780 }
00781 
00782 void cTextScroller::Set(cOsd *Osd, int Left, int Top, int Width, int Height, const char *Text, const cFont *Font, tColor ColorFg, tColor ColorBg)
00783 {
00784   osd = Osd;
00785   left = Left;
00786   top = Top;
00787   width = Width;
00788   height = Height;
00789   font = Font;
00790   colorFg = ColorFg;
00791   colorBg = ColorBg;
00792   offset = 0;
00793   textWrapper.Set(Text, Font, Width);
00794   shown = min(Total(), height / font->Height());
00795   height = shown * font->Height(); // sets height to the actually used height, which may be less than Height
00796   DrawText();
00797 }
00798 
00799 void cTextScroller::Reset(void)
00800 {
00801   osd = NULL; // just makes sure it won't draw anything
00802 }
00803 
00804 void cTextScroller::DrawText(void)
00805 {
00806   if (osd) {
00807      for (int i = 0; i < shown; i++)
00808          osd->DrawText(left, top + i * font->Height(), textWrapper.GetLine(offset + i), colorFg, colorBg, font, width);
00809      }
00810 }
00811 
00812 void cTextScroller::Scroll(bool Up, bool Page)
00813 {
00814   if (Up) {
00815      if (CanScrollUp()) {
00816         offset -= Page ? shown : 1;
00817         if (offset < 0)
00818            offset = 0;
00819         DrawText();
00820         }
00821      }
00822   else {
00823      if (CanScrollDown()) {
00824         offset += Page ? shown : 1;
00825         if (offset + shown > Total())
00826            offset = Total() - shown;
00827         DrawText();
00828         }
00829      }
00830 }

Generated on Tue Nov 6 19:57:54 2007 for VDR by  doxygen 1.5.3-20071008