Home

Dokumentation

Impressum

Dokumentation VDR
 

Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

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.39 2002/12/08 13:17:13 kls Exp $
00008  */
00009 
00010 #include "osd.h"
00011 #include <string.h>
00012 #include "device.h"
00013 #include "i18n.h"
00014 #include "status.h"
00015 
00016 // --- cOsd ------------------------------------------------------------------
00017 
00018 #ifdef DEBUG_OSD
00019   WINDOW *cOsd::window = NULL;
00020   int cOsd::colorPairs[MaxColorPairs] = { 0 };
00021 #else
00022   cOsdBase *cOsd::osd = NULL;
00023 #endif
00024   int cOsd::cols = 0;
00025   int cOsd::rows = 0;
00026 
00027 void cOsd::Initialize(void)
00028 {
00029 #if defined(DEBUG_OSD)
00030   initscr();
00031   start_color();
00032   leaveok(stdscr, true);
00033 #endif
00034 }
00035 
00036 void cOsd::Shutdown(void)
00037 {
00038   Close();
00039 #if defined(DEBUG_OSD)
00040   endwin();
00041 #endif
00042 }
00043 
00044 #ifdef DEBUG_OSD
00045 void cOsd::SetColor(eDvbColor colorFg, eDvbColor colorBg)
00046 {
00047   int color = (colorBg << 16) | colorFg | 0x80000000;
00048   for (int i = 0; i < MaxColorPairs; i++) {
00049       if (!colorPairs[i]) {
00050          colorPairs[i] = color;
00051          init_pair(i + 1, colorFg, colorBg);
00052          wattrset(window, COLOR_PAIR(i + 1));
00053          break;
00054          }
00055       else if (color == colorPairs[i]) {
00056          wattrset(window, COLOR_PAIR(i + 1));
00057          break;
00058          }
00059       }
00060 }
00061 #endif
00062 
00063 cOsdBase *cOsd::OpenRaw(int x, int y)
00064 {
00065 #ifdef DEBUG_OSD
00066   return NULL;
00067 #else
00068   return osd ? NULL : cDevice::PrimaryDevice()->NewOsd(x, y);
00069 #endif
00070 }
00071 
00072 void cOsd::Open(int w, int h)
00073 {
00074   int d = (h < 0) ? Setup.OSDheight + h : 0;
00075   h = abs(h);
00076   cols = w;
00077   rows = h;
00078 #ifdef DEBUG_OSD
00079   window = subwin(stdscr, h, w, d, (Setup.OSDwidth - w) / 2);
00080   syncok(window, true);
00081   #define B2C(b) (((b) * 1000) / 255)
00082   #define SETCOLOR(n, r, g, b, o) init_color(n, B2C(r), B2C(g), B2C(b))
00083   //XXX
00084   SETCOLOR(clrBackground,  0x00, 0x00, 0x00, 127); // background 50% gray
00085   SETCOLOR(clrBlack,       0x00, 0x00, 0x00, 255);
00086   SETCOLOR(clrRed,         0xFC, 0x14, 0x14, 255);
00087   SETCOLOR(clrGreen,       0x24, 0xFC, 0x24, 255);
00088   SETCOLOR(clrYellow,      0xFC, 0xC0, 0x24, 255);
00089   SETCOLOR(clrBlue,        0x00, 0x00, 0xFC, 255);
00090   SETCOLOR(clrCyan,        0x00, 0xFC, 0xFC, 255);
00091   SETCOLOR(clrMagenta,     0xB0, 0x00, 0xFC, 255);
00092   SETCOLOR(clrWhite,       0xFC, 0xFC, 0xFC, 255);
00093 #else
00094   w *= charWidth;
00095   h *= lineHeight;
00096   d *= lineHeight;
00097   int x = (720 - w + charWidth) / 2; //TODO PAL vs. NTSC???
00098   int y = (576 - Setup.OSDheight * lineHeight) / 2 + d;
00099   //XXX
00100   osd = OpenRaw(x, y);
00101   //XXX TODO this should be transferred to the places where the individual windows are requested (there's too much detailed knowledge here!)
00102   if (h / lineHeight == 5) { //XXX channel display
00103      osd->Create(0,              0, w, h, 4);
00104      }
00105   else if (h / lineHeight == 1) { //XXX info display
00106      osd->Create(0,              0, w, h, 4);
00107      }
00108   else if (d == 0) { //XXX full menu
00109      osd->Create(0,                            0, w,                         lineHeight, 2);
00110      osd->Create(0,                   lineHeight, w, (Setup.OSDheight - 3) * lineHeight, 2);
00111      osd->AddColor(clrBackground);
00112      osd->AddColor(clrCyan);
00113      osd->AddColor(clrWhite);
00114      osd->AddColor(clrBlack);
00115      osd->Create(0, (Setup.OSDheight - 2) * lineHeight, w,               2 * lineHeight, 4);
00116      }
00117   else { //XXX progress display
00118      /*XXX
00119      osd->Create(0,              0, w, lineHeight, 1);
00120      osd->Create(0,     lineHeight, w, lineHeight, 2, false);
00121      osd->Create(0, 2 * lineHeight, w, lineHeight, 1);
00122      XXX*///XXX some pixels are not drawn correctly with lower bpp values
00123      osd->Create(0,              0, w, h, 4);
00124      }
00125 #endif
00126 }
00127 
00128 void cOsd::Close(void)
00129 {
00130 #ifdef DEBUG_OSD
00131   if (window) {
00132      delwin(window);
00133      window = 0;
00134      }
00135 #else
00136   delete osd;
00137   osd = NULL;
00138 #endif
00139 }
00140 
00141 void cOsd::Clear(void)
00142 {
00143 #ifdef DEBUG_OSD
00144   SetColor(clrBackground, clrBackground);
00145   Fill(0, 0, cols, rows, clrBackground);
00146   refresh();
00147 #else
00148   osd->Clear();
00149 #endif
00150 }
00151 
00152 void cOsd::Fill(int x, int y, int w, int h, eDvbColor color)
00153 {
00154   if (x < 0) x = cols + x;
00155   if (y < 0) y = rows + y;
00156 #ifdef DEBUG_OSD
00157   SetColor(color, color);
00158   for (int r = 0; r < h; r++) {
00159       wmove(window, y + r, x); // ncurses wants 'y' before 'x'!
00160       whline(window, ' ', w);
00161       }
00162   wsyncup(window); // shouldn't be necessary because of 'syncok()', but w/o it doesn't work
00163 #else
00164   osd->Fill(x * charWidth, y * lineHeight, (x + w) * charWidth - 1, (y + h) * lineHeight - 1, color);
00165 #endif
00166 }
00167 
00168 void cOsd::SetBitmap(int x, int y, const cBitmap &Bitmap)
00169 {
00170 #ifndef DEBUG_OSD
00171   osd->SetBitmap(x, y, Bitmap);
00172 #endif
00173 }
00174 
00175 void cOsd::ClrEol(int x, int y, eDvbColor color)
00176 {
00177   Fill(x, y, cols - x, 1, color);
00178 }
00179 
00180 int cOsd::CellWidth(void)
00181 {
00182 #ifdef DEBUG_OSD
00183   return 1;
00184 #else
00185   return charWidth;
00186 #endif
00187 }
00188 
00189 int cOsd::LineHeight(void)
00190 {
00191 #ifdef DEBUG_OSD
00192   return 1;
00193 #else
00194   return lineHeight;
00195 #endif
00196 }
00197 
00198 int cOsd::Width(unsigned char c)
00199 {
00200 #ifdef DEBUG_OSD
00201   return 1;
00202 #else
00203   return osd->Width(c);
00204 #endif
00205 }
00206 
00207 int cOsd::WidthInCells(const char *s)
00208 {
00209 #ifdef DEBUG_OSD
00210   return strlen(s);
00211 #else
00212   return (osd->Width(s) + charWidth - 1) / charWidth;
00213 #endif
00214 }
00215 
00216 eDvbFont cOsd::SetFont(eDvbFont Font)
00217 {
00218 #ifdef DEBUG_OSD
00219   return Font;
00220 #else
00221   return osd->SetFont(Font);
00222 #endif
00223 }
00224 
00225 void cOsd::Text(int x, int y, const char *s, eDvbColor colorFg, eDvbColor colorBg)
00226 {
00227   if (x < 0) x = cols + x;
00228   if (y < 0) y = rows + y;
00229 #ifdef DEBUG_OSD
00230   SetColor(colorFg, colorBg);
00231   wmove(window, y, x); // ncurses wants 'y' before 'x'!
00232   waddnstr(window, s, cols - x);
00233 #else
00234   osd->Text(x * charWidth, y * lineHeight, s, colorFg, colorBg);
00235 #endif
00236 }
00237 
00238 void cOsd::Flush(void)
00239 {
00240 #ifdef DEBUG_OSD
00241   refresh();
00242 #else
00243   if (osd)
00244      osd->Flush();
00245 #endif
00246 }
00247 
00248 // --- cOsdItem --------------------------------------------------------------
00249 
00250 cOsdItem::cOsdItem(eOSState State)
00251 {
00252   text = NULL;
00253   offset = -1;
00254   state = State;
00255   fresh = false;
00256   userColor = false;
00257   fgColor = clrWhite;
00258   bgColor = clrBackground;
00259 }
00260 
00261 cOsdItem::cOsdItem(const char *Text, eOSState State)
00262 {
00263   text = NULL;
00264   offset = -1;
00265   state = State;
00266   fresh = false;
00267   userColor = false;
00268   fgColor = clrWhite;
00269   bgColor = clrBackground;
00270   SetText(Text);
00271 }
00272 
00273 cOsdItem::~cOsdItem()
00274 {
00275   free(text);
00276 }
00277 
00278 void cOsdItem::SetText(const char *Text, bool Copy)
00279 {
00280   free(text);
00281   text = Copy ? strdup(Text) : (char *)Text; // text assumes ownership!
00282 }
00283 
00284 void cOsdItem::SetColor(eDvbColor FgColor, eDvbColor BgColor)
00285 {
00286   userColor = true;
00287   fgColor = FgColor; 
00288   bgColor = BgColor; 
00289 }
00290 
00291 void cOsdItem::Display(int Offset, eDvbColor FgColor, eDvbColor BgColor)
00292 {
00293   if (Offset < 0) {
00294      FgColor = clrBlack;
00295      BgColor = clrCyan;
00296      }
00297   fresh |= Offset >= 0;
00298   if (Offset >= 0)
00299      offset = Offset;
00300   if (offset >= 0)
00301      Interface->WriteText(0, offset + 2, text, userColor ? fgColor : FgColor, userColor ? bgColor : BgColor);
00302 }
00303 
00304 eOSState cOsdItem::ProcessKey(eKeys Key)
00305 {
00306   return Key == kOk ? state : osUnknown;
00307 }
00308 
00309 // --- cOsdMenu --------------------------------------------------------------
00310 
00311 cOsdMenu::cOsdMenu(const char *Title, int c0, int c1, int c2, int c3, int c4)
00312 {
00313   isMenu = true;
00314   digit = 0;
00315   hasHotkeys = false;
00316   visible = false;
00317   title = NULL;
00318   SetTitle(Title);
00319   cols[0] = c0;
00320   cols[1] = c1;
00321   cols[2] = c2;
00322   cols[3] = c3;
00323   cols[4] = c4;
00324   first = 0;
00325   current = marked = -1;
00326   subMenu = NULL;
00327   helpRed = helpGreen = helpYellow = helpBlue = NULL;
00328   status = NULL;
00329   Interface->Open();
00330 }
00331 
00332 cOsdMenu::~cOsdMenu()
00333 {
00334   free(title);
00335   delete subMenu;
00336   free(status);
00337   Interface->Clear();
00338   Interface->Close();
00339 }
00340 
00341 const char *cOsdMenu::hk(const char *s)
00342 {
00343   static char buffer[64];
00344   if (s && hasHotkeys) {
00345      if (digit == 0 && '1' <= *s && *s <= '9' && *(s + 1) == ' ')
00346         digit = -1; // prevents automatic hotkeys - input already has them
00347      if (digit >= 0) {
00348         digit++;
00349         snprintf(buffer, sizeof(buffer), " %c %s", (digit < 10) ? '0' + digit : ' ' , s);
00350         s = buffer;
00351         }
00352      }
00353   return s;
00354 }
00355 
00356 void cOsdMenu::SetHasHotkeys(void)
00357 {
00358   hasHotkeys = true;
00359   digit = 0;
00360 }
00361 
00362 void cOsdMenu::SetStatus(const char *s)
00363 {
00364   free(status);
00365   status = s ? strdup(s) : NULL;
00366   if (visible)
00367      Interface->Status(status);
00368 }
00369 
00370 void cOsdMenu::SetTitle(const char *Title, bool ShowDate)
00371 {
00372   free(title);
00373   if (ShowDate)
00374      asprintf(&title, "%s\t%s", Title, DayDateTime(time(NULL)));
00375   else
00376      title = strdup(Title);
00377 }
00378 
00379 void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue)
00380 {
00381   // strings are NOT copied - must be constants!!!
00382   helpRed    = Red;
00383   helpGreen  = Green;
00384   helpYellow = Yellow;
00385   helpBlue   = Blue;
00386   if (visible)
00387      Interface->Help(helpRed, helpGreen, helpYellow, helpBlue);
00388 }
00389 
00390 void cOsdMenu::Del(int Index)
00391 {
00392   cList<cOsdItem>::Del(Get(Index));
00393   if (current == Count())
00394      current--;
00395   if (Index == first && first > 0)
00396      first--;
00397 }
00398 
00399 void cOsdMenu::Add(cOsdItem *Item, bool Current, cOsdItem *After)
00400 {
00401   cList<cOsdItem>::Add(Item, After);
00402   if (Current)
00403      current = Item->Index();
00404 }
00405 
00406 void cOsdMenu::Ins(cOsdItem *Item, bool Current, cOsdItem *Before)
00407 {
00408   cList<cOsdItem>::Ins(Item, Before);
00409   if (Current)
00410      current = Item->Index();
00411 }
00412 
00413 void cOsdMenu::Display(void)
00414 {
00415   if (subMenu) {
00416      subMenu->Display();
00417      return;
00418      }
00419   visible = true;
00420   Interface->Clear();
00421   Interface->SetCols(cols);
00422   Interface->Title(title);
00423   Interface->Help(helpRed, helpGreen, helpYellow, helpBlue);
00424   int count = Count();
00425   if (count > 0) {
00426      if (current < 0)
00427         current = 0; // just for safety - there HAS to be a current item!
00428      int n = 0;
00429      if (current - first >= MAXOSDITEMS) {
00430         first = current - MAXOSDITEMS / 2;
00431         if (first + MAXOSDITEMS > count)
00432            first = count - MAXOSDITEMS;
00433         if (first < 0)
00434            first = 0;
00435         }
00436      for (int i = first; i < count; i++) {
00437          cOsdItem *item = Get(i);
00438          if (item) {
00439             item->Display(i - first, i == current ? clrBlack : clrWhite, i == current ? clrCyan : clrBackground);
00440             if (i == current)
00441                cStatus::MsgOsdCurrentItem(item->Text());
00442             }
00443          if (++n == MAXOSDITEMS) //TODO get this from Interface!!!
00444             break;
00445          }
00446      }
00447   if (!isempty(status))
00448      Interface->Status(status);
00449 }
00450 
00451 void cOsdMenu::SetCurrent(cOsdItem *Item)
00452 {
00453   current = Item ? Item->Index() : -1;
00454 }
00455 
00456 void cOsdMenu::RefreshCurrent(void)
00457 {
00458   cOsdItem *item = Get(current);
00459   if (item)
00460      item->Set();
00461 }
00462 
00463 void cOsdMenu::DisplayCurrent(bool Current)
00464 {
00465   cOsdItem *item = Get(current);
00466   if (item) {
00467      item->Display(current - first, Current ? clrBlack : clrWhite, Current ? clrCyan : clrBackground);
00468      if (Current)
00469         cStatus::MsgOsdCurrentItem(item->Text());
00470      }
00471 }
00472 
00473 void cOsdMenu::Clear(void)
00474 {
00475   first = 0;
00476   current = marked = -1;
00477   cList<cOsdItem>::Clear();
00478 }
00479 
00480 bool cOsdMenu::SpecialItem(int idx)
00481 {
00482   cOsdItem *item = Get(idx);
00483   return item && item->HasUserColor();
00484 }
00485 
00486 void cOsdMenu::CursorUp(void)
00487 {
00488   if (current > 0) {
00489      int tmpCurrent = current;
00490      while (--tmpCurrent >= 0 && SpecialItem(tmpCurrent));
00491      if (tmpCurrent < 0)
00492         return;
00493      if (tmpCurrent >= first)
00494         DisplayCurrent(false);
00495      current = tmpCurrent;
00496      if (current < first) {
00497         first = first > MAXOSDITEMS - 1 ? first - (MAXOSDITEMS - 1) : 0;
00498         if (Setup.MenuScrollPage)
00499            current = SpecialItem(first) ? first + 1 : first;
00500         Display();
00501         }
00502      else
00503         DisplayCurrent(true);
00504      }
00505 }
00506 
00507 void cOsdMenu::CursorDown(void)
00508 {
00509   int last = Count() - 1;
00510   int lastOnScreen = first + MAXOSDITEMS - 1;
00511 
00512   if (current < last) {
00513      int tmpCurrent = current;
00514      while (++tmpCurrent <= last && SpecialItem(tmpCurrent));
00515      if (tmpCurrent > last)
00516         return;
00517      if (tmpCurrent <= lastOnScreen)
00518         DisplayCurrent(false);
00519      current = tmpCurrent;
00520      if (current > lastOnScreen) {
00521         first += MAXOSDITEMS - 1;
00522         lastOnScreen = first + MAXOSDITEMS - 1;
00523         if (lastOnScreen > last) {
00524            first = last - (MAXOSDITEMS - 1);
00525            lastOnScreen = last;
00526            }
00527         if (Setup.MenuScrollPage)
00528            current = SpecialItem(lastOnScreen) ? lastOnScreen - 1 : lastOnScreen;
00529         Display();
00530         }
00531      else
00532         DisplayCurrent(true);
00533      }
00534 }
00535 
00536 void cOsdMenu::PageUp(void)
00537 {
00538   if (Count() <= MAXOSDITEMS)
00539      return;
00540   current -= MAXOSDITEMS;
00541   first -= MAXOSDITEMS;
00542   if (first < 0)
00543      first = current = 0;
00544   if (SpecialItem(current)) {
00545      current -= (current > 0) ? 1 : -1;
00546      first = min(first, current - 1);
00547      }
00548   Display();
00549   DisplayCurrent(true);
00550 }
00551 
00552 void cOsdMenu::PageDown(void) 
00553 {
00554   if (Count() <= MAXOSDITEMS)
00555      return;
00556   current += MAXOSDITEMS;
00557   first += MAXOSDITEMS;
00558   if (current > Count() - 1) {
00559      current = Count() - 1;
00560      first = Count() - MAXOSDITEMS;
00561      }
00562   if (SpecialItem(current)) {
00563      current += (current < Count() - 1) ? 1 : -1;
00564      first = max(first, current - MAXOSDITEMS);
00565      }
00566   Display();
00567   DisplayCurrent(true);
00568 }
00569 
00570 void cOsdMenu::Mark(void)
00571 {
00572   if (Count() && marked < 0) {
00573      marked = current;
00574      SetStatus(tr("Up/Dn for new location - OK to move"));
00575      }
00576 }
00577 
00578 eOSState cOsdMenu::HotKey(eKeys Key)
00579 {
00580   for (cOsdItem *item = First(); item; item = Next(item)) {
00581       const char *s = item->Text();
00582       if (s && (s = skipspace(s)) != NULL) {
00583          if (*s == Key - k1 + '1') {
00584             current = item->Index();
00585             return ProcessKey(kOk);
00586             }
00587          }
00588       }
00589   return osContinue;
00590 }
00591 
00592 eOSState cOsdMenu::AddSubMenu(cOsdMenu *SubMenu)
00593 {
00594   delete subMenu;
00595   subMenu = SubMenu;
00596   subMenu->Display();
00597   return osContinue; // convenience return value
00598 }
00599 
00600 eOSState cOsdMenu::CloseSubMenu()
00601 {
00602   delete subMenu;
00603   subMenu = NULL;
00604   RefreshCurrent();
00605   Display();
00606   return osContinue; // convenience return value
00607 }
00608 
00609 eOSState cOsdMenu::ProcessKey(eKeys Key)
00610 {
00611   if (subMenu) {
00612      eOSState state = subMenu->ProcessKey(Key);
00613      if (state == osBack)
00614         return CloseSubMenu();
00615      return state;
00616      }
00617 
00618   cOsdItem *item = Get(current);
00619   if (marked < 0 && item) {
00620      eOSState state = item->ProcessKey(Key);
00621      if (state != osUnknown)
00622         return state;
00623      }
00624   switch (Key) {
00625     case k1...k9: return hasHotkeys ? HotKey(Key) : osUnknown;
00626     case kUp|k_Repeat:
00627     case kUp:   CursorUp();   break;
00628     case kDown|k_Repeat:
00629     case kDown: CursorDown(); break;
00630     case kLeft|k_Repeat:
00631     case kLeft: PageUp(); break;
00632     case kRight|k_Repeat:
00633     case kRight: PageDown(); break;
00634     case kBack: return osBack;
00635     case kOk:   if (marked >= 0) {
00636                    SetStatus(NULL);
00637                    if (marked != current)
00638                       Move(marked, current);
00639                    marked = -1;
00640                    break;
00641                    }
00642                 // else run into default
00643     default: if (marked < 0)
00644                 return osUnknown;
00645     }
00646   return osContinue;
00647 }
00648 

Generated on Wed Feb 5 23:30:10 2003 for VDR by doxygen1.3-rc2