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 {
86  menuCategory = mcUndefined;
87  SetTabs(0);
88 }
89 
91 {
92  menuCategory = MenuCategory;
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
void Lock(void)
Definition: thread.c:191
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
cSkin * current
Definition: skins.h:427
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 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
#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
static tThreadId IsMainThread(void)
Definition: thread.h:129
Definition: tools.h:489
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
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&#39;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
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
int Height(void) const
Definition: osd.h:189
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
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
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