vdr
1.7.27
|
00001 /* 00002 * skincurses.c: A plugin for the Video Disk Recorder 00003 * 00004 * See the README file for copyright information and how to reach the author. 00005 * 00006 * $Id: skincurses.c 2.8 2012/03/11 14:42:52 kls Exp $ 00007 */ 00008 00009 #include <ncurses.h> 00010 #include <vdr/osd.h> 00011 #include <vdr/plugin.h> 00012 #include <vdr/skins.h> 00013 00014 static const char *VERSION = "0.1.11"; 00015 static const char *DESCRIPTION = trNOOP("A text only skin"); 00016 static const char *MAINMENUENTRY = NULL; 00017 00018 // --- cCursesFont ----------------------------------------------------------- 00019 00020 class cCursesFont : public cFont { 00021 public: 00022 virtual int Width(uint c) const { return 1; } 00023 virtual int Width(const char *s) const { return s ? Utf8StrLen(s) : 0; } 00024 virtual int Height(void) const { return 1; } 00025 virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const {} 00026 virtual void DrawText(cPixmap *Pixmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const {} 00027 }; 00028 00029 static const cCursesFont Font = cCursesFont(); // w/o the '= cCursesFont()' gcc 4.6 complains - can anybody explain why this is necessary? 00030 00031 // --- cCursesOsd ------------------------------------------------------------ 00032 00033 #define clrBackground COLOR_BLACK 00034 #define clrTransparent clrBackground 00035 #define clrBlack clrBackground 00036 #define clrRed COLOR_RED 00037 #define clrGreen COLOR_GREEN 00038 #define clrYellow COLOR_YELLOW 00039 #define clrBlue COLOR_BLUE 00040 #define clrMagenta COLOR_MAGENTA 00041 #define clrCyan COLOR_CYAN 00042 #define clrWhite COLOR_WHITE 00043 00044 static int clrMessage[] = { 00045 clrBlack, 00046 clrCyan, 00047 clrBlack, 00048 clrGreen, 00049 clrBlack, 00050 clrYellow, 00051 clrWhite, 00052 clrRed 00053 }; 00054 00055 static int ScOsdWidth = 50; 00056 static int ScOsdHeight = 20; 00057 00058 class cCursesOsd : public cOsd { 00059 private: 00060 WINDOW *savedRegion; 00061 WINDOW *window; 00062 enum { MaxColorPairs = 16 }; 00063 int colorPairs[MaxColorPairs]; 00064 void SetColor(int colorFg, int colorBg = clrBackground); 00065 public: 00066 cCursesOsd(int Left, int Top); 00067 virtual ~cCursesOsd(); 00068 virtual void SaveRegion(int x1, int y1, int x2, int y2); 00069 virtual void RestoreRegion(void); 00070 virtual void DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width = 0, int Height = 0, int Alignment = taDefault); 00071 virtual void DrawRectangle(int x1, int y1, int x2, int y2, tColor Color); 00072 virtual void Flush(void); 00073 }; 00074 00075 cCursesOsd::cCursesOsd(int Left, int Top) 00076 :cOsd(Left, Top, 0) 00077 { 00078 savedRegion = NULL; 00079 00080 memset(colorPairs, 0x00, sizeof(colorPairs)); 00081 start_color(); 00082 leaveok(stdscr, true); 00083 00084 window = subwin(stdscr, ScOsdHeight, ScOsdWidth, 0, 0); 00085 syncok(window, true); 00086 } 00087 00088 cCursesOsd::~cCursesOsd() 00089 { 00090 if (window) { 00091 werase(window); 00092 Flush(); 00093 delwin(window); 00094 window = NULL; 00095 } 00096 } 00097 00098 void cCursesOsd::SetColor(int colorFg, int colorBg) 00099 { 00100 int color = (colorBg << 16) | colorFg | 0x80000000; 00101 for (int i = 0; i < MaxColorPairs; i++) { 00102 if (!colorPairs[i]) { 00103 colorPairs[i] = color; 00104 init_pair(i + 1, colorFg, colorBg); 00105 //XXX??? attron(COLOR_PAIR(WHITE_ON_BLUE)); 00106 wattrset(window, COLOR_PAIR(i + 1)); 00107 break; 00108 } 00109 else if (color == colorPairs[i]) { 00110 wattrset(window, COLOR_PAIR(i + 1)); 00111 break; 00112 } 00113 } 00114 } 00115 00116 void cCursesOsd::SaveRegion(int x1, int y1, int x2, int y2) 00117 { 00118 if (savedRegion) { 00119 delwin(savedRegion); 00120 savedRegion = NULL; 00121 } 00122 savedRegion = newwin(y2 - y1 + 1, x2 - x1 + 1, y1, x1); 00123 copywin(window, savedRegion, y1, x1, 0, 0, y2 - y1, x2 - x1, false); 00124 } 00125 00126 void cCursesOsd::RestoreRegion(void) 00127 { 00128 if (savedRegion) { 00129 copywin(savedRegion, window, 0, 0, savedRegion->_begy, savedRegion->_begx, savedRegion->_maxy - savedRegion->_begy, savedRegion->_maxx - savedRegion->_begx, false); 00130 delwin(savedRegion); 00131 savedRegion = NULL; 00132 } 00133 } 00134 00135 void cCursesOsd::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment) 00136 { 00137 int w = Font->Width(s); 00138 int h = Font->Height(); 00139 if (Width || Height) { 00140 int cw = Width ? Width : w; 00141 int ch = Height ? Height : h; 00142 DrawRectangle(x, y, x + cw - 1, y + ch - 1, ColorBg); 00143 if (Width) { 00144 if ((Alignment & taLeft) != 0) 00145 ; 00146 else if ((Alignment & taRight) != 0) { 00147 if (w < Width) 00148 x += Width - w; 00149 } 00150 else { // taCentered 00151 if (w < Width) 00152 x += (Width - w) / 2; 00153 } 00154 } 00155 if (Height) { 00156 if ((Alignment & taTop) != 0) 00157 ; 00158 else if ((Alignment & taBottom) != 0) { 00159 if (h < Height) 00160 y += Height - h; 00161 } 00162 else { // taCentered 00163 if (h < Height) 00164 y += (Height - h) / 2; 00165 } 00166 } 00167 } 00168 SetColor(ColorFg, ColorBg); 00169 wmove(window, y, x); // ncurses wants 'y' before 'x'! 00170 waddnstr(window, s, Width ? Width : ScOsdWidth - x); 00171 } 00172 00173 void cCursesOsd::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color) 00174 { 00175 SetColor(Color, Color); 00176 for (int y = y1; y <= y2; y++) { 00177 wmove(window, y, x1); // ncurses wants 'y' before 'x'! 00178 whline(window, ' ', x2 - x1 + 1); 00179 } 00180 wsyncup(window); // shouldn't be necessary because of 'syncok()', but w/o it doesn't work 00181 } 00182 00183 void cCursesOsd::Flush(void) 00184 { 00185 refresh(); 00186 } 00187 00188 // --- cSkinCursesDisplayChannel --------------------------------------------- 00189 00190 class cSkinCursesDisplayChannel : public cSkinDisplayChannel { 00191 private: 00192 cOsd *osd; 00193 int timeWidth; 00194 bool message; 00195 public: 00196 cSkinCursesDisplayChannel(bool WithInfo); 00197 virtual ~cSkinCursesDisplayChannel(); 00198 virtual void SetChannel(const cChannel *Channel, int Number); 00199 virtual void SetEvents(const cEvent *Present, const cEvent *Following); 00200 virtual void SetMessage(eMessageType Type, const char *Text); 00201 virtual void Flush(void); 00202 }; 00203 00204 cSkinCursesDisplayChannel::cSkinCursesDisplayChannel(bool WithInfo) 00205 { 00206 int Lines = WithInfo ? 5 : 1; 00207 message = false; 00208 osd = new cCursesOsd(0, Setup.ChannelInfoPos ? 0 : ScOsdHeight - Lines); 00209 timeWidth = strlen("00:00"); 00210 osd->DrawRectangle(0, 0, ScOsdWidth - 1, Lines - 1, clrBackground); 00211 } 00212 00213 cSkinCursesDisplayChannel::~cSkinCursesDisplayChannel() 00214 { 00215 delete osd; 00216 } 00217 00218 void cSkinCursesDisplayChannel::SetChannel(const cChannel *Channel, int Number) 00219 { 00220 osd->DrawRectangle(0, 0, ScOsdWidth - 1, 0, clrBackground); 00221 osd->DrawText(0, 0, ChannelString(Channel, Number), clrWhite, clrBackground, &Font); 00222 } 00223 00224 void cSkinCursesDisplayChannel::SetEvents(const cEvent *Present, const cEvent *Following) 00225 { 00226 osd->DrawRectangle(0, 1, timeWidth - 1, 4, clrRed); 00227 osd->DrawRectangle(timeWidth, 1, ScOsdWidth - 1, 4, clrBackground); 00228 for (int i = 0; i < 2; i++) { 00229 const cEvent *e = !i ? Present : Following; 00230 if (e) { 00231 osd->DrawText( 0, 2 * i + 1, e->GetTimeString(), clrWhite, clrRed, &Font); 00232 osd->DrawText(timeWidth + 1, 2 * i + 1, e->Title(), clrCyan, clrBackground, &Font); 00233 osd->DrawText(timeWidth + 1, 2 * i + 2, e->ShortText(), clrYellow, clrBackground, &Font); 00234 } 00235 } 00236 } 00237 00238 void cSkinCursesDisplayChannel::SetMessage(eMessageType Type, const char *Text) 00239 { 00240 if (Text) { 00241 osd->SaveRegion(0, 0, ScOsdWidth - 1, 0); 00242 osd->DrawText(0, 0, Text, clrMessage[2 * Type], clrMessage[2 * Type + 1], &Font, ScOsdWidth, 0, taCenter); 00243 message = true; 00244 } 00245 else { 00246 osd->RestoreRegion(); 00247 message = false; 00248 } 00249 } 00250 00251 void cSkinCursesDisplayChannel::Flush(void) 00252 { 00253 if (!message) { 00254 cString date = DayDateTime(); 00255 osd->DrawText(ScOsdWidth - Utf8StrLen(date), 0, date, clrWhite, clrBackground, &Font); 00256 } 00257 osd->Flush(); 00258 } 00259 00260 // --- cSkinCursesDisplayMenu ------------------------------------------------ 00261 00262 class cSkinCursesDisplayMenu : public cSkinDisplayMenu { 00263 private: 00264 cOsd *osd; 00265 void DrawScrollbar(int Total, int Offset, int Shown, int Top, int Height, bool CanScrollUp, bool CanScrollDown); 00266 void SetTextScrollbar(void); 00267 public: 00268 cSkinCursesDisplayMenu(void); 00269 virtual ~cSkinCursesDisplayMenu(); 00270 virtual void Scroll(bool Up, bool Page); 00271 virtual int MaxItems(void); 00272 virtual void Clear(void); 00273 virtual void SetTitle(const char *Title); 00274 virtual void SetButtons(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL); 00275 virtual void SetMessage(eMessageType Type, const char *Text); 00276 virtual void SetItem(const char *Text, int Index, bool Current, bool Selectable); 00277 virtual void SetScrollbar(int Total, int Offset); 00278 virtual void SetEvent(const cEvent *Event); 00279 virtual void SetRecording(const cRecording *Recording); 00280 virtual void SetText(const char *Text, bool FixedFont); 00281 virtual const cFont *GetTextAreaFont(bool FixedFont) const { return &Font; } 00282 virtual void Flush(void); 00283 }; 00284 00285 cSkinCursesDisplayMenu::cSkinCursesDisplayMenu(void) 00286 { 00287 osd = new cCursesOsd(0, 0); 00288 osd->DrawRectangle(0, 0, ScOsdWidth - 1, ScOsdHeight - 1, clrBackground); 00289 } 00290 00291 cSkinCursesDisplayMenu::~cSkinCursesDisplayMenu() 00292 { 00293 delete osd; 00294 } 00295 00296 void cSkinCursesDisplayMenu::DrawScrollbar(int Total, int Offset, int Shown, int Top, int Height, bool CanScrollUp, bool CanScrollDown) 00297 { 00298 if (Total > 0 && Total > Shown) { 00299 int yt = Top; 00300 int yb = yt + Height; 00301 int st = yt; 00302 int sb = yb; 00303 int th = max(int((sb - st) * double(Shown) / Total + 0.5), 1); 00304 int tt = min(int(st + (sb - st) * double(Offset) / Total + 0.5), sb - th); 00305 int tb = min(tt + th, sb); 00306 int xl = ScOsdWidth - 1; 00307 osd->DrawRectangle(xl, st, xl, sb - 1, clrWhite); 00308 osd->DrawRectangle(xl, tt, xl, tb - 1, clrCyan); 00309 } 00310 } 00311 00312 void cSkinCursesDisplayMenu::SetTextScrollbar(void) 00313 { 00314 if (textScroller.CanScroll()) 00315 DrawScrollbar(textScroller.Total(), textScroller.Offset(), textScroller.Shown(), textScroller.Top(), textScroller.Height(), textScroller.CanScrollUp(), textScroller.CanScrollDown()); 00316 } 00317 00318 void cSkinCursesDisplayMenu::Scroll(bool Up, bool Page) 00319 { 00320 cSkinDisplayMenu::Scroll(Up, Page); 00321 SetTextScrollbar(); 00322 } 00323 00324 int cSkinCursesDisplayMenu::MaxItems(void) 00325 { 00326 return ScOsdHeight - 4; 00327 } 00328 00329 void cSkinCursesDisplayMenu::Clear(void) 00330 { 00331 osd->DrawRectangle(0, 1, ScOsdWidth - 1, ScOsdHeight - 2, clrBackground); 00332 textScroller.Reset(); 00333 } 00334 00335 void cSkinCursesDisplayMenu::SetTitle(const char *Title) 00336 { 00337 osd->DrawText(0, 0, Title, clrBlack, clrCyan, &Font, ScOsdWidth); 00338 } 00339 00340 void cSkinCursesDisplayMenu::SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue) 00341 { 00342 int w = ScOsdWidth; 00343 int t0 = 0; 00344 int t1 = 0 + w / 4; 00345 int t2 = 0 + w / 2; 00346 int t3 = w - w / 4; 00347 int t4 = w; 00348 int y = ScOsdHeight - 1; 00349 osd->DrawText(t0, y, Red, clrWhite, Red ? clrRed : clrBackground, &Font, t1 - t0, 0, taCenter); 00350 osd->DrawText(t1, y, Green, clrBlack, Green ? clrGreen : clrBackground, &Font, t2 - t1, 0, taCenter); 00351 osd->DrawText(t2, y, Yellow, clrBlack, Yellow ? clrYellow : clrBackground, &Font, t3 - t2, 0, taCenter); 00352 osd->DrawText(t3, y, Blue, clrWhite, Blue ? clrBlue : clrBackground, &Font, t4 - t3, 0, taCenter); 00353 } 00354 00355 void cSkinCursesDisplayMenu::SetMessage(eMessageType Type, const char *Text) 00356 { 00357 if (Text) 00358 osd->DrawText(0, ScOsdHeight - 2, Text, clrMessage[2 * Type], clrMessage[2 * Type + 1], &Font, ScOsdWidth, 0, taCenter); 00359 else 00360 osd->DrawRectangle(0, ScOsdHeight - 2, ScOsdWidth - 1, ScOsdHeight - 2, clrBackground); 00361 } 00362 00363 void cSkinCursesDisplayMenu::SetItem(const char *Text, int Index, bool Current, bool Selectable) 00364 { 00365 int y = 2 + Index; 00366 int ColorFg, ColorBg; 00367 if (Current) { 00368 ColorFg = clrBlack; 00369 ColorBg = clrCyan; 00370 } 00371 else { 00372 ColorFg = Selectable ? clrWhite : clrCyan; 00373 ColorBg = clrBackground; 00374 } 00375 for (int i = 0; i < MaxTabs; i++) { 00376 const char *s = GetTabbedText(Text, i); 00377 if (s) { 00378 int xt = Tab(i) / AvgCharWidth();// Tab() is in "pixel" - see also skins.c!!! 00379 osd->DrawText(xt, y, s, ColorFg, ColorBg, &Font, ScOsdWidth - 2 - xt); 00380 } 00381 if (!Tab(i + 1)) 00382 break; 00383 } 00384 SetEditableWidth(ScOsdWidth - 2 - Tab(1) / AvgCharWidth()); // Tab() is in "pixel" - see also skins.c!!! 00385 } 00386 00387 void cSkinCursesDisplayMenu::SetScrollbar(int Total, int Offset) 00388 { 00389 DrawScrollbar(Total, Offset, MaxItems(), 2, MaxItems(), Offset > 0, Offset + MaxItems() < Total); 00390 } 00391 00392 void cSkinCursesDisplayMenu::SetEvent(const cEvent *Event) 00393 { 00394 if (!Event) 00395 return; 00396 int y = 2; 00397 cTextScroller ts; 00398 char t[32]; 00399 snprintf(t, sizeof(t), "%s %s - %s", *Event->GetDateString(), *Event->GetTimeString(), *Event->GetEndTimeString()); 00400 ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, t, &Font, clrYellow, clrBackground); 00401 if (Event->Vps() && Event->Vps() != Event->StartTime()) { 00402 cString buffer = cString::sprintf(" VPS: %s", *Event->GetVpsString()); 00403 osd->DrawText(ScOsdWidth - Utf8StrLen(buffer), y, buffer, clrBlack, clrYellow, &Font); 00404 } 00405 y += ts.Height(); 00406 if (Event->ParentalRating()) { 00407 cString buffer = cString::sprintf(" %s ", *Event->GetParentalRatingString()); 00408 osd->DrawText(ScOsdWidth - Utf8StrLen(buffer), y, buffer, clrBlack, clrYellow, &Font); 00409 } 00410 y += 1; 00411 ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, Event->Title(), &Font, clrCyan, clrBackground); 00412 y += ts.Height(); 00413 if (!isempty(Event->ShortText())) { 00414 ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, Event->ShortText(), &Font, clrYellow, clrBackground); 00415 y += ts.Height(); 00416 } 00417 for (int i = 0; Event->Contents(i); i++) { 00418 const char *s = Event->ContentToString(Event->Contents(i)); 00419 if (!isempty(s)) { 00420 ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, s, &Font, clrYellow, clrBackground); 00421 y += 1; 00422 } 00423 } 00424 y += 1; 00425 if (!isempty(Event->Description())) { 00426 textScroller.Set(osd, 0, y, ScOsdWidth - 2, ScOsdHeight - y - 2, Event->Description(), &Font, clrCyan, clrBackground); 00427 SetTextScrollbar(); 00428 } 00429 } 00430 00431 void cSkinCursesDisplayMenu::SetRecording(const cRecording *Recording) 00432 { 00433 if (!Recording) 00434 return; 00435 const cRecordingInfo *Info = Recording->Info(); 00436 int y = 2; 00437 cTextScroller ts; 00438 char t[32]; 00439 snprintf(t, sizeof(t), "%s %s", *DateString(Recording->Start()), *TimeString(Recording->Start())); 00440 ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, t, &Font, clrYellow, clrBackground); 00441 y += ts.Height(); 00442 if (Info->GetEvent()->ParentalRating()) { 00443 cString buffer = cString::sprintf(" %s ", *Info->GetEvent()->GetParentalRatingString()); 00444 osd->DrawText(ScOsdWidth - Utf8StrLen(buffer), y, buffer, clrBlack, clrYellow, &Font); 00445 } 00446 y += 1; 00447 const char *Title = Info->Title(); 00448 if (isempty(Title)) 00449 Title = Recording->Name(); 00450 ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, Title, &Font, clrCyan, clrBackground); 00451 y += ts.Height(); 00452 if (!isempty(Info->ShortText())) { 00453 ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, Info->ShortText(), &Font, clrYellow, clrBackground); 00454 y += ts.Height(); 00455 } 00456 for (int i = 0; Info->GetEvent()->Contents(i); i++) { 00457 const char *s = Info->GetEvent()->ContentToString(Info->GetEvent()->Contents(i)); 00458 if (!isempty(s)) { 00459 ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, s, &Font, clrYellow, clrBackground); 00460 y += 1; 00461 } 00462 } 00463 y += 1; 00464 if (!isempty(Info->Description())) { 00465 textScroller.Set(osd, 0, y, ScOsdWidth - 2, ScOsdHeight - y - 2, Info->Description(), &Font, clrCyan, clrBackground); 00466 SetTextScrollbar(); 00467 } 00468 } 00469 00470 void cSkinCursesDisplayMenu::SetText(const char *Text, bool FixedFont) 00471 { 00472 textScroller.Set(osd, 0, 2, ScOsdWidth - 2, ScOsdHeight - 4, Text, &Font, clrWhite, clrBackground); 00473 SetTextScrollbar(); 00474 } 00475 00476 void cSkinCursesDisplayMenu::Flush(void) 00477 { 00478 cString date = DayDateTime(); 00479 osd->DrawText(ScOsdWidth - Utf8StrLen(date) - 2, 0, date, clrBlack, clrCyan, &Font); 00480 osd->Flush(); 00481 } 00482 00483 // --- cSkinCursesDisplayReplay ---------------------------------------------- 00484 00485 class cSkinCursesDisplayReplay : public cSkinDisplayReplay { 00486 private: 00487 cOsd *osd; 00488 bool message; 00489 public: 00490 cSkinCursesDisplayReplay(bool ModeOnly); 00491 virtual ~cSkinCursesDisplayReplay(); 00492 virtual void SetTitle(const char *Title); 00493 virtual void SetMode(bool Play, bool Forward, int Speed); 00494 virtual void SetProgress(int Current, int Total); 00495 virtual void SetCurrent(const char *Current); 00496 virtual void SetTotal(const char *Total); 00497 virtual void SetJump(const char *Jump); 00498 virtual void SetMessage(eMessageType Type, const char *Text); 00499 virtual void Flush(void); 00500 }; 00501 00502 cSkinCursesDisplayReplay::cSkinCursesDisplayReplay(bool ModeOnly) 00503 { 00504 message = false; 00505 osd = new cCursesOsd(0, ScOsdHeight - 3); 00506 osd->DrawRectangle(0, 0, ScOsdWidth - 1, 2, ModeOnly ? clrTransparent : clrBackground); 00507 } 00508 00509 cSkinCursesDisplayReplay::~cSkinCursesDisplayReplay() 00510 { 00511 delete osd; 00512 } 00513 00514 void cSkinCursesDisplayReplay::SetTitle(const char *Title) 00515 { 00516 osd->DrawText(0, 0, Title, clrWhite, clrBackground, &Font, ScOsdWidth); 00517 } 00518 00519 void cSkinCursesDisplayReplay::SetMode(bool Play, bool Forward, int Speed) 00520 { 00521 if (Setup.ShowReplayMode) { 00522 const char *Mode; 00523 if (Speed == -1) Mode = Play ? " > " : " || "; 00524 else if (Play) Mode = Forward ? " X>> " : " <<X "; 00525 else Mode = Forward ? " X|> " : " <|X "; 00526 char buf[16]; 00527 strn0cpy(buf, Mode, sizeof(buf)); 00528 char *p = strchr(buf, 'X'); 00529 if (p) 00530 *p = Speed > 0 ? '1' + Speed - 1 : ' '; 00531 SetJump(buf); 00532 } 00533 } 00534 00535 void cSkinCursesDisplayReplay::SetProgress(int Current, int Total) 00536 { 00537 int p = Total > 0 ? ScOsdWidth * Current / Total : 0; 00538 osd->DrawRectangle(0, 1, p, 1, clrGreen); 00539 osd->DrawRectangle(p, 1, ScOsdWidth, 1, clrWhite); 00540 } 00541 00542 void cSkinCursesDisplayReplay::SetCurrent(const char *Current) 00543 { 00544 osd->DrawText(0, 2, Current, clrWhite, clrBackground, &Font, Utf8StrLen(Current) + 3); 00545 } 00546 00547 void cSkinCursesDisplayReplay::SetTotal(const char *Total) 00548 { 00549 osd->DrawText(ScOsdWidth - Utf8StrLen(Total), 2, Total, clrWhite, clrBackground, &Font); 00550 } 00551 00552 void cSkinCursesDisplayReplay::SetJump(const char *Jump) 00553 { 00554 osd->DrawText(ScOsdWidth / 4, 2, Jump, clrWhite, clrBackground, &Font, ScOsdWidth / 2, 0, taCenter); 00555 } 00556 00557 void cSkinCursesDisplayReplay::SetMessage(eMessageType Type, const char *Text) 00558 { 00559 if (Text) { 00560 osd->SaveRegion(0, 2, ScOsdWidth - 1, 2); 00561 osd->DrawText(0, 2, Text, clrMessage[2 * Type], clrMessage[2 * Type + 1], &Font, ScOsdWidth, 0, taCenter); 00562 message = true; 00563 } 00564 else { 00565 osd->RestoreRegion(); 00566 message = false; 00567 } 00568 } 00569 00570 void cSkinCursesDisplayReplay::Flush(void) 00571 { 00572 osd->Flush(); 00573 } 00574 00575 // --- cSkinCursesDisplayVolume ---------------------------------------------- 00576 00577 class cSkinCursesDisplayVolume : public cSkinDisplayVolume { 00578 private: 00579 cOsd *osd; 00580 public: 00581 cSkinCursesDisplayVolume(void); 00582 virtual ~cSkinCursesDisplayVolume(); 00583 virtual void SetVolume(int Current, int Total, bool Mute); 00584 virtual void Flush(void); 00585 }; 00586 00587 cSkinCursesDisplayVolume::cSkinCursesDisplayVolume(void) 00588 { 00589 osd = new cCursesOsd(0, ScOsdHeight - 1); 00590 } 00591 00592 cSkinCursesDisplayVolume::~cSkinCursesDisplayVolume() 00593 { 00594 delete osd; 00595 } 00596 00597 void cSkinCursesDisplayVolume::SetVolume(int Current, int Total, bool Mute) 00598 { 00599 if (Mute) { 00600 osd->DrawRectangle(0, 0, ScOsdWidth - 1, 0, clrTransparent); 00601 osd->DrawText(0, 0, tr("Key$Mute"), clrGreen, clrBackground, &Font); 00602 } 00603 else { 00604 const char *Prompt = tr("Volume "); 00605 int l = Utf8StrLen(Prompt); 00606 int p = (ScOsdWidth - l) * Current / Total; 00607 osd->DrawText(0, 0, Prompt, clrGreen, clrBackground, &Font); 00608 osd->DrawRectangle(l, 0, l + p - 1, 0, clrGreen); 00609 osd->DrawRectangle(l + p, 0, ScOsdWidth - 1, 0, clrWhite); 00610 } 00611 } 00612 00613 void cSkinCursesDisplayVolume::Flush(void) 00614 { 00615 osd->Flush(); 00616 } 00617 00618 // --- cSkinCursesDisplayTracks ---------------------------------------------- 00619 00620 class cSkinCursesDisplayTracks : public cSkinDisplayTracks { 00621 private: 00622 cOsd *osd; 00623 int itemsWidth; 00624 int currentIndex; 00625 void SetItem(const char *Text, int Index, bool Current); 00626 public: 00627 cSkinCursesDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks); 00628 virtual ~cSkinCursesDisplayTracks(); 00629 virtual void SetTrack(int Index, const char * const *Tracks); 00630 virtual void SetAudioChannel(int AudioChannel) {} 00631 virtual void Flush(void); 00632 }; 00633 00634 cSkinCursesDisplayTracks::cSkinCursesDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks) 00635 { 00636 currentIndex = -1; 00637 itemsWidth = Font.Width(Title); 00638 for (int i = 0; i < NumTracks; i++) 00639 itemsWidth = max(itemsWidth, Font.Width(Tracks[i])); 00640 itemsWidth = min(itemsWidth, ScOsdWidth); 00641 osd = new cCursesOsd(0, 0); 00642 osd->DrawRectangle(0, 0, ScOsdWidth - 1, ScOsdHeight - 1, clrBackground); 00643 osd->DrawText(0, 0, Title, clrBlack, clrCyan, &Font, itemsWidth); 00644 for (int i = 0; i < NumTracks; i++) 00645 SetItem(Tracks[i], i, false); 00646 } 00647 00648 cSkinCursesDisplayTracks::~cSkinCursesDisplayTracks() 00649 { 00650 delete osd; 00651 } 00652 00653 void cSkinCursesDisplayTracks::SetItem(const char *Text, int Index, bool Current) 00654 { 00655 int y = 1 + Index; 00656 int ColorFg, ColorBg; 00657 if (Current) { 00658 ColorFg = clrBlack; 00659 ColorBg = clrCyan; 00660 currentIndex = Index; 00661 } 00662 else { 00663 ColorFg = clrWhite; 00664 ColorBg = clrBackground; 00665 } 00666 osd->DrawText(0, y, Text, ColorFg, ColorBg, &Font, itemsWidth); 00667 } 00668 00669 void cSkinCursesDisplayTracks::SetTrack(int Index, const char * const *Tracks) 00670 { 00671 if (currentIndex >= 0) 00672 SetItem(Tracks[currentIndex], currentIndex, false); 00673 SetItem(Tracks[Index], Index, true); 00674 } 00675 00676 void cSkinCursesDisplayTracks::Flush(void) 00677 { 00678 osd->Flush(); 00679 } 00680 00681 // --- cSkinCursesDisplayMessage --------------------------------------------- 00682 00683 class cSkinCursesDisplayMessage : public cSkinDisplayMessage { 00684 private: 00685 cOsd *osd; 00686 public: 00687 cSkinCursesDisplayMessage(void); 00688 virtual ~cSkinCursesDisplayMessage(); 00689 virtual void SetMessage(eMessageType Type, const char *Text); 00690 virtual void Flush(void); 00691 }; 00692 00693 cSkinCursesDisplayMessage::cSkinCursesDisplayMessage(void) 00694 { 00695 osd = new cCursesOsd(0, ScOsdHeight - 1); 00696 } 00697 00698 cSkinCursesDisplayMessage::~cSkinCursesDisplayMessage() 00699 { 00700 delete osd; 00701 } 00702 00703 void cSkinCursesDisplayMessage::SetMessage(eMessageType Type, const char *Text) 00704 { 00705 osd->DrawText(0, 0, Text, clrMessage[2 * Type], clrMessage[2 * Type + 1], &Font, ScOsdWidth, 0, taCenter); 00706 } 00707 00708 void cSkinCursesDisplayMessage::Flush(void) 00709 { 00710 osd->Flush(); 00711 } 00712 00713 // --- cSkinCurses ----------------------------------------------------------- 00714 00715 class cSkinCurses : public cSkin { 00716 public: 00717 cSkinCurses(void); 00718 virtual const char *Description(void); 00719 virtual cSkinDisplayChannel *DisplayChannel(bool WithInfo); 00720 virtual cSkinDisplayMenu *DisplayMenu(void); 00721 virtual cSkinDisplayReplay *DisplayReplay(bool ModeOnly); 00722 virtual cSkinDisplayVolume *DisplayVolume(void); 00723 virtual cSkinDisplayTracks *DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks); 00724 virtual cSkinDisplayMessage *DisplayMessage(void); 00725 }; 00726 00727 cSkinCurses::cSkinCurses(void) 00728 :cSkin("curses") 00729 { 00730 } 00731 00732 const char *cSkinCurses::Description(void) 00733 { 00734 return tr("Text mode"); 00735 } 00736 00737 cSkinDisplayChannel *cSkinCurses::DisplayChannel(bool WithInfo) 00738 { 00739 return new cSkinCursesDisplayChannel(WithInfo); 00740 } 00741 00742 cSkinDisplayMenu *cSkinCurses::DisplayMenu(void) 00743 { 00744 return new cSkinCursesDisplayMenu; 00745 } 00746 00747 cSkinDisplayReplay *cSkinCurses::DisplayReplay(bool ModeOnly) 00748 { 00749 return new cSkinCursesDisplayReplay(ModeOnly); 00750 } 00751 00752 cSkinDisplayVolume *cSkinCurses::DisplayVolume(void) 00753 { 00754 return new cSkinCursesDisplayVolume; 00755 } 00756 00757 cSkinDisplayTracks *cSkinCurses::DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks) 00758 { 00759 return new cSkinCursesDisplayTracks(Title, NumTracks, Tracks); 00760 } 00761 00762 cSkinDisplayMessage *cSkinCurses::DisplayMessage(void) 00763 { 00764 return new cSkinCursesDisplayMessage; 00765 } 00766 00767 // --- cPluginSkinCurses ----------------------------------------------------- 00768 00769 class cPluginSkinCurses : public cPlugin { 00770 private: 00771 // Add any member variables or functions you may need here. 00772 public: 00773 cPluginSkinCurses(void); 00774 virtual ~cPluginSkinCurses(); 00775 virtual const char *Version(void) { return VERSION; } 00776 virtual const char *Description(void) { return tr(DESCRIPTION); } 00777 virtual const char *CommandLineHelp(void); 00778 virtual bool ProcessArgs(int argc, char *argv[]); 00779 virtual bool Initialize(void); 00780 virtual bool Start(void); 00781 virtual void Housekeeping(void); 00782 virtual const char *MainMenuEntry(void) { return tr(MAINMENUENTRY); } 00783 virtual cOsdObject *MainMenuAction(void); 00784 virtual cMenuSetupPage *SetupMenu(void); 00785 virtual bool SetupParse(const char *Name, const char *Value); 00786 }; 00787 00788 cPluginSkinCurses::cPluginSkinCurses(void) 00789 { 00790 // Initialize any member variables here. 00791 // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL 00792 // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! 00793 } 00794 00795 cPluginSkinCurses::~cPluginSkinCurses() 00796 { 00797 // Clean up after yourself! 00798 endwin(); 00799 } 00800 00801 const char *cPluginSkinCurses::CommandLineHelp(void) 00802 { 00803 // Return a string that describes all known command line options. 00804 return NULL; 00805 } 00806 00807 bool cPluginSkinCurses::ProcessArgs(int argc, char *argv[]) 00808 { 00809 // Implement command line argument processing here if applicable. 00810 return true; 00811 } 00812 00813 bool cPluginSkinCurses::Initialize(void) 00814 { 00815 // Initialize any background activities the plugin shall perform. 00816 WINDOW *w = initscr(); 00817 if (w) { 00818 ScOsdWidth = w->_maxx - w->_begx + 1; 00819 ScOsdHeight = w->_maxy - w->_begy + 1; 00820 return true; 00821 } 00822 return false; 00823 } 00824 00825 bool cPluginSkinCurses::Start(void) 00826 { 00827 // Start any background activities the plugin shall perform. 00828 cSkin *Skin = new cSkinCurses; 00829 // This skin is normally used for debugging, so let's make it the current one: 00830 Skins.SetCurrent(Skin->Name()); 00831 return true; 00832 } 00833 00834 void cPluginSkinCurses::Housekeeping(void) 00835 { 00836 // Perform any cleanup or other regular tasks. 00837 } 00838 00839 cOsdObject *cPluginSkinCurses::MainMenuAction(void) 00840 { 00841 // Perform the action when selected from the main VDR menu. 00842 return NULL; 00843 } 00844 00845 cMenuSetupPage *cPluginSkinCurses::SetupMenu(void) 00846 { 00847 // Return a setup menu in case the plugin supports one. 00848 return NULL; 00849 } 00850 00851 bool cPluginSkinCurses::SetupParse(const char *Name, const char *Value) 00852 { 00853 // Parse your own setup parameters and store their values. 00854 return false; 00855 } 00856 00857 VDRPLUGINCREATOR(cPluginSkinCurses); // Don't touch this!