vdr 2.7.2
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 5.4 2024/09/21 16:21:08 kls Exp $
8 */
9
10#include "skins.h"
11#include "interface.h"
12#include "status.h"
13
14// --- cSkinQueuedMessage ----------------------------------------------------
15
17 friend class cSkins;
18private:
20 char *message;
25 int state;
28public:
29 cSkinQueuedMessage(eMessageType Type, const char *s, int Seconds, int Timeout);
30 virtual ~cSkinQueuedMessage();
31 };
32
33cSkinQueuedMessage::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
48
50
51// --- cSkinDisplay ----------------------------------------------------------
52
54
56{
57 current = this;
58 editableWidth = 100; //XXX
59}
60
65
66// --- cSkinDisplayChannel ---------------------------------------------------
67
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
89
94
95void 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
107void cSkinDisplayMenu::Scroll(bool Up, bool Page)
108{
109 textScroller.Scroll(Up, Page);
110}
111
112const 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
133void cSkinDisplayMenu::SetScrollbar(int Total, int Offset)
134{
135}
136
138{
139 return 0;
140}
141
142const cFont *cSkinDisplayMenu::GetTextAreaFont(bool FixedFont) const
143{
144 return cFont::GetFont(FixedFont ? fontFix : fontOsd);
145}
146
147// --- cSkinDisplayReplay::cProgressBar --------------------------------------
148
149cSkinDisplayReplay::cProgressBar::cProgressBar(int Width, int Height, int Current, int Total, const cMarks *Marks, tColor ColorSeen, tColor ColorRest, tColor ColorSelected, tColor ColorMark, tColor ColorCurrent)
150:cSkinDisplayReplay::cProgressBar::cProgressBar(Width, Height, Current, Total, Marks, NULL, ColorSeen, ColorRest, ColorSelected, ColorMark, ColorCurrent, clrBlack)
151{
152}
153
154cSkinDisplayReplay::cProgressBar::cProgressBar(int Width, int Height, int Current, int Total, const cMarks *Marks, const cErrors *Errors, tColor ColorSeen, tColor ColorRest, tColor ColorSelected, tColor ColorMark, tColor ColorCurrent, tColor ColorError)
155:cBitmap(Width, Height, 4)
156{
157 total = Total;
158 if (total > 0) {
159 int p = Pos(Current);
160 DrawRectangle(0, 0, p, Height - 1, ColorSeen);
161 DrawRectangle(p + 1, 0, Width - 1, Height - 1, ColorRest);
162 if (Marks) {
163 bool Start = true;
164 for (const cMark *m = Marks->First(); m; m = Marks->Next(m)) {
165 int p1 = Pos(m->Position());
166 if (Start) {
167 const cMark *m2 = Marks->Next(m);
168 int p2 = Pos(m2 ? m2->Position() : total);
169 int h = Height / 3;
170 DrawRectangle(p1, h, p2, Height - h - 1, ColorSelected);
171 }
172 Mark(p1, Start, m->Position() == Current, ColorMark, ColorCurrent);
173 Start = !Start;
174 }
175 }
176 if (Errors) {
177 int LastPos = -1;
178 for (int i = 0; i < Errors->Size(); i++) {
179 int p1 = Errors->At(i);
180 if (p1 != LastPos) {
181 Error(Pos(Errors->At(i)), ColorError);
182 LastPos = p1;
183 }
184 }
185 }
186 }
187}
188
189void cSkinDisplayReplay::cProgressBar::Mark(int x, bool Start, bool Current, tColor ColorMark, tColor ColorCurrent)
190{
191 DrawRectangle(x, 0, x, Height() - 1, ColorMark);
192 const int d = Height() / (Current ? 3 : 9);
193 for (int i = 0; i < d; i++) {
194 int h = Start ? i : Height() - 1 - i;
195 DrawRectangle(x - d + i, h, x + d - i, h, Current ? ColorCurrent : ColorMark);
196 }
197}
198
200{
201 const int d = (Height() / 9) & ~0x01; // must be even
202 const int h = Height() / 2;
203 const int e = Height() / 4;
204 DrawRectangle(x, e, x, Height() -e - 1, ColorError);
205 DrawRectangle(x - d, h, x + d, h, ColorError);
206 for (int i = 1; i <= d; i++) {
207 DrawRectangle(x - d + i, h - i, x + d - i, h - i, ColorError);
208 DrawRectangle(x - d + i, h + i, x + d - i, h + i, ColorError);
209 }
210}
211
212// --- cSkinDisplayReplay ----------------------------------------------------
213
215{
216 marks = NULL;
217 errors = NULL;
218}
219
221{
222 SetTitle(Recording->Title());
223}
224
226{
227 marks = Marks;
228}
229
231{
232 errors = Errors;
233}
234
235// --- cSkin -----------------------------------------------------------------
236
237cSkin::cSkin(const char *Name, cTheme *Theme)
238{
239 name = strdup(Name);
240 theme = Theme;
241 if (theme)
242 cThemes::Save(name, theme);
243 Skins.Add(this);
244}
245
247{
248 free(name);
249}
250
251// --- cSkins ----------------------------------------------------------------
252
254
256{
257 displayMessage = NULL;
258}
259
261{
262 delete displayMessage;
263}
264
265bool cSkins::SetCurrent(const char *Name)
266{
267 if (Name) {
268 for (cSkin *Skin = First(); Skin; Skin = Next(Skin)) {
269 if (strcmp(Skin->Name(), Name) == 0) {
270 isyslog("setting current skin to \"%s\"", Name);
271 current = Skin;
272 return true;
273 }
274 }
275 }
276 current = First();
277 if (current)
278 isyslog("skin \"%s\" not available - using \"%s\" instead", Name, current->Name());
279 else
280 esyslog("ERROR: no skin available");
281 return current != NULL;
282}
283
284eKeys cSkins::Message(eMessageType Type, const char *s, int Seconds)
285{
286 if (!cThread::IsMainThread()) {
287 if (Type != mtStatus)
288 QueueMessage(Type, s, Seconds);
289 else
290 dsyslog("cSkins::Message(%d, \"%s\", %d) called from background thread - ignored! (Use cSkins::QueueMessage() instead)", Type, s, Seconds);
291 return kNone;
292 }
293 switch (Type) {
294 case mtInfo: isyslog("info: %s", s); break;
295 case mtWarning: isyslog("warning: %s", s); break;
296 case mtError: esyslog("ERROR: %s", s); break;
297 default: ;
298 }
299 if (!Current())
300 return kNone;
301 if (!cSkinDisplay::Current()) {
302 if (displayMessage)
303 delete displayMessage;
304 displayMessage = Current()->DisplayMessage();
305 }
309 eKeys k = kNone;
310 if (Type != mtStatus) {
311 k = Interface->Wait(Seconds);
312 if (displayMessage) {
313 delete displayMessage;
314 displayMessage = NULL;
316 }
317 else {
318 cSkinDisplay::Current()->SetMessage(Type, NULL);
320 }
321 }
322 else if (!s && displayMessage) {
323 delete displayMessage;
324 displayMessage = NULL;
326 }
327 return k;
328}
329
330int cSkins::QueueMessage(eMessageType Type, const char *s, int Seconds, int Timeout)
331{
332 if (Type == mtStatus) {
333 dsyslog("cSkins::QueueMessage() called with mtStatus - ignored!");
334 return kNone;
335 }
336 if (isempty(s)) {
337 if (!cThread::IsMainThread()) {
338 queueMessageMutex.Lock();
339 for (cSkinQueuedMessage *m = SkinQueuedMessages.Last(); m; m = SkinQueuedMessages.Prev(m)) {
340 if (m->threadId == cThread::ThreadId() && m->state == 0)
341 m->state = 2; // done
342 }
343 queueMessageMutex.Unlock();
344 }
345 else
346 dsyslog("cSkins::QueueMessage() called with empty message from main thread - ignored!");
347 return kNone;
348 }
349 int k = kNone;
350 if (Timeout > 0) {
351 if (cThread::IsMainThread()) {
352 dsyslog("cSkins::QueueMessage() called from main thread with Timeout = %d - ignored!", Timeout);
353 return k;
354 }
355 cSkinQueuedMessage *m = new cSkinQueuedMessage(Type, s, Seconds, Timeout);
356 queueMessageMutex.Lock();
357 SkinQueuedMessages.Add(m);
358 m->mutex.Lock();
359 queueMessageMutex.Unlock();
360 if (m->condVar.TimedWait(m->mutex, Timeout * 1000))
361 k = m->key;
362 else
363 k = -1; // timeout, nothing has been displayed
364 m->state = 2; // done
365 m->mutex.Unlock();
366 }
367 else {
368 queueMessageMutex.Lock();
369 // Check if there is a waiting message w/o timeout for this thread:
370 if (Timeout == -1) {
371 for (cSkinQueuedMessage *m = SkinQueuedMessages.Last(); m; m = SkinQueuedMessages.Prev(m)) {
372 if (m->threadId == cThread::ThreadId()) {
373 if (m->state == 0 && m->timeout == -1)
374 m->state = 2; // done
375 break;
376 }
377 }
378 }
379 // Add the new message:
380 SkinQueuedMessages.Add(new cSkinQueuedMessage(Type, s, Seconds, Timeout));
381 queueMessageMutex.Unlock();
382 }
383 return k;
384}
385
387{
388 if (!cThread::IsMainThread()) {
389 dsyslog("cSkins::ProcessQueuedMessages() called from background thread - ignored!");
390 return;
391 }
392 // Check whether there is a cSkinDisplay object (if any) that implements SetMessage():
394 if (!(dynamic_cast<cSkinDisplayChannel *>(sd) ||
395 dynamic_cast<cSkinDisplayMenu *>(sd) ||
396 dynamic_cast<cSkinDisplayReplay *>(sd) ||
397 dynamic_cast<cSkinDisplayMessage *>(sd)))
398 return;
399 }
400 cSkinQueuedMessage *msg = NULL;
401 // Get the first waiting message:
402 queueMessageMutex.Lock();
403 for (cSkinQueuedMessage *m = SkinQueuedMessages.First(); m; m = SkinQueuedMessages.Next(m)) {
404 if (m->state == 0) { // waiting
405 m->state = 1; // active
406 msg = m;
407 break;
408 }
409 }
410 queueMessageMutex.Unlock();
411 // Display the message:
412 if (msg) {
413 msg->mutex.Lock();
414 if (msg->state == 1) { // might have changed since we got it
415 msg->key = Skins.Message(msg->type, msg->message, msg->seconds);
416 if (msg->timeout == 0)
417 msg->state = 2; // done
418 else
419 msg->condVar.Broadcast();
420 }
421 msg->mutex.Unlock();
422 }
423 // Remove done messages from the queue:
424 queueMessageMutex.Lock();
425 for (;;) {
427 if (m && m->state == 2) { // done
428 SkinQueuedMessages.Del(m);
429 }
430 else
431 break;
432 }
433 queueMessageMutex.Unlock();
434}
435
437{
440}
441
443{
444 if (displayMessage) {
445 delete displayMessage;
446 displayMessage = NULL;
447 }
449}
Definition osd.h:169
int Height(void) const
Definition osd.h:189
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
int Width(void) const
Definition osd.h:188
bool TimedWait(cMutex &Mutex, int TimeoutMs)
Definition thread.c:132
void Broadcast(void)
Definition thread.c:150
Definition font.h:37
static const cFont * GetFont(eDvbFont Font)
Gets the given Font, which was previously set by a call to SetFont().
Definition font.c:412
eKeys Wait(int Seconds=0, bool KeepChar=false)
Definition interface.c:41
virtual void Clear(void)
Definition tools.c:2245
void Add(cListObject *Object, cListObject *After=NULL)
Definition tools.c:2168
cListObject * Prev(void) const
Definition tools.h:546
cListObject * Next(void) const
Definition tools.h:547
Definition tools.h:631
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition tools.h:643
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:650
int Position(void) const
Definition recording.h:387
void Lock(void)
Definition thread.c:222
void Unlock(void)
Definition thread.c:228
A steerable satellite dish generally points to the south on the northern hemisphere,...
Definition positioner.h:31
int TargetLongitude(void) const
Returns the longitude the dish is supposed to be moved to.
Definition positioner.h:105
const char * Title(char Delimiter=' ', bool NewIndicator=false, int Level=-1) const
Definition recording.c:1159
virtual void SetPositioner(const cPositioner *Positioner)
Sets the Positioner used to move the satellite dish.
Definition skins.c:73
cSkinDisplayChannel(void)
Definition skins.c:68
const cPositioner * positioner
< This class is used to display the current channel, together with the present and following EPG even...
Definition skins.h:70
virtual void SetMessage(eMessageType Type, const char *Text)=0
Sets a one line message Text, with the given Type.
eMenuCategory menuCategory
Definition skins.h:170
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
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
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
cTextScroller textScroller
Definition skins.h:173
int Tab(int n)
Returns the offset of the given tab from the left border of the item display area.
Definition skins.h:174
eMenuCategory MenuCategory(void) const
Returns the menu category, set by a previous call to SetMenuCategory().
Definition skins.h:183
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
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
cSkinDisplayMenu(void)
Definition skins.c:84
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
virtual void SetMenuCategory(eMenuCategory MenuCategory)
Sets the current menu category.
Definition skins.c:90
int tabs[MaxTabs]
Definition skins.h:171
void Mark(int x, bool Start, bool Current, tColor ColorMark, tColor ColorCurrent)
Definition skins.c:189
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
void Error(int x, tColor ColorError)
Definition skins.c:199
virtual void SetErrors(const cErrors *Errors)
Sets the errors found in the recording to Errors, which shall be used to display the progress bar thr...
Definition skins.c:230
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:225
virtual void SetTitle(const char *Title)=0
Sets the title of the recording.
virtual void SetRecording(const cRecording *Recording)
Sets the recording that is currently being played.
Definition skins.c:220
const cErrors * errors
Definition skins.h:314
cSkinDisplayReplay(void)
Definition skins.c:214
const cMarks * marks
< This class implements the progress display used during replay of a recording.
Definition skins.h:313
static cSkinDisplay * Current(void)
Returns the currently active cSkinDisplay.
Definition skins.h:61
static cSkinDisplay * current
Definition skins.h:41
virtual void Flush(void)
Actually draws the OSD display to the output device.
Definition skins.h:59
cSkinDisplay(void)
Definition skins.c:55
int editableWidth
Definition skins.h:42
virtual ~cSkinDisplay()
Definition skins.c:61
virtual void SetMessage(eMessageType Type, const char *Text)
Sets a one line message Text, with the given Type.
Definition skins.h:56
static int AvgCharWidth(void)
Returns the average width of a character in pixel (just a raw estimate).
Definition skins.h:46
virtual ~cSkinQueuedMessage()
Definition skins.c:44
cSkinQueuedMessage(eMessageType Type, const char *s, int Seconds, int Timeout)
Definition skins.c:33
tThreadId threadId
Definition skins.c:23
eMessageType type
Definition skins.c:19
char * message
Definition skins.c:20
cCondVar condVar
Definition skins.c:27
Definition skins.h:398
cSkin(const char *Name, cTheme *Theme=NULL)
Creates a new skin class, with the given Name and Theme.
Definition skins.c:237
virtual ~cSkin()
Definition skins.c:246
bool SetCurrent(const char *Name=NULL)
Sets the current skin to the one indicated by name.
Definition skins.c:265
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:284
void Flush(void)
Flushes the currently active cSkinDisplay, if any.
Definition skins.c:436
~cSkins()
Definition skins.c:260
cSkin * Current(void)
Returns a pointer to the current skin.
Definition skins.h:464
virtual void Clear(void)
Free up all registered skins.
Definition skins.c:442
void ProcessQueuedMessages(void)
Processes the first queued message, if any.
Definition skins.c:386
cSkins(void)
Definition skins.c:255
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:330
static void MsgOsdStatusMessage(const char *Message)
Definition status.c:98
static void MsgOsdClear(void)
Definition status.c:86
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition tools.c:1188
void Scroll(bool Up, bool Page)
Definition osd.c:2451
static void Save(const char *SkinName, cTheme *Theme)
Definition themes.c:309
static tThreadId IsMainThread(void)
Definition thread.h:131
static tThreadId ThreadId(void)
Definition thread.c:372
int Size(void) const
Definition tools.h:754
T & At(int Index) const
Definition tools.h:731
@ fontOsd
Definition font.h:22
@ fontFix
Definition font.h:23
uint32_t tColor
Definition font.h:30
#define tr(s)
Definition i18n.h:85
cInterface * Interface
Definition interface.c:20
eKeys
Definition keys.h:16
@ kNone
Definition keys.h:55
static cTheme Theme
Definition skinclassic.c:21
#define clrBlack
Definition skincurses.c:37
cList< cSkinQueuedMessage > SkinQueuedMessages
Definition skins.c:49
cSkins Skins
Definition skins.c:253
eMenuCategory
Definition skins.h:104
@ mcUndefined
Definition skins.h:105
eMessageType
Definition skins.h:37
@ mtWarning
Definition skins.h:37
@ mtInfo
Definition skins.h:37
@ mtError
Definition skins.h:37
@ mtStatus
Definition skins.h:37
pid_t tThreadId
Definition thread.h:17
bool isempty(const char *s)
Definition tools.c:354
#define dsyslog(a...)
Definition tools.h:37
#define esyslog(a...)
Definition tools.h:35
#define isyslog(a...)
Definition tools.h:36