vdr  2.6.1
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 
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 int cOsdMenu::osdState = 0;
81 
82 cOsdMenu::cOsdMenu(const char *Title, int c0, int c1, int c2, int c3, int c4)
83 {
84  isMenu = true;
85  digit = 0;
86  hasHotkeys = false;
87  displayMenuItems = 0;
88  title = NULL;
92  SetTitle(Title);
93  SetCols(c0, c1, c2, c3, c4);
94  first = 0;
95  lastOffset = -1;
96  current = marked = -1;
97  subMenu = NULL;
98  helpRed = helpGreen = helpYellow = helpBlue = NULL;
99  helpDisplayed = false;
100  status = NULL;
101  if (!displayMenuCount++) {
102  cOsdProvider::OsdSizeChanged(osdState); // to get the current state
103  SetDisplayMenu();
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  }
135 }
136 
137 const 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 
152 void 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 
161 void cOsdMenu::SetHasHotkeys(bool HasHotkeys)
162 {
163  hasHotkeys = HasHotkeys;
164  digit = 0;
165 }
166 
167 void cOsdMenu::SetStatus(const char *s)
168 {
169  free(status);
170  status = s ? strdup(s) : NULL;
172 }
173 
174 void cOsdMenu::SetTitle(const char *Title)
175 {
176  free(title);
177  title = strdup(Title);
178 }
179 
180 void cOsdMenu::DisplayHelp(bool Force)
181 {
182  if (!helpDisplayed || Force) {
185  helpDisplayed = true;
186  }
187 }
188 
189 void 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 
199 void cOsdMenu::Del(int Index)
200 {
201  cList<cOsdItem>::Del(Get(Index));
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 
213 void cOsdMenu::Add(cOsdItem *Item, bool Current, cOsdItem *After)
214 {
215  cList<cOsdItem>::Add(Item, After);
216  if (Current)
217  current = Item->Index();
218 }
219 
220 void 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  }
234  SetDisplayMenu();
236  displayMenu->Clear();
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
258  if (current - first >= displayMenuItems || current < first) {
260  if (first + displayMenuItems > count)
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 
297 void 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 
329 void cOsdMenu::Clear(void)
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  }
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) {
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  }
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) {
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 
496 void cOsdMenu::Mark(void)
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();
511  RefreshCurrent();
512  Display();
513  cRemote::Put(kOk, true);
514  break;
515  }
516  }
517  }
518  return osContinue;
519 }
520 
522 {
523  delete subMenu;
524  subMenu = SubMenu;
525  subMenu->Display();
526  return osContinue; // convenience return value
527 }
528 
530 {
531  delete subMenu;
532  subMenu = NULL;
533  if (ReDisplay) {
534  RefreshCurrent();
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)
572  Move(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:2261
void Ins(cListObject *Object, cListObject *Before=NULL)
Definition: tools.c:2200
void Del(cListObject *Object, bool DeleteObject=true)
Definition: tools.c:2216
virtual void Move(int From, int To)
Definition: tools.c:2232
int count
Definition: tools.h:577
int Count(void) const
Definition: tools.h:637
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:2184
int Index(void) const
Definition: tools.c:2104
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 * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition: tools.h:653
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
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
const char * Text(void) const
Definition: osdbase.h:63
void Ins(cOsdItem *Item, bool Current=false, cOsdItem *Before=NULL)
Definition: osdbase.c:220
const char * Title(void)
Definition: osdbase.h:112
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
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
cOsdMenu * SubMenu(void)
Definition: osdbase.h:127
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
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