vdr  2.4.1
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 4.0.1.2 2019/05/29 16:49:48 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 {
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  if (Type != mtStatus)
254  QueueMessage(Type, s, Seconds);
255  else
256  dsyslog("cSkins::Message(%d, \"%s\", %d) called from background thread - ignored! (Use cSkins::QueueMessage() instead)", Type, s, Seconds);
257  return kNone;
258  }
259  switch (Type) {
260  case mtInfo: isyslog("info: %s", s); break;
261  case mtWarning: isyslog("warning: %s", s); break;
262  case mtError: esyslog("ERROR: %s", s); break;
263  default: ;
264  }
265  if (!Current())
266  return kNone;
267  if (!cSkinDisplay::Current()) {
268  if (displayMessage)
269  delete displayMessage;
270  displayMessage = Current()->DisplayMessage();
271  }
272  cSkinDisplay::Current()->SetMessage(Type, s);
273  cSkinDisplay::Current()->Flush();
275  eKeys k = kNone;
276  if (Type != mtStatus) {
277  k = Interface->Wait(Seconds);
278  if (displayMessage) {
279  delete displayMessage;
280  displayMessage = NULL;
282  }
283  else {
284  cSkinDisplay::Current()->SetMessage(Type, NULL);
286  }
287  }
288  else if (!s && displayMessage) {
289  delete displayMessage;
290  displayMessage = NULL;
292  }
293  return k;
294 }
295 
296 int cSkins::QueueMessage(eMessageType Type, const char *s, int Seconds, int Timeout)
297 {
298  if (Type == mtStatus) {
299  dsyslog("cSkins::QueueMessage() called with mtStatus - ignored!");
300  return kNone;
301  }
302  if (isempty(s)) {
303  if (!cThread::IsMainThread()) {
305  for (cSkinQueuedMessage *m = SkinQueuedMessages.Last(); m; m = SkinQueuedMessages.Prev(m)) {
306  if (m->threadId == cThread::ThreadId() && m->state == 0)
307  m->state = 2; // done
308  }
310  }
311  else
312  dsyslog("cSkins::QueueMessage() called with empty message from main thread - ignored!");
313  return kNone;
314  }
315  int k = kNone;
316  if (Timeout > 0) {
317  if (cThread::IsMainThread()) {
318  dsyslog("cSkins::QueueMessage() called from main thread with Timeout = %d - ignored!", Timeout);
319  return k;
320  }
321  cSkinQueuedMessage *m = new cSkinQueuedMessage(Type, s, Seconds, Timeout);
323  SkinQueuedMessages.Add(m);
324  m->mutex.Lock();
326  if (m->condVar.TimedWait(m->mutex, Timeout * 1000))
327  k = m->key;
328  else
329  k = -1; // timeout, nothing has been displayed
330  m->state = 2; // done
331  m->mutex.Unlock();
332  }
333  else {
335  // Check if there is a waiting message w/o timeout for this thread:
336  if (Timeout == -1) {
337  for (cSkinQueuedMessage *m = SkinQueuedMessages.Last(); m; m = SkinQueuedMessages.Prev(m)) {
338  if (m->threadId == cThread::ThreadId()) {
339  if (m->state == 0 && m->timeout == -1)
340  m->state = 2; // done
341  break;
342  }
343  }
344  }
345  // Add the new message:
346  SkinQueuedMessages.Add(new cSkinQueuedMessage(Type, s, Seconds, Timeout));
348  }
349  return k;
350 }
351 
353 {
354  if (!cThread::IsMainThread()) {
355  dsyslog("cSkins::ProcessQueuedMessages() called from background thread - ignored!");
356  return;
357  }
358  // Check whether there is a cSkinDisplay object (if any) that implements SetMessage():
359  if (cSkinDisplay *sd = cSkinDisplay::Current()) {
360  if (!(dynamic_cast<cSkinDisplayChannel *>(sd) ||
361  dynamic_cast<cSkinDisplayMenu *>(sd) ||
362  dynamic_cast<cSkinDisplayReplay *>(sd) ||
363  dynamic_cast<cSkinDisplayMessage *>(sd)))
364  return;
365  }
366  cSkinQueuedMessage *msg = NULL;
367  // Get the first waiting message:
369  for (cSkinQueuedMessage *m = SkinQueuedMessages.First(); m; m = SkinQueuedMessages.Next(m)) {
370  if (m->state == 0) { // waiting
371  m->state = 1; // active
372  msg = m;
373  break;
374  }
375  }
377  // Display the message:
378  if (msg) {
379  msg->mutex.Lock();
380  if (msg->state == 1) { // might have changed since we got it
381  msg->key = Skins.Message(msg->type, msg->message, msg->seconds);
382  if (msg->timeout == 0)
383  msg->state = 2; // done
384  else
385  msg->condVar.Broadcast();
386  }
387  msg->mutex.Unlock();
388  }
389  // Remove done messages from the queue:
391  for (;;) {
393  if (m && m->state == 2) { // done
394  SkinQueuedMessages.Del(m);
395  }
396  else
397  break;
398  }
400 }
401 
402 void cSkins::Flush(void)
403 {
404  if (cSkinDisplay::Current())
405  cSkinDisplay::Current()->Flush();
406 }
407 
408 void cSkins::Clear(void)
409 {
410  if (displayMessage) {
411  delete displayMessage;
412  displayMessage = NULL;
413  }
415 }
cSkinDisplayMenu::SetTabs
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
cSkinDisplayChannel::SetMessage
virtual void SetMessage(eMessageType Type, const char *Text)=0
Sets a one line message Text, with the given Type.
cString::sprintf
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1127
tColor
uint32_t tColor
Definition: font.h:29
cSkinDisplayChannel::cSkinDisplayChannel
cSkinDisplayChannel(void)
Definition: skins.c:68
cSkinDisplayMenu::cSkinDisplayMenu
cSkinDisplayMenu(void)
Definition: skins.c:84
cSkinDisplayChannel
Definition: skins.h:65
Interface
cInterface * Interface
Definition: interface.c:20
cSkinDisplayChannel::SetPositioner
virtual void SetPositioner(const cPositioner *Positioner)
Sets the Positioner used to move the satellite dish.
Definition: skins.c:73
mcUndefined
@ mcUndefined
Definition: skins.h:105
isempty
bool isempty(const char *s)
Definition: tools.c:331
cSkinDisplayMenu::GetTabbedText
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
mtStatus
@ mtStatus
Definition: skins.h:37
cSkin
Definition: skins.h:402
cSkins::Message
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
kNone
@ kNone
Definition: keys.h:55
cSkin::~cSkin
virtual ~cSkin()
Definition: skins.c:212
cCondVar
Definition: thread.h:44
cSkinDisplay::~cSkinDisplay
virtual ~cSkinDisplay()
Definition: skins.c:61
cSkinQueuedMessage::message
char * message
Definition: skins.c:20
cBitmap::Width
int Width(void) const
Definition: osd.h:188
cSkinDisplayReplay::SetMarks
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
cSkinDisplayReplay::cProgressBar::total
int total
Definition: skins.h:326
cSkinDisplayMenu::MaxTabs
@ MaxTabs
Definition: skins.h:168
cSkinQueuedMessage::seconds
int seconds
Definition: skins.c:21
cSkins::queueMessageMutex
cMutex queueMessageMutex
Definition: skins.h:461
cBitmap::DrawRectangle
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
eKeys
eKeys
Definition: keys.h:16
cStatus::MsgOsdStatusMessage
static void MsgOsdStatusMessage(const char *Message)
Definition: status.c:98
cSkinDisplayChannel::positioner
const cPositioner * positioner
< This class is used to display the current channel, together with the present and following EPG even...
Definition: skins.h:70
cListBase::Add
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:2152
tr
#define tr(s)
Definition: i18n.h:85
cSkinQueuedMessage::threadId
tThreadId threadId
Definition: skins.c:23
cFont
Definition: font.h:37
cRecording::Title
const char * Title(char Delimiter=' ', bool NewIndicator=false, int Level=-1) const
Definition: recording.c:1076
cSkinDisplay
Definition: skins.h:39
cSkins::QueueMessage
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:296
cMarks
Definition: recording.h:371
cCondVar::Broadcast
void Broadcast(void)
Definition: thread.c:150
cThread::ThreadId
static tThreadId ThreadId(void)
Definition: thread.c:372
cSkinDisplayMessage
Definition: skins.h:394
cMutex
Definition: thread.h:67
Theme
static cTheme Theme
Definition: skinclassic.c:21
cTextScroller::Scroll
void Scroll(bool Up, bool Page)
Definition: osd.c:2178
cThemes::Save
static void Save(const char *SkinName, cTheme *Theme)
Definition: themes.c:309
cSkinDisplay::editableWidth
int editableWidth
Definition: skins.h:42
cListObject
Definition: tools.h:493
eMenuCategory
eMenuCategory
Definition: skins.h:104
cBitmap
Definition: osd.h:169
cTheme
Definition: themes.h:17
tThreadId
pid_t tThreadId
Definition: thread.h:17
cListBase::Clear
virtual void Clear(void)
Definition: tools.c:2229
cSkins::cSkins
cSkins(void)
Definition: skins.c:221
cSkinDisplayMenu::textScroller
cTextScroller textScroller
Definition: skins.h:173
cPositioner
A steerable satellite dish generally points to the south on the northern hemisphere,...
Definition: positioner.h:31
cStatus::MsgOsdClear
static void MsgOsdClear(void)
Definition: status.c:86
cSkinQueuedMessage::cSkinQueuedMessage
cSkinQueuedMessage(eMessageType Type, const char *s, int Seconds, int Timeout)
Definition: skins.c:33
interface.h
cSkinDisplayReplay::SetRecording
virtual void SetRecording(const cRecording *Recording)
Sets the recording that is currently being played.
Definition: skins.c:191
cSkinQueuedMessage::condVar
cCondVar condVar
Definition: skins.c:27
cMutex::Unlock
void Unlock(void)
Definition: thread.c:228
cMark
Definition: recording.h:353
cSkinQueuedMessage::~cSkinQueuedMessage
virtual ~cSkinQueuedMessage()
Definition: skins.c:44
cSkin::cSkin
cSkin(const char *Name, cTheme *Theme=NULL)
Creates a new skin class, with the given Name and Theme.
Definition: skins.c:203
cRecording
Definition: recording.h:98
cMutex::Lock
void Lock(void)
Definition: thread.c:222
cList
Definition: tools.h:594
cSkinQueuedMessage::state
int state
Definition: skins.c:25
cSkinDisplay::current
static cSkinDisplay * current
Definition: skins.h:41
cThread::IsMainThread
static tThreadId IsMainThread(void)
Definition: thread.h:131
cSkinDisplayReplay::cProgressBar::Mark
void Mark(int x, bool Start, bool Current, tColor ColorMark, tColor ColorCurrent)
Definition: skins.c:174
cSkinDisplayMenu
Definition: skins.h:150
cSkins::Clear
virtual void Clear(void)
Free up all registered skins.
Definition: skins.c:408
cSkinDisplayReplay
Definition: skins.h:319
dsyslog
#define dsyslog(a...)
Definition: tools.h:37
mtWarning
@ mtWarning
Definition: skins.h:37
cSkinDisplayMenu::SetScrollbar
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
cSkinDisplayReplay::SetTitle
virtual void SetTitle(const char *Title)=0
Sets the title of the recording.
cSkins::ProcessQueuedMessages
void ProcessQueuedMessages(void)
Processes the first queued message, if any.
Definition: skins.c:352
cSkinDisplayMenu::menuCategory
eMenuCategory menuCategory
Definition: skins.h:170
cSkinQueuedMessage::mutex
cMutex mutex
Definition: skins.c:26
cSkinDisplayReplay::marks
const cMarks * marks
< This class implements the progress display used during replay of a recording.
Definition: skins.h:323
cSkinDisplay::cSkinDisplay
cSkinDisplay(void)
Definition: skins.c:55
cSkinQueuedMessage::type
eMessageType type
Definition: skins.c:19
cSkinDisplayMenu::GetTextAreaFont
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
cSkins::~cSkins
~cSkins()
Definition: skins.c:226
cSkinDisplayReplay::cProgressBar::Pos
int Pos(int p)
Definition: skins.h:327
Skins
cSkins Skins
Definition: skins.c:219
cSkinQueuedMessage::timeout
int timeout
Definition: skins.c:22
cSkins::displayMessage
cSkinDisplayMessage * displayMessage
Definition: skins.h:460
skins.h
cSkins
Definition: skins.h:457
cSkinQueuedMessage
Definition: skins.c:16
cSkinDisplayMenu::Scroll
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
cSkinDisplayMenu::SetMenuCategory
virtual void SetMenuCategory(eMenuCategory MenuCategory)
Sets the current menu category.
Definition: skins.c:90
mtError
@ mtError
Definition: skins.h:37
SkinQueuedMessages
cList< cSkinQueuedMessage > SkinQueuedMessages
Definition: skins.c:49
mtInfo
@ mtInfo
Definition: skins.h:37
cCondVar::TimedWait
bool TimedWait(cMutex &Mutex, int TimeoutMs)
Definition: thread.c:132
cBitmap::Height
int Height(void) const
Definition: osd.h:189
cList::Next
const T * Next(const T *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
Definition: tools.h:613
cSkinDisplayMenu::GetTextAreaWidth
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
cSkinDisplayMenu::tabs
int tabs[MaxTabs]
Definition: skins.h:171
cInterface::Wait
eKeys Wait(int Seconds=0, bool KeepChar=false)
Definition: interface.c:41
isyslog
#define isyslog(a...)
Definition: tools.h:36
cSkinDisplayReplay::cSkinDisplayReplay
cSkinDisplayReplay(void)
Definition: skins.c:186
cSkinQueuedMessage::key
eKeys key
Definition: skins.c:24
cSkins::Flush
void Flush(void)
Flushes the currently active cSkinDisplay, if any.
Definition: skins.c:402
esyslog
#define esyslog(a...)
Definition: tools.h:35
eMessageType
eMessageType
Definition: skins.h:37
cMark::Position
int Position(void) const
Definition: recording.h:362
cSkinDisplayReplay::cProgressBar::cProgressBar
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
status.h
cSkinDisplayMessage::SetMessage
virtual void SetMessage(eMessageType Type, const char *Text)=0
< This class implements a simple message display.
cSkins::SetCurrent
bool SetCurrent(const char *Name=NULL)
Sets the current skin to the one indicated by name.
Definition: skins.c:231