vdr 2.6.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 4.5 2018/03/24 11:47:45 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
48void cOsdItem::SetSelectable(bool Selectable)
49{
51}
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);
114 if (!--displayMenuCount)
116}
117
119{
120 menuCategory = MenuCategory;
121}
122
124{
125 menuSortMode = MenuSortMode;
126}
127
129{
130 if (displayMenu) {
132 delete displayMenu;
133 }
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;
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 }
243 displayMenu->SetTabs(cols[0], cols[1], cols[2], cols[3], cols[4]);//XXX
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 }
278 if (!isempty(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
297void cOsdMenu::DisplayCurrent(bool Current)
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{
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 }
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) {
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{
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 }
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) {
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{
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 DisplayCurrent(true);
456 }
457 else if (Setup.MenuScrollWrap)
458 CursorUp();
459}
460
462{
464 int oldCurrent = current;
465 int oldFirst = first;
468 int last = Count() - 1;
469 if (current > last)
470 current = last;
471 if (first + displayMenuItems > last)
472 first = max(0, last - displayMenuItems + 1);
473 int tmpCurrent = current;
474 while (!SelectableItem(tmpCurrent) && ++tmpCurrent <= last)
475 ;
476 if (tmpCurrent > last) {
477 tmpCurrent = current;
478 while (--tmpCurrent >= 0 && !SelectableItem(tmpCurrent))
479 ;
480 }
481 current = tmpCurrent > 0 ? tmpCurrent : -1;
482 if (current >= 0) {
483 if (current < first)
484 first = current;
485 else if (current - first >= displayMenuItems)
487 }
488 if (current != oldCurrent || first != oldFirst) {
489 Display();
490 DisplayCurrent(true);
491 }
492 else if (Setup.MenuScrollWrap)
493 CursorDown();
494}
495
497{
498 if (Count() && marked < 0) {
499 marked = current;
500 SetStatus(tr("Up/Dn for new location - OK to move"));
501 }
502}
503
505{
506 for (cOsdItem *item = First(); item; item = Next(item)) {
507 const char *s = item->Text();
508 if (s && (s = skipspace(s)) != NULL) {
509 if (*s == Key - k1 + '1') {
510 current = item->Index();
512 Display();
513 cRemote::Put(kOk, true);
514 break;
515 }
516 }
517 }
518 return osContinue;
519}
520
522{
523 delete subMenu;
525 subMenu->Display();
526 return osContinue; // convenience return value
527}
528
530{
531 delete subMenu;
532 subMenu = NULL;
533 if (ReDisplay) {
535 Display();
536 }
537 return osContinue; // convenience return value
538}
539
541{
542 if (subMenu) {
543 eOSState state = subMenu->ProcessKey(Key);
544 if (state == osBack)
545 return CloseSubMenu();
546 return state;
547 }
548
549 cOsdItem *item = Get(current);
550 if (marked < 0 && item) {
551 eOSState state = item->ProcessKey(Key);
552 if (state != osUnknown) {
553 DisplayCurrent(true);
554 return state;
555 }
556 }
557 switch (int(Key)) {
558 case k0: return osUnknown;
559 case k1...k9: return hasHotkeys ? HotKey(Key) : osUnknown;
560 case kUp|k_Repeat:
561 case kUp: if (menuOrientation == moHorizontal) PageUp(); else CursorUp(); break;
562 case kDown|k_Repeat:
563 case kDown: if (menuOrientation == moHorizontal) PageDown(); else CursorDown(); break;
564 case kLeft|k_Repeat:
565 case kLeft: if (menuOrientation == moHorizontal) CursorUp(); else PageUp(); break;
566 case kRight|k_Repeat:
567 case kRight: if (menuOrientation == moHorizontal) CursorDown(); else PageDown(); break;
568 case kBack: return osBack;
569 case kOk: if (marked >= 0) {
570 SetStatus(NULL);
571 if (marked != current)
573 marked = -1;
574 break;
575 }
576 // else run into default
577 default: if (marked < 0)
578 return osUnknown;
579 }
580 return osContinue;
581}
virtual void Clear(void)
Definition: tools.c:2265
void Ins(cListObject *Object, cListObject *Before=NULL)
Definition: tools.c:2204
void Del(cListObject *Object, bool DeleteObject=true)
Definition: tools.c:2220
virtual void Move(int From, int To)
Definition: tools.c:2236
int count
Definition: tools.h:577
int Count(void) const
Definition: tools.h:637
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:2188
int Index(void) const
Definition: tools.c:2108
const cOsdItem * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition: tools.h:653
const cOsdItem * Next(const cOsdItem *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
Definition: tools.h:660
const cOsdItem * Get(int Index) const
Returns the list element at the given Index, or NULL if no such element exists.
Definition: tools.h:650
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:504
eOSState CloseSubMenu(bool ReDisplay=true)
Definition: osdbase.c:529
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:496
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:521
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:461
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
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:540
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:2262
bool Put(uint64_t Code, bool Repeat=false, bool Release=false)
Definition: remote.c:124
int MenuScrollPage
Definition: config.h:271
int MenuScrollWrap
Definition: config.h:272
virtual void SetMenuSortMode(eMenuSortMode MenuSortMode)
Sets the mode by which the items in this menu are sorted.
Definition: skins.h:196
virtual int MaxItems(void)=0
Returns the maximum number of items the menu can display.
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 void SetButtons(const char *Red, const char *Green=NULL, const char *Yellow=NULL, const char *Blue=NULL)=0
Sets the color buttons to the given strings.
virtual eMenuOrientation MenuOrientation(void)
Asks the skin for the orientation of the displayed menu.
Definition: skins.h:200
virtual void SetItem(const char *Text, int Index, bool Current, bool Selectable)=0
Sets the item at the given Index to Text.
virtual void SetMessage(eMessageType Type, const char *Text)=0
Sets a one line message Text, with the given Type.
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 void SetTitle(const char *Title)=0
Sets the title of this menu to Title.
virtual void Clear(void)=0
Clears the entire central area of the menu.
virtual void SetMenuCategory(eMenuCategory MenuCategory)
Sets the current menu category.
Definition: skins.c:90
virtual cSkinDisplayMenu * DisplayMenu(void)=0
Creates and returns a new object for displaying a menu.
cSkin * Current(void)
Returns a pointer to the current skin.
Definition: skins.h:468
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
Definition: tools.h:178
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1149
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:219
@ 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:349
char * skipspace(const char *s)
Definition: tools.h:241
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