vdr  1.7.31
skinlcars.c
Go to the documentation of this file.
1 /*
2  * skinlcars.c: A VDR skin with Star Trek's "LCARS" layout
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: skinlcars.c 2.15 2012/09/19 11:05:50 kls Exp $
8  */
9 
10 // "Star Trek: The Next Generation"(R) is a registered trademark of Paramount Pictures,
11 // registered in the United States Patent and Trademark Office, all rights reserved.
12 // The LCARS system is based upon the designs of Michael Okuda and his Okudagrams.
13 //
14 // "LCARS" is short for "Library Computer Access and Retrieval System".
15 // Some resources used for writing this skin can be found at
16 // http://www.lcars.org.uk
17 // http://www.lcarsdeveloper.com
18 // http://www.lcarscom.net
19 // http://lds-jedi.deviantart.com/art/LCARS-Swept-Tutorial-213936938
20 // http://lds-jedi.deviantart.com/art/LCARS-Button-Tutorial-210783437
21 // http://zelldenver.deviantart.com/art/LCARS-Color-Standard-179565780
22 // http://www.lcars47.com
23 // http://www.bracercom.com/tutorial/content/CoherentLCARSInterface/LCARSCoherentInterface.html
24 // http://www.bracercom.com/tutorial/content/lcars_manifesto/the_lcars_manifesto.html
25 
26 #include "skinlcars.h"
27 #include "font.h"
28 #include "menu.h"
29 #include "osd.h"
30 #include "themes.h"
31 #include "videodir.h"
32 
33 #include "symbols/arrowdown.xpm"
34 #include "symbols/arrowup.xpm"
35 #include "symbols/audio.xpm"
36 #include "symbols/audioleft.xpm"
37 #include "symbols/audioright.xpm"
38 #include "symbols/audiostereo.xpm"
39 #include "symbols/dolbydigital.xpm"
40 #include "symbols/encrypted.xpm"
41 #include "symbols/ffwd.xpm"
42 #include "symbols/ffwd1.xpm"
43 #include "symbols/ffwd2.xpm"
44 #include "symbols/ffwd3.xpm"
45 #include "symbols/frew.xpm"
46 #include "symbols/frew1.xpm"
47 #include "symbols/frew2.xpm"
48 #include "symbols/frew3.xpm"
49 #include "symbols/mute.xpm"
50 #include "symbols/pause.xpm"
51 #include "symbols/play.xpm"
52 #include "symbols/radio.xpm"
53 #include "symbols/recording.xpm"
54 #include "symbols/sfwd.xpm"
55 #include "symbols/sfwd1.xpm"
56 #include "symbols/sfwd2.xpm"
57 #include "symbols/sfwd3.xpm"
58 #include "symbols/srew.xpm"
59 #include "symbols/srew1.xpm"
60 #include "symbols/srew2.xpm"
61 #include "symbols/srew3.xpm"
62 #include "symbols/teletext.xpm"
63 #include "symbols/volume.xpm"
64 
65 #define Gap (Setup.FontOsdSize / 5 & ~1) // must be even
66 #define TextFrame (Setup.FontOsdSize / TEXT_ALIGN_BORDER)
67 #define TextSpacing (2 * TextFrame)
68 #define SymbolSpacing TextSpacing
69 #define ShowSeenExtent (Setup.FontOsdSize / 5) // pixels by which the "seen" bar extends out of the frame
70 
71 #define DISKUSAGEALERTLIMIT 95 // percent of disk usage above which the display goes into alert mode
72 #define SIGNALDISPLAYDELTA 2 // seconds between subsequent device signal displays
73 
74 static cTheme Theme;
75 
76 // Color domains:
77 
78 #define CLR_BACKGROUND 0x99000000
79 #define CLR_MAIN_FRAME 0xFFFF9966
80 #define CLR_CHANNEL_FRAME 0xFF8A9EC9
81 #define CLR_REPLAY_FRAME 0xFFCC6666
82 #define CLR_DATE 0xFF99CCFF
83 #define CLR_MENU_ITEMS 0xFF9999FF
84 #define CLR_TIMER 0xFF99CCFF
85 #define CLR_DEVICE 0xFFF1B1AF
86 #define CLR_CHANNEL_NAME 0xFF99CCFF
87 #define CLR_EVENT_TITLE 0xFF99CCFF
88 #define CLR_EVENT_TIME 0xFFFFCC66
89 #define CLR_EVENT_SHORTTEXT 0xFFFFCC66
90 #define CLR_TEXT 0xFF99CCFF
91 #define CLR_TRACK 0xFFFFCC66
92 #define CLR_SEEN 0xFFCC99CC
93 #define CLR_ALERT 0xFFFF0000
94 #define CLR_EXPOSED 0xFF990000
95 #define CLR_WHITE 0xFFFFFFFF
96 #define CLR_RED 0xFFCC6666
97 #define CLR_GREEN 0xFFA0FF99
98 #define CLR_YELLOW 0xFFF1DF60
99 #define CLR_BLUE 0xFF9A99FF
100 #define CLR_BLACK 0xFF000000
101 
102 // General colors:
103 
105 THEME_CLR(Theme, clrDateFg, CLR_BLACK);
106 THEME_CLR(Theme, clrDateBg, CLR_DATE);
107 THEME_CLR(Theme, clrTimerFg, CLR_BLACK);
108 THEME_CLR(Theme, clrTimerBg, CLR_TIMER);
109 THEME_CLR(Theme, clrDeviceFg, CLR_BLACK);
110 THEME_CLR(Theme, clrDeviceBg, CLR_DEVICE);
111 THEME_CLR(Theme, clrSignalValue, CLR_GREEN);
112 THEME_CLR(Theme, clrSignalRest, CLR_RED);
113 THEME_CLR(Theme, clrSeen, CLR_SEEN);
114 THEME_CLR(Theme, clrTrackName, CLR_TRACK);
115 THEME_CLR(Theme, clrAlertFg, CLR_WHITE);
116 THEME_CLR(Theme, clrAlertBg, CLR_ALERT);
117 THEME_CLR(Theme, clrChannelName, CLR_CHANNEL_NAME);
118 THEME_CLR(Theme, clrEventTitle, CLR_EVENT_TITLE);
119 THEME_CLR(Theme, clrEventTime, CLR_EVENT_TIME);
120 THEME_CLR(Theme, clrEventShortText, CLR_EVENT_SHORTTEXT);
121 THEME_CLR(Theme, clrEventDescription, CLR_TEXT);
122 
123 // Buttons:
124 
125 THEME_CLR(Theme, clrButtonRedFg, CLR_BLACK);
126 THEME_CLR(Theme, clrButtonRedBg, CLR_RED);
127 THEME_CLR(Theme, clrButtonGreenFg, CLR_BLACK);
128 THEME_CLR(Theme, clrButtonGreenBg, CLR_GREEN);
129 THEME_CLR(Theme, clrButtonYellowFg, CLR_BLACK);
130 THEME_CLR(Theme, clrButtonYellowBg, CLR_YELLOW);
131 THEME_CLR(Theme, clrButtonBlueFg, CLR_BLACK);
132 THEME_CLR(Theme, clrButtonBlueBg, CLR_BLUE);
133 
134 // Messages:
135 
136 THEME_CLR(Theme, clrMessageStatusFg, CLR_BLACK);
137 THEME_CLR(Theme, clrMessageStatusBg, CLR_BLUE);
138 THEME_CLR(Theme, clrMessageInfoFg, CLR_BLACK);
139 THEME_CLR(Theme, clrMessageInfoBg, CLR_GREEN);
140 THEME_CLR(Theme, clrMessageWarningFg, CLR_BLACK);
141 THEME_CLR(Theme, clrMessageWarningBg, CLR_YELLOW);
142 THEME_CLR(Theme, clrMessageErrorFg, CLR_BLACK);
143 THEME_CLR(Theme, clrMessageErrorBg, CLR_RED);
144 
145 // Volume:
146 
147 THEME_CLR(Theme, clrVolumeFrame, CLR_MAIN_FRAME);
148 THEME_CLR(Theme, clrVolumeSymbol, CLR_BLACK);
149 THEME_CLR(Theme, clrVolumeBarUpper, RgbShade(CLR_MAIN_FRAME, -0.2));
150 THEME_CLR(Theme, clrVolumeBarLower, CLR_GREEN);
151 
152 // Channel display:
153 
154 THEME_CLR(Theme, clrChannelFrameFg, CLR_BLACK);
155 THEME_CLR(Theme, clrChannelFrameBg, CLR_CHANNEL_FRAME);
156 THEME_CLR(Theme, clrChannelSymbolOn, CLR_BLACK);
157 THEME_CLR(Theme, clrChannelSymbolOff, RgbShade(CLR_CHANNEL_FRAME, -0.2));
158 THEME_CLR(Theme, clrChannelSymbolRecFg, CLR_WHITE);
159 THEME_CLR(Theme, clrChannelSymbolRecBg, CLR_RED);
160 
161 // Menu:
162 
163 THEME_CLR(Theme, clrMenuFrameFg, CLR_BLACK);
164 THEME_CLR(Theme, clrMenuFrameBg, CLR_MAIN_FRAME);
165 THEME_CLR(Theme, clrMenuTitle, CLR_MAIN_FRAME);
166 THEME_CLR(Theme, clrMenuMainBracket, CLR_MENU_ITEMS);
167 THEME_CLR(Theme, clrMenuTimerRecording, CLR_DEVICE);
168 THEME_CLR(Theme, clrMenuDeviceRecording, CLR_TIMER);
169 THEME_CLR(Theme, clrMenuItemCurrentFg, CLR_MAIN_FRAME);
170 THEME_CLR(Theme, clrMenuItemCurrentBg, RgbShade(CLR_MENU_ITEMS, -0.5));
171 THEME_CLR(Theme, clrMenuItemSelectable, CLR_MENU_ITEMS);
172 THEME_CLR(Theme, clrMenuItemNonSelectable, CLR_TEXT);
173 THEME_CLR(Theme, clrMenuScrollbarTotal, RgbShade(CLR_MAIN_FRAME, 0.2));
174 THEME_CLR(Theme, clrMenuScrollbarShown, CLR_SEEN);
175 THEME_CLR(Theme, clrMenuScrollbarArrow, CLR_BLACK);
176 THEME_CLR(Theme, clrMenuText, CLR_TEXT);
177 
178 // Replay display:
179 
180 THEME_CLR(Theme, clrReplayFrameFg, CLR_BLACK);
181 THEME_CLR(Theme, clrReplayFrameBg, CLR_REPLAY_FRAME);
182 THEME_CLR(Theme, clrReplayPosition, CLR_SEEN);
183 THEME_CLR(Theme, clrReplayJumpFg, CLR_BLACK);
184 THEME_CLR(Theme, clrReplayJumpBg, CLR_SEEN);
185 THEME_CLR(Theme, clrReplayProgressSeen, CLR_SEEN);
186 THEME_CLR(Theme, clrReplayProgressRest, RgbShade(CLR_WHITE, -0.2));
187 THEME_CLR(Theme, clrReplayProgressSelected, CLR_EXPOSED);
188 THEME_CLR(Theme, clrReplayProgressMark, CLR_BLACK);
189 THEME_CLR(Theme, clrReplayProgressCurrent, CLR_EXPOSED);
190 
191 // Track display:
192 
193 THEME_CLR(Theme, clrTrackFrameFg, CLR_BLACK);
194 THEME_CLR(Theme, clrTrackFrameBg, CLR_TRACK);
195 THEME_CLR(Theme, clrTrackItemFg, CLR_BLACK);
196 THEME_CLR(Theme, clrTrackItemBg, RgbShade(CLR_TRACK, 0.5));
197 THEME_CLR(Theme, clrTrackItemCurrentFg, CLR_BLACK);
198 THEME_CLR(Theme, clrTrackItemCurrentBg, CLR_TRACK);
199 
200 // --- Helper functions ------------------------------------------------------
201 
202 static cOsd *CreateOsd(int Left, int Top, int x0, int y0, int x1, int y1)
203 {
204  cOsd *Osd = cOsdProvider::NewOsd(Left, Top);
205  int Bpp[] = { 32, 8, 4, 2, 1 };
206  tArea Area = { x0, y0, x1, y1, 0 };
207  for (unsigned int i = 0; i < sizeof(Bpp) / sizeof(int); i++) {
208  Area.bpp = Bpp[i];
209  if (Osd->CanHandleAreas(&Area, 1) == oeOk) {
210  Osd->SetAreas(&Area, 1);
211  break;
212  }
213  }
214  return Osd;
215 }
216 
217 static cFont *CreateTinyFont(int LineHeight)
218 {
219  // Creates a font that is not higher than half of LineHeight.
220  LineHeight /= 2;
221  int Height = LineHeight;
222  for (;;) {
223  cFont *TinyFont = cFont::CreateFont(Setup.FontOsd, Height);
224  if (Height < 2 || TinyFont->Height() <= LineHeight)
225  return TinyFont;
226  delete TinyFont;
227  Height -= 1;
228  }
229 }
230 
231 static bool DrawDeviceData(cOsd *Osd, const cDevice *Device, int x0, int y0, int x1, int y1, int &xs, const cFont *TinyFont, cString &LastDeviceType, cCamSlot *&LastCamSlot, bool Initial)
232 {
233  cString DeviceType = Device->DeviceType();
234  cCamSlot *CamSlot = Device->CamSlot();
235  if (Initial || strcmp(DeviceType, LastDeviceType) || CamSlot != LastCamSlot) {
236  const cFont *font = cFont::GetFont(fontOsd);
237  tColor ColorFg = Theme.Color(clrDeviceFg);
238  tColor ColorBg = Theme.Color(clrDeviceBg);
239  Osd->DrawRectangle(x0, y0, x1 - 1, y1 - 1, ColorBg);
240  int x = x0;
241  // Device number:
242  cString Nr = itoa(Device->DeviceNumber() + 1);
243  int w = max(font->Width(Nr), y1 - y0);
244  Osd->DrawText(x, y0, Nr, ColorFg, ColorBg, font, w, y1 - y0, taCenter);
245  x += w;
246  // Device type:
247  Osd->DrawText(x, y0, DeviceType, ColorFg, ColorBg, TinyFont);
248  xs = max(xs, x + TinyFont->Width(DeviceType));
249  LastDeviceType = DeviceType;
250  // CAM:
251  if (CamSlot) {
252  cString s = cString::sprintf("CAM %d", CamSlot->SlotNumber());
253  Osd->DrawText(x, y1 - TinyFont->Height(), s, ColorFg, ColorBg, TinyFont);
254  xs = max(xs, x + TinyFont->Width(s));
255  }
256  LastCamSlot = CamSlot;
257  return true;
258  }
259  return false;
260 }
261 
262 static void DrawDeviceSignal(cOsd *Osd, const cDevice *Device, int x0, int y0, int x1, int y1, int &LastSignalStrength, int &LastSignalQuality, bool Initial)
263 {
264  int SignalStrength = Device->SignalStrength();
265  int SignalQuality = Device->SignalQuality();
266  int d = max((y1 - y0) / 10, 1);
267  int x00 = x0 + d;
268  int x01 = x1 - d;
269  int h = (y1 - y0 - 3 * d) / 2;
270  int w = x01 - x00;
271  int y00 = y0 + d;
272  int y01 = y00 + h;
273  int y03 = y1 - d;
274  int y02 = y03 - h;
275  if (SignalStrength >= 0 && (Initial || SignalStrength != LastSignalStrength)) {
276  int s = SignalStrength * w / 100;
277  Osd->DrawRectangle(x00, y00, x00 + s - 1, y01 - 1, Theme.Color(clrSignalValue));
278  Osd->DrawRectangle(x00 + s, y00, x01 - 1, y01 - 1, Theme.Color(clrSignalRest));
279  LastSignalStrength = SignalStrength;
280  }
281  if (SignalQuality >= 0 && (Initial || SignalQuality != LastSignalQuality)) {
282  int q = SignalQuality * w / 100;
283  Osd->DrawRectangle(x00, y02, x00 + q - 1, y03 - 1, Theme.Color(clrSignalValue));
284  Osd->DrawRectangle(x00 + q, y02, x01 - 1, y03 - 1, Theme.Color(clrSignalRest));
285  LastSignalQuality = SignalQuality;
286  }
287 }
288 
289 // --- cSkinLCARSDisplayChannel ----------------------------------------------
290 
292 private:
296  int xs; // starting column for signal display
297  bool withInfo;
302  bool message;
303  const cEvent *present;
304  bool initial;
306  int lastSeen;
315  void DrawDate(void);
316  void DrawTrack(void);
317  void DrawSeen(int Current, int Total);
318  void DrawDevice(void);
319  void DrawSignal(void);
320 public:
321  cSkinLCARSDisplayChannel(bool WithInfo);
322  virtual ~cSkinLCARSDisplayChannel();
323  virtual void SetChannel(const cChannel *Channel, int Number);
324  virtual void SetEvents(const cEvent *Present, const cEvent *Following);
325  virtual void SetMessage(eMessageType Type, const char *Text);
326  virtual void Flush(void);
327  };
328 
335 
337 {
339  initial = true;
340  present = NULL;
341  lastSeen = -1;
342  lastDeviceNumber = -1;
343  lastCamSlot = NULL;
344  lastSignalStrength = -1;
345  lastSignalQuality = -1;
346  lastSignalDisplay = 0;
347  memset(&lastTrackId, 0, sizeof(lastTrackId));
348  const cFont *font = cFont::GetFont(fontOsd);
349  withInfo = WithInfo;
350  lineHeight = font->Height();
352  frameColor = Theme.Color(clrChannelFrameBg);
353  message = false;
354  int d = 5 * lineHeight;
355  xc00 = 0;
356  xc01 = xc00 + d / 2;
357  xc02 = xc00 + d;
358  xc03 = xc02 + lineHeight;
359  xc04 = xc02 + d / 4;
360  xc05 = xc02 + d;
361  xc06 = xc05 + Gap;
362  xc15 = cOsd::OsdWidth();
363  xc14 = xc15 - lineHeight;
364  xc13 = xc14 - Gap;
365  xc07 = (xc15 + xc00) / 2;
366  xc08 = xc07 + Gap;
367  xc09 = xc08 + lineHeight;
368  xc10 = xc09 + Gap;
369  xc11 = (xc10 + xc13 + Gap) / 2;
370  xc12 = xc11 + Gap;
371 
372  yc00 = 0;
373  yc01 = yc00 + lineHeight;
374  yc02 = yc01 + lineHeight;
375  yc03 = yc02 + Gap;
376  yc04 = yc03 + 2 * lineHeight;
377  yc05 = yc04 + Gap;
378  yc06 = yc05 + 2 * lineHeight;
379 
380  yc07 = yc06 + Gap;
381  yc12 = yc07 + 3 * lineHeight + Gap / 2;
382  yc11 = yc12 - lineHeight;
383  yc10 = yc11 - lineHeight;
384  yc09 = yc11 - d / 4;
385  yc08 = yc12 - d / 2;
386 
387  xs = 0;
388 
389  int y1 = withInfo ? yc12 : yc02;
390  int y0 = cOsd::OsdTop() + (Setup.ChannelInfoPos ? 0 : cOsd::OsdHeight() - y1);
391  osd = CreateOsd(cOsd::OsdLeft(), y0, xc00, yc00, xc15 - 1, y1 - 1);
392  osd->DrawRectangle(xc00, yc00, xc15 - 1, y1 - 1, Theme.Color(clrBackground));
393  // Rectangles:
394  osd->DrawRectangle(xc00, yc00, xc02 - 1, yc02 - 1, frameColor);
395  if (withInfo) {
396  osd->DrawRectangle(xc00, yc03, xc02 - 1, yc04 - 1, frameColor);
397  osd->DrawRectangle(xc00, yc05, xc02 - 1, yc06 - 1, frameColor);
398  // Elbow:
399  osd->DrawRectangle(xc00, yc07, xc01 - 1, yc08 - 1, frameColor);
401  osd->DrawEllipse (xc00, yc08, xc01 - 1, yc12 - 1, frameColor, 3);
402  osd->DrawRectangle(xc01, yc07, xc02 - 1, yc12 - 1, frameColor);
403  osd->DrawEllipse (xc02, yc09, xc04 - 1, yc11 - 1, frameColor, -3);
404  osd->DrawRectangle(xc02, yc11, xc05 - 1, yc12 - 1, frameColor);
405  // Status area:
406  osd->DrawRectangle(xc06, yc11 + lineHeight / 2, xc07 - 1, yc12 - 1, frameColor);
407  osd->DrawRectangle(xc08, yc11, xc09 - 1, yc12 - 1, frameColor);
408  osd->DrawRectangle(xc10, yc11, xc11 - 1, yc12 - 1, Theme.Color(clrDeviceBg));
409  osd->DrawRectangle(xc12, yc11, xc13 - 1, yc12 - 1, Theme.Color(clrDateBg));
410  osd->DrawRectangle(xc14, yc11, xc14 + lineHeight / 2 - 1, yc12 - 1, frameColor);
411  osd->DrawRectangle(xc14 + lineHeight / 2, yc11 + lineHeight / 2, xc15 - 1, yc12 - 1, clrTransparent);
412  osd->DrawEllipse (xc14 + lineHeight / 2, yc11, xc15 - 1, yc12 - 1, frameColor, 5);
413  }
414  // Icons:
415  osd->DrawRectangle(xc14, yc00, xc14 + lineHeight / 2 - 1, yc01 - 1, frameColor);
416  osd->DrawRectangle(xc14 + lineHeight / 2, yc00, xc15 - 1, yc00 + lineHeight / 2 - 1, clrTransparent);
417  osd->DrawEllipse (xc14 + lineHeight / 2, yc00, xc15 - 1, yc01 - 1, frameColor, 5);
418 }
419 
421 {
422  delete tallFont;
423  delete tinyFont;
424  delete osd;
425 }
426 
428 {
429  cString s = DayDateTime();
430  if (initial || strcmp(s, lastDate)) {
431  osd->DrawText(xc12, yc11, s, Theme.Color(clrDateFg), Theme.Color(clrDateBg), cFont::GetFont(fontOsd), xc13 - xc12, lineHeight, taRight | taBorder);
432  lastDate = s;
433  }
434 }
435 
437 {
438  cDevice *Device = cDevice::PrimaryDevice();
439  const tTrackId *Track = Device->GetTrack(Device->GetCurrentAudioTrack());
440  if (!Track && *lastTrackId.description || Track && strcmp(lastTrackId.description, Track->description)) {
441  osd->DrawText(xc03, yc07, Track ? Track->description : "", Theme.Color(clrTrackName), Theme.Color(clrBackground), cFont::GetFont(fontOsd), xc07 - xc03);
442  strn0cpy(lastTrackId.description, Track ? Track->description : "", sizeof(lastTrackId.description));
443  }
444 }
445 
446 void cSkinLCARSDisplayChannel::DrawSeen(int Current, int Total)
447 {
448  int Seen = min(xc07 - xc06, int((xc07 - xc06) * double(Current) / Total));
449  if (initial || Seen != lastSeen) {
450  int y0 = yc11 - ShowSeenExtent;
451  int y1 = yc11 + lineHeight / 2 - Gap / 2;
452  osd->DrawRectangle(xc06, y0, xc06 + Seen - 1, y1 - 1, Theme.Color(clrSeen));
453  osd->DrawRectangle(xc06 + Seen, y0, xc07 - 1, y1 - 1, Theme.Color(clrBackground));
454  lastSeen = Seen;
455  }
456 }
457 
459 {
460  const cDevice *Device = cDevice::ActualDevice();
462  lastDeviceNumber = Device->DeviceNumber();
463  // Make sure signal meters are redrawn:
464  lastSignalStrength = -1;
465  lastSignalQuality = -1;
466  lastSignalDisplay = 0;
467  }
468 }
469 
471 {
472  time_t Now = time(NULL);
473  if (Now != lastSignalDisplay) {
475  lastSignalDisplay = Now;
476  }
477 }
478 
479 void cSkinLCARSDisplayChannel::SetChannel(const cChannel *Channel, int Number)
480 {
481  int x = xc13;
482  int xi = x - SymbolSpacing -
488  osd->DrawRectangle(xi, yc00, xc13 - 1, yc01 - 1, frameColor);
489  if (Channel && !Channel->GroupSep()) {
490  bool rec = cRecordControls::Active();
492  osd->DrawBitmap(x, yc00 + (yc01 - yc00 - bmRecording.Height()) / 2, bmRecording, Theme.Color(rec ? clrChannelSymbolRecFg : clrChannelSymbolOff), rec ? Theme.Color(clrChannelSymbolRecBg) : frameColor);
494  osd->DrawBitmap(x, yc00 + (yc01 - yc00 - bmEncrypted.Height()) / 2, bmEncrypted, Theme.Color(Channel->Ca() ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
496  osd->DrawBitmap(x, yc00 + (yc01 - yc00 - bmDolbyDigital.Height()) / 2, bmDolbyDigital, Theme.Color(Channel->Dpid(0) ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
497  x -= bmAudio.Width() + SymbolSpacing;
498  osd->DrawBitmap(x, yc00 + (yc01 - yc00 - bmAudio.Height()) / 2, bmAudio, Theme.Color(Channel->Apid(1) ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
499  if (Channel->Vpid()) {
500  x -= bmTeletext.Width() + SymbolSpacing;
501  osd->DrawBitmap(x, yc00 + (yc01 - yc00 - bmTeletext.Height()) / 2, bmTeletext, Theme.Color(Channel->Tpid() ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
502  }
503  else if (Channel->Apid(0)) {
504  x -= bmRadio.Width() + SymbolSpacing;
505  osd->DrawBitmap(x, yc00 + (yc01 - yc00 - bmRadio.Height()) / 2, bmRadio, Theme.Color(clrChannelSymbolOn), frameColor);
506  }
507  }
508  cString ChNumber("");
509  cString ChName("");
510  if (Channel) {
511  ChName = Channel->Name();
512  if (!Channel->GroupSep())
513  ChNumber = cString::sprintf("%d%s", Channel->Number(), Number ? "-" : "");
514  }
515  else if (Number)
516  ChNumber = cString::sprintf("%d-", Number);
517  else
518  ChName = ChannelString(NULL, 0);
519  osd->DrawText(xc00, yc00, ChNumber, Theme.Color(clrChannelFrameFg), frameColor, tallFont, xc02 - xc00, yc02 - yc00, taTop | taRight | taBorder);
520  osd->DrawText(xc03, yc00, ChName, Theme.Color(clrChannelName), Theme.Color(clrBackground), tallFont, xi - xc03 - lineHeight, 0, taTop | taLeft);
521  lastSignalDisplay = 0;
522  if (withInfo)
523  DrawDevice();
524 }
525 
526 void cSkinLCARSDisplayChannel::SetEvents(const cEvent *Present, const cEvent *Following)
527 {
528  if (!withInfo)
529  return;
530  if (present != Present)
531  lastSeen = -1;
532  present = Present;
533  for (int i = 0; i < 2; i++) {
534  const cEvent *e = !i ? Present : Following;
535  int y = !i ? yc03 : yc05;
536  if (e) {
537  osd->DrawText(xc00, y, e->GetTimeString(), Theme.Color(clrChannelFrameFg), frameColor, cFont::GetFont(fontOsd), xc02 - xc00, 0, taRight | taBorder);
538  osd->DrawText(xc03, y, e->Title(), Theme.Color(clrEventTitle), Theme.Color(clrBackground), cFont::GetFont(fontOsd), xc13 - xc03);
539  osd->DrawText(xc03, y + lineHeight, e->ShortText(), Theme.Color(clrEventShortText), Theme.Color(clrBackground), cFont::GetFont(fontSml), xc13 - xc03);
540  }
541  else {
543  osd->DrawRectangle(xc02, y, xc13 - 1, y + 2 * lineHeight, Theme.Color(clrBackground));
544  }
545  }
546 }
547 
549 {
550  if (Text) {
551  int x0, x1, y0, y1, y2;
552  if (withInfo) {
553  x0 = xc06;
554  x1 = xc13;
555  y0 = yc11 - ShowSeenExtent;
556  y1 = yc11;
557  y2 = yc12;
558  }
559  else {
560  x0 = xc03;
561  x1 = xc13;
562  y0 = y1 = yc00;
563  y2 = yc02;
564  }
565  osd->SaveRegion(x0, y0, x1 - 1, y2 - 1);
566  if (withInfo)
567  osd->DrawRectangle(xc06, y0, xc07, y1 - 1, Theme.Color(clrBackground)); // clears the "seen" bar
568  osd->DrawText(x0, y1, Text, Theme.Color(clrMessageStatusFg + 2 * Type), Theme.Color(clrMessageStatusBg + 2 * Type), cFont::GetFont(fontSml), x1 - x0, y2 - y1, taCenter);
569  message = true;
570  }
571  else {
572  osd->RestoreRegion();
573  message = false;
574  }
575 }
576 
578 {
579  if (withInfo) {
580  if (!message) {
581  DrawDate();
582  DrawTrack();
583  DrawDevice();
584  DrawSignal();
585  int Current = 0;
586  int Total = 0;
587  if (present) {
588  time_t t = time(NULL);
589  if (t > present->StartTime())
590  Current = t - present->StartTime();
591  Total = present->Duration();
592  }
593  DrawSeen(Current, Total);
594  }
595  }
596  osd->Flush();
597  initial = false;
598 }
599 
600 // --- cSkinLCARSDisplayMenu -------------------------------------------------
601 
603 private:
613  int xi00, xi01, xi02, xi03;
614  int yi00, yi01;
618  int xs; // starting column for signal display
630  bool initial;
645  int lastSeen;
647  void DrawMainFrameUpper(tColor Color);
648  void DrawMainFrameLower(void);
649  void DrawMainButton(const char *Text, int x0, int x1, int x2, int x3, int y0, int y1, tColor ColorFg, tColor ColorBg, const cFont *Font);
650  void DrawMenuFrame(void);
651  void DrawMainBracket(void);
652  void DrawStatusElbows(void);
653  void DrawDate(void);
654  void DrawDisk(void);
655  void DrawLoad(void);
656  void DrawFrameDisplay(void);
657  void DrawScrollbar(int Total, int Offset, int Shown, bool CanScrollUp, bool CanScrollDown);
658  void DrawTimer(const cTimer *Timer, int y, bool MultiRec);
659  void DrawTimers(void);
660  void DrawDevice(const cDevice *Device);
661  void DrawDevices(void);
662  void DrawLiveIndicator(void);
663  void DrawSignals(void);
664  void DrawLive(const cChannel *Channel);
665  void DrawPlay(cControl *Control);
666  void DrawInfo(const cEvent *Event, bool WithTime);
667  void DrawSeen(int Current, int Total);
668  void DrawTextScrollbar(void);
669 public:
670  cSkinLCARSDisplayMenu(void);
671  virtual ~cSkinLCARSDisplayMenu();
672  virtual void Scroll(bool Up, bool Page);
673  virtual int MaxItems(void);
674  virtual void Clear(void);
676  virtual void SetTitle(const char *Title);
677  virtual void SetButtons(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL);
678  virtual void SetMessage(eMessageType Type, const char *Text);
679  virtual void SetItem(const char *Text, int Index, bool Current, bool Selectable);
680  virtual void SetScrollbar(int Total, int Offset);
681  virtual void SetEvent(const cEvent *Event);
682  virtual void SetRecording(const cRecording *Recording);
683  virtual void SetText(const char *Text, bool FixedFont);
684  virtual int GetTextAreaWidth(void) const;
685  virtual const cFont *GetTextAreaFont(bool FixedFont) const;
686  virtual void Flush(void);
687  };
688 
692 
694 {
696  initial = true;
698  lastChannel = NULL;
699  lastEvent = NULL;
700  lastRecording = NULL;
701  lastSeen = -1;
702  lastTimersState = -1;
703  lastSignalDisplay = 0;
704  lastLiveIndicatorY = -1;
706  lastDiskUsageState = -1;
707  lastDiskAlert = false;
708  lastSystemLoad = -1;
709  const cFont *font = cFont::GetFont(fontOsd);
710  lineHeight = font->Height();
712  frameColor = Theme.Color(clrMenuFrameBg);
713  currentIndex = -1;
714  // The outer frame:
715  int d = 5 * lineHeight;
716  xa00 = 0;
717  xa01 = xa00 + d / 2;
718  xa02 = xa00 + d;
719  xa03 = xa02 + lineHeight;
720  xa04 = xa02 + d / 4;
721  xa05 = xa02 + d;
722  xa06 = xa05 + Gap;
723  xa09 = cOsd::OsdWidth();
724  xa08 = xa09 - lineHeight;
725  xa07 = xa08 - Gap;
726 
727  yt00 = 0;
728  yt01 = yt00 + lineHeight;
729  yt02 = yt01 + lineHeight;
730  yt03 = yt01 + d / 4;
731  yt04 = yt02 + Gap;
732  yt05 = yt00 + d / 2;
733  yt06 = yt04 + 2 * lineHeight;
734 
735  yc00 = yt06 + Gap;
736  yc05 = yc00 + 3 * lineHeight + Gap / 2;
737  yc04 = yc05 - lineHeight;
738  yc03 = yc04 - lineHeight;
739  yc02 = yc04 - d / 4;
740  yc01 = yc05 - d / 2;
741 
742  yc06 = yc05 + Gap;
743  yc07 = yc06 + lineHeight;
744  yc08 = yc07 + lineHeight;
745  yc09 = yc07 + d / 4;
746  yc10 = yc06 + d / 2;
747  yc11 = yc06 + 3 * lineHeight + Gap / 2;
748 
749  yb00 = yc11 + Gap;
750  yb01 = yb00 + 2 * lineHeight;
751  yb02 = yb01 + Gap;
752  yb03 = yb02 + 2 * lineHeight;
753  yb04 = yb03 + Gap;
754  yb05 = yb04 + 2 * lineHeight;
755  yb06 = yb05 + Gap;
756  yb07 = yb06 + 2 * lineHeight;
757  yb08 = yb07 + Gap;
758 
759  yb15 = cOsd::OsdHeight();
760  yb14 = yb15 - lineHeight;
761  yb13 = yb14 - lineHeight;
762  yb12 = yb14 - d / 4;
763  yb11 = yb15 - d / 2;
764  yb10 = yb13 - Gap - 2 * lineHeight;
765  yb09 = yb10 - Gap;
766 
767  // Compensate for large font size:
768  if (yb09 - yb08 < 2 * lineHeight) {
769  yb08 = yb06;
770  yb06 = 0; // drop empty rectangle
771  }
772  if (yb09 - yb08 < 2 * lineHeight) {
773  yb05 = yb09;
774  yb08 = 0; // drop "LCARS" display
775  }
776  if (yb05 - yb04 < 2 * lineHeight) {
777  yb03 = yb09;
778  yb04 = 0; // drop "LOAD" display
779  }
780  if (yb03 - yb02 < 2 * lineHeight) {
781  yb01 = yb09;
782  yb02 = 0; // drop "DISK" display
783  }
784  // Anything else is just insanely large...
785 
786  // The main command menu:
787  xm00 = xa03;
788  xm01 = xa05;
789  xm02 = xa06;
790  xm08 = (xa09 + xa00) / 2;
791  xm07 = xm08 - lineHeight;
792  xm06 = xm07 - lineHeight / 2;
793  xm05 = xm06 - lineHeight / 2;
794  xm04 = xm05 - lineHeight;
795  xm03 = xm04 - Gap;
796  ym00 = yc08;
797  ym01 = ym00 + lineHeight / 2;
798  ym02 = ym01 + lineHeight / 2;
799  ym03 = ym02 + Gap;
800  ym07 = yb15;
801  ym06 = ym07 - lineHeight / 2;
802  ym05 = ym06 - lineHeight / 2;
803  ym04 = ym05 - Gap;
804 
805  // The status area:
806  xs00 = xm08 + Gap + lineHeight + Gap;
807  xs13 = xa09;
808  xs12 = xa08;
809  xs11 = xa07;
810  xs05 = (xs00 + xs11 + Gap) / 2;
811  xs04 = xs05 - lineHeight / 2;
812  xs03 = xs04 - lineHeight / 2;
813  xs02 = xs03 - 2 * lineHeight;
814  xs01 = xs02 - Gap;
815  xs06 = xs05 + Gap;
816  xs07 = xs06 + lineHeight / 2;
817  xs08 = xs07 + lineHeight / 2;
818  xs09 = xs08 + 2 * lineHeight;
819  xs10 = xs09 + Gap;
820  ys00 = yc06;
821  ys01 = ys00 + lineHeight;
822  ys02 = ys01 + lineHeight / 2;
823  ys04 = ys01 + lineHeight;
824  ys03 = ys04 - Gap;
825  ys05 = yb15;
826 
827  // The color buttons in submenus:
828  xb00 = xa06;
829  xb15 = xa07;
830  int w = (xa08 - xa06) / 4;
831  xb01 = xb00 + lineHeight / 2;
832  xb02 = xb01 + Gap;
833  xb04 = xb00 + w;
834  xb03 = xb04 - Gap;
835  xb05 = xb04 + lineHeight / 2;
836  xb06 = xb05 + Gap;
837  xb08 = xb04 + w;
838  xb07 = xb08 - Gap;
839  xb09 = xb08 + lineHeight / 2;
840  xb10 = xb09 + Gap;
841  xb12 = xb08 + w;
842  xb11 = xb12 - Gap;
843  xb13 = xb12 + lineHeight / 2;
844  xb14 = xb13 + Gap;;
845 
846  // The color buttons in the main menu:
847  int r = lineHeight;
848  xd07 = xa09;
849  xd06 = xd07 - r;
850  xd05 = xd06 - 4 * r;
851  xd04 = xd05 - r;
852  xd03 = xd04 - Gap;
853  xd02 = xd03 - r;
854  xd01 = xd02 - 4 * r;
855  xd00 = xd01 - r;
856  yd00 = yt00;
857  yd05 = yc04 - Gap;
858  yd04 = yd05 - 2 * r;
859  yd03 = yd04 - Gap;
860  yd02 = yd03 - 2 * r;
861  yd01 = yd02 - Gap;
862 
863  xs = 0;
864 
866 }
867 
869 {
870  delete tallFont;
871  delete tinyFont;
872  delete osd;
873 }
874 
876 {
877  if (initial || MenuCategory != cSkinDisplayMenu::MenuCategory()) {
878  cSkinDisplayMenu::SetMenuCategory(MenuCategory);
879  initial = true;
880  osd->DrawRectangle(xa00, yt00, xa09 - 1, yb15 - 1, Theme.Color(clrBackground));
881  if (MenuCategory == mcMain) {
882  yi00 = ym03;
883  yi01 = ym04;
884  xi00 = xm00;
885  xi01 = xm03;
886  xi02 = xm04;
887  xi03 = xm05;
888  lastTimersState = -1;
890  DrawMainBracket();
892  }
893  else {
894  yi00 = yt02;
895  yi01 = yb13;
896  xi00 = xa03;
897  xi01 = xa07;
898  xi02 = xa08;
899  xi03 = xa09;
900  DrawMenuFrame();
901  }
902  }
903 }
904 
906 {
907  // Top left rectangles:
908  osd->DrawRectangle(xa00, yt00, xa02 - 1, yt02 - 1, Color);
909  osd->DrawRectangle(xa00, yt04, xa02 - 1, yt06 - 1, Color);
910  // Upper elbow:
911  osd->DrawRectangle(xa00, yc00, xa01 - 1, yc01 - 1, Color);
912  osd->DrawEllipse (xa00, yc01, xa01 - 1, yc05 - 1, Color, 3);
913  osd->DrawRectangle(xa01, yc00, xa02 - 1, yc05 - 1, Color);
914  osd->DrawEllipse (xa02, yc02, xa04 - 1, yc04 - 1, Color, -3);
915  osd->DrawRectangle(xa02, yc04, xa05 - 1, yc05 - 1, Color);
916  // Upper delimiter:
917  osd->DrawRectangle(xa06, yc04 + lineHeight / 2, xm08 - 1, yc05 - 1, Color);
918  osd->DrawRectangle(xm08 + Gap, yc04, xs00 - Gap - 1, yc05 - 1, Color);
919  osd->DrawRectangle(xs00, yc04, xs05 - 1, yc05 - 1, Color);
920  osd->DrawRectangle(xs06, yc04, xa07 - 1, yc05 - 1, Color);
921  osd->DrawRectangle(xa08, yc04, xa09 - 1, yc05 - 1, Color);
922 }
923 
925 {
926  const cFont *font = cFont::GetFont(fontOsd);
927  // Lower elbow:
928  osd->DrawRectangle(xa00, yc10, xa01 - 1, yc11 - 1, frameColor);
929  osd->DrawEllipse (xa00, yc06, xa01 - 1, yc10 - 1, frameColor, 2);
930  osd->DrawRectangle(xa01, yc06, xa02 - 1, yc11 - 1, frameColor);
931  osd->DrawEllipse (xa02, yc07, xa04 - 1, yc09 - 1, frameColor, -2);
932  osd->DrawRectangle(xa02, yc06, xa05 - 1, yc07 - 1, frameColor);
933  // Lower delimiter:
934  osd->DrawRectangle(xa06, yc06, xm08 - 1, yc07 - lineHeight / 2 - 1, frameColor);
935  osd->DrawRectangle(xm08 + Gap, yc06, xs00 - Gap - 1, yc07 - 1, frameColor);
936  osd->DrawRectangle(xa08, yc06, xa09 - 1, yc07 - 1, frameColor);
937  // VDR version:
938  osd->DrawRectangle(xa00, yb10, xa02 - 1, yb15 - 1, frameColor);
939  osd->DrawText(xa00, yb10, "VDR", Theme.Color(clrMenuFrameFg), frameColor, tallFont, xa02 - xa00, yb11 - yb10, taTop | taRight | taBorder);
940  osd->DrawText(xa00, yb15 - lineHeight, VDRVERSION, Theme.Color(clrMenuFrameFg), frameColor, font, xa02 - xa00, lineHeight, taBottom | taRight | taBorder);
941 }
942 
943 void cSkinLCARSDisplayMenu::DrawMainButton(const char *Text, int x0, int x1, int x2, int x3, int y0, int y1, tColor ColorFg, tColor ColorBg, const cFont *Font)
944 {
945  int h = y1 - y0;
946  osd->DrawEllipse(x0, y0, x1 - 1, y1 - 1, ColorBg, 7);
947  osd->DrawText(x1, y0, Text, ColorFg, ColorBg, Font, x2 - x1, h, taBottom | taRight);
948  osd->DrawEllipse(x2, y0, x3 - 1, y1 - 1, ColorBg, 5);
949 }
950 
952 {
953  // Upper elbow:
954  osd->DrawRectangle(xa00, yt05, xa01 - 1, yt06 - 1, frameColor);
956  osd->DrawEllipse (xa00, yt00, xa01 - 1, yt05 - 1, frameColor, 2);
957  osd->DrawRectangle(xa01, yt00, xa02 - 1, yt06 - 1, frameColor);
958  osd->DrawEllipse (xa02, yt01, xa04 - 1, yt03 - 1, frameColor, -2);
959  osd->DrawRectangle(xa02, yt00, xa05 - 1, yt01 - 1, frameColor);
960  osd->DrawRectangle(xa06, yt00, xa07 - 1, yt01 - 1, frameColor);
961  osd->DrawRectangle(xa08, yt00, xa08 + lineHeight / 2 - 1, yt01 - 1, frameColor);
963  osd->DrawEllipse (xa08 + lineHeight / 2, yt00, xa09 - 1, yt01 - 1, frameColor, 5);
964  // Center part:
965  osd->DrawRectangle(xa00, yc00, xa02 - 1, yc11 - 1, frameColor);
966  // Lower elbow:
967  osd->DrawRectangle(xa00, yb10, xa02 - 1, yb11 - 1, frameColor);
969  osd->DrawEllipse (xa00, yb11, xa01 - 1, yb15 - 1, frameColor, 3);
970  osd->DrawRectangle(xa01, yb11, xa02 - 1, yb15 - 1, frameColor);
971  osd->DrawEllipse (xa02, yb12, xa04 - 1, yb14 - 1, frameColor, -3);
972  osd->DrawRectangle(xa02, yb14, xa05 - 1, yb15 - 1, frameColor);
973  osd->DrawRectangle(xa08, yb14, xa08 + lineHeight / 2 - 1, yb15 - 1, frameColor);
975  osd->DrawEllipse (xa08 + lineHeight / 2, yb14, xa09 - 1, yb15 - 1, frameColor, 5);
976  osd->DrawText(xa00, yb10, "VDR", Theme.Color(clrMenuFrameFg), frameColor, tallFont, xa02 - xa00, yb11 - yb10, taTop | taRight | taBorder);
977  // Color buttons:
978  tColor lutBg[] = { clrButtonRedBg, clrButtonGreenBg, clrButtonYellowBg, clrButtonBlueBg };
979  osd->DrawRectangle(xb00, yb14, xb01 - 1, yb15 - 1, Theme.Color(lutBg[Setup.ColorKey0]));
980  osd->DrawRectangle(xb04, yb14, xb05 - 1, yb15 - 1, Theme.Color(lutBg[Setup.ColorKey1]));
981  osd->DrawRectangle(xb08, yb14, xb09 - 1, yb15 - 1, Theme.Color(lutBg[Setup.ColorKey2]));
982  osd->DrawRectangle(xb12, yb14, xb13 - 1, yb15 - 1, Theme.Color(lutBg[Setup.ColorKey3]));
983 }
984 
986 {
987  cString s = DayDateTime();
988  if (initial || strcmp(s, lastDate)) {
989  const cFont *font = cFont::GetFont(fontOsd);
990  tColor ColorFg = Theme.Color(clrDateFg);
991  tColor ColorBg = Theme.Color(clrDateBg);
992  lastDate = s;
993  const char *t = strrchr(s, ' ');
994  osd->DrawText(xa00, yb01 - lineHeight, t, ColorFg, ColorBg, font, xa02 - xa00, lineHeight, taBottom | taRight | taBorder);
995  s.Truncate(t - s);
996  osd->DrawText(xa00, yb00, s, ColorFg, ColorBg, font, xa02 - xa00, yb01 - yb00 - lineHeight, taTop | taRight | taBorder);
997  }
998 }
999 
1001 {
1002  if (yb02) {
1003  if (cVideoDiskUsage::HasChanged(lastDiskUsageState) || initial) { // must call HasChanged() first, or it shows an outdated value in the 'initial' case!
1004  const cFont *font = cFont::GetFont(fontOsd);
1005  int DiskUsage = cVideoDiskUsage::UsedPercent();
1006  bool DiskAlert = DiskUsage > DISKUSAGEALERTLIMIT;
1007  tColor ColorFg = DiskAlert ? Theme.Color(clrAlertFg) : Theme.Color(clrMenuFrameFg);
1008  tColor ColorBg = DiskAlert ? Theme.Color(clrAlertBg) : frameColor;
1009  if (initial || DiskAlert != lastDiskAlert)
1010  osd->DrawText(xa00, yb02, tr("DISK"), ColorFg, ColorBg, tinyFont, xa02 - xa00, yb03 - yb02, taTop | taLeft | taBorder);
1011  osd->DrawText(xa01, yb02, itoa(DiskUsage), ColorFg, ColorBg, font, xa02 - xa01, lineHeight, taBottom | taRight | taBorder);
1012  osd->DrawText(xa00, yb03 - lineHeight, cString::sprintf("%02d:%02d", cVideoDiskUsage::FreeMinutes() / 60, cVideoDiskUsage::FreeMinutes() % 60), ColorFg, ColorBg, font, xa02 - xa00, 0, taBottom | taRight | taBorder);
1013  lastDiskAlert = DiskAlert;
1014  }
1015  }
1016 }
1017 
1019 {
1020  if (yb04) {
1021  tColor ColorFg = Theme.Color(clrMenuFrameFg);
1022  tColor ColorBg = frameColor;
1023  if (initial)
1024  osd->DrawText(xa00, yb04, tr("LOAD"), ColorFg, ColorBg, tinyFont, xa02 - xa00, yb05 - yb04, taTop | taLeft | taBorder);
1025  double SystemLoad;
1026  if (getloadavg(&SystemLoad, 1) > 0) {
1027  if (initial || SystemLoad != lastSystemLoad) {
1028  osd->DrawText(xa00, yb05 - lineHeight, cString::sprintf("%.1f", SystemLoad), ColorFg, ColorBg, cFont::GetFont(fontOsd), xa02 - xa00, lineHeight, taBottom | taRight | taBorder);
1029  lastSystemLoad = SystemLoad;
1030  }
1031  }
1032  }
1033 }
1034 
1036 {
1037  tColor Color = Theme.Color(clrMenuMainBracket);
1038  osd->DrawRectangle(xm00, ym00, xm01 - 1, ym01 - 1, Color);
1039  osd->DrawRectangle(xm02, ym00, xm07 - 1, ym01 - 1, Color);
1040  osd->DrawEllipse (xm07, ym00, xm08 - 1, ym02 - 1, Color, 1);
1041  osd->DrawEllipse (xm06, ym01, xm07 - 1, ym02 - 1, Color, -1);
1042  osd->DrawRectangle(xm07, ym03, xm08 - 1, ym04 - 1, Color);
1043  osd->DrawEllipse (xm06, ym05, xm07 - 1, ym06 - 1, Color, -4);
1044  osd->DrawEllipse (xm07, ym05, xm08 - 1, ym07 - 1, Color, 4);
1045  osd->DrawRectangle(xm02, ym06, xm07 - 1, ym07 - 1, Color);
1046  osd->DrawRectangle(xm00, ym06, xm01 - 1, ym07 - 1, Color);
1047 }
1048 
1050 {
1051  const cFont *font = cFont::GetFont(fontOsd);
1052  osd->DrawText (xs00, ys00, tr("TIMERS"), Theme.Color(clrMenuFrameFg), frameColor, font, xs01 - xs00, lineHeight, taBottom | taLeft | taBorder);
1053  osd->DrawRectangle(xs02, ys00, xs03 - 1, ys01 - 1, frameColor);
1054  osd->DrawEllipse (xs03, ys00, xs05 - 1, ys01 - 1, frameColor, 1);
1055  osd->DrawEllipse (xs03, ys01, xs04 - 1, ys02 - 1, frameColor, -1);
1056  osd->DrawRectangle(xs04, ys01, xs05 - 1, ys03 - 1, frameColor);
1057  osd->DrawRectangle(xs04, ys04, xs05 - 1, ys05 - 1, frameColor);
1058  osd->DrawText (xs10, ys00, tr("DEVICES"), Theme.Color(clrMenuFrameFg), frameColor, font, xs11 - xs10, lineHeight, taBottom | taRight | taBorder);
1059  osd->DrawRectangle(xs08, ys00, xs09 - 1, ys01 - 1, frameColor);
1060  osd->DrawEllipse (xs06, ys00, xs08 - 1, ys01 - 1, frameColor, 2);
1061  osd->DrawEllipse (xs07, ys01, xs08 - 1, ys02 - 1, frameColor, -2);
1062  osd->DrawRectangle(xs06, ys01, xs07 - 1, ys03 - 1, frameColor);
1063  osd->DrawRectangle(xs06, ys04, xs07 - 1, ys05 - 1, frameColor);
1064  osd->DrawRectangle(xs12, ys00, xs13 - 1, ys01 - 1, frameColor);
1065 }
1066 
1068 {
1069  DrawDate();
1070  DrawDisk();
1071  DrawLoad();
1072  if (initial) {
1073  if (yb06)
1074  osd->DrawRectangle(xa00, yb06, xa02 - 1, yb07 - 1, frameColor);
1075  if (yb08) {
1076  const cFont *font = cFont::GetFont(fontOsd);
1077  osd->DrawRectangle(xa00, yb08, xa02 - 1, yb09 - 1, frameColor);
1078  osd->DrawText(xa00, yb09 - lineHeight, "LCARS", Theme.Color(clrMenuFrameFg), frameColor, font, xa02 - xa00, lineHeight, taBottom | taRight | taBorder);
1079  }
1080  }
1081 }
1082 
1083 void cSkinLCARSDisplayMenu::DrawScrollbar(int Total, int Offset, int Shown, bool CanScrollUp, bool CanScrollDown)
1084 {
1085  int x0, x1, tt, tb;
1086  tColor ClearColor;
1087  if (MenuCategory() == mcMain) {
1088  x0 = xm07;
1089  x1 = xm08;
1090  tt = ym03;
1091  tb = ym04;
1092  ClearColor = Theme.Color(clrMenuMainBracket);
1093  }
1094  else {
1095  x0 = xa02 + Gap;
1096  x1 = x0 + lineHeight / 2;
1097  tt = yc00;
1098  tb = yc11;
1099  ClearColor = Theme.Color(clrBackground);
1100  int d = TextFrame;
1101  if (CanScrollUp)
1102  osd->DrawBitmap(xa02 - bmArrowUp.Width() - d, yc00 + d, bmArrowUp, Theme.Color(clrMenuScrollbarArrow), frameColor);
1103  else
1104  osd->DrawRectangle(xa02 - bmArrowUp.Width() - d, yc00 + d, xa02 - d - 1, yc00 + d + bmArrowUp.Height() - 1, frameColor);
1105  if (CanScrollDown)
1106  osd->DrawBitmap(xa02 - bmArrowDown.Width() - d, yc11 - d - bmArrowDown.Height(), bmArrowDown, Theme.Color(clrMenuScrollbarArrow), frameColor);
1107  else
1108  osd->DrawRectangle(xa02 - bmArrowDown.Width() - d, yc11 - d - bmArrowDown.Height(), xa02 - d - 1, yc11 - d - 1, frameColor);
1109  }
1110  if (Total > 0 && Total > Shown) {
1111  int sw = x1 - x0;
1112  int sh = max(int((tb - tt) * double(Shown) / Total + 0.5), sw);
1113  int st = min(int(tt + (tb - tt) * double(Offset) / Total + 0.5), tb - sh);
1114  int sb = min(st + sh, tb);
1115  osd->DrawRectangle(x0, tt, x1 - 1, tb - 1, Theme.Color(clrMenuScrollbarTotal));
1116  osd->DrawRectangle(x0, st, x1 - 1, sb - 1, Theme.Color(clrMenuScrollbarShown));
1117  }
1118  else if (MenuCategory() != mcMain)
1119  osd->DrawRectangle(x0, tt, x1 - 1, tb - 1, ClearColor);
1120 }
1121 
1122 void cSkinLCARSDisplayMenu::DrawTimer(const cTimer *Timer, int y, bool MultiRec)
1123 {
1124  // The timer data:
1125  bool Alert = !Timer->Recording() && Timer->Pending();
1126  tColor ColorFg = Alert ? Theme.Color(clrAlertFg) : Theme.Color(clrTimerFg);
1127  tColor ColorBg = Alert ? Theme.Color(clrAlertFg) : Theme.Color(clrTimerBg);
1128  osd->DrawRectangle(xs00, y, xs03 - 1, y + lineHeight - 1, ColorBg);
1129  cString Date;
1130  if (Timer->Recording())
1131  Date = cString::sprintf("-%s", *TimeString(Timer->StopTime()));
1132  else {
1133  time_t Now = time(NULL);
1134  cString Today = WeekDayName(Now);
1135  cString Time = TimeString(Timer->StartTime());
1136  cString Day = WeekDayName(Timer->StartTime());
1137  if (Timer->StartTime() > Now + 6 * SECSINDAY)
1138  Date = DayDateTime(Timer->StartTime());
1139  else if (strcmp(Day, Today) != 0)
1140  Date = cString::sprintf("%s %s", *Day, *Time);
1141  else
1142  Date = Time;
1143  }
1144  if (Timer->Flags() & tfVps)
1145  Date = cString::sprintf("VPS %s", *Date);
1146  const cChannel *Channel = Timer->Channel();
1147  const cEvent *Event = Timer->Event();
1148  int d = max(TextFrame / 2, 1);
1149  if (Channel) {
1150  osd->DrawText(xs00 + d, y, Channel->Name(), ColorFg, ColorBg, tinyFont, xs03 - xs00 - d);
1151  osd->DrawText(xs03 - tinyFont->Width(Date) - d, y, Date, ColorFg, ColorBg, tinyFont);
1152  }
1153  if (Event)
1154  osd->DrawText(xs00 + d, y + lineHeight - tinyFont->Height(), Event->Title(), ColorFg, ColorBg, tinyFont, xs03 - xs00 - 2 * d);
1155  // The timer recording indicator:
1156  if (Timer->Recording())
1157  osd->DrawRectangle(xs03 + Gap, y - (MultiRec ? Gap : 0), xs04 - Gap / 2 - 1, y + lineHeight - 1, Theme.Color(clrMenuTimerRecording));
1158 }
1159 
1161 {
1164  const cFont *font = cFont::GetFont(fontOsd);
1165  osd->DrawRectangle(xs00, ys04, xs04 - 1, ys05 - 1, Theme.Color(clrBackground));
1166  osd->DrawRectangle(xs07, ys04, xs13 - 1, ys05 - 1, Theme.Color(clrBackground));
1167  cSortedTimers SortedTimers;
1168  cVector<int> FreeDeviceSlots;
1169  int NumDevices = 0;
1170  int y = ys04;
1171  // Timers and recording devices:
1172  while (1) {
1173  int NumTimers = 0;
1174  const cDevice *Device = NULL;
1175  for (int i = 0; i < SortedTimers.Size(); i++) {
1176  if (y + lineHeight > ys05)
1177  break;
1178  if (const cTimer *Timer = SortedTimers[i]) {
1179  if (Timer->Recording()) {
1180  if (cRecordControl *RecordControl = cRecordControls::GetRecordControl(Timer)) {
1181  if (!Device || Device == RecordControl->Device()) {
1182  DrawTimer(Timer, y, NumTimers > 0);
1183  NumTimers++;
1184  if (!Device) {
1185  Device = RecordControl->Device();
1186  deviceOffset[Device->DeviceNumber()] = y;
1187  deviceRecording[Device->DeviceNumber()] = true;
1188  NumDevices++;
1189  }
1190  else
1191  FreeDeviceSlots.Append(y);
1192  y += lineHeight + Gap;
1193  }
1194  else
1195  continue;
1196  }
1197  SortedTimers[i] = NULL;
1198  }
1199  else if (!Device && Timer->HasFlags(tfActive)) {
1200  DrawTimer(Timer, y, false);
1201  FreeDeviceSlots.Append(y);
1202  y += lineHeight + Gap;
1203  SortedTimers[i] = NULL;
1204  }
1205  }
1206  }
1207  if (!Device)
1208  break;
1209  }
1210  // Devices currently not recording:
1211  int Slot = 0;
1212  for (int i = 0; i < cDevice::NumDevices(); i++) {
1213  if (const cDevice *Device = cDevice::GetDevice(i)) {
1214  if (Device->NumProvidedSystems()) {
1215  if (!deviceRecording[Device->DeviceNumber()]) {
1216  if (Slot < FreeDeviceSlots.Size()) {
1217  y = FreeDeviceSlots[Slot];
1218  Slot++;
1219  }
1220  if (y + lineHeight > ys05)
1221  break;
1222  deviceOffset[Device->DeviceNumber()] = y;
1223  y += lineHeight + Gap;
1224  NumDevices++;
1225  }
1226  }
1227  }
1228  }
1229  // Total number of active timers:
1230  int NumTimers = 0;
1231  for (cTimer *Timer = Timers.First(); Timer; Timer = Timers.Next(Timer)) {
1232  if (Timer->HasFlags(tfActive))
1233  NumTimers++;
1234  }
1235  osd->DrawText(xs02, ys00, itoa(NumTimers), Theme.Color(clrMenuFrameFg), frameColor, font, xs03 - xs02, ys01 - ys00, taBottom | taLeft | taBorder);
1236  osd->DrawText(xs08, ys00, itoa(NumDevices), Theme.Color(clrMenuFrameFg), frameColor, font, xs09 - xs08, ys01 - ys00, taBottom | taRight | taBorder);
1237  lastSignalDisplay = 0;
1238  initial = true; // forces redrawing of devices
1239  }
1240 }
1241 
1243 {
1244  int dn = Device->DeviceNumber();
1245  int y = deviceOffset[dn];
1246  if (y + lineHeight <= ys05) {
1247  if (DrawDeviceData(osd, Device, xs08, y, xs11, y + lineHeight, xs, tinyFont, lastDeviceType[dn], lastCamSlot[dn], initial)) {
1248  // Make sure signal meters are redrawn:
1249  lastSignalStrength[dn] = -1;
1250  lastSignalQuality[dn] = -1;
1251  lastSignalDisplay = 0;
1252  }
1253  // The device recording indicator:
1254  if (deviceRecording[dn])
1255  osd->DrawRectangle(xs07 + Gap / 2, y, xs08 - Gap - 1, y + lineHeight - 1, Theme.Color(clrMenuDeviceRecording));
1256  }
1257 }
1258 
1260 {
1261  for (int i = 0; i < cDevice::NumDevices(); i++) {
1262  if (const cDevice *Device = cDevice::GetDevice(i)) {
1263  if (Device->NumProvidedSystems())
1264  DrawDevice(Device);
1265  }
1266  }
1267 }
1268 
1270 {
1271  cDevice *Device = cDevice::PrimaryDevice();
1272  int y = -1;
1273  bool Transferring = Device->Transferring();
1274  if (!Device->Replaying() || Transferring)
1276  if (initial || y != lastLiveIndicatorY || Transferring != lastLiveIndicatorTransferring) {
1277  if (lastLiveIndicatorY >= 0)
1279  if (y >= 0) {
1280  tColor ColorBg = Theme.Color(clrChannelFrameBg);
1281  osd->DrawRectangle(xs12, y, xs12 + lineHeight / 2 - 1, y + lineHeight - 1, ColorBg);
1282  osd->DrawEllipse (xs12 + lineHeight / 2, y, xs13 - 1, y + lineHeight - 1, ColorBg, 5);
1283  if (Transferring) {
1284  int w = bmTransferMode.Width();
1285  int h = bmTransferMode.Height();
1286  int b = w * w + h * h; // the diagonal of the bitmap (squared)
1287  int c = lineHeight * lineHeight; // the diameter of the circle (squared)
1288  const cBitmap *bm = &bmTransferMode;
1289  if (b > c) {
1290  // the bitmap doesn't fit, so scale it down:
1291  double f = sqrt(double(c) / (2 * b));
1292  bm = bmTransferMode.Scaled(f, f);
1293  }
1294  osd->DrawBitmap((xs12 + xs13 - bm->Width()) / 2, y + (lineHeight - bm->Height()) / 2, *bm, Theme.Color(clrChannelFrameFg), ColorBg);
1295  if (bm != &bmTransferMode)
1296  delete bm;
1297  }
1298  }
1299  lastLiveIndicatorY = y;
1300  lastLiveIndicatorTransferring = Transferring;
1301  }
1302 }
1303 
1305 {
1306  time_t Now = time(NULL);
1307  if (initial || Now - lastSignalDisplay >= SIGNALDISPLAYDELTA) {
1308  for (int i = 0; i < cDevice::NumDevices(); i++) {
1309  if (const cDevice *Device = cDevice::GetDevice(i)) {
1310  if (Device->NumProvidedSystems()) {
1311  if (int y = deviceOffset[i])
1313  }
1314  }
1315  }
1316  lastSignalDisplay = Now;
1317  }
1318 }
1319 
1321 {
1322  if (lastMode != cmLive) {
1323  initial = true;
1324  lastMode = cmLive;
1325  }
1326  if (initial) {
1327  DrawMainFrameUpper(Theme.Color(clrChannelFrameBg));
1328  osd->DrawText(xd00, yd00, tr("LIVE"), Theme.Color(clrChannelFrameBg), Theme.Color(clrBackground), tallFont, xd07 - xd00, yd01 - yd00, taTop | taRight | taBorder);
1329  }
1330  if (initial || Channel != lastChannel) {
1331  osd->DrawText(xa00, yt00, itoa(Channel->Number()), Theme.Color(clrChannelFrameFg), Theme.Color(clrChannelFrameBg), tallFont, xa02 - xa00, yt02 - yt00, taTop | taRight | taBorder);
1332  osd->DrawText(xa03, yt00, Channel->Name(), Theme.Color(clrChannelName), Theme.Color(clrBackground), tallFont, xd00 - xa03, yd01 - yd00, taTop | taLeft);
1333  lastChannel = Channel;
1334  }
1335  // The current programme:
1336  cSchedulesLock SchedulesLock;
1337  if (const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock)) {
1338  if (const cSchedule *Schedule = Schedules->GetSchedule(Channel)) {
1339  const cEvent *Event = Schedule->GetPresentEvent();
1340  if (initial || Event != lastEvent) {
1341  DrawInfo(Event, true);
1342  lastEvent = Event;
1343  lastSeen = -1;
1344  }
1345  int Current = 0;
1346  int Total = 0;
1347  if (Event) {
1348  time_t t = time(NULL);
1349  if (t > Event->StartTime())
1350  Current = t - Event->StartTime();
1351  Total = Event->Duration();
1352  }
1353  DrawSeen(Current, Total);
1354  }
1355  }
1356 }
1357 
1359 {
1360  if (lastMode != cmPlay) {
1361  initial = true;
1362  lastMode = cmPlay;
1363  }
1364  if (initial) {
1365  DrawMainFrameUpper(Theme.Color(clrReplayFrameBg));
1366  osd->DrawText(xd00, yd00, tr("PLAY"), Theme.Color(clrReplayFrameBg), Theme.Color(clrBackground), tallFont, xd07 - xd00, yd01 - yd00, taTop | taRight | taBorder);
1367  }
1368  // The current progress:
1369  int Current = 0;
1370  int Total = 0;
1371  if (Control->GetIndex(Current, Total))
1372  DrawSeen(Current, Total);
1373  // The current programme:
1374  if (const cRecording *Recording = Control->GetRecording()) {
1375  if (initial || Recording != lastRecording) {
1376  const cFont *font = cFont::GetFont(fontOsd);
1377  if (const cRecordingInfo *Info = Recording->Info()) {
1378  osd->DrawText(xa03, yt00, Info->ChannelName(), Theme.Color(clrChannelName), Theme.Color(clrBackground), tallFont, xd00 - xa03, yd01 - yd00, taTop | taLeft);
1379  DrawInfo(Info->GetEvent(), false);
1380  }
1381  else
1382  osd->DrawText(xa03, yt04, Recording->Name(), Theme.Color(clrEventTitle), Theme.Color(clrBackground), font, xd00 - xa03, 0, taTop | taLeft);
1383  osd->DrawText(xa00, yt04, ShortDateString(Recording->Start()), Theme.Color(clrReplayFrameFg), Theme.Color(clrReplayFrameBg), font, xa02 - xa00, 0, taTop | taRight | taBorder);
1384  osd->DrawText(xa00, yt06 - lineHeight, TimeString(Recording->Start()), Theme.Color(clrReplayFrameFg), Theme.Color(clrReplayFrameBg), font, xa02 - xa00, 0, taBottom | taRight | taBorder);
1385  lastRecording = Recording;
1386  }
1387  }
1388  else {
1389  cString Header = Control->GetHeader();
1390  if (!*lastHeader || strcmp(Header, lastHeader)) {
1391  osd->DrawText(xa03, yt00, Header, Theme.Color(clrMenuText), Theme.Color(clrBackground), tallFont, xd00 - xa03, yd01 - yd00, taTop | taLeft);
1392  lastHeader = Header;
1393  }
1394  }
1395 }
1396 
1397 void cSkinLCARSDisplayMenu::DrawInfo(const cEvent *Event, bool WithTime)
1398 {
1399  if (Event) {
1400  const cFont *font = cFont::GetFont(fontOsd);
1401  int y = yt04;
1402  osd->DrawText(xa03, y, Event->Title(), Theme.Color(clrEventTitle), Theme.Color(clrBackground), font, xd00 - xa03 - lineHeight, lineHeight, taBottom | taLeft);
1403  y += lineHeight;
1404  osd->DrawText(xa03, y, Event->ShortText(), Theme.Color(clrEventShortText), Theme.Color(clrBackground), cFont::GetFont(fontSml), xd00 - xa03 - lineHeight, lineHeight, taTop | taLeft);
1405  if (WithTime) {
1406  osd->DrawText(xa00, yt04, Event->GetTimeString(), Theme.Color(clrChannelFrameFg), Theme.Color(clrChannelFrameBg), font, xa02 - xa00, lineHeight, taTop | taRight | taBorder);
1407  osd->DrawText(xa00, yt06 - lineHeight, cString::sprintf("-%s", *Event->GetEndTimeString()), Theme.Color(clrChannelFrameFg), Theme.Color(clrChannelFrameBg), font, xa02 - xa00, lineHeight, taBottom | taRight | taBorder);
1408  }
1409  }
1410 }
1411 
1412 void cSkinLCARSDisplayMenu::DrawSeen(int Current, int Total)
1413 {
1414  int Seen = min(xm08 - xm02, int((xm08 - xm02) * double(Current) / Total));
1415  if (initial || Seen != lastSeen) {
1416  int y0 = yc04 - ShowSeenExtent;
1417  int y1 = yc04 + lineHeight / 2 - Gap / 2;
1418  osd->DrawRectangle(xm02, y0, xm02 + Seen - 1, y1 - 1, Theme.Color(clrSeen));
1419  osd->DrawRectangle(xm02 + Seen, y0, xm08 - 1, y1 - 1, Theme.Color(clrBackground));
1420  lastSeen = Seen;
1421  }
1422 }
1423 
1425 {
1426  if (textScroller.CanScroll())
1428 }
1429 
1430 void cSkinLCARSDisplayMenu::Scroll(bool Up, bool Page)
1431 {
1432  cSkinDisplayMenu::Scroll(Up, Page);
1434 }
1435 
1437 {
1438  if (MenuCategory() == mcMain)
1439  return (ym04 - ym03) / lineHeight;
1440  else
1441  return (yb13 - yt02) / lineHeight;
1442 }
1443 
1445 {
1446  textScroller.Reset();
1447  osd->DrawRectangle(xi00, yi00, xi03 - 1, yi01 - 1, Theme.Color(clrBackground));
1448 }
1449 
1450 void cSkinLCARSDisplayMenu::SetTitle(const char *Title)
1451 {
1452  if (MenuCategory() != mcMain) {
1453  const cFont *font = cFont::GetFont(fontOsd);
1454  int w = font->Width(Title);
1455  osd->DrawRectangle(xa06, yt00, xa07 - w - Gap - 1, yt01 - 1, frameColor);
1456  osd->DrawText(xa07 - w - Gap, yt00, Title, Theme.Color(clrMenuTitle), Theme.Color(clrBackground), font, w + Gap, yt01 - yt00, taRight);
1457  }
1458 }
1459 
1460 void cSkinLCARSDisplayMenu::SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue)
1461 {
1462  const char *lutText[] = { Red, Green, Yellow, Blue };
1463  tColor lutFg[] = { clrButtonRedFg, clrButtonGreenFg, clrButtonYellowFg, clrButtonBlueFg };
1464  tColor lutBg[] = { clrButtonRedBg, clrButtonGreenBg, clrButtonYellowBg, clrButtonBlueBg };
1465  const cFont *font = cFont::GetFont(fontSml);
1466  if (MenuCategory() == mcMain) {
1467  DrawMainButton(lutText[Setup.ColorKey0], xd00, xd01, xd02, xd03, yd02, yd03, Theme.Color(lutFg[Setup.ColorKey0]), Theme.Color(lutBg[Setup.ColorKey0]), font);
1468  DrawMainButton(lutText[Setup.ColorKey1], xd04, xd05, xd06, xd07, yd02, yd03, Theme.Color(lutFg[Setup.ColorKey1]), Theme.Color(lutBg[Setup.ColorKey1]), font);
1469  DrawMainButton(lutText[Setup.ColorKey2], xd00, xd01, xd02, xd03, yd04, yd05, Theme.Color(lutFg[Setup.ColorKey2]), Theme.Color(lutBg[Setup.ColorKey2]), font);
1470  DrawMainButton(lutText[Setup.ColorKey3], xd04, xd05, xd06, xd07, yd04, yd05, Theme.Color(lutFg[Setup.ColorKey3]), Theme.Color(lutBg[Setup.ColorKey3]), font);
1471  }
1472  else {
1473  int h = yb15 - yb14;
1474  osd->DrawText(xb02, yb14, lutText[Setup.ColorKey0], Theme.Color(lutFg[Setup.ColorKey0]), Theme.Color(lutBg[Setup.ColorKey0]), font, xb03 - xb02, h, taLeft | taBorder);
1475  osd->DrawText(xb06, yb14, lutText[Setup.ColorKey1], Theme.Color(lutFg[Setup.ColorKey1]), Theme.Color(lutBg[Setup.ColorKey1]), font, xb07 - xb06, h, taLeft | taBorder);
1476  osd->DrawText(xb10, yb14, lutText[Setup.ColorKey2], Theme.Color(lutFg[Setup.ColorKey2]), Theme.Color(lutBg[Setup.ColorKey2]), font, xb11 - xb10, h, taLeft | taBorder);
1477  osd->DrawText(xb14, yb14, lutText[Setup.ColorKey3], Theme.Color(lutFg[Setup.ColorKey3]), Theme.Color(lutBg[Setup.ColorKey3]), font, xb15 - xb14, h, taLeft | taBorder);
1478  }
1479 }
1480 
1482 {
1483  if (Text) {
1484  osd->SaveRegion(xb00, yb14, xb15 - 1, yb15 - 1);
1485  osd->DrawText(xb00, yb14, Text, Theme.Color(clrMessageStatusFg + 2 * Type), Theme.Color(clrMessageStatusBg + 2 * Type), cFont::GetFont(fontSml), xb15 - xb00, yb15 - yb14, taCenter);
1486  }
1487  else
1488  osd->RestoreRegion();
1489 }
1490 
1491 void cSkinLCARSDisplayMenu::SetItem(const char *Text, int Index, bool Current, bool Selectable)
1492 {
1493  int y = yi00 + Index * lineHeight;
1494  tColor ColorFg, ColorBg;
1495  if (Current) {
1496  ColorFg = Theme.Color(clrMenuItemCurrentFg);
1497  ColorBg = Theme.Color(clrMenuItemCurrentBg);
1498  osd->DrawRectangle(xi00, y, xi01 - 1, y + lineHeight - 1, ColorBg);
1499  osd->DrawRectangle(xi02, y, xi02 + lineHeight / 2 - 1, y + lineHeight - 1, ColorBg);
1500  osd->DrawEllipse (xi02 + lineHeight / 2, y, xi03 - 1, y + lineHeight - 1, ColorBg, 5);
1501  currentIndex = Index;
1502  }
1503  else {
1504  ColorFg = Theme.Color(Selectable ? clrMenuItemSelectable : clrMenuItemNonSelectable);
1505  ColorBg = Theme.Color(clrBackground);
1506  if (currentIndex == Index)
1507  osd->DrawRectangle(xi00, y, xi03 - 1, y + lineHeight - 1, Theme.Color(clrBackground));
1508  }
1509  const cFont *font = cFont::GetFont(fontOsd);
1510  for (int i = 0; i < MaxTabs; i++) {
1511  const char *s = GetTabbedText(Text, i);
1512  if (s) {
1513  int xt = xi00 + TextSpacing + Tab(i);
1514  osd->DrawText(xt, y, s, ColorFg, ColorBg, font, xi01 - xt);
1515  }
1516  if (!Tab(i + 1))
1517  break;
1518  }
1520 }
1521 
1522 void cSkinLCARSDisplayMenu::SetScrollbar(int Total, int Offset)
1523 {
1524  DrawScrollbar(Total, Offset, MaxItems(), Offset > 0, Offset + MaxItems() < Total);
1525 }
1526 
1528 {
1529  if (!Event)
1530  return;
1531  const cFont *font = cFont::GetFont(fontOsd);
1532  int xl = xi00;
1533  int y = yi00;
1534  cTextScroller ts;
1535  char t[32];
1536  snprintf(t, sizeof(t), "%s %s - %s", *Event->GetDateString(), *Event->GetTimeString(), *Event->GetEndTimeString());
1537  ts.Set(osd, xl, y, xi01 - xl, yi01 - y, t, font, Theme.Color(clrEventTime), Theme.Color(clrBackground));
1538  if (Event->Vps() && Event->Vps() != Event->StartTime()) {
1539  cString buffer = cString::sprintf(" VPS: %s ", *Event->GetVpsString());
1540  const cFont *font = cFont::GetFont(fontSml);
1541  int w = font->Width(buffer);
1542  osd->DrawText(xi01 - w, y, buffer, Theme.Color(clrMenuFrameFg), frameColor, font, w);
1543  int yb = y + font->Height();
1544  osd->DrawRectangle(xi02, y, xi02 + lineHeight / 2 - 1, yb - 1, frameColor);
1545  osd->DrawEllipse (xi02 + lineHeight / 2, y, xi03 - 1, yb - 1, frameColor, 5);
1546  }
1547  y += ts.Height();
1548  if (Event->ParentalRating()) {
1549  cString buffer = cString::sprintf(" %s ", *Event->GetParentalRatingString());
1550  const cFont *font = cFont::GetFont(fontSml);
1551  int w = font->Width(buffer);
1552  osd->DrawText(xi01 - w, y, buffer, Theme.Color(clrMenuFrameFg), frameColor, font, w);
1553  int yb = y + font->Height();
1554  osd->DrawRectangle(xi02, y, xi02 + lineHeight / 2 - 1, yb - 1, frameColor);
1555  osd->DrawEllipse (xi02 + lineHeight / 2, y, xi03 - 1, yb - 1, frameColor, 5);
1556  }
1557  y += font->Height();
1558  ts.Set(osd, xl, y, xi01 - xl, yi01 - y, Event->Title(), font, Theme.Color(clrEventTitle), Theme.Color(clrBackground));
1559  y += ts.Height();
1560  if (!isempty(Event->ShortText())) {
1561  const cFont *font = cFont::GetFont(fontSml);
1562  ts.Set(osd, xl, y, xi01 - xl, yi01 - y, Event->ShortText(), font, Theme.Color(clrEventShortText), Theme.Color(clrBackground));
1563  y += ts.Height();
1564  }
1565  y += font->Height();
1566  if (!isempty(Event->Description())) {
1567  int yt = y;
1568  int yb = yi01;
1569  textScroller.Set(osd, xl, yt, xi01 - xl, yb - yt, Event->Description(), font, Theme.Color(clrEventDescription), Theme.Color(clrBackground));
1571  }
1572 }
1573 
1575 {
1576  if (!Recording)
1577  return;
1578  const cRecordingInfo *Info = Recording->Info();
1579  const cFont *font = cFont::GetFont(fontOsd);
1580  int xl = xi00;
1581  int y = yi00;
1582  cTextScroller ts;
1583  char t[32];
1584  snprintf(t, sizeof(t), "%s %s", *DateString(Recording->Start()), *TimeString(Recording->Start()));
1585  ts.Set(osd, xl, y, xi01 - xl, yi01 - y, t, font, Theme.Color(clrEventTime), Theme.Color(clrBackground));
1586  y += ts.Height();
1587  if (Info->GetEvent()->ParentalRating()) {
1588  cString buffer = cString::sprintf(" %s ", *Info->GetEvent()->GetParentalRatingString());
1589  const cFont *font = cFont::GetFont(fontSml);
1590  int w = font->Width(buffer);
1591  osd->DrawText(xi01 - w, y, buffer, Theme.Color(clrMenuFrameFg), frameColor, font, w);
1592  int yb = y + font->Height();
1593  osd->DrawRectangle(xi02, y, xi02 + lineHeight / 2 - 1, yb - 1, frameColor);
1594  osd->DrawEllipse (xi02 + lineHeight / 2, y, xi03 - 1, yb - 1, frameColor, 5);
1595  }
1596  y += font->Height();
1597  const char *Title = Info->Title();
1598  if (isempty(Title))
1599  Title = Recording->Name();
1600  ts.Set(osd, xl, y, xi01 - xl, yi01 - y, Title, font, Theme.Color(clrEventTitle), Theme.Color(clrBackground));
1601  y += ts.Height();
1602  if (!isempty(Info->ShortText())) {
1603  const cFont *font = cFont::GetFont(fontSml);
1604  ts.Set(osd, xl, y, xi01 - xl, yi01 - y, Info->ShortText(), font, Theme.Color(clrEventShortText), Theme.Color(clrBackground));
1605  y += ts.Height();
1606  }
1607  y += font->Height();
1608  if (!isempty(Info->Description())) {
1609  int yt = y;
1610  int yb = yi01;
1611  textScroller.Set(osd, xl, yt, xi01 - xl, yb - yt, Info->Description(), font, Theme.Color(clrEventDescription), Theme.Color(clrBackground));
1613  }
1614 }
1615 
1616 void cSkinLCARSDisplayMenu::SetText(const char *Text, bool FixedFont)
1617 {
1618  textScroller.Set(osd, xi00, yi00, GetTextAreaWidth(), yi01 - yi00, Text, GetTextAreaFont(FixedFont), Theme.Color(clrMenuText), Theme.Color(clrBackground));
1620 }
1621 
1623 {
1624  return xi01 - xi00;
1625 }
1626 
1627 const cFont *cSkinLCARSDisplayMenu::GetTextAreaFont(bool FixedFont) const
1628 {
1629  const cFont *font = cFont::GetFont(FixedFont ? fontFix : fontOsd);
1630  //XXX -> make a way to let the text define which font to use
1631  return font;
1632 }
1633 
1635 {
1636  if (MenuCategory() == mcMain) {
1637  cDevice *Device = cDevice::PrimaryDevice();
1638  if (!Device->Replaying() || Device->Transferring()) {
1639  const cChannel *Channel = Channels.GetByNumber(cDevice::PrimaryDevice()->CurrentChannel());
1640  DrawLive(Channel);
1641  }
1642  else if (cControl *Control = cControl::Control(true))
1643  DrawPlay(Control);
1644  DrawTimers();
1645  DrawDevices();
1647  DrawSignals();
1648  }
1649  DrawFrameDisplay();
1650  osd->Flush();
1651  initial = false;
1652 }
1653 
1654 // --- cSkinLCARSDisplayReplay -----------------------------------------------
1655 
1657 private:
1661  bool modeOnly;
1667  void DrawDate(void);
1668  void DrawTrack(void);
1669 public:
1670  cSkinLCARSDisplayReplay(bool ModeOnly);
1671  virtual ~cSkinLCARSDisplayReplay();
1672  virtual void SetRecording(const cRecording *Recording);
1673  virtual void SetTitle(const char *Title);
1674  virtual void SetMode(bool Play, bool Forward, int Speed);
1675  virtual void SetProgress(int Current, int Total);
1676  virtual void SetCurrent(const char *Current);
1677  virtual void SetTotal(const char *Total);
1678  virtual void SetJump(const char *Jump);
1679  virtual void SetMessage(eMessageType Type, const char *Text);
1680  virtual void Flush(void);
1681  };
1682 
1684 {
1685  const cFont *font = cFont::GetFont(fontOsd);
1686  modeOnly = ModeOnly;
1687  lineHeight = font->Height();
1688  frameColor = Theme.Color(clrReplayFrameBg);
1689  lastCurrentWidth = 0;
1690  int d = 5 * lineHeight;
1691  xp00 = 0;
1692  xp01 = xp00 + d / 2;
1693  xp02 = xp00 + d;
1694  xp03 = xp02 + lineHeight;
1695  xp04 = xp02 + d / 4;
1696  xp05 = xp02 + d;
1697  xp06 = xp05 + Gap;
1698  xp15 = cOsd::OsdWidth();
1699  xp14 = xp15 - lineHeight;
1700  xp13 = xp14 - Gap;
1701  xp07 = (xp15 + xp00) / 2;
1702  xp08 = xp07 + Gap;
1703  xp09 = xp08 + lineHeight;
1704  xp10 = xp09 + Gap;
1705  xp11 = (xp10 + xp13 + Gap) / 2;
1706  xp12 = xp11 + Gap;
1707 
1708  yp00 = 0;
1709  yp01 = yp00 + 2 * lineHeight;
1710  yp02 = yp01 + Gap;
1711  yp03 = yp02 + 2 * lineHeight;
1712 
1713  yp04 = yp03 + Gap;
1714  yp09 = yp04 + 3 * lineHeight + Gap / 2;
1715  yp08 = yp09 - lineHeight;
1716  yp07 = yp08 - lineHeight;
1717  yp06 = yp08 - d / 4;
1718  yp05 = yp09 - d / 2;
1719 
1722  // Rectangles:
1723  if (!modeOnly)
1724  osd->DrawRectangle(xp00, yp00, xp02 - 1, yp01 - 1, frameColor);
1725  osd->DrawRectangle(xp00, yp02, xp02 - 1, yp03 - 1, frameColor);
1726  if (!modeOnly) {
1727  // Elbow:
1728  osd->DrawRectangle(xp00, yp04, xp01 - 1, yp05 - 1, frameColor);
1730  osd->DrawEllipse (xp00, yp05, xp01 - 1, yp09 - 1, frameColor, 3);
1731  osd->DrawRectangle(xp01, yp04, xp02 - 1, yp09 - 1, frameColor);
1732  osd->DrawEllipse (xp02, yp06, xp04 - 1, yp08 - 1, frameColor, -3);
1733  osd->DrawRectangle(xp02, yp08, xp05 - 1, yp09 - 1, frameColor);
1734  // Status area:
1735  osd->DrawRectangle(xp06, yp08, xp07 - 1, yp09 - 1, frameColor);
1736  osd->DrawRectangle(xp08, yp08, xp09 - 1, yp09 - 1, frameColor);
1737  osd->DrawRectangle(xp10, yp08, xp11 - 1, yp09 - 1, frameColor);
1738  osd->DrawRectangle(xp12, yp08, xp13 - 1, yp09 - 1, Theme.Color(clrDateBg));
1739  osd->DrawRectangle(xp14, yp08, xp14 + lineHeight / 2 - 1, yp09 - 1, frameColor);
1740  osd->DrawRectangle(xp14 + lineHeight / 2, yp08 + lineHeight / 2, xp15 - 1, yp09 - 1, clrTransparent);
1741  osd->DrawEllipse (xp14 + lineHeight / 2, yp08, xp15 - 1, yp09 - 1, frameColor, 5);
1742  }
1743 }
1744 
1746 {
1747  delete osd;
1748 }
1749 
1751 {
1752  cString s = DayDateTime();
1753  if (!*lastDate || strcmp(s, lastDate)) {
1754  osd->DrawText(xp12, yp08, s, Theme.Color(clrDateFg), Theme.Color(clrDateBg), cFont::GetFont(fontOsd), xp13 - xp12, lineHeight, taRight | taBorder);
1755  lastDate = s;
1756  }
1757 }
1758 
1760 {
1761  cDevice *Device = cDevice::PrimaryDevice();
1762  const tTrackId *Track = Device->GetTrack(Device->GetCurrentAudioTrack());
1763  if (!Track && *lastTrackId.description || Track && strcmp(lastTrackId.description, Track->description)) {
1764  osd->DrawText(xp03, yp04, Track ? Track->description : "", Theme.Color(clrTrackName), Theme.Color(clrBackground), cFont::GetFont(fontOsd), xp07 - xp03);
1765  strn0cpy(lastTrackId.description, Track ? Track->description : "", sizeof(lastTrackId.description));
1766  }
1767 }
1768 
1770 {
1771  const cRecordingInfo *RecordingInfo = Recording->Info();
1772  SetTitle(RecordingInfo->Title());
1773  osd->DrawText(xp03, yp01 - lineHeight, RecordingInfo->ShortText(), Theme.Color(clrEventShortText), Theme.Color(clrBackground), cFont::GetFont(fontSml), xp13 - xp03);
1774  osd->DrawText(xp00, yp00, ShortDateString(Recording->Start()), Theme.Color(clrReplayFrameFg), frameColor, cFont::GetFont(fontOsd), xp02 - xp00, 0, taTop | taRight | taBorder);
1775  osd->DrawText(xp00, yp01 - lineHeight, TimeString(Recording->Start()), Theme.Color(clrReplayFrameFg), frameColor, cFont::GetFont(fontOsd), xp02 - xp00, 0, taBottom | taRight | taBorder);
1776 }
1777 
1778 void cSkinLCARSDisplayReplay::SetTitle(const char *Title)
1779 {
1780  osd->DrawText(xp03, yp00, Title, Theme.Color(clrEventTitle), Theme.Color(clrBackground), cFont::GetFont(fontOsd), xp13 - xp03);
1781 }
1782 
1783 static const char *const *ReplaySymbols[2][2][5] = {
1784  { { pause_xpm, srew_xpm, srew1_xpm, srew2_xpm, srew3_xpm },
1785  { pause_xpm, sfwd_xpm, sfwd1_xpm, sfwd2_xpm, sfwd3_xpm }, },
1786  { { play_xpm, frew_xpm, frew1_xpm, frew2_xpm, frew3_xpm },
1787  { play_xpm, ffwd_xpm, ffwd1_xpm, ffwd2_xpm, ffwd3_xpm } }
1788  };
1789 
1790 void cSkinLCARSDisplayReplay::SetMode(bool Play, bool Forward, int Speed)
1791 {
1792  Speed = constrain(Speed, -1, 3);
1793  cBitmap bm(ReplaySymbols[Play][Forward][Speed + 1]);
1794  osd->DrawBitmap(xp01 - bm.Width() / 2, (yp02 + yp03 - bm.Height()) / 2, bm, Theme.Color(clrReplayFrameFg), frameColor);
1795 }
1796 
1797 void cSkinLCARSDisplayReplay::SetProgress(int Current, int Total)
1798 {
1799  cProgressBar pb(xp13 - xp03, lineHeight, Current, Total, marks, Theme.Color(clrReplayProgressSeen), Theme.Color(clrReplayProgressRest), Theme.Color(clrReplayProgressSelected), Theme.Color(clrReplayProgressMark), Theme.Color(clrReplayProgressCurrent));
1800  osd->DrawBitmap(xp03, yp02, pb);
1801 }
1802 
1803 void cSkinLCARSDisplayReplay::SetCurrent(const char *Current)
1804 {
1805  const cFont *font = cFont::GetFont(fontOsd);
1806  int w = font->Width(Current);
1807  osd->DrawText(xp03, yp03 - lineHeight, Current, Theme.Color(clrReplayPosition), Theme.Color(clrBackground), font, lastCurrentWidth > w ? lastCurrentWidth : w, 0, taLeft);
1808  lastCurrentWidth = w;
1809 }
1810 
1811 void cSkinLCARSDisplayReplay::SetTotal(const char *Total)
1812 {
1813  const cFont *font = cFont::GetFont(fontOsd);
1814  int w = font->Width(Total) + 10;
1815  osd->DrawText(xp13 - w, yp03 - lineHeight, Total, Theme.Color(clrReplayPosition), Theme.Color(clrBackground), font, w, 0, taRight);
1816 }
1817 
1818 void cSkinLCARSDisplayReplay::SetJump(const char *Jump)
1819 {
1820  osd->DrawText(xp06, yp08, Jump, Theme.Color(clrReplayJumpFg), Jump ? Theme.Color(clrReplayJumpBg) : frameColor, cFont::GetFont(fontOsd), xp07 - xp06, 0, taCenter);
1821 }
1822 
1824 {
1825  if (Text) {
1826  osd->SaveRegion(xp06, yp08, xp13 - 1, yp09 - 1);
1827  osd->DrawText(xp06, yp08, Text, Theme.Color(clrMessageStatusFg + 2 * Type), Theme.Color(clrMessageStatusBg + 2 * Type), cFont::GetFont(fontSml), xp13 - xp06, yp09 - yp08, taCenter);
1828  }
1829  else
1830  osd->RestoreRegion();
1831 }
1832 
1834 {
1835  if (!modeOnly) {
1836  DrawDate();
1837  DrawTrack();
1838  }
1839  osd->Flush();
1840 }
1841 
1842 // --- cSkinLCARSDisplayVolume -----------------------------------------------
1843 
1845 private:
1847  int x0, x1, x2, x3, x4, x5, x6, x7;
1848  int y0, y1;
1850  int mute;
1851 public:
1853  virtual ~cSkinLCARSDisplayVolume();
1854  virtual void SetVolume(int Current, int Total, bool Mute);
1855  virtual void Flush(void);
1856  };
1857 
1859 {
1860  const cFont *font = cFont::GetFont(fontOsd);
1861  int lineHeight = font->Height();
1862  frameColor = Theme.Color(clrVolumeFrame);
1863  mute = -1;
1864  x0 = 0;
1865  x1 = lineHeight / 2;
1866  x2 = lineHeight;
1867  x3 = x2 + Gap;
1868  x7 = cOsd::OsdWidth();
1869  x6 = x7 - lineHeight / 2;
1870  x5 = x6 - lineHeight / 2;
1871  x4 = x5 - Gap;
1872  y0 = 0;
1873  y1 = lineHeight;
1874  osd = CreateOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - y1, x0, y0, x7 - 1, y1 - 1);
1875  osd->DrawRectangle(x0, y0, x7 - 1, y1 - 1, Theme.Color(clrBackground));
1876  osd->DrawRectangle(x0, y0, x1 - 1, y1 - 1, clrTransparent);
1877  osd->DrawEllipse (x0, y0, x1 - 1, y1 - 1, frameColor, 7);
1878  osd->DrawRectangle(x1, y0, x2 - 1, y1 - 1, frameColor);
1879  osd->DrawRectangle(x3, y0, x4 - 1, y1 - 1, frameColor);
1880  osd->DrawRectangle(x5, y0, x6 - 1, y1 - 1, frameColor);
1881  osd->DrawRectangle(x6, y0, x7 - 1, y1 - 1, clrTransparent);
1882  osd->DrawEllipse (x6, y0, x7 - 1, y1 - 1, frameColor, 5);
1883 }
1884 
1886 {
1887  delete osd;
1888 }
1889 
1890 void cSkinLCARSDisplayVolume::SetVolume(int Current, int Total, bool Mute)
1891 {
1892  int xl = x3 + TextSpacing;
1893  int xr = x4 - TextSpacing;
1894  int yt = y0 + TextFrame;
1895  int yb = y1 - TextFrame;
1896  if (mute != Mute) {
1897  osd->DrawRectangle(x3, y0, x4 - 1, y1 - 1, frameColor);
1898  mute = Mute;
1899  }
1900  cBitmap bm(Mute ? mute_xpm : volume_xpm);
1901  osd->DrawBitmap(xl, y0 + (y1 - y0 - bm.Height()) / 2, bm, Theme.Color(clrVolumeSymbol), frameColor);
1902  if (!Mute) {
1903  xl += bm.Width() + TextSpacing;
1904  int w = (y1 - y0) / 3;
1905  int d = TextFrame;
1906  int n = (xr - xl + d) / (w + d);
1907  int x = xr - n * (w + d);
1908  tColor Color = Theme.Color(clrVolumeBarLower);
1909  for (int i = 0; i < n; i++) {
1910  if (Total * i >= Current * n)
1911  Color = Theme.Color(clrVolumeBarUpper);
1912  osd->DrawRectangle(x, yt, x + w - 1, yb - 1, Color);
1913  x += w + d;
1914  }
1915  }
1916 }
1917 
1919 {
1920  osd->Flush();
1921 }
1922 
1923 // --- cSkinLCARSDisplayTracks -----------------------------------------------
1924 
1926 private:
1934  void SetItem(const char *Text, int Index, bool Current);
1935 public:
1936  cSkinLCARSDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks);
1937  virtual ~cSkinLCARSDisplayTracks();
1938  virtual void SetTrack(int Index, const char * const *Tracks);
1939  virtual void SetAudioChannel(int AudioChannel);
1940  virtual void Flush(void);
1941  };
1942 
1946 
1947 cSkinLCARSDisplayTracks::cSkinLCARSDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks)
1948 {
1949  const cFont *font = cFont::GetFont(fontOsd);
1950  lineHeight = font->Height();
1951  frameColor = Theme.Color(clrTrackFrameBg);
1952  currentIndex = -1;
1953  xt00 = 0;
1954  xt01 = xt00 + lineHeight / 2;
1955  xt02 = xt01 + Gap;
1956  xt03 = xt00 + 2 * lineHeight;
1957  int ItemsWidth = font->Width(Title) + xt03 - xt02;
1958  for (int i = 0; i < NumTracks; i++)
1959  ItemsWidth = max(ItemsWidth, font->Width(Tracks[i]) + 2 * TextFrame);
1960  xt04 = xt02 + ItemsWidth;
1961  xt05 = xt04 + Gap;
1962  xt06 = xt04 + lineHeight;
1963  xt07 = xt05 + lineHeight;
1964  xt08 = xt07 + lineHeight;
1965  xt09 = xt08 + Gap;
1966  xt10 = xt09 + lineHeight / 2;
1967  xt11 = xt10 + Gap;
1968  xt12 = xt11 + lineHeight;
1969  yt00 = 0;
1970  yt01 = yt00 + lineHeight;
1971  yt02 = yt01 + lineHeight;
1972  yt03 = yt02 + Gap;
1973  yt04 = yt03 + NumTracks * lineHeight + (NumTracks - 1) * Gap;
1974  yt05 = yt04 + Gap;
1975  yt06 = yt05 + lineHeight;
1976  yt07 = yt06 + lineHeight;
1977  while (yt07 > cOsd::OsdHeight()) {
1978  yt04 -= lineHeight + Gap;
1979  yt05 = yt04 + Gap;
1980  yt06 = yt05 + lineHeight;
1981  yt07 = yt06 + lineHeight;
1982  }
1984  // The upper elbow:
1985  osd->DrawRectangle(xt00, yt00, xt12 - 1, yt07 - 1, Theme.Color(clrBackground));
1987  osd->DrawEllipse (xt00, yt00, xt03 - 1, yt02 - 1, frameColor, 2);
1988  osd->DrawRectangle(xt03, yt00, xt04 - 1, yt02 - 1, frameColor);
1989  osd->DrawRectangle(xt04, yt00, xt08 - 1, yt01 - 1, frameColor);
1990  osd->DrawEllipse (xt04, yt01, xt06 - 1, yt02 - 1, frameColor, -2);
1991  osd->DrawRectangle(xt09, yt00, xt10 - 1, yt01 - 1, frameColor);
1992  osd->DrawRectangle(xt11, yt00, xt11 + lineHeight / 2 - 1, yt01 - 1, frameColor);
1993  osd->DrawRectangle(xt11 + lineHeight / 2, yt00, xt12 - 1, yt00 + lineHeight / 2 - 1, clrTransparent);
1994  osd->DrawEllipse (xt11 + lineHeight / 2, yt00, xt12 - 1, yt01 - 1, frameColor, 5);
1995  osd->DrawText(xt03, yt00, Title, Theme.Color(clrTrackFrameFg), frameColor, font, xt04 - xt03, 0, taTop | taRight);
1996  // The items:
1997  for (int i = 0; i < NumTracks; i++)
1998  SetItem(Tracks[i], i, false);
1999  // The lower elbow:
2000  osd->DrawRectangle(xt00, yt05, xt03 - 1, yt07 - 1, clrTransparent);
2001  osd->DrawEllipse (xt00, yt05, xt03 - 1, yt07 - 1, frameColor, 3);
2002  osd->DrawRectangle(xt03, yt05, xt04 - 1, yt07 - 1, frameColor);
2003  osd->DrawRectangle(xt04, yt06, xt08 - 1, yt07 - 1, frameColor);
2004  osd->DrawEllipse (xt04, yt05, xt06 - 1, yt06 - 1, frameColor, -3);
2005  osd->DrawRectangle(xt09, yt06, xt10 - 1, yt07 - 1, frameColor);
2006  osd->DrawRectangle(xt11, yt06, xt11 + lineHeight / 2 - 1, yt07 - 1, frameColor);
2007  osd->DrawRectangle(xt11 + lineHeight / 2, yt06 + lineHeight / 2, xt12 - 1, yt07 - 1, clrTransparent);
2008  osd->DrawEllipse (xt11 + lineHeight / 2, yt06, xt12 - 1, yt07 - 1, frameColor, 5);
2009 }
2010 
2012 {
2013  delete osd;
2014 }
2015 
2016 void cSkinLCARSDisplayTracks::SetItem(const char *Text, int Index, bool Current)
2017 {
2018  int y0 = yt03 + Index * (lineHeight + Gap);
2019  int y1 = y0 + lineHeight;
2020  if (y1 > yt04)
2021  return;
2022  tColor ColorFg, ColorBg;
2023  if (Current) {
2024  ColorFg = Theme.Color(clrTrackItemCurrentFg);
2025  ColorBg = Theme.Color(clrTrackItemCurrentBg);
2026  osd->DrawRectangle(xt00, y0, xt01 - 1, y1 - 1, frameColor);
2027  osd->DrawRectangle(xt02, y0, xt04 - 1, y1 - 1, ColorBg);
2028  osd->DrawRectangle(xt05, y0, xt05 + lineHeight / 2 - 1, y1 - 1, ColorBg);
2029  osd->DrawEllipse (xt05 + lineHeight / 2, y0, xt07 - 1, y1 - 1, ColorBg, 5);
2030  currentIndex = Index;
2031  }
2032  else {
2033  ColorFg = Theme.Color(clrTrackItemFg);
2034  ColorBg = Theme.Color(clrTrackItemBg);
2035  osd->DrawRectangle(xt00, y0, xt01 - 1, y1 - 1, frameColor);
2036  osd->DrawRectangle(xt02, y0, xt04 - 1, y1 - 1, ColorBg);
2037  if (currentIndex == Index)
2038  osd->DrawRectangle(xt05, y0, xt07 - 1, y1 - 1, Theme.Color(clrBackground));
2039  }
2040  const cFont *font = cFont::GetFont(fontOsd);
2041  osd->DrawText(xt02, y0, Text, ColorFg, ColorBg, font, xt04 - xt02, y1 - y0, taTop | taLeft | taBorder);
2042 }
2043 
2044 void cSkinLCARSDisplayTracks::SetTrack(int Index, const char * const *Tracks)
2045 {
2046  if (currentIndex >= 0)
2047  SetItem(Tracks[currentIndex], currentIndex, false);
2048  SetItem(Tracks[Index], Index, true);
2049 }
2050 
2052 {
2053  cBitmap *bm = NULL;
2054  switch (AudioChannel) {
2055  case 0: bm = &bmAudioStereo; break;
2056  case 1: bm = &bmAudioLeft; break;
2057  case 2: bm = &bmAudioRight; break;
2058  default: ;
2059  }
2060  if (bm)
2061  osd->DrawBitmap(xt04 - bm->Width(), (yt06 + yt07 - bm->Height()) / 2, *bm, Theme.Color(clrTrackFrameFg), frameColor);
2062  else
2063  osd->DrawRectangle(xt03, yt06, xt04 - 1, yt07 - 1, frameColor);
2064 }
2065 
2067 {
2068  osd->Flush();
2069 }
2070 
2071 // --- cSkinLCARSDisplayMessage ----------------------------------------------
2072 
2074 private:
2076  int x0, x1, x2, x3, x4, x5, x6, x7;
2077  int y0, y1;
2078 public:
2080  virtual ~cSkinLCARSDisplayMessage();
2081  virtual void SetMessage(eMessageType Type, const char *Text);
2082  virtual void Flush(void);
2083  };
2084 
2086 {
2087  const cFont *font = cFont::GetFont(fontOsd);
2088  int lineHeight = font->Height();
2089  x0 = 0;
2090  x1 = lineHeight / 2;
2091  x2 = lineHeight;
2092  x3 = x2 + Gap;
2093  x7 = cOsd::OsdWidth();
2094  x6 = x7 - lineHeight / 2;
2095  x5 = x6 - lineHeight / 2;
2096  x4 = x5 - Gap;
2097  y0 = 0;
2098  y1 = lineHeight;
2099  osd = CreateOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - y1, x0, y0, x7 - 1, y1 - 1);
2100 }
2101 
2103 {
2104  delete osd;
2105 }
2106 
2108 {
2109  tColor ColorFg = Theme.Color(clrMessageStatusFg + 2 * Type);
2110  tColor ColorBg = Theme.Color(clrMessageStatusBg + 2 * Type);
2111  osd->DrawRectangle(x0, y0, x7 - 1, y1 - 1, Theme.Color(clrBackground));
2112  osd->DrawRectangle(x0, y0, x1 - 1, y1 - 1, clrTransparent);
2113  osd->DrawEllipse (x0, y0, x1 - 1, y1 - 1, ColorBg, 7);
2114  osd->DrawRectangle(x1, y0, x2 - 1, y1 - 1, ColorBg);
2115  osd->DrawText(x3, y0, Text, ColorFg, ColorBg, cFont::GetFont(fontSml), x4 - x3, y1 - y0, taCenter);
2116  osd->DrawRectangle(x5, y0, x6 - 1, y1 - 1, ColorBg);
2117  osd->DrawRectangle(x6, y0, x7 - 1, y1 - 1, clrTransparent);
2118  osd->DrawEllipse (x6, y0, x7 - 1, y1 - 1, ColorBg, 5);
2119 }
2120 
2122 {
2123  osd->Flush();
2124 }
2125 
2126 // --- cSkinLCARS ------------------------------------------------------------
2127 
2129 :cSkin("lcars", &::Theme)
2130 {
2131 }
2132 
2133 const char *cSkinLCARS::Description(void)
2134 {
2135  return "LCARS";
2136 }
2137 
2139 {
2140  return new cSkinLCARSDisplayChannel(WithInfo);
2141 }
2142 
2144 {
2145  return new cSkinLCARSDisplayMenu;
2146 }
2147 
2149 {
2150  return new cSkinLCARSDisplayReplay(ModeOnly);
2151 }
2152 
2154 {
2155  return new cSkinLCARSDisplayVolume;
2156 }
2157 
2158 cSkinDisplayTracks *cSkinLCARS::DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks)
2159 {
2160  return new cSkinLCARSDisplayTracks(Title, NumTracks, Tracks);
2161 }
2162 
2164 {
2165  return new cSkinLCARSDisplayMessage;
2166 }