vdr  2.0.6
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 2.7 2012/12/07 09:50: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 
28 cOsdItem::cOsdItem(const char *Text, eOSState State, bool Selectable)
29 {
30  text = NULL;
31  state = State;
33  fresh = true;
34  SetText(Text);
35 }
36 
38 {
39  free(text);
40 }
41 
42 void cOsdItem::SetText(const char *Text, bool Copy)
43 {
44  free(text);
45  text = Copy ? strdup(Text ? Text : "") : (char *)Text; // text assumes ownership!
46 }
47 
48 void cOsdItem::SetSelectable(bool Selectable)
49 {
51 }
52 
53 void cOsdItem::SetFresh(bool Fresh)
54 {
55  fresh = Fresh;
56 }
57 
58 void 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 
70 void cOsdObject::Show(void)
71 {
72  if (isMenu)
73  ((cOsdMenu *)this)->Display();
74 }
75 
76 // --- cOsdMenu --------------------------------------------------------------
77 
80 
81 cOsdMenu::cOsdMenu(const char *Title, int c0, int c1, int c2, int c3, int c4)
82 {
83  isMenu = true;
84  digit = 0;
85  key_nr = -1;
86  hasHotkeys = false;
87  displayMenuItems = 0;
88  title = NULL;
90  SetTitle(Title);
91  SetCols(c0, c1, c2, c3, c4);
92  first = 0;
93  current = marked = -1;
94  subMenu = NULL;
95  helpRed = helpGreen = helpYellow = helpBlue = NULL;
96  helpDisplayed = false;
97  status = NULL;
98  if (!displayMenuCount++)
100 }
101 
103 {
104  free(title);
105  delete subMenu;
106  free(status);
107  displayMenu->Clear();
109  if (!--displayMenuCount)
111 }
112 
114 {
115  menuCategory = MenuCategory;
116 }
117 
119 {
120  if (displayMenu) {
121  displayMenu->Clear();
122  delete displayMenu;
123  }
125 }
126 
127 const char *cOsdMenu::hk(const char *s)
128 {
129  static cString buffer;
130  if (s && hasHotkeys) {
131  if (digit == 0 && '1' <= *s && *s <= '9' && *(s + 1) == ' ')
132  digit = -1; // prevents automatic hotkeys - input already has them
133  if (digit >= 0) {
134  digit++;
135  buffer = cString::sprintf(" %2d%s %s", digit, (digit > 9) ? "" : " ", s);
136  s = buffer;
137  }
138  }
139  return s;
140 }
141 
142 void cOsdMenu::SetCols(int c0, int c1, int c2, int c3, int c4)
143 {
144  cols[0] = c0;
145  cols[1] = c1;
146  cols[2] = c2;
147  cols[3] = c3;
148  cols[4] = c4;
149 }
150 
151 void cOsdMenu::SetHasHotkeys(bool HasHotkeys)
152 {
153  hasHotkeys = HasHotkeys;
154  digit = 0;
155 }
156 
157 void cOsdMenu::SetStatus(const char *s)
158 {
159  free(status);
160  status = s ? strdup(s) : NULL;
162 }
163 
164 void cOsdMenu::SetTitle(const char *Title)
165 {
166  free(title);
167  title = strdup(Title);
168 }
169 
170 void cOsdMenu::DisplayHelp(bool Force)
171 {
172  if (!helpDisplayed || Force) {
175  helpDisplayed = true;
176  }
177 }
178 
179 void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue)
180 {
181  // strings are NOT copied - must be constants!!!
182  helpRed = Red;
183  helpGreen = Green;
184  helpYellow = Yellow;
185  helpBlue = Blue;
186  DisplayHelp(true);
187 }
188 
189 void cOsdMenu::Del(int Index)
190 {
191  cList<cOsdItem>::Del(Get(Index));
192  int count = Count();
193  while (current < count && !SelectableItem(current))
194  current++;
195  if (current == count) {
196  while (current > 0 && !SelectableItem(current))
197  current--;
198  }
199  if (Index == first && first > 0)
200  first--;
201 }
202 
203 void cOsdMenu::Add(cOsdItem *Item, bool Current, cOsdItem *After)
204 {
205  cList<cOsdItem>::Add(Item, After);
206  if (Current)
207  current = Item->Index();
208 }
209 
210 void cOsdMenu::Ins(cOsdItem *Item, bool Current, cOsdItem *Before)
211 {
212  cList<cOsdItem>::Ins(Item, Before);
213  if (Current)
214  current = Item->Index();
215 }
216 
218 {
219  if (subMenu) {
220  subMenu->Display();
221  return;
222  }
224  displayMenu->Clear();
229  displayMenu->SetTabs(cols[0], cols[1], cols[2], cols[3], cols[4]);//XXX
232  DisplayHelp(true);
233  int count = Count();
234  if (count > 0) {
235  int ni = 0;
236  for (cOsdItem *item = First(); item; item = Next(item)) {
237  cStatus::MsgOsdItem(item->Text(), ni++);
238  if (current < 0 && item->Selectable())
239  current = item->Index();
240  }
241  if (current < 0)
242  current = 0; // just for safety - there HAS to be a current item!
243  first = min(first, max(0, count - displayMenuItems)); // in case the menu size has changed
244  if (current - first >= displayMenuItems || current < first) {
246  if (first + displayMenuItems > count)
247  first = count - displayMenuItems;
248  if (first < 0)
249  first = 0;
250  }
251  int i = first;
252  int n = 0;
253  for (cOsdItem *item = Get(first); item; item = Next(item)) {
254  bool CurrentSelectable = (i == current) && item->Selectable();
255  item->SetMenuItem(displayMenu, i - first, CurrentSelectable, item->Selectable());
256  if (CurrentSelectable)
257  cStatus::MsgOsdCurrentItem(item->Text());
258  if (++n == displayMenuItems)
259  break;
260  i++;
261  }
262  }
263  displayMenu->SetScrollbar(count, first);
264  if (!isempty(status))
266 }
267 
269 {
270  current = Item ? Item->Index() : -1;
271 }
272 
274 {
275  cOsdItem *item = Get(current);
276  if (item)
277  item->Set();
278 }
279 
280 void cOsdMenu::DisplayCurrent(bool Current)
281 {
282  cOsdItem *item = Get(current);
283  if (item) {
284  item->SetMenuItem(displayMenu, current - first, Current && item->Selectable(), item->Selectable());
285  if (Current && item->Selectable())
287  if (!Current)
288  item->SetFresh(true); // leaving the current item resets 'fresh'
289  if (cMenuEditItem *MenuEditItem = dynamic_cast<cMenuEditItem *>(item)) {
290  if (!MenuEditItem->DisplayHelp())
291  DisplayHelp();
292  else
293  helpDisplayed = false;
294  }
295  }
296 }
297 
299 {
300  if (Item) {
301  int Index = Item->Index();
302  int Offset = Index - first;
303  if (Offset >= 0 && Offset < first + displayMenuItems) {
304  bool Current = Index == current;
305  Item->SetMenuItem(displayMenu, Offset, Current && Item->Selectable(), Item->Selectable());
306  if (Current && Item->Selectable())
308  }
309  }
310 }
311 
312 void cOsdMenu::Clear(void)
313 {
314  if (marked >= 0)
315  SetStatus(NULL);
316  first = 0;
317  current = marked = -1;
319 }
320 
322 {
323  cOsdItem *item = Get(idx);
324  return item && item->Selectable();
325 }
326 
328 {
330  int tmpCurrent = current;
331  int lastOnScreen = first + displayMenuItems - 1;
332  int last = Count() - 1;
333  if (last < 0)
334  return;
335  while (--tmpCurrent != current) {
336  if (tmpCurrent < 0) {
337  if (first > 0) {
338  // make non-selectable items at the beginning visible:
339  first = 0;
340  Display();
341  return;
342  }
343  if (Setup.MenuScrollWrap)
344  tmpCurrent = last + 1;
345  else
346  return;
347  }
348  else if (SelectableItem(tmpCurrent))
349  break;
350  }
351  if (first <= tmpCurrent && tmpCurrent <= lastOnScreen)
352  DisplayCurrent(false);
353  current = tmpCurrent;
354  if (current < first) {
355  first = Setup.MenuScrollPage ? max(0, current - displayMenuItems + 1) : current;
356  Display();
357  }
358  else if (current > lastOnScreen) {
359  first = max(0, current - displayMenuItems + 1);
360  Display();
361  }
362  else
363  DisplayCurrent(true);
364 }
365 
367 {
369  int tmpCurrent = current;
370  int lastOnScreen = first + displayMenuItems - 1;
371  int last = Count() - 1;
372  if (last < 0)
373  return;
374  while (++tmpCurrent != current) {
375  if (tmpCurrent > last) {
376  if (first < last - displayMenuItems) {
377  // make non-selectable items at the end visible:
378  first = last - displayMenuItems + 1;
379  Display();
380  return;
381  }
382  if (Setup.MenuScrollWrap)
383  tmpCurrent = -1;
384  else
385  return;
386  }
387  else if (SelectableItem(tmpCurrent))
388  break;
389  }
390  if (first <= tmpCurrent && tmpCurrent <= lastOnScreen)
391  DisplayCurrent(false);
392  current = tmpCurrent;
393  if (current > lastOnScreen) {
394  first = Setup.MenuScrollPage ? current : max(0, current - displayMenuItems + 1);
395  if (first + displayMenuItems > last)
396  first = max(0, last - displayMenuItems + 1);
397  Display();
398  }
399  else if (current < first) {
400  first = current;
401  Display();
402  }
403  else
404  DisplayCurrent(true);
405 }
406 
408 {
410  int oldCurrent = current;
411  int oldFirst = first;
414  int last = Count() - 1;
415  if (current < 0)
416  current = 0;
417  if (first < 0)
418  first = 0;
419  int tmpCurrent = current;
420  while (!SelectableItem(tmpCurrent) && --tmpCurrent >= 0)
421  ;
422  if (tmpCurrent < 0) {
423  tmpCurrent = current;
424  while (++tmpCurrent <= last && !SelectableItem(tmpCurrent))
425  ;
426  }
427  current = tmpCurrent <= last ? tmpCurrent : -1;
428  if (current >= 0) {
429  if (current < first)
430  first = current;
431  else if (current - first >= displayMenuItems)
433  }
434  if (current != oldCurrent || first != oldFirst) {
435  Display();
436  DisplayCurrent(true);
437  }
438  else if (Setup.MenuScrollWrap)
439  CursorUp();
440 }
441 
443 {
445  int oldCurrent = current;
446  int oldFirst = first;
449  int last = Count() - 1;
450  if (current > last)
451  current = last;
452  if (first + displayMenuItems > last)
453  first = max(0, last - displayMenuItems + 1);
454  int tmpCurrent = current;
455  while (!SelectableItem(tmpCurrent) && ++tmpCurrent <= last)
456  ;
457  if (tmpCurrent > last) {
458  tmpCurrent = current;
459  while (--tmpCurrent >= 0 && !SelectableItem(tmpCurrent))
460  ;
461  }
462  current = tmpCurrent > 0 ? tmpCurrent : -1;
463  if (current >= 0) {
464  if (current < first)
465  first = current;
466  else if (current - first >= displayMenuItems)
468  }
469  if (current != oldCurrent || first != oldFirst) {
470  Display();
471  DisplayCurrent(true);
472  }
473  else if (Setup.MenuScrollWrap)
474  CursorDown();
475 }
476 
477 void cOsdMenu::Mark(void)
478 {
479  if (Count() && marked < 0) {
480  marked = current;
481  SetStatus(tr("Up/Dn for new location - OK to move"));
482  }
483 }
484 
485 #define MENUKEY_TIMEOUT 1500
486 
488 {
489  bool match = false;
490  bool highlight = false;
491  int item_nr;
492  int i;
493 
494  if (Key == kNone) {
495  if (lastActivity.TimedOut())
496  Key = kOk;
497  else
498  return osContinue;
499  }
500  else
502  for (cOsdItem *item = Last(); item; item = Prev(item)) {
503  const char *s = item->Text();
504  i = 0;
505  item_nr = 0;
506  if (s && (s = skipspace(s)) != '\0' && '0' <= s[i] && s[i] <= '9') {
507  do {
508  item_nr = item_nr * 10 + (s[i] - '0');
509  }
510  while ( !((s[++i] == '\t')||(s[i] == ' ')) && (s[i] != '\0') && ('0' <= s[i]) && (s[i] <= '9'));
511  if ((Key == kOk) && (item_nr == key_nr)) {
512  current = item->Index();
513  RefreshCurrent();
514  Display();
515  cRemote::Put(kOk, true);
516  key_nr = -1;
517  break;
518  }
519  else if (Key != kOk) {
520  if (!highlight && (item_nr == (Key - k0))) {
521  highlight = true;
522  current = item->Index();
523  }
524  if (!match && (key_nr == -1) && ((item_nr / 10) == (Key - k0))) {
525  match = true;
526  key_nr = (Key - k0);
527  }
528  else if (((key_nr == -1) && (item_nr == (Key - k0))) || (!match && (key_nr >= 0) && (item_nr == (10 * key_nr + Key - k0)))) {
529  current = item->Index();
530  cRemote::Put(kOk, true);
531  key_nr = -1;
532  break;
533  }
534  }
535  }
536  }
537  if ((!match) && (Key != kNone))
538  key_nr = -1;
539  return osContinue;
540 }
541 
543 {
544  delete subMenu;
545  subMenu = SubMenu;
546  subMenu->Display();
547  return osContinue; // convenience return value
548 }
549 
551 {
552  delete subMenu;
553  subMenu = NULL;
554  RefreshCurrent();
555  Display();
556  return osContinue; // convenience return value
557 }
558 
560 {
561  if (subMenu) {
562  eOSState state = subMenu->ProcessKey(Key);
563  if (state == osBack)
564  return CloseSubMenu();
565  return state;
566  }
567 
568  cOsdItem *item = Get(current);
569  if (marked < 0 && item) {
570  eOSState state = item->ProcessKey(Key);
571  if (state != osUnknown) {
572  DisplayCurrent(true);
573  return state;
574  }
575  }
576  switch (int(Key)) {
577  case kNone:
578  case k0...k9: return hasHotkeys ? HotKey(Key) : osUnknown;
579  case kUp|k_Repeat:
580  case kUp: CursorUp(); break;
581  case kDown|k_Repeat:
582  case kDown: CursorDown(); break;
583  case kLeft|k_Repeat:
584  case kLeft: PageUp(); break;
585  case kRight|k_Repeat:
586  case kRight: PageDown(); break;
587  case kBack: return osBack;
588  case kOk: if (marked >= 0) {
589  SetStatus(NULL);
590  if (marked != current)
591  Move(marked, current);
592  marked = -1;
593  break;
594  }
595  // else run into default
596  default: if (marked < 0)
597  return osUnknown;
598  }
599  return osContinue;
600 }
virtual ~cOsdMenu()
Definition: osdbase.c:102
void SetStatus(const char *s)
Definition: osdbase.c:157
void DisplayItem(cOsdItem *Item)
Definition: osdbase.c:298
static void MsgOsdCurrentItem(const char *Text)
Definition: status.c:104
virtual void Del(int Index)
Definition: osdbase.c:189
bool isempty(const char *s)
Definition: tools.c:248
const char * helpGreen
Definition: osdbase.h:97
int Index(void) const
Definition: tools.c:1920
void Set(int Ms=0)
Definition: tools.c:689
const char * helpBlue
Definition: osdbase.h:97
int key_nr
Definition: osdbase.h:102
Definition: keys.h:23
void Add(cOsdItem *Item, bool Current=false, cOsdItem *After=NULL)
Definition: osdbase.c:203
cOsdItem(eOSState State=osUnknown)
Definition: osdbase.c:20
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:1945
eMenuCategory menuCategory
Definition: osdbase.h:95
bool hasHotkeys
Definition: osdbase.h:101
cOsdMenu * subMenu
Definition: osdbase.h:96
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1011
Definition: keys.h:17
virtual void SetMessage(eMessageType Type, const char *Text)=0
Sets a one line message Text, with the given Type.
Definition: keys.h:61
int displayMenuItems
Definition: osdbase.h:91
cOsdMenu * SubMenu(void)
Definition: osdbase.h:127
virtual void Clear(void)
Definition: osdbase.c:312
cOsdItem * Get(int Index) const
Definition: tools.h:481
bool TimedOut(void)
Definition: tools.c:694
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:117
eMenuCategory MenuCategory(void) const
Returns the menu category, set by a previous call to SetMenuCategory().
Definition: skins.h:141
eOSState HotKey(eKeys Key)
Definition: osdbase.c:487
void RefreshCurrent(void)
Definition: osdbase.c:273
T max(T a, T b)
Definition: tools.h:55
bool selectable
Definition: osdbase.h:54
void PageUp(void)
Definition: osdbase.c:407
virtual cSkinDisplayMenu * DisplayMenu(void)=0
Creates and returns a new object for displaying a menu.
bool fresh
Definition: osdbase.h:56
void SetFresh(bool Fresh)
Definition: osdbase.c:53
void SetDisplayMenu(void)
Definition: osdbase.c:118
int Current(void) const
Definition: osdbase.h:137
int Count(void) const
Definition: tools.h:475
T min(T a, T b)
Definition: tools.h:54
#define MENUKEY_TIMEOUT
Definition: osdbase.c:485
static void MsgOsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue)
Definition: status.c:92
virtual void SetItem(const char *Text, int Index, bool Current, bool Selectable)=0
Sets the item at the given Index to Text.
cTimeMs lastActivity
Definition: osdbase.h:103
virtual void Clear(void)
Definition: tools.c:2018
Definition: keys.h:55
int marked
Definition: osdbase.h:94
cOsdItem * Last(void) const
Definition: tools.h:483
static cSkinDisplayMenu * displayMenu
Definition: osdbase.h:89
char * status
Definition: osdbase.h:99
eOSState
Definition: osdbase.h:18
const char * Text(void) const
Definition: osdbase.h:65
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:79
void SetHasHotkeys(bool HasHotkeys=true)
Definition: osdbase.c:151
bool Selectable(void) const
Definition: osdbase.h:61
virtual eOSState ProcessKey(eKeys Key)
Definition: osdbase.c:559
void PageDown(void)
Definition: osdbase.c:442
void Ins(cOsdItem *Item, bool Current=false, cOsdItem *Before=NULL)
Definition: osdbase.c:210
cOsdItem * Next(const cOsdItem *object) const
Definition: tools.h:485
void SetCols(int c0, int c1=0, int c2=0, int c3=0, int c4=0)
Definition: osdbase.c:142
void SetMenuCategory(eMenuCategory MenuCategory)
Definition: osdbase.c:113
static void MsgOsdTitle(const char *Title)
Definition: status.c:80
void CursorDown(void)
Definition: osdbase.c:366
char * title
Definition: osdbase.h:92
cOsdMenu(const char *Title, int c0=0, int c1=0, int c2=0, int c3=0, int c4=0)
Definition: osdbase.c:81
void SetText(const char *Text, bool Copy=true)
Definition: osdbase.c:42
void SetSelectable(bool Selectable)
Definition: osdbase.c:48
Definition: keys.h:18
const char * helpYellow
Definition: osdbase.h:97
void Ins(cListObject *Object, cListObject *Before=NULL)
Definition: tools.c:1961
virtual ~cOsdItem()
Definition: osdbase.c:37
virtual void Display(void)
Definition: osdbase.c:217
cSetup Setup
Definition: config.c:373
bool Put(uint64_t Code, bool Repeat=false, bool Release=false)
Definition: remote.c:124
Definition: keys.h:20
void Mark(void)
Definition: osdbase.c:477
int digit
Definition: osdbase.h:100
static int displayMenuCount
Definition: osdbase.h:90
int current
Definition: osdbase.h:94
Definition: skins.h:23
virtual eOSState ProcessKey(eKeys Key)
Definition: osdbase.c:63
virtual void Show(void)
Definition: osdbase.c:70
void DisplayHelp(bool Force=false)
Definition: osdbase.c:170
int first
Definition: osdbase.h:94
Definition: keys.h:21
void SetCurrent(cOsdItem *Item)
Definition: osdbase.c:268
void DisplayCurrent(bool Current)
Definition: osdbase.c:280
cOsdItem * First(void) const
Definition: tools.h:482
void Del(cListObject *Object, bool DeleteObject=true)
Definition: tools.c:1977
eMenuCategory
Definition: skins.h:76
static void MsgOsdClear(void)
Definition: status.c:74
bool isMenu
Definition: osdbase.h:74
virtual void SetMenuCategory(eMenuCategory MenuCategory)
Sets the current menu category.
Definition: skins.c:74
const char * hk(const char *s)
Definition: osdbase.c:127
#define tr(s)
Definition: i18n.h:85
virtual void Move(int From, int To)
Definition: tools.c:1989
void DELETENULL(T *&p)
Definition: tools.h:48
eOSState CloseSubMenu()
Definition: osdbase.c:550
char * skipspace(const char *s)
Definition: tools.h:194
void SetHelp(const char *Red, const char *Green=NULL, const char *Yellow=NULL, const char *Blue=NULL)
Definition: osdbase.c:179
bool SelectableItem(int idx)
Definition: osdbase.c:321
int count
Definition: tools.h:465
virtual int MaxItems(void)=0
Returns the maximum number of items the menu can display.
char * text
Definition: osdbase.h:52
virtual void SetTitle(const char *Title)=0
Sets the title of this menu to Title.
void CursorUp(void)
Definition: osdbase.c:327
Definition: keys.h:28
int MenuScrollWrap
Definition: config.h:267
virtual void Set(void)
Definition: osdbase.h:66
bool helpDisplayed
Definition: osdbase.h:98
int MenuScrollPage
Definition: config.h:266
Definition: osdbase.h:35
eOSState state
Definition: osdbase.h:53
virtual void Clear(void)=0
Clears the entire central area of the menu.
const char * helpRed
Definition: osdbase.h:97
void SetTitle(const char *Title)
Definition: osdbase.c:164
cSkin * Current(void)
Returns a pointer to the current skin.
Definition: skins.h:408
eOSState AddSubMenu(cOsdMenu *SubMenu)
Definition: osdbase.c:542
static void MsgOsdItem(const char *Text, int Index)
Definition: status.c:98
virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
Definition: osdbase.c:58
cOsdItem * Prev(const cOsdItem *object) const
Definition: tools.h:484
int cols[cSkinDisplayMenu::MaxTabs]
Definition: osdbase.h:93
eKeys
Definition: keys.h:16
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.
Definition: tools.h:166
Definition: keys.h:22
cSkins Skins
Definition: skins.c:203