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 {
329  int tmpCurrent = current;
330  int lastOnScreen = first + displayMenuItems - 1;
331  int last = Count() - 1;
332  if (last < 0)
333  return;
334  while (--tmpCurrent != current) {
335  if (tmpCurrent < 0) {
336  if (first > 0) {
337  // make non-selectable items at the beginning visible:
338  first = 0;
339  Display();
340  return;
341  }
342  if (Setup.MenuScrollWrap)
343  tmpCurrent = last + 1;
344  else
345  return;
346  }
347  else if (SelectableItem(tmpCurrent))
348  break;
349  }
350  if (first <= tmpCurrent && tmpCurrent <= lastOnScreen)
351  DisplayCurrent(false);
352  current = tmpCurrent;
353  if (current < first) {
354  first = Setup.MenuScrollPage ? max(0, current - displayMenuItems + 1) : current;
355  Display();
356  }
357  else if (current > lastOnScreen) {
358  first = max(0, current - displayMenuItems + 1);
359  Display();
360  }
361  else
362  DisplayCurrent(true);
363 }
364 
366 {
367  int tmpCurrent = current;
368  int lastOnScreen = first + displayMenuItems - 1;
369  int last = Count() - 1;
370  if (last < 0)
371  return;
372  while (++tmpCurrent != current) {
373  if (tmpCurrent > last) {
374  if (first < last - displayMenuItems) {
375  // make non-selectable items at the end visible:
376  first = last - displayMenuItems + 1;
377  Display();
378  return;
379  }
380  if (Setup.MenuScrollWrap)
381  tmpCurrent = -1;
382  else
383  return;
384  }
385  else if (SelectableItem(tmpCurrent))
386  break;
387  }
388  if (first <= tmpCurrent && tmpCurrent <= lastOnScreen)
389  DisplayCurrent(false);
390  current = tmpCurrent;
391  if (current > lastOnScreen) {
392  first = Setup.MenuScrollPage ? current : max(0, current - displayMenuItems + 1);
393  if (first + displayMenuItems > last)
394  first = max(0, last - displayMenuItems + 1);
395  Display();
396  }
397  else if (current < first) {
398  first = current;
399  Display();
400  }
401  else
402  DisplayCurrent(true);
403 }
404 
406 {
407  int oldCurrent = current;
408  int oldFirst = first;
411  int last = Count() - 1;
412  if (current < 0)
413  current = 0;
414  if (first < 0)
415  first = 0;
416  int tmpCurrent = current;
417  while (!SelectableItem(tmpCurrent) && --tmpCurrent >= 0)
418  ;
419  if (tmpCurrent < 0) {
420  tmpCurrent = current;
421  while (++tmpCurrent <= last && !SelectableItem(tmpCurrent))
422  ;
423  }
424  current = tmpCurrent <= last ? tmpCurrent : -1;
425  if (current >= 0) {
426  if (current < first)
427  first = current;
428  else if (current - first >= displayMenuItems)
430  }
431  if (current != oldCurrent || first != oldFirst) {
432  Display();
433  DisplayCurrent(true);
434  }
435  else if (Setup.MenuScrollWrap)
436  CursorUp();
437 }
438 
440 {
441  int oldCurrent = current;
442  int oldFirst = first;
445  int last = Count() - 1;
446  if (current > last)
447  current = last;
448  if (first + displayMenuItems > last)
449  first = max(0, last - displayMenuItems + 1);
450  int tmpCurrent = current;
451  while (!SelectableItem(tmpCurrent) && ++tmpCurrent <= last)
452  ;
453  if (tmpCurrent > last) {
454  tmpCurrent = current;
455  while (--tmpCurrent >= 0 && !SelectableItem(tmpCurrent))
456  ;
457  }
458  current = tmpCurrent > 0 ? tmpCurrent : -1;
459  if (current >= 0) {
460  if (current < first)
461  first = current;
462  else if (current - first >= displayMenuItems)
464  }
465  if (current != oldCurrent || first != oldFirst) {
466  Display();
467  DisplayCurrent(true);
468  }
469  else if (Setup.MenuScrollWrap)
470  CursorDown();
471 }
472 
473 void cOsdMenu::Mark(void)
474 {
475  if (Count() && marked < 0) {
476  marked = current;
477  SetStatus(tr("Up/Dn for new location - OK to move"));
478  }
479 }
480 
481 #define MENUKEY_TIMEOUT 1500
482 
484 {
485  bool match = false;
486  bool highlight = false;
487  int item_nr;
488  int i;
489 
490  if (Key == kNone) {
491  if (lastActivity.TimedOut())
492  Key = kOk;
493  else
494  return osContinue;
495  }
496  else
498  for (cOsdItem *item = Last(); item; item = Prev(item)) {
499  const char *s = item->Text();
500  i = 0;
501  item_nr = 0;
502  if (s && (s = skipspace(s)) != '\0' && '0' <= s[i] && s[i] <= '9') {
503  do {
504  item_nr = item_nr * 10 + (s[i] - '0');
505  }
506  while ( !((s[++i] == '\t')||(s[i] == ' ')) && (s[i] != '\0') && ('0' <= s[i]) && (s[i] <= '9'));
507  if ((Key == kOk) && (item_nr == key_nr)) {
508  current = item->Index();
509  RefreshCurrent();
510  Display();
511  cRemote::Put(kOk, true);
512  key_nr = -1;
513  break;
514  }
515  else if (Key != kOk) {
516  if (!highlight && (item_nr == (Key - k0))) {
517  highlight = true;
518  current = item->Index();
519  }
520  if (!match && (key_nr == -1) && ((item_nr / 10) == (Key - k0))) {
521  match = true;
522  key_nr = (Key - k0);
523  }
524  else if (((key_nr == -1) && (item_nr == (Key - k0))) || (!match && (key_nr >= 0) && (item_nr == (10 * key_nr + Key - k0)))) {
525  current = item->Index();
526  cRemote::Put(kOk, true);
527  key_nr = -1;
528  break;
529  }
530  }
531  }
532  }
533  if ((!match) && (Key != kNone))
534  key_nr = -1;
535  return osContinue;
536 }
537 
539 {
540  delete subMenu;
541  subMenu = SubMenu;
542  subMenu->Display();
543  return osContinue; // convenience return value
544 }
545 
547 {
548  delete subMenu;
549  subMenu = NULL;
550  RefreshCurrent();
551  Display();
552  return osContinue; // convenience return value
553 }
554 
556 {
557  if (subMenu) {
558  eOSState state = subMenu->ProcessKey(Key);
559  if (state == osBack)
560  return CloseSubMenu();
561  return state;
562  }
563 
564  cOsdItem *item = Get(current);
565  if (marked < 0 && item) {
566  eOSState state = item->ProcessKey(Key);
567  if (state != osUnknown) {
568  DisplayCurrent(true);
569  return state;
570  }
571  }
572  switch (int(Key)) {
573  case kNone:
574  case k0...k9: return hasHotkeys ? HotKey(Key) : osUnknown;
575  case kUp|k_Repeat:
576  case kUp: CursorUp(); break;
577  case kDown|k_Repeat:
578  case kDown: CursorDown(); break;
579  case kLeft|k_Repeat:
580  case kLeft: PageUp(); break;
581  case kRight|k_Repeat:
582  case kRight: PageDown(); break;
583  case kBack: return osBack;
584  case kOk: if (marked >= 0) {
585  SetStatus(NULL);
586  if (marked != current)
587  Move(marked, current);
588  marked = -1;
589  break;
590  }
591  // else run into default
592  default: if (marked < 0)
593  return osUnknown;
594  }
595  return osContinue;
596 }
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:96
int Index(void) const
Definition: tools.c:1920
void Set(int Ms=0)
Definition: tools.c:689
const char * helpBlue
Definition: osdbase.h:96
int key_nr
Definition: osdbase.h:101
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:94
bool hasHotkeys
Definition: osdbase.h:100
cOsdMenu * subMenu
Definition: osdbase.h:95
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:90
cOsdMenu * SubMenu(void)
Definition: osdbase.h:126
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:483
void RefreshCurrent(void)
Definition: osdbase.c:273
T max(T a, T b)
Definition: tools.h:55
bool selectable
Definition: osdbase.h:53
void PageUp(void)
Definition: osdbase.c:405
virtual cSkinDisplayMenu * DisplayMenu(void)=0
Creates and returns a new object for displaying a menu.
bool fresh
Definition: osdbase.h:55
void SetFresh(bool Fresh)
Definition: osdbase.c:53
void SetDisplayMenu(void)
Definition: osdbase.c:118
int Current(void) const
Definition: osdbase.h:136
int Count(void) const
Definition: tools.h:475
T min(T a, T b)
Definition: tools.h:54
#define MENUKEY_TIMEOUT
Definition: osdbase.c:481
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:102
virtual void Clear(void)
Definition: tools.c:2018
Definition: keys.h:55
int marked
Definition: osdbase.h:93
cOsdItem * Last(void) const
Definition: tools.h:483
static cSkinDisplayMenu * displayMenu
Definition: osdbase.h:88
char * status
Definition: osdbase.h:98
eOSState
Definition: osdbase.h:18
const char * Text(void) const
Definition: osdbase.h:64
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:60
virtual eOSState ProcessKey(eKeys Key)
Definition: osdbase.c:555
void PageDown(void)
Definition: osdbase.c:439
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 FILE * idx
Definition: vdr-genindex.c:58
static void MsgOsdTitle(const char *Title)
Definition: status.c:80
void CursorDown(void)
Definition: osdbase.c:365
char * title
Definition: osdbase.h:91
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:96
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:372
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:473
int digit
Definition: osdbase.h:99
static int displayMenuCount
Definition: osdbase.h:89
int current
Definition: osdbase.h:93
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:93
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:73
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:546
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:51
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:265
virtual void Set(void)
Definition: osdbase.h:65
bool helpDisplayed
Definition: osdbase.h:97
int MenuScrollPage
Definition: config.h:264
Definition: osdbase.h:34
eOSState state
Definition: osdbase.h:52
virtual void Clear(void)=0
Clears the entire central area of the menu.
const char * helpRed
Definition: osdbase.h:96
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:538
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:92
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