vdr 2.7.4
osdbase.c
Go to the documentation of this file.
1/*
2 * osdbase.c: Basic interface to the On Screen Display
3 *
4 * See the main source file 'vdr.c' for copyright information and
5 * how to reach the author.
6 *
7 * $Id: osdbase.c 5.9 2025/02/17 10:49:10 kls Exp $
8 */
9
10#include "osdbase.h"
11#include <string.h>
12#include "device.h"
13#include "i18n.h"
14#include "menuitems.h"
15#include "remote.h"
16#include "status.h"
17
18// --- cOsdItem --------------------------------------------------------------
19
21{
22 text = NULL;
23 state = State;
24 selectable = true;
25 fresh = true;
26}
27
28cOsdItem::cOsdItem(const char *Text, eOSState State, bool Selectable)
29{
30 text = NULL;
31 state = State;
33 fresh = true;
35}
36
38{
39 free(text);
40}
41
42void cOsdItem::SetText(const char *Text, bool Copy)
43{
44 free(text);
45 text = Copy ? strdup(Text ? Text : "") : (char *)Text; // text assumes ownership!
46}
47
52
53void cOsdItem::SetFresh(bool Fresh)
54{
55 fresh = Fresh;
56}
57
58void cOsdItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
59{
60 DisplayMenu->SetItem(Text(), Index, Current, Selectable);
61}
62
64{
65 return Key == kOk ? state : osUnknown;
66}
67
68// --- cOsdObject ------------------------------------------------------------
69
71{
72 if (isMenu)
73 ((cOsdMenu *)this)->Display();
74}
75
76// --- cOsdMenu --------------------------------------------------------------
77
80int cOsdMenu::osdState = 0;
82
83cOsdMenu::cOsdMenu(const char *Title, int c0, int c1, int c2, int c3, int c4)
84{
85 isMenu = true;
86 digit = 0;
87 hasHotkeys = false;
88 if (!topMenu)
89 topMenu = this;
90 active = this == topMenu;
92 title = NULL;
97 SetCols(c0, c1, c2, c3, c4);
98 first = 0;
99 lastOffset = -1;
100 conveyStatus = true;
101 current = marked = -1;
102 subMenu = NULL;
104 helpDisplayed = false;
105 status = NULL;
106 if (!displayMenuCount++) {
107 cOsdProvider::OsdSizeChanged(osdState); // to get the current state
109 }
110}
111
113{
114 free(title);
115 delete subMenu;
116 free(status);
117 displayMenu->Clear();
119 if (!--displayMenuCount)
121 if (this == topMenu)
122 topMenu = NULL;
123}
124
126{
127 menuCategory = MenuCategory;
128}
129
131{
132 menuSortMode = MenuSortMode;
133}
134
135void cOsdMenu::SetActive(bool Active)
136{
137 active = Active;
138}
139
141{
142 if (displayMenu) {
143 displayMenu->Clear();
144 delete displayMenu;
145 }
146 displayMenu = Skins.Current()->DisplayMenu();
147}
148
149const char *cOsdMenu::hk(const char *s)
150{
151 static cString buffer;
152 if (s && hasHotkeys) {
153 if (digit == 0 && '1' <= *s && *s <= '9' && *(s + 1) == ' ')
154 digit = -1; // prevents automatic hotkeys - input already has them
155 if (digit >= 0) {
156 digit++;
157 buffer = cString::sprintf(" %c %s", (digit < 10) ? '0' + digit : ' ' , s);
158 s = buffer;
159 }
160 }
161 return s;
162}
163
164void cOsdMenu::SetCols(int c0, int c1, int c2, int c3, int c4)
165{
166 cols[0] = c0;
167 cols[1] = c1;
168 cols[2] = c2;
169 cols[3] = c3;
170 cols[4] = c4;
171}
172
173void cOsdMenu::SetHasHotkeys(bool HasHotkeys)
174{
175 hasHotkeys = HasHotkeys;
176 digit = 0;
177}
178
179void cOsdMenu::SetStatus(const char *s)
180{
181 free(status);
182 status = s ? strdup(s) : NULL;
183 displayMenu->SetMessage(mtStatus, s);
185}
186
187void cOsdMenu::SetTitle(const char *Title)
188{
189 free(title);
190 title = strdup(Title);
191}
192
193void cOsdMenu::DisplayHelp(bool Force)
194{
195 if (!helpDisplayed || Force) {
197 if (conveyStatus)
199 helpDisplayed = true;
200 }
201}
202
203void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue)
204{
205 // strings are NOT copied - must be constants!!!
206 helpRed = Red;
207 helpGreen = Green;
208 helpYellow = Yellow;
209 helpBlue = Blue;
210 DisplayHelp(true);
211}
212
213void cOsdMenu::Del(int Index)
214{
216 int count = Count();
217 while (current < count && !SelectableItem(current))
218 current++;
219 if (current == count) {
220 while (current > 0 && !SelectableItem(current))
221 current--;
222 }
223 if (Index == first && first > 0)
224 first--;
225}
226
227void cOsdMenu::Add(cOsdItem *Item, bool Current, cOsdItem *After)
228{
229 cList<cOsdItem>::Add(Item, After);
230 if (Current)
231 current = Item->Index();
232}
233
234void cOsdMenu::Ins(cOsdItem *Item, bool Current, cOsdItem *Before)
235{
236 cList<cOsdItem>::Ins(Item, Before);
237 if (Current)
238 current = Item->Index();
239}
240
242{
243 conveyStatus = false;
244 Display();
245 conveyStatus = true;
246}
247
249{
250 if (subMenu) {
251 subMenu->Display();
252 return;
253 }
254 if (!active)
255 return;
258 displayMenu->SetMessage(mtStatus, NULL);
260 displayMenu->Clear();
261 if (conveyStatus)
263 if (menuCategory != displayMenu->MenuCategory())
264 displayMenu->SetMenuCategory(menuCategory);
265 displayMenu->SetMenuSortMode(menuSortMode);
266 menuOrientation = displayMenu->MenuOrientation();
267 displayMenuItems = displayMenu->MaxItems();
268 displayMenu->SetTabs(cols[0], cols[1], cols[2], cols[3], cols[4]);//XXX
269 displayMenu->SetTitle(title);
270 if (conveyStatus)
272 DisplayHelp(true);
273 int count = Count();
274 if (count > 0) {
275 int ni = 0;
276 for (cOsdItem *item = First(); item; item = Next(item)) {
277 if (conveyStatus)
278 cStatus::MsgOsdItem(item->Text(), ni++, item->Selectable());
279 if (current < 0 && item->Selectable())
280 current = item->Index();
281 }
282 if (current < 0)
283 current = 0; // just for safety - there HAS to be a current item!
284 first = max(0, min(first, max(0, count - displayMenuItems))); // in case the menu size has changed
289 if (first < 0)
290 first = 0;
291 }
292 int i = first;
293 int n = 0;
294 for (cOsdItem *item = Get(first); item; item = Next(item)) {
295 bool CurrentSelectable = (i == current) && item->Selectable();
296 item->SetMenuItem(displayMenu, i - first, CurrentSelectable, item->Selectable());
297 if (CurrentSelectable) // not checking conveyStatus here!
298 cStatus::MsgOsdCurrentItem(item->Text(), i);
299 if (++n == displayMenuItems)
300 break;
301 i++;
302 }
303 }
304 displayMenu->SetScrollbar(count, first);
305 if (!isempty(status)) {
306 displayMenu->SetMessage(mtStatus, status);
308 }
309}
310
312{
313 current = Item ? Item->Index() : -1;
314 if (current >= 0 && lastOffset >= 0)
315 first = max(0, current - lastOffset);
316 lastOffset = -1;
317}
318
320{
321 cOsdItem *item = Get(current);
322 if (item)
323 item->Set();
324}
325
327{
328 cOsdItem *item = Get(current);
329 if (item) {
330 item->SetMenuItem(displayMenu, current - first, Current && item->Selectable(), item->Selectable());
331 if (Current) {
334 else if (item->Selectable())
336 }
337 else
338 item->SetFresh(true); // leaving the current item resets 'fresh'
339 if (cMenuEditItem *MenuEditItem = dynamic_cast<cMenuEditItem *>(item)) {
340 if (!MenuEditItem->DisplayHelp(Current))
341 DisplayHelp();
342 else
343 helpDisplayed = false;
344 }
345 }
346}
347
349{
350 if (Item) {
351 int Index = Item->Index();
352 int Offset = Index - first;
353 if (Offset >= 0 && Offset < first + displayMenuItems) {
354 bool Current = Index == current;
355 Item->SetMenuItem(displayMenu, Offset, Current && Item->Selectable(), Item->Selectable());
356 if (Current && Item->Selectable())
357 cStatus::MsgOsdCurrentItem(Item->Text(), Index);
358 }
359 }
360}
361
363{
364 if (marked >= 0)
365 SetStatus(NULL);
366 if (current >= 0)
367 lastOffset = (current > first) ? current - first : 0;
368 first = 0;
369 current = marked = -1;
371}
372
374{
375 cOsdItem *item = Get(idx);
376 return item && item->Selectable();
377}
378
380{
381 displayMenuItems = displayMenu->MaxItems();
382 int tmpCurrent = current;
383 int lastOnScreen = first + displayMenuItems - 1;
384 int last = Count() - 1;
385 if (last < 0)
386 return;
387 while (--tmpCurrent != current) {
388 if (tmpCurrent < 0) {
389 if (first > 0) {
390 // make non-selectable items at the beginning visible:
391 first = 0;
393 return;
394 }
395 if (Setup.MenuScrollWrap)
396 tmpCurrent = last + 1;
397 else
398 return;
399 }
400 else if (SelectableItem(tmpCurrent))
401 break;
402 }
403 if (first <= tmpCurrent && tmpCurrent <= lastOnScreen)
404 DisplayCurrent(false);
405 current = tmpCurrent;
406 if (current < first) {
407 first = Setup.MenuScrollPage ? max(0, current - displayMenuItems + 1) : current;
409 }
410 else if (current > lastOnScreen) {
411 first = max(0, current - displayMenuItems + 1);
413 }
414 else
415 DisplayCurrent(true);
416}
417
419{
420 displayMenuItems = displayMenu->MaxItems();
421 int tmpCurrent = current;
422 int lastOnScreen = first + displayMenuItems - 1;
423 int last = Count() - 1;
424 if (last < 0)
425 return;
426 while (++tmpCurrent != current) {
427 if (tmpCurrent > last) {
428 if (first < last - displayMenuItems) {
429 // make non-selectable items at the end visible:
430 first = last - displayMenuItems + 1;
432 return;
433 }
434 if (Setup.MenuScrollWrap)
435 tmpCurrent = -1;
436 else
437 return;
438 }
439 else if (SelectableItem(tmpCurrent))
440 break;
441 }
442 if (first <= tmpCurrent && tmpCurrent <= lastOnScreen)
443 DisplayCurrent(false);
444 current = tmpCurrent;
445 if (current > lastOnScreen) {
446 first = Setup.MenuScrollPage ? current : max(0, current - displayMenuItems + 1);
447 if (first + displayMenuItems > last)
448 first = max(0, last - displayMenuItems + 1);
450 }
451 else if (current < first) {
452 first = current;
454 }
455 else
456 DisplayCurrent(true);
457}
458
460{
461 displayMenuItems = displayMenu->MaxItems();
462 int oldCurrent = current;
463 int oldFirst = first;
466 int last = Count() - 1;
467 if (current < 0)
468 current = 0;
469 if (first < 0)
470 first = 0;
471 int tmpCurrent = current;
472 while (!SelectableItem(tmpCurrent) && --tmpCurrent >= 0)
473 ;
474 if (tmpCurrent < 0) {
475 tmpCurrent = current;
476 while (++tmpCurrent <= last && !SelectableItem(tmpCurrent))
477 ;
478 }
479 current = tmpCurrent <= last ? tmpCurrent : -1;
480 if (current >= 0) {
481 if (current < first)
482 first = current;
483 else if (current - first >= displayMenuItems)
485 }
486 if (current != oldCurrent || first != oldFirst)
488 else if (Setup.MenuScrollWrap)
489 CursorUp();
490}
491
493{
494 displayMenuItems = displayMenu->MaxItems();
495 int oldCurrent = current;
496 int oldFirst = first;
499 int last = Count() - 1;
500 if (current > last)
501 current = last;
502 if (first + displayMenuItems > last)
503 first = max(0, last - displayMenuItems + 1);
504 int tmpCurrent = current;
505 while (!SelectableItem(tmpCurrent) && ++tmpCurrent <= last)
506 ;
507 if (tmpCurrent > last) {
508 tmpCurrent = current;
509 while (--tmpCurrent >= 0 && !SelectableItem(tmpCurrent))
510 ;
511 }
512 current = tmpCurrent > 0 ? tmpCurrent : -1;
513 if (current >= 0) {
514 if (current < first)
515 first = current;
516 else if (current - first >= displayMenuItems)
518 }
519 if (current != oldCurrent || first != oldFirst)
521 else if (Setup.MenuScrollWrap)
522 CursorDown();
523}
524
526{
527 if (Count() && marked < 0) {
528 marked = current;
529 SetStatus(tr("Up/Dn for new location - OK to move"));
530 }
531}
532
534{
535 for (cOsdItem *item = First(); item; item = Next(item)) {
536 const char *s = item->Text();
537 if (s && (s = skipspace(s)) != NULL) {
538 if (*s == Key - k1 + '1') {
539 DisplayCurrent(false);
540 current = item->Index();
542 DisplayCurrent(true);
543 cRemote::Put(kOk, true);
544 break;
545 }
546 }
547 }
548 return osContinue;
549}
550
552{
553 SetActive(false);
554 delete subMenu;
556 subMenu->SetActive(true);
557 subMenu->Display();
558 return osContinue; // convenience return value
559}
560
562{
563 delete subMenu;
564 subMenu = NULL;
565 SetActive(true);
566 if (ReDisplay) {
568 Display();
569 }
570 return osContinue; // convenience return value
571}
572
574{
575 if (subMenu) {
576 eOSState state = subMenu->ProcessKey(Key);
577 if (state == osBack)
578 return CloseSubMenu();
579 return state;
580 }
581
582 cOsdItem *item = Get(current);
583 if (marked < 0 && item) {
584 eOSState state = item->ProcessKey(Key);
585 if (state != osUnknown) {
586 if (Key != kNone)
587 DisplayCurrent(true);
588 return state;
589 }
590 }
591 switch (int(Key)) {
592 case k0: return osUnknown;
593 case k1...k9: return hasHotkeys ? HotKey(Key) : osUnknown;
594 case kUp|k_Repeat:
595 case kUp: if (menuOrientation == moHorizontal) PageUp(); else CursorUp(); break;
596 case kDown|k_Repeat:
597 case kDown: if (menuOrientation == moHorizontal) PageDown(); else CursorDown(); break;
598 case kLeft|k_Repeat:
599 case kLeft: if (menuOrientation == moHorizontal) CursorUp(); else PageUp(); break;
600 case kRight|k_Repeat:
601 case kRight: if (menuOrientation == moHorizontal) CursorDown(); else PageDown(); break;
602 case kBack: return osBack;
603 case kOk: if (marked >= 0) {
604 SetStatus(NULL);
605 if (marked != current)
607 marked = -1;
608 break;
609 }
610 // else run into default
611 default: if (marked < 0)
612 return osUnknown;
613 }
614 return osContinue;
615}
virtual void Clear(void)
Definition tools.c:2252
void Ins(cListObject *Object, cListObject *Before=NULL)
Definition tools.c:2191
void Del(cListObject *Object, bool DeleteObject=true)
Definition tools.c:2207
virtual void Move(int From, int To)
Definition tools.c:2223
int count
Definition tools.h:567
int Count(void) const
Definition tools.h:627
void Add(cListObject *Object, cListObject *After=NULL)
Definition tools.c:2175
int Index(void) const
Definition tools.c:2095
const cOsdItem * First(void) const
Definition tools.h:643
const cOsdItem * Next(const cOsdItem *Object) const
Definition tools.h:650
const cOsdItem * Get(int Index) const
Definition tools.h:640
virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
Definition osdbase.c:58
const char * Text(void) const
Definition osdbase.h:63
bool selectable
Definition osdbase.h:52
void SetSelectable(bool Selectable)
Definition osdbase.c:48
virtual eOSState ProcessKey(eKeys Key)
Definition osdbase.c:63
eOSState state
Definition osdbase.h:51
virtual void Set(void)
Definition osdbase.h:64
char * text
Definition osdbase.h:50
bool fresh
Definition osdbase.h:54
void SetFresh(bool Fresh)
Definition osdbase.c:53
virtual ~cOsdItem()
Definition osdbase.c:37
bool Selectable(void) const
Definition osdbase.h:59
void SetText(const char *Text, bool Copy=true)
Definition osdbase.c:42
cOsdItem(eOSState State=osUnknown)
Definition osdbase.c:20
void Ins(cOsdItem *Item, bool Current=false, cOsdItem *Before=NULL)
Definition osdbase.c:234
int displayMenuItems
Definition osdbase.h:91
int marked
Definition osdbase.h:94
eOSState HotKey(eKeys Key)
Definition osdbase.c:533
eOSState CloseSubMenu(bool ReDisplay=true)
Definition osdbase.c:561
void SetTitle(const char *Title)
Definition osdbase.c:187
char * title
Definition osdbase.h:92
static int osdState
Definition osdbase.h:89
void PageUp(void)
Definition osdbase.c:459
const char * helpBlue
Definition osdbase.h:101
bool conveyStatus
Definition osdbase.h:96
void DisplayCurrent(bool Current)
Definition osdbase.c:326
bool helpDisplayed
Definition osdbase.h:102
char * status
Definition osdbase.h:103
static cOsdMenu * topMenu
Definition osdbase.h:90
void SetActive(bool Active)
Definition osdbase.c:135
int Current(void) const
Definition osdbase.h:143
const char * helpYellow
Definition osdbase.h:101
int cols[cSkinDisplayMenu::MaxTabs]
Definition osdbase.h:93
virtual ~cOsdMenu()
Definition osdbase.c:112
bool SelectableItem(int idx)
Definition osdbase.c:373
const char * hk(const char *s)
Definition osdbase.c:149
void CursorDown(void)
Definition osdbase.c:418
void Mark(void)
Definition osdbase.c:525
void SetStatus(const char *s)
Definition osdbase.c:179
cOsdMenu * SubMenu(void)
Definition osdbase.h:132
void CursorUp(void)
Definition osdbase.c:379
void DisplayHelp(bool Force=false)
Definition osdbase.c:193
void DisplayItem(cOsdItem *Item)
Definition osdbase.c:348
eMenuCategory menuCategory
Definition osdbase.h:97
eOSState AddSubMenu(cOsdMenu *SubMenu)
Definition osdbase.c:551
void SetDisplayMenu(void)
Definition osdbase.c:140
void Add(cOsdItem *Item, bool Current=false, cOsdItem *After=NULL)
Definition osdbase.c:227
void PageDown(void)
Definition osdbase.c:492
void SetHasHotkeys(bool HasHotkeys=true)
Definition osdbase.c:173
void SetCols(int c0, int c1=0, int c2=0, int c3=0, int c4=0)
Definition osdbase.c:164
void SetCurrent(cOsdItem *Item)
Definition osdbase.c:311
bool hasHotkeys
Definition osdbase.h:105
int lastOffset
Definition osdbase.h:95
eMenuOrientation menuOrientation
Definition osdbase.h:99
cOsdMenu(const char *Title, int c0=0, int c1=0, int c2=0, int c3=0, int c4=0)
Definition osdbase.c:83
void SetMenuCategory(eMenuCategory MenuCategory)
Definition osdbase.c:125
void RefreshCurrent(void)
Definition osdbase.c:319
const char * helpRed
Definition osdbase.h:101
static cSkinDisplayMenu * displayMenu
Definition osdbase.h:87
void SetHelp(const char *Red, const char *Green=NULL, const char *Yellow=NULL, const char *Blue=NULL)
Definition osdbase.c:203
static int displayMenuCount
Definition osdbase.h:88
virtual void Display(void)
Definition osdbase.c:248
void DisplayNoStatus(void)
Definition osdbase.c:241
virtual void Del(int Index)
Definition osdbase.c:213
const char * Title(void)
Definition osdbase.h:117
bool active
Definition osdbase.h:106
virtual void Clear(void)
Definition osdbase.c:362
void SetMenuSortMode(eMenuSortMode MenuSortMode)
Definition osdbase.c:130
virtual eOSState ProcessKey(eKeys Key)
Definition osdbase.c:573
cOsdMenu * subMenu
Definition osdbase.h:100
int current
Definition osdbase.h:94
eMenuSortMode menuSortMode
Definition osdbase.h:98
const char * helpGreen
Definition osdbase.h:101
int digit
Definition osdbase.h:104
int first
Definition osdbase.h:94
bool isMenu
Definition osdbase.h:72
virtual void Show(void)
Definition osdbase.c:70
friend class cOsdMenu
Definition osdbase.h:70
static bool OsdSizeChanged(int &State)
Checks if the OSD size has changed and a currently displayed OSD needs to be redrawn.
Definition osd.c:2337
bool Put(uint64_t Code, bool Repeat=false, bool Release=false)
Definition remote.c:124
virtual void SetItem(const char *Text, int Index, bool Current, bool Selectable)=0
Sets the item at the given Index to Text.
static void MsgOsdTitle(const char *Title)
Definition status.c:92
static void MsgOsdItem(const char *Text, int Index, bool Selectable=true)
Definition status.c:110
static void MsgOsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue)
Definition status.c:104
static void MsgOsdStatusMessage(const char *Message)
Definition status.h:127
static void MsgOsdClear(void)
Definition status.c:86
static void MsgOsdCurrentItem(const char *Text, int Index=-1)
Definition status.c:116
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition tools.c:1195
cSetup Setup
Definition config.c:372
#define tr(s)
Definition i18n.h:85
eKeys
Definition keys.h:16
@ kRight
Definition keys.h:23
@ kUp
Definition keys.h:17
@ kNone
Definition keys.h:55
@ kDown
Definition keys.h:18
@ k1
Definition keys.h:28
@ kLeft
Definition keys.h:22
@ k0
Definition keys.h:28
@ kBack
Definition keys.h:21
@ k_Repeat
Definition keys.h:61
@ kOk
Definition keys.h:20
eOSState
Definition osdbase.h:18
@ osContinue
Definition osdbase.h:19
@ osUnknown
Definition osdbase.h:18
@ osBack
Definition osdbase.h:33
cSkins Skins
Definition skins.c:253
@ moHorizontal
Definition skins.h:147
@ moVertical
Definition skins.h:146
eMenuCategory
Definition skins.h:104
@ mcUnknown
Definition skins.h:106
@ mtStatus
Definition skins.h:37
eMenuSortMode
Definition skins.h:137
@ msmUnknown
Definition skins.h:138
bool isempty(const char *s)
Definition tools.c:357
char * skipspace(const char *s)
Definition tools.h:244
void DELETENULL(T *&p)
Definition tools.h:49
T min(T a, T b)
Definition tools.h:63
T max(T a, T b)
Definition tools.h:64