vdr 2.7.3
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.1 2024/01/19 12:10:47 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;
81
82cOsdMenu::cOsdMenu(const char *Title, int c0, int c1, int c2, int c3, int c4)
83{
84 isMenu = true;
85 digit = 0;
86 hasHotkeys = false;
88 title = NULL;
93 SetCols(c0, c1, c2, c3, c4);
94 first = 0;
95 lastOffset = -1;
96 current = marked = -1;
97 subMenu = NULL;
99 helpDisplayed = false;
100 status = NULL;
101 if (!displayMenuCount++) {
102 cOsdProvider::OsdSizeChanged(osdState); // to get the current state
104 }
105}
106
108{
109 free(title);
110 delete subMenu;
111 free(status);
112 displayMenu->Clear();
114 if (!--displayMenuCount)
116}
117
119{
120 menuCategory = MenuCategory;
121}
122
124{
125 menuSortMode = MenuSortMode;
126}
127
129{
130 if (displayMenu) {
131 displayMenu->Clear();
132 delete displayMenu;
133 }
134 displayMenu = Skins.Current()->DisplayMenu();
135}
136
137const char *cOsdMenu::hk(const char *s)
138{
139 static cString buffer;
140 if (s && hasHotkeys) {
141 if (digit == 0 && '1' <= *s && *s <= '9' && *(s + 1) == ' ')
142 digit = -1; // prevents automatic hotkeys - input already has them
143 if (digit >= 0) {
144 digit++;
145 buffer = cString::sprintf(" %c %s", (digit < 10) ? '0' + digit : ' ' , s);
146 s = buffer;
147 }
148 }
149 return s;
150}
151
152void cOsdMenu::SetCols(int c0, int c1, int c2, int c3, int c4)
153{
154 cols[0] = c0;
155 cols[1] = c1;
156 cols[2] = c2;
157 cols[3] = c3;
158 cols[4] = c4;
159}
160
161void cOsdMenu::SetHasHotkeys(bool HasHotkeys)
162{
163 hasHotkeys = HasHotkeys;
164 digit = 0;
165}
166
167void cOsdMenu::SetStatus(const char *s)
168{
169 free(status);
170 status = s ? strdup(s) : NULL;
171 displayMenu->SetMessage(mtStatus, s);
172}
173
174void cOsdMenu::SetTitle(const char *Title)
175{
176 free(title);
177 title = strdup(Title);
178}
179
180void cOsdMenu::DisplayHelp(bool Force)
181{
182 if (!helpDisplayed || Force) {
185 helpDisplayed = true;
186 }
187}
188
189void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue)
190{
191 // strings are NOT copied - must be constants!!!
192 helpRed = Red;
193 helpGreen = Green;
194 helpYellow = Yellow;
195 helpBlue = Blue;
196 DisplayHelp(true);
197}
198
199void cOsdMenu::Del(int Index)
200{
202 int count = Count();
203 while (current < count && !SelectableItem(current))
204 current++;
205 if (current == count) {
206 while (current > 0 && !SelectableItem(current))
207 current--;
208 }
209 if (Index == first && first > 0)
210 first--;
211}
212
213void cOsdMenu::Add(cOsdItem *Item, bool Current, cOsdItem *After)
214{
215 cList<cOsdItem>::Add(Item, After);
216 if (Current)
217 current = Item->Index();
218}
219
220void cOsdMenu::Ins(cOsdItem *Item, bool Current, cOsdItem *Before)
221{
222 cList<cOsdItem>::Ins(Item, Before);
223 if (Current)
224 current = Item->Index();
225}
226
228{
229 if (subMenu) {
230 subMenu->Display();
231 return;
232 }
235 displayMenu->SetMessage(mtStatus, NULL);
236 displayMenu->Clear();
238 if (menuCategory != displayMenu->MenuCategory())
239 displayMenu->SetMenuCategory(menuCategory);
240 displayMenu->SetMenuSortMode(menuSortMode);
241 menuOrientation = displayMenu->MenuOrientation();
242 displayMenuItems = displayMenu->MaxItems();
243 displayMenu->SetTabs(cols[0], cols[1], cols[2], cols[3], cols[4]);//XXX
244 displayMenu->SetTitle(title);
246 DisplayHelp(true);
247 int count = Count();
248 if (count > 0) {
249 int ni = 0;
250 for (cOsdItem *item = First(); item; item = Next(item)) {
251 cStatus::MsgOsdItem(item->Text(), ni++);
252 if (current < 0 && item->Selectable())
253 current = item->Index();
254 }
255 if (current < 0)
256 current = 0; // just for safety - there HAS to be a current item!
257 first = max(0, min(first, max(0, count - displayMenuItems))); // in case the menu size has changed
262 if (first < 0)
263 first = 0;
264 }
265 int i = first;
266 int n = 0;
267 for (cOsdItem *item = Get(first); item; item = Next(item)) {
268 bool CurrentSelectable = (i == current) && item->Selectable();
269 item->SetMenuItem(displayMenu, i - first, CurrentSelectable, item->Selectable());
270 if (CurrentSelectable)
271 cStatus::MsgOsdCurrentItem(item->Text());
272 if (++n == displayMenuItems)
273 break;
274 i++;
275 }
276 }
277 displayMenu->SetScrollbar(count, first);
278 if (!isempty(status))
279 displayMenu->SetMessage(mtStatus, status);
280}
281
283{
284 current = Item ? Item->Index() : -1;
285 if (current >= 0 && lastOffset >= 0)
286 first = max(0, current - lastOffset);
287 lastOffset = -1;
288}
289
291{
292 cOsdItem *item = Get(current);
293 if (item)
294 item->Set();
295}
296
298{
299 cOsdItem *item = Get(current);
300 if (item) {
301 item->SetMenuItem(displayMenu, current - first, Current && item->Selectable(), item->Selectable());
302 if (Current && item->Selectable())
304 if (!Current)
305 item->SetFresh(true); // leaving the current item resets 'fresh'
306 if (cMenuEditItem *MenuEditItem = dynamic_cast<cMenuEditItem *>(item)) {
307 if (!MenuEditItem->DisplayHelp(Current))
308 DisplayHelp();
309 else
310 helpDisplayed = false;
311 }
312 }
313}
314
316{
317 if (Item) {
318 int Index = Item->Index();
319 int Offset = Index - first;
320 if (Offset >= 0 && Offset < first + displayMenuItems) {
321 bool Current = Index == current;
322 Item->SetMenuItem(displayMenu, Offset, Current && Item->Selectable(), Item->Selectable());
323 if (Current && Item->Selectable())
325 }
326 }
327}
328
330{
331 if (marked >= 0)
332 SetStatus(NULL);
333 if (current >= 0)
334 lastOffset = (current > first) ? current - first : 0;
335 first = 0;
336 current = marked = -1;
338}
339
341{
342 cOsdItem *item = Get(idx);
343 return item && item->Selectable();
344}
345
347{
348 displayMenuItems = displayMenu->MaxItems();
349 int tmpCurrent = current;
350 int lastOnScreen = first + displayMenuItems - 1;
351 int last = Count() - 1;
352 if (last < 0)
353 return;
354 while (--tmpCurrent != current) {
355 if (tmpCurrent < 0) {
356 if (first > 0) {
357 // make non-selectable items at the beginning visible:
358 first = 0;
359 Display();
360 return;
361 }
362 if (Setup.MenuScrollWrap)
363 tmpCurrent = last + 1;
364 else
365 return;
366 }
367 else if (SelectableItem(tmpCurrent))
368 break;
369 }
370 if (first <= tmpCurrent && tmpCurrent <= lastOnScreen)
371 DisplayCurrent(false);
372 current = tmpCurrent;
373 if (current < first) {
374 first = Setup.MenuScrollPage ? max(0, current - displayMenuItems + 1) : current;
375 Display();
376 }
377 else if (current > lastOnScreen) {
378 first = max(0, current - displayMenuItems + 1);
379 Display();
380 }
381 else
382 DisplayCurrent(true);
383}
384
386{
387 displayMenuItems = displayMenu->MaxItems();
388 int tmpCurrent = current;
389 int lastOnScreen = first + displayMenuItems - 1;
390 int last = Count() - 1;
391 if (last < 0)
392 return;
393 while (++tmpCurrent != current) {
394 if (tmpCurrent > last) {
395 if (first < last - displayMenuItems) {
396 // make non-selectable items at the end visible:
397 first = last - displayMenuItems + 1;
398 Display();
399 return;
400 }
401 if (Setup.MenuScrollWrap)
402 tmpCurrent = -1;
403 else
404 return;
405 }
406 else if (SelectableItem(tmpCurrent))
407 break;
408 }
409 if (first <= tmpCurrent && tmpCurrent <= lastOnScreen)
410 DisplayCurrent(false);
411 current = tmpCurrent;
412 if (current > lastOnScreen) {
413 first = Setup.MenuScrollPage ? current : max(0, current - displayMenuItems + 1);
414 if (first + displayMenuItems > last)
415 first = max(0, last - displayMenuItems + 1);
416 Display();
417 }
418 else if (current < first) {
419 first = current;
420 Display();
421 }
422 else
423 DisplayCurrent(true);
424}
425
427{
428 displayMenuItems = displayMenu->MaxItems();
429 int oldCurrent = current;
430 int oldFirst = first;
433 int last = Count() - 1;
434 if (current < 0)
435 current = 0;
436 if (first < 0)
437 first = 0;
438 int tmpCurrent = current;
439 while (!SelectableItem(tmpCurrent) && --tmpCurrent >= 0)
440 ;
441 if (tmpCurrent < 0) {
442 tmpCurrent = current;
443 while (++tmpCurrent <= last && !SelectableItem(tmpCurrent))
444 ;
445 }
446 current = tmpCurrent <= last ? tmpCurrent : -1;
447 if (current >= 0) {
448 if (current < first)
449 first = current;
450 else if (current - first >= displayMenuItems)
452 }
453 if (current != oldCurrent || first != oldFirst)
454 Display();
455 else if (Setup.MenuScrollWrap)
456 CursorUp();
457}
458
460{
461 displayMenuItems = displayMenu->MaxItems();
462 int oldCurrent = current;
463 int oldFirst = first;
466 int last = Count() - 1;
467 if (current > last)
468 current = last;
469 if (first + displayMenuItems > last)
470 first = max(0, last - displayMenuItems + 1);
471 int tmpCurrent = current;
472 while (!SelectableItem(tmpCurrent) && ++tmpCurrent <= last)
473 ;
474 if (tmpCurrent > last) {
475 tmpCurrent = current;
476 while (--tmpCurrent >= 0 && !SelectableItem(tmpCurrent))
477 ;
478 }
479 current = tmpCurrent > 0 ? 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)
487 Display();
488 else if (Setup.MenuScrollWrap)
489 CursorDown();
490}
491
493{
494 if (Count() && marked < 0) {
495 marked = current;
496 SetStatus(tr("Up/Dn for new location - OK to move"));
497 }
498}
499
501{
502 for (cOsdItem *item = First(); item; item = Next(item)) {
503 const char *s = item->Text();
504 if (s && (s = skipspace(s)) != NULL) {
505 if (*s == Key - k1 + '1') {
506 current = item->Index();
508 Display();
509 cRemote::Put(kOk, true);
510 break;
511 }
512 }
513 }
514 return osContinue;
515}
516
518{
519 delete subMenu;
521 subMenu->Display();
522 return osContinue; // convenience return value
523}
524
526{
527 delete subMenu;
528 subMenu = NULL;
529 if (ReDisplay) {
531 Display();
532 }
533 return osContinue; // convenience return value
534}
535
537{
538 if (subMenu) {
539 eOSState state = subMenu->ProcessKey(Key);
540 if (state == osBack)
541 return CloseSubMenu();
542 return state;
543 }
544
545 cOsdItem *item = Get(current);
546 if (marked < 0 && item) {
547 eOSState state = item->ProcessKey(Key);
548 if (state != osUnknown) {
549 DisplayCurrent(true);
550 return state;
551 }
552 }
553 switch (int(Key)) {
554 case k0: return osUnknown;
555 case k1...k9: return hasHotkeys ? HotKey(Key) : osUnknown;
556 case kUp|k_Repeat:
557 case kUp: if (menuOrientation == moHorizontal) PageUp(); else CursorUp(); break;
558 case kDown|k_Repeat:
559 case kDown: if (menuOrientation == moHorizontal) PageDown(); else CursorDown(); break;
560 case kLeft|k_Repeat:
561 case kLeft: if (menuOrientation == moHorizontal) CursorUp(); else PageUp(); break;
562 case kRight|k_Repeat:
563 case kRight: if (menuOrientation == moHorizontal) CursorDown(); else PageDown(); break;
564 case kBack: return osBack;
565 case kOk: if (marked >= 0) {
566 SetStatus(NULL);
567 if (marked != current)
569 marked = -1;
570 break;
571 }
572 // else run into default
573 default: if (marked < 0)
574 return osUnknown;
575 }
576 return osContinue;
577}
virtual void Clear(void)
Definition tools.c:2245
void Ins(cListObject *Object, cListObject *Before=NULL)
Definition tools.c:2184
void Del(cListObject *Object, bool DeleteObject=true)
Definition tools.c:2200
virtual void Move(int From, int To)
Definition tools.c:2216
int count
Definition tools.h:567
int Count(void) const
Definition tools.h:627
void Add(cListObject *Object, cListObject *After=NULL)
Definition tools.c:2168
int Index(void) const
Definition tools.c:2088
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:220
int displayMenuItems
Definition osdbase.h:90
int marked
Definition osdbase.h:93
eOSState HotKey(eKeys Key)
Definition osdbase.c:500
eOSState CloseSubMenu(bool ReDisplay=true)
Definition osdbase.c:525
void SetTitle(const char *Title)
Definition osdbase.c:174
char * title
Definition osdbase.h:91
static int osdState
Definition osdbase.h:89
void PageUp(void)
Definition osdbase.c:426
const char * helpBlue
Definition osdbase.h:99
void DisplayCurrent(bool Current)
Definition osdbase.c:297
bool helpDisplayed
Definition osdbase.h:100
char * status
Definition osdbase.h:101
int Current(void) const
Definition osdbase.h:138
const char * helpYellow
Definition osdbase.h:99
int cols[cSkinDisplayMenu::MaxTabs]
Definition osdbase.h:92
virtual ~cOsdMenu()
Definition osdbase.c:107
bool SelectableItem(int idx)
Definition osdbase.c:340
const char * hk(const char *s)
Definition osdbase.c:137
void CursorDown(void)
Definition osdbase.c:385
void Mark(void)
Definition osdbase.c:492
void SetStatus(const char *s)
Definition osdbase.c:167
cOsdMenu * SubMenu(void)
Definition osdbase.h:127
void CursorUp(void)
Definition osdbase.c:346
void DisplayHelp(bool Force=false)
Definition osdbase.c:180
void DisplayItem(cOsdItem *Item)
Definition osdbase.c:315
eMenuCategory menuCategory
Definition osdbase.h:95
eOSState AddSubMenu(cOsdMenu *SubMenu)
Definition osdbase.c:517
void SetDisplayMenu(void)
Definition osdbase.c:128
void Add(cOsdItem *Item, bool Current=false, cOsdItem *After=NULL)
Definition osdbase.c:213
void PageDown(void)
Definition osdbase.c:459
void SetHasHotkeys(bool HasHotkeys=true)
Definition osdbase.c:161
void SetCols(int c0, int c1=0, int c2=0, int c3=0, int c4=0)
Definition osdbase.c:152
void SetCurrent(cOsdItem *Item)
Definition osdbase.c:282
bool hasHotkeys
Definition osdbase.h:103
int lastOffset
Definition osdbase.h:94
eMenuOrientation menuOrientation
Definition osdbase.h:97
cOsdMenu(const char *Title, int c0=0, int c1=0, int c2=0, int c3=0, int c4=0)
Definition osdbase.c:82
void SetMenuCategory(eMenuCategory MenuCategory)
Definition osdbase.c:118
void RefreshCurrent(void)
Definition osdbase.c:290
const char * helpRed
Definition osdbase.h:99
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:189
static int displayMenuCount
Definition osdbase.h:88
virtual void Display(void)
Definition osdbase.c:227
virtual void Del(int Index)
Definition osdbase.c:199
const char * Title(void)
Definition osdbase.h:112
virtual void Clear(void)
Definition osdbase.c:329
void SetMenuSortMode(eMenuSortMode MenuSortMode)
Definition osdbase.c:123
virtual eOSState ProcessKey(eKeys Key)
Definition osdbase.c:536
cOsdMenu * subMenu
Definition osdbase.h:98
int current
Definition osdbase.h:93
eMenuSortMode menuSortMode
Definition osdbase.h:96
const char * helpGreen
Definition osdbase.h:99
int digit
Definition osdbase.h:102
int first
Definition osdbase.h:93
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 MsgOsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue)
Definition status.c:104
static void MsgOsdItem(const char *Text, int Index)
Definition status.c:110
static void MsgOsdClear(void)
Definition status.c:86
static void MsgOsdCurrentItem(const char *Text)
Definition status.c:116
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition tools.c:1188
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
@ 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:354
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