vdr  2.2.0
skins.c
Go to the documentation of this file.
1 /*
2  * skins.c: The optical appearance of the OSD
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: skins.c 3.1 2013/08/18 12:07:22 kls Exp $
8  */
9 
10 #include "skins.h"
11 #include "interface.h"
12 #include "status.h"
13 
14 // --- cSkinQueuedMessage ----------------------------------------------------
15 
17  friend class cSkins;
18 private:
20  char *message;
21  int seconds;
22  int timeout;
25  int state;
28 public:
29  cSkinQueuedMessage(eMessageType Type, const char *s, int Seconds, int Timeout);
30  virtual ~cSkinQueuedMessage();
31  };
32 
33 cSkinQueuedMessage::cSkinQueuedMessage(eMessageType Type, const char *s, int Seconds, int Timeout)
34 {
35  type = Type;
36  message = s ? strdup(s) : NULL;
37  seconds = Seconds;
38  timeout = Timeout;
40  key = kNone;
41  state = 0; // waiting
42 }
43 
45 {
46  free(message);
47 }
48 
50 
51 // --- cSkinDisplay ----------------------------------------------------------
52 
54 
56 {
57  current = this;
58  editableWidth = 100; //XXX
59 }
60 
62 {
63  current = NULL;
64 }
65 
66 // --- cSkinDisplayChannel ---------------------------------------------------
67 
69 {
70  positioner = NULL;
71 }
72 
74 {
75  if (positioner && Positioner != positioner)
76  SetMessage(mtInfo, NULL);
77  positioner = Positioner;
78  if (positioner)
79  SetMessage(mtInfo, cString::sprintf(tr("Moving dish to %.1f..."), double(positioner->TargetLongitude()) / 10));
80 }
81 
82 // --- cSkinDisplayMenu ------------------------------------------------------
83 
85 {
87  SetTabs(0);
88 }
89 
91 {
93 }
94 
95 void cSkinDisplayMenu::SetTabs(int Tab1, int Tab2, int Tab3, int Tab4, int Tab5)
96 {
97  tabs[0] = 0;
98  tabs[1] = Tab1 ? tabs[0] + Tab1 : 0;
99  tabs[2] = Tab2 ? tabs[1] + Tab2 : 0;
100  tabs[3] = Tab3 ? tabs[2] + Tab3 : 0;
101  tabs[4] = Tab4 ? tabs[3] + Tab4 : 0;
102  tabs[5] = Tab5 ? tabs[4] + Tab5 : 0;
103  for (int i = 1; i < MaxTabs; i++)
104  tabs[i] *= AvgCharWidth();
105 }
106 
107 void cSkinDisplayMenu::Scroll(bool Up, bool Page)
108 {
109  textScroller.Scroll(Up, Page);
110 }
111 
112 const char *cSkinDisplayMenu::GetTabbedText(const char *s, int Tab)
113 {
114  if (!s)
115  return NULL;
116  static char buffer[1000];
117  const char *a = s;
118  const char *b = strchrnul(a, '\t');
119  while (*b && Tab-- > 0) {
120  a = b + 1;
121  b = strchrnul(a, '\t');
122  }
123  if (!*b)
124  return (Tab <= 0) ? a : NULL;
125  unsigned int n = b - a;
126  if (n >= sizeof(buffer))
127  n = sizeof(buffer) - 1;
128  strncpy(buffer, a, n);
129  buffer[n] = 0;
130  return buffer;
131 }
132 
133 void cSkinDisplayMenu::SetScrollbar(int Total, int Offset)
134 {
135 }
136 
138 {
139  return 0;
140 }
141 
143 {
144  return NULL;
145 }
146 
147 // --- cSkinDisplayReplay::cProgressBar --------------------------------------
148 
149 cSkinDisplayReplay::cProgressBar::cProgressBar(int Width, int Height, int Current, int Total, const cMarks *Marks, tColor ColorSeen, tColor ColorRest, tColor ColorSelected, tColor ColorMark, tColor ColorCurrent)
150 :cBitmap(Width, Height, 2)
151 {
152  total = Total;
153  if (total > 0) {
154  int p = Pos(Current);
155  DrawRectangle(0, 0, p, Height - 1, ColorSeen);
156  DrawRectangle(p + 1, 0, Width - 1, Height - 1, ColorRest);
157  if (Marks) {
158  bool Start = true;
159  for (const cMark *m = Marks->First(); m; m = Marks->Next(m)) {
160  int p1 = Pos(m->Position());
161  if (Start) {
162  const cMark *m2 = Marks->Next(m);
163  int p2 = Pos(m2 ? m2->Position() : total);
164  int h = Height / 3;
165  DrawRectangle(p1, h, p2, Height - h, ColorSelected);
166  }
167  Mark(p1, Start, m->Position() == Current, ColorMark, ColorCurrent);
168  Start = !Start;
169  }
170  }
171  }
172 }
173 
174 void cSkinDisplayReplay::cProgressBar::Mark(int x, bool Start, bool Current, tColor ColorMark, tColor ColorCurrent)
175 {
176  DrawRectangle(x, 0, x, Height() - 1, ColorMark);
177  const int d = Height() / (Current ? 3 : 9);
178  for (int i = 0; i < d; i++) {
179  int h = Start ? i : Height() - 1 - i;
180  DrawRectangle(x - d + i, h, x + d - i, h, Current ? ColorCurrent : ColorMark);
181  }
182 }
183 
184 // --- cSkinDisplayReplay ----------------------------------------------------
185 
187 {
188  marks = NULL;
189 }
190 
192 {
193  SetTitle(Recording->Title());
194 }
195 
197 {
198  marks = Marks;
199 }
200 
201 // --- cSkin -----------------------------------------------------------------
202 
203 cSkin::cSkin(const char *Name, cTheme *Theme)
204 {
205  name = strdup(Name);
206  theme = Theme;
207  if (theme)
208  cThemes::Save(name, theme);
209  Skins.Add(this);
210 }
211 
213 {
214  free(name);
215 }
216 
217 // --- cSkins ----------------------------------------------------------------
218 
220 
222 {
223  displayMessage = NULL;
224 }
225 
227 {
228  delete displayMessage;
229 }
230 
231 bool cSkins::SetCurrent(const char *Name)
232 {
233  if (Name) {
234  for (cSkin *Skin = First(); Skin; Skin = Next(Skin)) {
235  if (strcmp(Skin->Name(), Name) == 0) {
236  isyslog("setting current skin to \"%s\"", Name);
237  current = Skin;
238  return true;
239  }
240  }
241  }
242  current = First();
243  if (current)
244  isyslog("skin \"%s\" not available - using \"%s\" instead", Name, current->Name());
245  else
246  esyslog("ERROR: no skin available");
247  return current != NULL;
248 }
249 
250 eKeys cSkins::Message(eMessageType Type, const char *s, int Seconds)
251 {
252  if (!cThread::IsMainThread()) {
253  dsyslog("cSkins::Message() called from background thread - ignored! (Use cSkins::QueueMessage() instead)");
254  return kNone;
255  }
256  switch (Type) {
257  case mtInfo: isyslog("info: %s", s); break;
258  case mtWarning: isyslog("warning: %s", s); break;
259  case mtError: esyslog("ERROR: %s", s); break;
260  default: ;
261  }
262  if (!Current())
263  return kNone;
264  if (!cSkinDisplay::Current()) {
265  if (displayMessage)
266  delete displayMessage;
267  displayMessage = Current()->DisplayMessage();
268  }
269  cSkinDisplay::Current()->SetMessage(Type, s);
272  eKeys k = kNone;
273  if (Type != mtStatus) {
274  k = Interface->Wait(Seconds);
275  if (displayMessage) {
276  delete displayMessage;
277  displayMessage = NULL;
279  }
280  else {
281  cSkinDisplay::Current()->SetMessage(Type, NULL);
283  }
284  }
285  else if (!s && displayMessage) {
286  delete displayMessage;
287  displayMessage = NULL;
289  }
290  return k;
291 }
292 
293 int cSkins::QueueMessage(eMessageType Type, const char *s, int Seconds, int Timeout)
294 {
295  if (Type == mtStatus) {
296  dsyslog("cSkins::QueueMessage() called with mtStatus - ignored!");
297  return kNone;
298  }
299  if (isempty(s)) {
300  if (!cThread::IsMainThread()) {
302  for (cSkinQueuedMessage *m = SkinQueuedMessages.Last(); m; m = SkinQueuedMessages.Prev(m)) {
303  if (m->threadId == cThread::ThreadId() && m->state == 0)
304  m->state = 2; // done
305  }
307  }
308  else
309  dsyslog("cSkins::QueueMessage() called with empty message from main thread - ignored!");
310  return kNone;
311  }
312  int k = kNone;
313  if (Timeout > 0) {
314  if (cThread::IsMainThread()) {
315  dsyslog("cSkins::QueueMessage() called from main thread with Timeout = %d - ignored!", Timeout);
316  return k;
317  }
318  cSkinQueuedMessage *m = new cSkinQueuedMessage(Type, s, Seconds, Timeout);
320  SkinQueuedMessages.Add(m);
321  m->mutex.Lock();
323  if (m->condVar.TimedWait(m->mutex, Timeout * 1000))
324  k = m->key;
325  else
326  k = -1; // timeout, nothing has been displayed
327  m->state = 2; // done
328  m->mutex.Unlock();
329  }
330  else {
332  // Check if there is a waiting message w/o timeout for this thread:
333  if (Timeout == -1) {
334  for (cSkinQueuedMessage *m = SkinQueuedMessages.Last(); m; m = SkinQueuedMessages.Prev(m)) {
335  if (m->threadId == cThread::ThreadId()) {
336  if (m->state == 0 && m->timeout == -1)
337  m->state = 2; // done
338  break;
339  }
340  }
341  }
342  // Add the new message:
343  SkinQueuedMessages.Add(new cSkinQueuedMessage(Type, s, Seconds, Timeout));
345  }
346  return k;
347 }
348 
350 {
351  if (!cThread::IsMainThread()) {
352  dsyslog("cSkins::ProcessQueuedMessages() called from background thread - ignored!");
353  return;
354  }
355  cSkinQueuedMessage *msg = NULL;
356  // Get the first waiting message:
358  for (cSkinQueuedMessage *m = SkinQueuedMessages.First(); m; m = SkinQueuedMessages.Next(m)) {
359  if (m->state == 0) { // waiting
360  m->state = 1; // active
361  msg = m;
362  break;
363  }
364  }
366  // Display the message:
367  if (msg) {
368  msg->mutex.Lock();
369  if (msg->state == 1) { // might have changed since we got it
370  msg->key = Skins.Message(msg->type, msg->message, msg->seconds);
371  if (msg->timeout == 0)
372  msg->state = 2; // done
373  else
374  msg->condVar.Broadcast();
375  }
376  msg->mutex.Unlock();
377  }
378  // Remove done messages from the queue:
380  for (;;) {
381  cSkinQueuedMessage *m = SkinQueuedMessages.First();
382  if (m && m->state == 2) { // done
383  SkinQueuedMessages.Del(m);
384  }
385  else
386  break;
387  }
389 }
390 
391 void cSkins::Flush(void)
392 {
393  if (cSkinDisplay::Current())
395 }
396 
397 void cSkins::Clear(void)
398 {
399  if (displayMessage) {
400  delete displayMessage;
401  displayMessage = NULL;
402  }
404 }
cSkins(void)
Definition: skins.c:221
virtual void Scroll(bool Up, bool Page)
If this menu contains a text area that can be scrolled, this function will be called to actually scro...
Definition: skins.c:107
static int AvgCharWidth(void)
Returns the average width of a character in pixel (just a raw estimate).
Definition: skins.h:33
void Lock(void)
Definition: thread.c:191
int tabs[MaxTabs]
Definition: skins.h:153
int Position(void) const
Definition: recording.h:344
eMessageType
Definition: skins.h:24
bool isempty(const char *s)
Definition: tools.c:297
#define dsyslog(a...)
Definition: tools.h:36
cSkinDisplayReplay(void)
Definition: skins.c:186
cCondVar condVar
Definition: skins.c:27
virtual ~cSkin()
Definition: skins.c:212
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:2014
const char * Title(char Delimiter= ' ', bool NewIndicator=false, int Level=-1) const
Definition: recording.c:1060
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1080
int TargetLongitude(void) const
Returns the longitude the dish is supposed to be moved to.
Definition: positioner.h:105
int QueueMessage(eMessageType Type, const char *s, int Seconds=0, int Timeout=0)
Like Message(), but this function may be called from a background thread.
Definition: skins.c:293
void ProcessQueuedMessages(void)
Processes the first queued message, if any.
Definition: skins.c:349
const cPositioner * positioner
< This class is used to display the current channel, together with the present and following EPG even...
Definition: skins.h:57
#define esyslog(a...)
Definition: tools.h:34
virtual void SetScrollbar(int Total, int Offset)
Sets the Total number of items in the currently displayed list, and the Offset of the first item that...
Definition: skins.c:133
eMenuCategory MenuCategory(void) const
Returns the menu category, set by a previous call to SetMenuCategory().
Definition: skins.h:165
static tThreadId IsMainThread(void)
Definition: thread.h:129
Definition: tools.h:489
int editableWidth
Definition: skins.h:29
cSkinDisplayMessage * displayMessage
Definition: skins.h:428
cSkinDisplayChannel(void)
Definition: skins.c:68
static cSkinDisplay * Current(void)
Returns the currently active cSkinDisplay.
Definition: skins.h:48
cSkinQueuedMessage(eMessageType Type, const char *s, int Seconds, int Timeout)
Definition: skins.c:33
cSkinDisplayMenu(void)
Definition: skins.c:84
cProgressBar(int Width, int Height, int Current, int Total, const cMarks *Marks, tColor ColorSeen, tColor ColorRest, tColor ColorSelected, tColor ColorMark, tColor ColorCurrent)
Definition: skins.c:149
virtual void SetRecording(const cRecording *Recording)
Sets the recording that is currently being played.
Definition: skins.c:191
cList< cSkinQueuedMessage > SkinQueuedMessages
Definition: skins.c:49
virtual void Clear(void)
Definition: tools.c:2087
Definition: osd.h:169
void Scroll(bool Up, bool Page)
Definition: osd.c:2167
static cSkinDisplay * current
Definition: skins.h:28
char * message
Definition: skins.c:20
Definition: keys.h:55
A steerable satellite dish generally points to the south on the northern hemisphere, and to the north on the southern hemisphere (unless you're located directly on the equator, in which case the general direction is "up").
Definition: positioner.h:31
T * Last(void) const
Definition: tools.h:493
virtual void SetMarks(const cMarks *Marks)
Sets the editing marks to Marks, which shall be used to display the progress bar through a cProgressB...
Definition: skins.c:196
virtual void SetTabs(int Tab1, int Tab2=0, int Tab3=0, int Tab4=0, int Tab5=0)
Sets the tab columns to the given values, which are the number of characters in each column...
Definition: skins.c:95
eKeys Wait(int Seconds=0, bool KeepChar=false)
Definition: interface.c:49
T * Next(const T *object) const
Definition: tools.h:495
cTextScroller textScroller
Definition: skins.h:155
static void Save(const char *SkinName, cTheme *Theme)
Definition: themes.c:309
virtual void Flush(void)
Actually draws the OSD display to the output device.
Definition: skins.h:46
Definition: themes.h:17
static void MsgOsdStatusMessage(const char *Message)
Definition: status.c:92
void Broadcast(void)
Definition: thread.c:135
virtual void Clear(void)
Free up all registered skins.
Definition: skins.c:397
cSkin(const char *Name, cTheme *Theme=NULL)
Creates a new skin class, with the given Name and Theme.
Definition: skins.c:203
void Flush(void)
Flushes the currently active cSkinDisplay, if any.
Definition: skins.c:391
cSkinDisplay(void)
Definition: skins.c:55
void DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
Draws a filled rectangle defined by the upper left (x1, y1) and lower right (x2, y2) corners with the...
Definition: osd.c:611
Definition: skins.h:24
virtual void SetMessage(eMessageType Type, const char *Text)=0
Sets a one line message Text, with the given Type.
pid_t tThreadId
Definition: thread.h:75
static cTheme Theme
Definition: skinclassic.c:21
Definition: thread.h:63
static tThreadId ThreadId(void)
Definition: thread.c:341
bool TimedWait(cMutex &Mutex, int TimeoutMs)
Definition: thread.c:117
Definition: skins.h:425
~cSkins()
Definition: skins.c:226
Definition: skins.h:370
eKeys Message(eMessageType Type, const char *s, int Seconds=0)
Displays the given message, either through a currently visible display object that is capable of doin...
Definition: skins.c:250
Definition: skins.h:24
cMutex queueMessageMutex
Definition: skins.h:429
Definition: skins.h:24
eMenuCategory menuCategory
Definition: skins.h:152
T * First(void) const
Definition: tools.h:492
void Del(cListObject *Object, bool DeleteObject=true)
Definition: tools.c:2046
eMenuCategory
Definition: skins.h:91
static void MsgOsdClear(void)
Definition: status.c:80
virtual void SetMenuCategory(eMenuCategory MenuCategory)
Sets the current menu category.
Definition: skins.c:90
tThreadId threadId
Definition: skins.c:23
#define tr(s)
Definition: i18n.h:85
virtual const cFont * GetTextAreaFont(bool FixedFont) const
Returns a pointer to the font which is used to display text with SetText().
Definition: skins.c:142
#define isyslog(a...)
Definition: tools.h:35
virtual void SetPositioner(const cPositioner *Positioner)
Sets the Positioner used to move the satellite dish.
Definition: skins.c:73
void Mark(int x, bool Start, bool Current, tColor ColorMark, tColor ColorCurrent)
Definition: skins.c:174
cMutex mutex
Definition: skins.c:26
const char * GetTabbedText(const char *s, int Tab)
Returns the part of the given string that follows the given Tab (where 0 indicates the beginning of t...
Definition: skins.c:112
const cMarks * marks
< This class implements the progress display used during replay of a recording.
Definition: skins.h:291
eMessageType type
Definition: skins.c:19
cInterface * Interface
Definition: interface.c:20
virtual void SetTitle(const char *Title)=0
Sets the title of the recording.
cSkin * Current(void)
Returns a pointer to the current skin.
Definition: skins.h:436
virtual void SetMessage(eMessageType Type, const char *Text)
Sets a one line message Text, with the given Type.
Definition: skins.h:43
T * Prev(const T *object) const
Definition: tools.h:494
bool SetCurrent(const char *Name=NULL)
Sets the current skin to the one indicated by name.
Definition: skins.c:231
eKeys
Definition: keys.h:16
virtual ~cSkinQueuedMessage()
Definition: skins.c:44
Definition: font.h:37
virtual int GetTextAreaWidth(void) const
Returns the width in pixel of the area which is used to display text with SetText().
Definition: skins.c:137
uint32_t tColor
Definition: font.h:29
virtual ~cSkinDisplay()
Definition: skins.c:61
cSkins Skins
Definition: skins.c:219
void Unlock(void)
Definition: thread.c:197