vdr  2.0.6
menu.c
Go to the documentation of this file.
1 /*
2  * menu.c: The actual menu implementations
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: menu.c 2.82.1.8 2014/02/26 11:42:28 kls Exp $
8  */
9 
10 #include "menu.h"
11 #include "iconpatch.h"
12 #include <ctype.h>
13 #include <limits.h>
14 #include <math.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include "channels.h"
19 #include "config.h"
20 #include "cutter.h"
21 #include "eitscan.h"
22 #include "i18n.h"
23 #include "interface.h"
24 #include "plugin.h"
25 #include "recording.h"
26 #include "remote.h"
27 #include "shutdown.h"
28 #include "sourceparams.h"
29 #include "sources.h"
30 #include "status.h"
31 #include "themes.h"
32 #include "timers.h"
33 #include "transfer.h"
34 #include "videodir.h"
35 
36 #define MAXWAIT4EPGINFO 3 // seconds
37 #define MODETIMEOUT 3 // seconds
38 #define NEWTIMERLIMIT 120 // seconds until the start time of a new timer created from the Schedule menu,
39  // within which it will go directly into the "Edit timer" menu to allow
40  // further parameter settings
41 #define DEFERTIMER 60 // seconds by which a timer is deferred in case of problems
42 
43 #define MAXRECORDCONTROLS (MAXDEVICES * MAXRECEIVERS)
44 #define MAXINSTANTRECTIME (24 * 60 - 1) // 23:59 hours
45 #define MAXWAITFORCAMMENU 10 // seconds to wait for the CAM menu to open
46 #define CAMMENURETYTIMEOUT 3 // seconds after which opening the CAM menu is retried
47 #define CAMRESPONSETIMEOUT 5 // seconds to wait for a response from a CAM
48 #define MINFREEDISK 300 // minimum free disk space (in MB) required to start recording
49 #define NODISKSPACEDELTA 300 // seconds between "Not enough disk space to start recording!" messages
50 #define MAXCHNAMWIDTH 16 // maximum number of characters of channels' short names shown in schedules menus
51 
52 #define CHNUMWIDTH (numdigits(Channels.MaxNumber()) + 1)
53 #define CHNAMWIDTH (min(MAXCHNAMWIDTH, Channels.MaxShortChannelNameLength() + 1))
54 
55 // --- cMenuEditCaItem -------------------------------------------------------
56 
58 protected:
59  virtual void Set(void);
60 public:
61  cMenuEditCaItem(const char *Name, int *Value);
63  };
64 
65 cMenuEditCaItem::cMenuEditCaItem(const char *Name, int *Value)
66 :cMenuEditIntItem(Name, Value, 0)
67 {
68  Set();
69 }
70 
72 {
73  if (*value == CA_FTA)
74  SetValue(tr("Free To Air"));
75  else if (*value >= CA_ENCRYPTED_MIN)
76  SetValue(tr("encrypted"));
77  else
79 }
80 
82 {
84 
85  if (state == osUnknown) {
86  if (NORMALKEY(Key) == kLeft && *value >= CA_ENCRYPTED_MIN)
87  *value = CA_FTA;
88  else
89  return cMenuEditIntItem::ProcessKey(Key);
90  Set();
91  state = osContinue;
92  }
93  return state;
94 }
95 
96 // --- cMenuEditSrcItem ------------------------------------------------------
97 
99 private:
100  const cSource *source;
101 protected:
102  virtual void Set(void);
103 public:
104  cMenuEditSrcItem(const char *Name, int *Value);
106  };
107 
108 cMenuEditSrcItem::cMenuEditSrcItem(const char *Name, int *Value)
109 :cMenuEditIntItem(Name, Value, 0)
110 {
111  source = Sources.Get(*Value);
112  Set();
113 }
114 
116 {
117  if (source)
119  else
121 }
122 
124 {
126 
127  if (state == osUnknown) {
128  bool IsRepeat = Key & k_Repeat;
129  Key = NORMALKEY(Key);
130  if (Key == kLeft) { // TODO might want to increase the delta if repeated quickly?
131  if (source) {
132  if (source->Prev())
133  source = (cSource *)source->Prev();
134  else if (!IsRepeat)
135  source = Sources.Last();
136  *value = source->Code();
137  }
138  }
139  else if (Key == kRight) {
140  if (source) {
141  if (source->Next())
142  source = (cSource *)source->Next();
143  else if (!IsRepeat)
144  source = Sources.First();
145  }
146  else
147  source = Sources.First();
148  if (source)
149  *value = source->Code();
150  }
151  else
152  return state; // we don't call cMenuEditIntItem::ProcessKey(Key) here since we don't accept numerical input
153  Set();
154  state = osContinue;
155  }
156  return state;
157 }
158 
159 // --- cMenuEditChannel ------------------------------------------------------
160 
161 class cMenuEditChannel : public cOsdMenu {
162 private:
166  char name[256];
167  void Setup(void);
168 public:
169  cMenuEditChannel(cChannel *Channel, bool New = false);
170  virtual eOSState ProcessKey(eKeys Key);
171  };
172 
174 :cOsdMenu(tr("Edit channel"), 16)
175 {
177  channel = Channel;
178  sourceParam = NULL;
179  *name = 0;
180  if (channel) {
181  data = *channel;
182  strn0cpy(name, data.name, sizeof(name));
183  if (New) {
184  channel = NULL;
185  // clear non-editable members:
186  data.nid = 0;
187  data.tid = 0;
188  data.rid = 0;
189  *data.shortName = 0;
190  *data.provider = 0;
191  *data.portalName = 0;
192  }
193  }
194  Setup();
195 }
196 
198 {
199  int current = Current();
200 
201  Clear();
202 
203  // Parameters for all types of sources:
204  Add(new cMenuEditStrItem( tr("Name"), name, sizeof(name)));
205  Add(new cMenuEditSrcItem( tr("Source"), &data.source));
206  Add(new cMenuEditIntItem( tr("Frequency"), &data.frequency));
207  Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 0x1FFF));
208  Add(new cMenuEditIntItem( tr("Ppid"), &data.ppid, 0, 0x1FFF));
209  Add(new cMenuEditIntItem( tr("Apid1"), &data.apids[0], 0, 0x1FFF));
210  Add(new cMenuEditIntItem( tr("Apid2"), &data.apids[1], 0, 0x1FFF));
211  Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpids[0], 0, 0x1FFF));
212  Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpids[1], 0, 0x1FFF));
213  Add(new cMenuEditIntItem( tr("Spid1"), &data.spids[0], 0, 0x1FFF));
214  Add(new cMenuEditIntItem( tr("Spid2"), &data.spids[1], 0, 0x1FFF));
215  Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0x1FFF));
216  Add(new cMenuEditCaItem( tr("CA"), &data.caids[0]));
217  Add(new cMenuEditIntItem( tr("Sid"), &data.sid, 1, 0xFFFF));
218  /* XXX not yet used
219  Add(new cMenuEditIntItem( tr("Nid"), &data.nid, 0));
220  Add(new cMenuEditIntItem( tr("Tid"), &data.tid, 0));
221  Add(new cMenuEditIntItem( tr("Rid"), &data.rid, 0));
222  XXX*/
223  // Parameters for specific types of sources:
225  if (sourceParam) {
227  cOsdItem *Item;
228  while ((Item = sourceParam->GetOsdItem()) != NULL)
229  Add(Item);
230  }
231 
232  SetCurrent(Get(current));
233  Display();
234 }
235 
237 {
238  int oldSource = data.source;
239  eOSState state = cOsdMenu::ProcessKey(Key);
240 
241  if (state == osUnknown) {
242  if (Key == kOk) {
243  if (sourceParam)
247  if (channel) {
248  *channel = data;
249  isyslog("edited channel %d %s", channel->Number(), *data.ToText());
250  state = osBack;
251  }
252  else {
253  channel = new cChannel;
254  *channel = data;
256  Channels.ReNumber();
257  isyslog("added channel %d %s", channel->Number(), *data.ToText());
258  state = osUser1;
259  }
260  Channels.SetModified(true);
261  }
262  else {
263  Skins.Message(mtError, tr("Channel settings are not unique!"));
264  state = osContinue;
265  }
266  }
267  }
268  if (Key != kNone && (data.source & cSource::st_Mask) != (oldSource & cSource::st_Mask)) {
269  if (sourceParam)
271  Setup();
272  }
273  return state;
274 }
275 
276 // --- cMenuChannelItem ------------------------------------------------------
277 
278 class cMenuChannelItem : public cOsdItem {
279 public:
281 private:
284 public:
286  static void SetSortMode(eChannelSortMode SortMode) { sortMode = SortMode; }
287  static void IncSortMode(void) { sortMode = eChannelSortMode((sortMode == csmProvider) ? csmNumber : sortMode + 1); }
288  static eChannelSortMode SortMode(void) { return sortMode; }
289  virtual int Compare(const cListObject &ListObject) const;
290  virtual void Set(void);
291  cChannel *Channel(void) { return channel; }
292  virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable);
293  };
294 
296 
298 {
299  channel = Channel;
300  if (channel->GroupSep())
301  SetSelectable(false);
302  Set();
303 }
304 
305 int cMenuChannelItem::Compare(const cListObject &ListObject) const
306 {
307  cMenuChannelItem *p = (cMenuChannelItem *)&ListObject;
308  int r = -1;
309  if (sortMode == csmProvider)
310  r = strcoll(channel->Provider(), p->channel->Provider());
311  if (sortMode == csmName || r == 0)
312  r = strcoll(channel->Name(), p->channel->Name());
313  if (sortMode == csmNumber || r == 0)
314  r = channel->Number() - p->channel->Number();
315  return r;
316 }
317 
319 {
320  cString buffer;
321  if (!channel->GroupSep()) {
322  if (sortMode == csmProvider)
323  buffer = cString::sprintf("%d\t%s - %s", channel->Number(), channel->Provider(), channel->Name());
324  else if (Setup.WarEagleIcons) {
325  if (channel->Vpid() == 1 || channel->Vpid() == 0)
326  buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_RADIO_UTF8 : ICON_RADIO, channel->Name());
327  else if (channel->Ca() == 0)
328  buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_TV_UTF8 : ICON_TV, channel->Name());
329  else
331  }
332  else
333  buffer = cString::sprintf("%d\t%s", channel->Number(), channel->Name());
334  }
335  else
336  buffer = cString::sprintf("---\t%s ----------------------------------------------------------------", channel->Name());
337  SetText(buffer);
338 }
339 
340 void cMenuChannelItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
341 {
342  if (!DisplayMenu->SetItemChannel(channel, Index, Current, Selectable, sortMode == csmProvider))
343  DisplayMenu->SetItem(Text(), Index, Current, Selectable);
344 }
345 
346 // --- cMenuChannels ---------------------------------------------------------
347 
348 #define CHANNELNUMBERTIMEOUT 1000 //ms
349 
350 class cMenuChannels : public cOsdMenu {
351 private:
352  int number;
354  void Setup(void);
355  cChannel *GetChannel(int Index);
356  void Propagate(void);
357 protected:
358  eOSState Number(eKeys Key);
359  eOSState Switch(void);
360  eOSState Edit(void);
361  eOSState New(void);
362  eOSState Delete(void);
363  virtual void Move(int From, int To);
364 public:
365  cMenuChannels(void);
366  ~cMenuChannels();
367  virtual eOSState ProcessKey(eKeys Key);
368  };
369 
371 :cOsdMenu(tr("Channels"), CHNUMWIDTH)
372 {
374  number = 0;
375  Setup();
377 }
378 
380 {
382 }
383 
385 {
386  cChannel *currentChannel = GetChannel(Current());
387  if (!currentChannel)
388  currentChannel = Channels.GetByNumber(cDevice::CurrentChannel());
389  cMenuChannelItem *currentItem = NULL;
390  Clear();
391  for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) {
392  if (!channel->GroupSep() || cMenuChannelItem::SortMode() == cMenuChannelItem::csmNumber && *channel->Name()) {
393  cMenuChannelItem *item = new cMenuChannelItem(channel);
394  Add(item);
395  if (channel == currentChannel)
396  currentItem = item;
397  }
398  }
400  Sort();
401  SetCurrent(currentItem);
402  SetHelp(tr("Button$Edit"), tr("Button$New"), tr("Button$Delete"), tr("Button$Mark"));
403  Display();
404 }
405 
407 {
408  cMenuChannelItem *p = (cMenuChannelItem *)Get(Index);
409  return p ? (cChannel *)p->Channel() : NULL;
410 }
411 
413 {
414  Channels.ReNumber();
415  for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next())
416  ci->Set();
417  Display();
418  Channels.SetModified(true);
419 }
420 
422 {
423  if (HasSubMenu())
424  return osContinue;
425  if (numberTimer.TimedOut())
426  number = 0;
427  if (!number && Key == k0) {
429  Setup();
430  }
431  else {
432  number = number * 10 + Key - k0;
433  for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) {
434  if (!ci->Channel()->GroupSep() && ci->Channel()->Number() == number) {
435  SetCurrent(ci);
436  Display();
437  break;
438  }
439  }
441  }
442  return osContinue;
443 }
444 
446 {
447  if (HasSubMenu())
448  return osContinue;
449  cChannel *ch = GetChannel(Current());
450  if (ch)
451  return cDevice::PrimaryDevice()->SwitchChannel(ch, true) ? osEnd : osContinue;
452  return osEnd;
453 }
454 
456 {
457  if (HasSubMenu() || Count() == 0)
458  return osContinue;
459  cChannel *ch = GetChannel(Current());
460  if (ch)
461  return AddSubMenu(new cMenuEditChannel(ch));
462  return osContinue;
463 }
464 
466 {
467  if (HasSubMenu())
468  return osContinue;
469  return AddSubMenu(new cMenuEditChannel(GetChannel(Current()), true));
470 }
471 
473 {
474  if (!HasSubMenu() && Count() > 0) {
475  int CurrentChannelNr = cDevice::CurrentChannel();
476  cChannel *CurrentChannel = Channels.GetByNumber(CurrentChannelNr);
477  int Index = Current();
478  cChannel *channel = GetChannel(Current());
479  int DeletedChannel = channel->Number();
480  // Check if there is a timer using this channel:
481  if (channel->HasTimer()) {
482  Skins.Message(mtError, tr("Channel is being used by a timer!"));
483  return osContinue;
484  }
485  if (Interface->Confirm(tr("Delete channel?"))) {
486  if (CurrentChannel && channel == CurrentChannel) {
487  int n = Channels.GetNextNormal(CurrentChannel->Index());
488  if (n < 0)
489  n = Channels.GetPrevNormal(CurrentChannel->Index());
490  CurrentChannel = Channels.Get(n);
491  CurrentChannelNr = 0; // triggers channel switch below
492  }
493  Channels.Del(channel);
494  cOsdMenu::Del(Index);
495  Propagate();
496  Channels.SetModified(true);
497  isyslog("channel %d deleted", DeletedChannel);
498  if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) {
500  Channels.SwitchTo(CurrentChannel->Number());
501  else
502  cDevice::SetCurrentChannel(CurrentChannel);
503  }
504  }
505  }
506  return osContinue;
507 }
508 
509 void cMenuChannels::Move(int From, int To)
510 {
511  int CurrentChannelNr = cDevice::CurrentChannel();
512  cChannel *CurrentChannel = Channels.GetByNumber(CurrentChannelNr);
513  cChannel *FromChannel = GetChannel(From);
514  cChannel *ToChannel = GetChannel(To);
515  if (FromChannel && ToChannel) {
516  int FromNumber = FromChannel->Number();
517  int ToNumber = ToChannel->Number();
518  Channels.Move(FromChannel, ToChannel);
519  cOsdMenu::Move(From, To);
520  Propagate();
521  Channels.SetModified(true);
522  isyslog("channel %d moved to %d", FromNumber, ToNumber);
523  if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) {
525  Channels.SwitchTo(CurrentChannel->Number());
526  else
527  cDevice::SetCurrentChannel(CurrentChannel);
528  }
529  }
530 }
531 
533 {
534  eOSState state = cOsdMenu::ProcessKey(Key);
535 
536  switch (state) {
537  case osUser1: {
538  cChannel *channel = Channels.Last();
539  if (channel) {
540  Add(new cMenuChannelItem(channel), true);
541  return CloseSubMenu();
542  }
543  }
544  break;
545  default:
546  if (state == osUnknown) {
547  switch (Key) {
548  case k0 ... k9:
549  return Number(Key);
550  case kOk: return Switch();
551  case kRed: return Edit();
552  case kGreen: return New();
553  case kYellow: return Delete();
554  case kBlue: if (!HasSubMenu())
555  Mark();
556  break;
557  default: break;
558  }
559  }
560  }
561  return state;
562 }
563 
564 // --- cMenuText -------------------------------------------------------------
565 
566 cMenuText::cMenuText(const char *Title, const char *Text, eDvbFont Font)
567 :cOsdMenu(Title)
568 {
570  text = NULL;
571  font = Font;
572  SetText(Text);
573 }
574 
576 {
577  free(text);
578 }
579 
580 void cMenuText::SetText(const char *Text)
581 {
582  free(text);
583  text = Text ? strdup(Text) : NULL;
584 }
585 
587 {
589  DisplayMenu()->SetText(text, font == fontFix); //XXX define control character in text to choose the font???
590  if (text)
592 }
593 
595 {
596  switch (int(Key)) {
597  case kUp|k_Repeat:
598  case kUp:
599  case kDown|k_Repeat:
600  case kDown:
601  case kLeft|k_Repeat:
602  case kLeft:
603  case kRight|k_Repeat:
604  case kRight:
605  DisplayMenu()->Scroll(NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft, NORMALKEY(Key) == kLeft || NORMALKEY(Key) == kRight);
606  cStatus::MsgOsdTextItem(NULL, NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft);
607  return osContinue;
608  default: break;
609  }
610 
611  eOSState state = cOsdMenu::ProcessKey(Key);
612 
613  if (state == osUnknown) {
614  switch (Key) {
615  case kOk: return osBack;
616  default: state = osContinue;
617  }
618  }
619  return state;
620 }
621 
622 // --- cMenuFolderItem -------------------------------------------------------
623 
624 class cMenuFolderItem : public cOsdItem {
625 private:
627 public:
629  cNestedItem *Folder(void) { return folder; }
630  };
631 
633 :cOsdItem(Folder->Text())
634 {
635  folder = Folder;
636  if (folder->SubItems())
637  SetText(cString::sprintf("%s...", folder->Text()));
638 }
639 
640 // --- cMenuEditFolder -------------------------------------------------------
641 
642 class cMenuEditFolder : public cOsdMenu {
643 private:
646  char name[PATH_MAX];
648  eOSState Confirm(void);
649 public:
650  cMenuEditFolder(const char *Dir, cList<cNestedItem> *List, cNestedItem *Folder = NULL);
651  cString GetFolder(void);
652  virtual eOSState ProcessKey(eKeys Key);
653  };
654 
656 :cOsdMenu(Folder ? tr("Edit folder") : tr("New folder"), 12)
657 {
659  list = List;
660  folder = Folder;
661  if (folder) {
662  strn0cpy(name, folder->Text(), sizeof(name));
663  subFolder = folder->SubItems() != NULL;
664  }
665  else {
666  *name = 0;
667  subFolder = 0;
668  cRemote::Put(kRight, true); // go right into string editing mode
669  }
670  if (!isempty(Dir)) {
671  cOsdItem *DirItem = new cOsdItem(Dir);
672  DirItem->SetSelectable(false);
673  Add(DirItem);
674  }
675  Add(new cMenuEditStrItem( tr("Name"), name, sizeof(name)));
676  Add(new cMenuEditBoolItem(tr("Sub folder"), &subFolder));
677 }
678 
680 {
681  return folder ? folder->Text() : "";
682 }
683 
685 {
686  if (!folder || strcmp(folder->Text(), name) != 0) {
687  // each name may occur only once in a folder list
688  for (cNestedItem *Folder = list->First(); Folder; Folder = list->Next(Folder)) {
689  if (strcmp(Folder->Text(), name) == 0) {
690  Skins.Message(mtError, tr("Folder name already exists!"));
691  return osContinue;
692  }
693  }
694  char *p = strpbrk(name, "\\{}#~"); // FOLDERDELIMCHAR
695  if (p) {
696  Skins.Message(mtError, cString::sprintf(tr("Folder name must not contain '%c'!"), *p));
697  return osContinue;
698  }
699  }
700  if (folder) {
701  folder->SetText(name);
703  }
704  else
706  return osEnd;
707 }
708 
710 {
711  eOSState state = cOsdMenu::ProcessKey(Key);
712 
713  if (state == osUnknown) {
714  switch (Key) {
715  case kOk: return Confirm();
716  case kRed:
717  case kGreen:
718  case kYellow:
719  case kBlue: return osContinue;
720  default: break;
721  }
722  }
723  return state;
724 }
725 
726 // --- cMenuFolder -----------------------------------------------------------
727 
728 cMenuFolder::cMenuFolder(const char *Title, cNestedItemList *NestedItemList, const char *Path)
729 :cOsdMenu(Title)
730 {
732  list = nestedItemList = NestedItemList;
733  firstFolder = NULL;
734  editing = false;
735  Set();
736  SetHelpKeys();
737  DescendPath(Path);
738 }
739 
740 cMenuFolder::cMenuFolder(const char *Title, cList<cNestedItem> *List, cNestedItemList *NestedItemList, const char *Dir, const char *Path)
741 :cOsdMenu(Title)
742 {
744  list = List;
745  nestedItemList = NestedItemList;
746  dir = Dir;
747  firstFolder = NULL;
748  editing = false;
749  Set();
750  SetHelpKeys();
751  DescendPath(Path);
752 }
753 
755 {
756  SetHelp(firstFolder ? tr("Button$Select") : NULL, tr("Button$New"), firstFolder ? tr("Button$Delete") : NULL, firstFolder ? tr("Button$Edit") : NULL);
757 }
758 
759 void cMenuFolder::Set(const char *CurrentFolder)
760 {
761  firstFolder = NULL;
762  Clear();
763  if (!isempty(dir)) {
764  cOsdItem *DirItem = new cOsdItem(dir);
765  DirItem->SetSelectable(false);
766  Add(DirItem);
767  }
768  list->Sort();
769  for (cNestedItem *Folder = list->First(); Folder; Folder = list->Next(Folder)) {
770  cOsdItem *FolderItem = new cMenuFolderItem(Folder);
771  Add(FolderItem, CurrentFolder ? strcmp(Folder->Text(), CurrentFolder) == 0 : false);
772  if (!firstFolder)
773  firstFolder = FolderItem;
774  }
775 }
776 
777 void cMenuFolder::DescendPath(const char *Path)
778 {
779  if (Path) {
780  const char *p = strchr(Path, FOLDERDELIMCHAR);
781  if (p) {
782  for (cMenuFolderItem *Folder = (cMenuFolderItem *)firstFolder; Folder; Folder = (cMenuFolderItem *)Next(Folder)) {
783  if (strncmp(Folder->Folder()->Text(), Path, p - Path) == 0) {
784  SetCurrent(Folder);
785  if (Folder->Folder()->SubItems())
786  AddSubMenu(new cMenuFolder(Title(), Folder->Folder()->SubItems(), nestedItemList, !isempty(dir) ? *cString::sprintf("%s%c%s", *dir, FOLDERDELIMCHAR, Folder->Folder()->Text()) : Folder->Folder()->Text(), p + 1));
787  break;
788  }
789  }
790  }
791  }
792 }
793 
795 {
796  if (firstFolder) {
797  cMenuFolderItem *Folder = (cMenuFolderItem *)Get(Current());
798  if (Folder) {
799  if (Folder->Folder()->SubItems())
800  return AddSubMenu(new cMenuFolder(Title(), Folder->Folder()->SubItems(), nestedItemList, !isempty(dir) ? *cString::sprintf("%s%c%s", *dir, FOLDERDELIMCHAR, Folder->Folder()->Text()) : Folder->Folder()->Text()));
801  else
802  return osEnd;
803  }
804  }
805  return osContinue;
806 }
807 
809 {
810  editing = true;
811  return AddSubMenu(new cMenuEditFolder(dir, list));
812 }
813 
815 {
816  if (!HasSubMenu() && firstFolder) {
817  cMenuFolderItem *Folder = (cMenuFolderItem *)Get(Current());
818  if (Folder && Interface->Confirm(Folder->Folder()->SubItems() ? tr("Delete folder and all sub folders?") : tr("Delete folder?"))) {
819  list->Del(Folder->Folder());
820  Del(Folder->Index());
821  firstFolder = Get(isempty(dir) ? 0 : 1);
822  Display();
823  SetHelpKeys();
824  nestedItemList->Save();
825  }
826  }
827  return osContinue;
828 }
829 
831 {
832  if (!HasSubMenu() && firstFolder) {
833  cMenuFolderItem *Folder = (cMenuFolderItem *)Get(Current());
834  if (Folder) {
835  editing = true;
836  return AddSubMenu(new cMenuEditFolder(dir, list, Folder->Folder()));
837  }
838  }
839  return osContinue;
840 }
841 
843 {
845  if (mef) {
846  Set(mef->GetFolder());
847  SetHelpKeys();
848  Display();
849  nestedItemList->Save();
850  }
851  return CloseSubMenu();
852 }
853 
855 {
856  if (firstFolder) {
857  cMenuFolderItem *Folder = (cMenuFolderItem *)Get(Current());
858  if (Folder) {
859  cMenuFolder *mf = (cMenuFolder *)SubMenu();
860  if (mf)
861  return cString::sprintf("%s%c%s", Folder->Folder()->Text(), FOLDERDELIMCHAR, *mf->GetFolder());
862  return Folder->Folder()->Text();
863  }
864  }
865  return "";
866 }
867 
869 {
870  if (!HasSubMenu())
871  editing = false;
872  eOSState state = cOsdMenu::ProcessKey(Key);
873 
874  if (state == osUnknown) {
875  switch (Key) {
876  case kOk:
877  case kRed: return Select();
878  case kGreen: return New();
879  case kYellow: return Delete();
880  case kBlue: return Edit();
881  default: state = osContinue;
882  }
883  }
884  else if (state == osEnd && HasSubMenu() && editing)
885  state = SetFolder();
886  return state;
887 }
888 
889 // --- cMenuEditTimer --------------------------------------------------------
890 
892 :cOsdMenu(tr("Edit timer"), 12)
893 {
895  file = NULL;
896  day = firstday = NULL;
897  timer = Timer;
898  addIfConfirmed = New;
899  if (timer) {
900  data = *timer;
901  if (New)
903  channel = data.Channel()->Number();
904  Add(new cMenuEditBitItem( tr("Active"), &data.flags, tfActive));
905  Add(new cMenuEditChanItem(tr("Channel"), &channel));
906  Add(day = new cMenuEditDateItem(tr("Day"), &data.day, &data.weekdays));
907  Add(new cMenuEditTimeItem(tr("Start"), &data.start));
908  Add(new cMenuEditTimeItem(tr("Stop"), &data.stop));
909  Add(new cMenuEditBitItem( tr("VPS"), &data.flags, tfVps));
910  Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY));
911  Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME));
912  Add(file = new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file)));
913  SetFirstDayItem();
914  }
915  SetHelpKeys();
917 }
918 
920 {
921  if (timer && addIfConfirmed)
922  delete timer; // apparently it wasn't confirmed
924 }
925 
927 {
928  SetHelp(tr("Button$Folder"), data.weekdays ? tr("Button$Single") : tr("Button$Repeating"));
929 }
930 
932 {
933  if (!firstday && !data.IsSingleEvent()) {
934  Add(firstday = new cMenuEditDateItem(tr("First day"), &data.day));
935  Display();
936  }
937  else if (firstday && data.IsSingleEvent()) {
938  Del(firstday->Index());
939  firstday = NULL;
940  Display();
941  }
942 }
943 
945 {
946  cMenuFolder *mf = (cMenuFolder *)SubMenu();
947  if (mf) {
948  cString Folder = mf->GetFolder();
949  char *p = strrchr(data.file, FOLDERDELIMCHAR);
950  if (p)
951  p++;
952  else
953  p = data.file;
954  if (!isempty(*Folder))
955  strn0cpy(data.file, cString::sprintf("%s%c%s", *Folder, FOLDERDELIMCHAR, p), sizeof(data.file));
956  else if (p != data.file)
957  memmove(data.file, p, strlen(p) + 1);
958  SetCurrent(file);
959  Display();
960  }
961  return CloseSubMenu();
962 }
963 
965 {
966  eOSState state = cOsdMenu::ProcessKey(Key);
967 
968  if (state == osUnknown) {
969  switch (Key) {
970  case kOk: {
972  if (ch)
973  data.channel = ch;
974  else {
975  Skins.Message(mtError, tr("*** Invalid Channel ***"));
976  break;
977  }
978  if (!*data.file)
979  strcpy(data.file, data.Channel()->ShortName(true));
980  if (timer) {
981  if (memcmp(timer, &data, sizeof(data)) != 0)
982  *timer = data;
983  if (addIfConfirmed)
984  Timers.Add(timer);
986  timer->Matches();
988  isyslog("timer %s %s (%s)", *timer->ToDescr(), addIfConfirmed ? "added" : "modified", timer->HasFlags(tfActive) ? "active" : "inactive");
989  addIfConfirmed = false;
990  }
991  }
992  return osBack;
993  case kRed: return AddSubMenu(new cMenuFolder(tr("Select folder"), &Folders, data.file));
994  case kGreen: if (day) {
995  day->ToggleRepeating();
996  SetCurrent(day);
997  SetFirstDayItem();
998  SetHelpKeys();
999  Display();
1000  }
1001  return osContinue;
1002  case kYellow:
1003  case kBlue: return osContinue;
1004  default: break;
1005  }
1006  }
1007  else if (state == osEnd && HasSubMenu())
1008  state = SetFolder();
1009  if (Key != kNone)
1010  SetFirstDayItem();
1011  return state;
1012 }
1013 
1014 // --- cMenuTimerItem --------------------------------------------------------
1015 
1016 class cMenuTimerItem : public cOsdItem {
1017 private:
1019 public:
1021  virtual int Compare(const cListObject &ListObject) const;
1022  virtual void Set(void);
1023  cTimer *Timer(void) { return timer; }
1024  virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable);
1025  };
1026 
1028 {
1029  timer = Timer;
1030  Set();
1031 }
1032 
1033 int cMenuTimerItem::Compare(const cListObject &ListObject) const
1034 {
1035  return timer->Compare(*((cMenuTimerItem *)&ListObject)->timer);
1036 }
1037 
1039 {
1040  cString day, name("");
1041  if (timer->WeekDays())
1042  day = timer->PrintDay(0, timer->WeekDays(), false);
1043  else if (timer->Day() - time(NULL) < 28 * SECSINDAY) {
1044  day = itoa(timer->GetMDay(timer->Day()));
1045  name = WeekDayName(timer->Day());
1046  }
1047  else {
1048  struct tm tm_r;
1049  time_t Day = timer->Day();
1050  localtime_r(&Day, &tm_r);
1051  char buffer[16];
1052  strftime(buffer, sizeof(buffer), "%Y%m%d", &tm_r);
1053  day = buffer;
1054  }
1055  const char *File = Setup.FoldersInTimerMenu ? NULL : strrchr(timer->File(), FOLDERDELIMCHAR);
1056  if (File && strcmp(File + 1, TIMERMACRO_TITLE) && strcmp(File + 1, TIMERMACRO_EPISODE))
1057  File++;
1058  else
1059  File = timer->File();
1060  SetText(cString::sprintf("%s\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s",
1062  timer->Channel()->Number(),
1063  *name,
1064  *name && **name ? " " : "",
1065  *day,
1066  timer->Start() / 100,
1067  timer->Start() % 100,
1068  timer->Stop() / 100,
1069  timer->Stop() % 100,
1070  File));
1071 }
1072 
1073 void cMenuTimerItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
1074 {
1075  if (!DisplayMenu->SetItemTimer(timer, Index, Current, Selectable))
1076  DisplayMenu->SetItem(Text(), Index, Current, Selectable);
1077 }
1078 
1079 // --- cMenuTimers -----------------------------------------------------------
1080 
1081 class cMenuTimers : public cOsdMenu {
1082 private:
1084  eOSState Edit(void);
1085  eOSState New(void);
1086  eOSState Delete(void);
1087  eOSState OnOff(void);
1088  eOSState Info(void);
1089  cTimer *CurrentTimer(void);
1090  void SetHelpKeys(void);
1091 public:
1092  cMenuTimers(void);
1093  virtual ~cMenuTimers();
1094  virtual eOSState ProcessKey(eKeys Key);
1095  };
1096 
1098 :cOsdMenu(tr("Timers"), 2, CHNUMWIDTH, 10, 6, 6)
1099 {
1101  helpKeys = -1;
1102  for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) {
1103  timer->SetEventFromSchedule(); // make sure the event is current
1104  Add(new cMenuTimerItem(timer));
1105  }
1106  Sort();
1107  SetCurrent(First());
1108  SetHelpKeys();
1110 }
1111 
1113 {
1115 }
1116 
1118 {
1119  cMenuTimerItem *item = (cMenuTimerItem *)Get(Current());
1120  return item ? item->Timer() : NULL;
1121 }
1122 
1124 {
1125  int NewHelpKeys = 0;
1126  cTimer *timer = CurrentTimer();
1127  if (timer) {
1128  if (timer->Event())
1129  NewHelpKeys = 2;
1130  else
1131  NewHelpKeys = 1;
1132  }
1133  if (NewHelpKeys != helpKeys) {
1134  helpKeys = NewHelpKeys;
1135  SetHelp(helpKeys > 0 ? tr("Button$On/Off") : NULL, tr("Button$New"), helpKeys > 0 ? tr("Button$Delete") : NULL, helpKeys == 2 ? tr("Button$Info") : NULL);
1136  }
1137 }
1138 
1140 {
1141  if (HasSubMenu())
1142  return osContinue;
1143  cTimer *timer = CurrentTimer();
1144  if (timer) {
1145  timer->OnOff();
1146  timer->SetEventFromSchedule();
1147  RefreshCurrent();
1148  DisplayCurrent(true);
1149  if (timer->FirstDay())
1150  isyslog("timer %s first day set to %s", *timer->ToDescr(), *timer->PrintFirstDay());
1151  else
1152  isyslog("timer %s %sactivated", *timer->ToDescr(), timer->HasFlags(tfActive) ? "" : "de");
1153  Timers.SetModified();
1154  }
1155  return osContinue;
1156 }
1157 
1159 {
1160  if (HasSubMenu() || Count() == 0)
1161  return osContinue;
1162  isyslog("editing timer %s", *CurrentTimer()->ToDescr());
1163  return AddSubMenu(new cMenuEditTimer(CurrentTimer()));
1164 }
1165 
1167 {
1168  if (HasSubMenu())
1169  return osContinue;
1170  return AddSubMenu(new cMenuEditTimer(new cTimer, true));
1171 }
1172 
1174 {
1175  // Check if this timer is active:
1176  cTimer *ti = CurrentTimer();
1177  if (ti) {
1178  if (Interface->Confirm(tr("Delete timer?"))) {
1179  if (ti->Recording()) {
1180  if (Interface->Confirm(tr("Timer still recording - really delete?"))) {
1181  ti->Skip();
1182  cRecordControls::Process(time(NULL));
1183  }
1184  else
1185  return osContinue;
1186  }
1187  isyslog("deleting timer %s", *ti->ToDescr());
1188  Timers.Del(ti);
1190  Timers.SetModified();
1191  Display();
1192  }
1193  }
1194  return osContinue;
1195 }
1196 
1198 {
1199  if (HasSubMenu() || Count() == 0)
1200  return osContinue;
1201  cTimer *ti = CurrentTimer();
1202  if (ti && ti->Event())
1203  return AddSubMenu(new cMenuEvent(ti->Event()));
1204  return osContinue;
1205 }
1206 
1208 {
1209  int TimerNumber = HasSubMenu() ? Count() : -1;
1210  eOSState state = cOsdMenu::ProcessKey(Key);
1211 
1212  if (state == osUnknown) {
1213  switch (Key) {
1214  case kOk: return Edit();
1215  case kRed: state = OnOff(); break; // must go through SetHelpKeys()!
1216  case kGreen: return New();
1217  case kYellow: state = Delete(); break;
1218  case kInfo:
1219  case kBlue: return Info();
1220  break;
1221  default: break;
1222  }
1223  }
1224  if (TimerNumber >= 0 && !HasSubMenu() && Timers.Get(TimerNumber)) {
1225  // a newly created timer was confirmed with Ok
1226  Add(new cMenuTimerItem(Timers.Get(TimerNumber)), true);
1227  Display();
1228  }
1229  if (Key != kNone)
1230  SetHelpKeys();
1231  return state;
1232 }
1233 
1234 // --- cMenuEvent ------------------------------------------------------------
1235 
1236 cMenuEvent::cMenuEvent(const cEvent *Event, bool CanSwitch, bool Buttons)
1237 :cOsdMenu(tr("Event"))
1238 {
1240  event = Event;
1241  if (event) {
1242  cChannel *channel = Channels.GetByChannelID(event->ChannelID(), true);
1243  if (channel) {
1244  SetTitle(channel->Name());
1245  eTimerMatch TimerMatch = tmNone;
1246  Timers.GetMatch(event, &TimerMatch);
1247  if (Buttons)
1248  SetHelp(TimerMatch == tmFull ? tr("Button$Timer") : tr("Button$Record"), NULL, NULL, CanSwitch ? tr("Button$Switch") : NULL);
1249  }
1250  }
1251 }
1252 
1254 {
1257  if (event->Description())
1259 }
1260 
1262 {
1263  switch (int(Key)) {
1264  case kUp|k_Repeat:
1265  case kUp:
1266  case kDown|k_Repeat:
1267  case kDown:
1268  case kLeft|k_Repeat:
1269  case kLeft:
1270  case kRight|k_Repeat:
1271  case kRight:
1272  DisplayMenu()->Scroll(NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft, NORMALKEY(Key) == kLeft || NORMALKEY(Key) == kRight);
1273  cStatus::MsgOsdTextItem(NULL, NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft);
1274  return osContinue;
1275  case kInfo: return osBack;
1276  default: break;
1277  }
1278 
1279  eOSState state = cOsdMenu::ProcessKey(Key);
1280 
1281  if (state == osUnknown) {
1282  switch (Key) {
1283  case kGreen:
1284  case kYellow: return osContinue;
1285  case kOk: return osBack;
1286  default: break;
1287  }
1288  }
1289  return state;
1290 }
1291 
1292 // --- cMenuScheduleItem -----------------------------------------------------
1293 
1294 class cMenuScheduleItem : public cOsdItem {
1295 public:
1296  enum eScheduleSortMode { ssmAllThis, ssmThisThis, ssmThisAll, ssmAllAll }; // "which event(s) on which channel(s)"
1297 private:
1299 public:
1300  const cEvent *event;
1302  bool withDate;
1304  cMenuScheduleItem(const cEvent *Event, cChannel *Channel = NULL, bool WithDate = false);
1305  static void SetSortMode(eScheduleSortMode SortMode) { sortMode = SortMode; }
1306  static void IncSortMode(void) { sortMode = eScheduleSortMode((sortMode == ssmAllAll) ? ssmAllThis : sortMode + 1); }
1307  static eScheduleSortMode SortMode(void) { return sortMode; }
1308  virtual int Compare(const cListObject &ListObject) const;
1309  bool Update(bool Force = false);
1310  virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable);
1311  };
1312 
1314 
1315 cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event, cChannel *Channel, bool WithDate)
1316 {
1317  event = Event;
1318  channel = Channel;
1319  withDate = WithDate;
1320  timerMatch = tmNone;
1321  Update(true);
1322 }
1323 
1324 int cMenuScheduleItem::Compare(const cListObject &ListObject) const
1325 {
1326  cMenuScheduleItem *p = (cMenuScheduleItem *)&ListObject;
1327  int r = -1;
1328  if (sortMode != ssmAllThis)
1329  r = strcoll(event->Title(), p->event->Title());
1330  if (sortMode == ssmAllThis || r == 0)
1331  r = event->StartTime() - p->event->StartTime();
1332  return r;
1333 }
1334 
1335 static const char *TimerMatchChars[9] =
1336 {
1337  " ", "t", "T",
1340 };
1341 
1343 {
1344  bool result = false;
1345  eTimerMatch OldTimerMatch = timerMatch;
1347  if (Force || timerMatch != OldTimerMatch) {
1348  cString buffer;
1350  const char *v = event->Vps() && (event->Vps() - event->StartTime()) ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_VPS_UTF8 : ICON_VPS : "V" : " ";
1351  const char *r = event->SeenWithin(30) && event->IsRunning() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_RUNNING_UTF8 : ICON_RUNNING : "*" : " ";
1352  const char *csn = channel ? channel->ShortName(true) : NULL;
1353  cString eds = event->GetDateString();
1354  if (channel && withDate)
1355  buffer = cString::sprintf("%d\t%.*s\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title());
1356  else if (channel)
1357  buffer = cString::sprintf("%d\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title());
1358  else
1359  buffer = cString::sprintf("%.*s\t%s\t%s%s%s\t%s", Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title());
1360  SetText(buffer);
1361  result = true;
1362  }
1363  return result;
1364 }
1365 
1366 void cMenuScheduleItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
1367 {
1368  if (!DisplayMenu->SetItemEvent(event, Index, Current, Selectable, channel, withDate, timerMatch))
1369  DisplayMenu->SetItem(Text(), Index, Current, Selectable);
1370 }
1371 
1372 // --- cMenuWhatsOn ----------------------------------------------------------
1373 
1374 class cMenuWhatsOn : public cOsdMenu {
1375 private:
1376  bool now;
1379  eOSState Record(void);
1380  eOSState Switch(void);
1381  static int currentChannel;
1382  static const cEvent *scheduleEvent;
1383  bool Update(void);
1384  void SetHelpKeys(void);
1385 public:
1386  cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr);
1387  static int CurrentChannel(void) { return currentChannel; }
1388  static void SetCurrentChannel(int ChannelNr) { currentChannel = ChannelNr; }
1389  static const cEvent *ScheduleEvent(void);
1390  virtual eOSState ProcessKey(eKeys Key);
1391  };
1392 
1394 const cEvent *cMenuWhatsOn::scheduleEvent = NULL;
1395 
1396 cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr)
1397 :cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, CHNAMWIDTH, 6, 4)
1398 {
1400  now = Now;
1401  helpKeys = -1;
1402  timerState = 0;
1404  for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
1405  if (!Channel->GroupSep()) {
1406  const cSchedule *Schedule = Schedules->GetSchedule(Channel);
1407  if (Schedule) {
1408  const cEvent *Event = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent();
1409  if (Event)
1410  Add(new cMenuScheduleItem(Event, Channel), Channel->Number() == CurrentChannelNr);
1411  }
1412  }
1413  }
1414  currentChannel = CurrentChannelNr;
1415  Display();
1416  SetHelpKeys();
1417 }
1418 
1420 {
1421  bool result = false;
1422  if (Timers.Modified(timerState)) {
1423  for (cOsdItem *item = First(); item; item = Next(item)) {
1424  if (((cMenuScheduleItem *)item)->Update())
1425  result = true;
1426  }
1427  }
1428  return result;
1429 }
1430 
1432 {
1434  int NewHelpKeys = 0;
1435  if (item) {
1436  if (item->timerMatch == tmFull)
1437  NewHelpKeys = 2;
1438  else
1439  NewHelpKeys = 1;
1440  }
1441  if (NewHelpKeys != helpKeys) {
1442  const char *Red[] = { NULL, tr("Button$Record"), tr("Button$Timer") };
1443  SetHelp(Red[NewHelpKeys], now ? tr("Button$Next") : tr("Button$Now"), tr("Button$Schedule"), tr("Button$Switch"));
1444  helpKeys = NewHelpKeys;
1445  }
1446 }
1447 
1449 {
1450  const cEvent *ei = scheduleEvent;
1451  scheduleEvent = NULL;
1452  return ei;
1453 }
1454 
1456 {
1458  if (item) {
1459  cChannel *channel = Channels.GetByChannelID(item->event->ChannelID(), true);
1460  if (channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true))
1461  return osEnd;
1462  }
1463  Skins.Message(mtError, tr("Can't switch channel!"));
1464  return osContinue;
1465 }
1466 
1468 {
1470  if (item) {
1471  if (item->timerMatch == tmFull) {
1472  eTimerMatch tm = tmNone;
1473  cTimer *timer = Timers.GetMatch(item->event, &tm);
1474  if (timer)
1475  return AddSubMenu(new cMenuEditTimer(timer));
1476  }
1477  cTimer *timer = new cTimer(item->event);
1478  cTimer *t = Timers.GetTimer(timer);
1479  if (t) {
1480  delete timer;
1481  timer = t;
1482  return AddSubMenu(new cMenuEditTimer(timer));
1483  }
1484  else {
1485  Timers.Add(timer);
1486  Timers.SetModified();
1487  isyslog("timer %s added (active)", *timer->ToDescr());
1488  if (timer->Matches(0, false, NEWTIMERLIMIT))
1489  return AddSubMenu(new cMenuEditTimer(timer));
1490  if (HasSubMenu())
1491  CloseSubMenu();
1492  if (Update())
1493  Display();
1494  SetHelpKeys();
1495  }
1496  }
1497  return osContinue;
1498 }
1499 
1501 {
1502  bool HadSubMenu = HasSubMenu();
1503  eOSState state = cOsdMenu::ProcessKey(Key);
1504 
1505  if (state == osUnknown) {
1506  switch (Key) {
1507  case kRecord:
1508  case kRed: return Record();
1509  case kYellow: state = osBack;
1510  // continue with kGreen
1511  case kGreen: {
1513  if (mi) {
1514  scheduleEvent = mi->event;
1515  currentChannel = mi->channel->Number();
1516  }
1517  }
1518  break;
1519  case kBlue: return Switch();
1520  case kInfo:
1521  case kOk: if (Count())
1522  return AddSubMenu(new cMenuEvent(((cMenuScheduleItem *)Get(Current()))->event, true, true));
1523  break;
1524  default: break;
1525  }
1526  }
1527  else if (!HasSubMenu()) {
1528  if (HadSubMenu && Update())
1529  Display();
1530  if (Key != kNone)
1531  SetHelpKeys();
1532  }
1533  return state;
1534 }
1535 
1536 // --- cMenuSchedule ---------------------------------------------------------
1537 
1538 class cMenuSchedule : public cOsdMenu {
1539 private:
1542  bool now, next;
1546  eOSState Number(void);
1547  eOSState Record(void);
1548  eOSState Switch(void);
1549  void PrepareScheduleAllThis(const cEvent *Event, const cChannel *Channel);
1550  void PrepareScheduleThisThis(const cEvent *Event, const cChannel *Channel);
1551  void PrepareScheduleThisAll(const cEvent *Event, const cChannel *Channel);
1552  void PrepareScheduleAllAll(const cEvent *Event, const cChannel *Channel);
1553  bool Update(void);
1554  void SetHelpKeys(void);
1555 public:
1556  cMenuSchedule(void);
1557  virtual ~cMenuSchedule();
1558  virtual eOSState ProcessKey(eKeys Key);
1559  };
1560 
1562 :cOsdMenu("")
1563 {
1565  now = next = false;
1566  otherChannel = 0;
1567  helpKeys = -1;
1568  timerState = 0;
1572  if (channel) {
1575  PrepareScheduleAllThis(NULL, channel);
1576  SetHelpKeys();
1577  }
1578 }
1579 
1581 {
1582  cMenuWhatsOn::ScheduleEvent(); // makes sure any posted data is cleared
1583 }
1584 
1585 void cMenuSchedule::PrepareScheduleAllThis(const cEvent *Event, const cChannel *Channel)
1586 {
1587  Clear();
1588  SetCols(7, 6, 4);
1589  SetTitle(cString::sprintf(tr("Schedule - %s"), Channel->Name()));
1590  if (schedules && Channel) {
1591  const cSchedule *Schedule = schedules->GetSchedule(Channel);
1592  if (Schedule) {
1593  const cEvent *PresentEvent = Event ? Event : Schedule->GetPresentEvent();
1594  time_t now = time(NULL) - Setup.EPGLinger * 60;
1595  for (const cEvent *ev = Schedule->Events()->First(); ev; ev = Schedule->Events()->Next(ev)) {
1596  if (ev->EndTime() > now || ev == PresentEvent)
1597  Add(new cMenuScheduleItem(ev), ev == PresentEvent);
1598  }
1599  }
1600  }
1601 }
1602 
1603 void cMenuSchedule::PrepareScheduleThisThis(const cEvent *Event, const cChannel *Channel)
1604 {
1605  Clear();
1606  SetCols(7, 6, 4);
1607  SetTitle(cString::sprintf(tr("This event - %s"), Channel->Name()));
1608  if (schedules && Channel && Event) {
1609  const cSchedule *Schedule = schedules->GetSchedule(Channel);
1610  if (Schedule) {
1611  time_t now = time(NULL) - Setup.EPGLinger * 60;
1612  for (const cEvent *ev = Schedule->Events()->First(); ev; ev = Schedule->Events()->Next(ev)) {
1613  if ((ev->EndTime() > now || ev == Event) && !strcmp(ev->Title(), Event->Title()))
1614  Add(new cMenuScheduleItem(ev), ev == Event);
1615  }
1616  }
1617  }
1618 }
1619 
1620 void cMenuSchedule::PrepareScheduleThisAll(const cEvent *Event, const cChannel *Channel)
1621 {
1622  Clear();
1623  SetCols(CHNUMWIDTH, CHNAMWIDTH, 7, 6, 4);
1624  SetTitle(tr("This event - all channels"));
1625  if (schedules && Event) {
1626  for (cChannel *ch = Channels.First(); ch; ch = Channels.Next(ch)) {
1627  const cSchedule *Schedule = schedules->GetSchedule(ch);
1628  if (Schedule) {
1629  time_t now = time(NULL) - Setup.EPGLinger * 60;
1630  for (const cEvent *ev = Schedule->Events()->First(); ev; ev = Schedule->Events()->Next(ev)) {
1631  if ((ev->EndTime() > now || ev == Event) && !strcmp(ev->Title(), Event->Title()))
1632  Add(new cMenuScheduleItem(ev, ch, true), ev == Event && ch == Channel);
1633  }
1634  }
1635  }
1636  }
1637 }
1638 
1639 void cMenuSchedule::PrepareScheduleAllAll(const cEvent *Event, const cChannel *Channel)
1640 {
1641  Clear();
1642  SetCols(CHNUMWIDTH, CHNAMWIDTH, 7, 6, 4);
1643  SetTitle(tr("All events - all channels"));
1644  if (schedules) {
1645  for (cChannel *ch = Channels.First(); ch; ch = Channels.Next(ch)) {
1646  const cSchedule *Schedule = schedules->GetSchedule(ch);
1647  if (Schedule) {
1648  time_t now = time(NULL) - Setup.EPGLinger * 60;
1649  for (const cEvent *ev = Schedule->Events()->First(); ev; ev = Schedule->Events()->Next(ev)) {
1650  if (ev->EndTime() > now || ev == Event)
1651  Add(new cMenuScheduleItem(ev, ch, true), ev == Event && ch == Channel);
1652  }
1653  }
1654  }
1655  }
1656 }
1657 
1659 {
1660  bool result = false;
1661  if (Timers.Modified(timerState)) {
1662  for (cOsdItem *item = First(); item; item = Next(item)) {
1663  if (((cMenuScheduleItem *)item)->Update())
1664  result = true;
1665  }
1666  }
1667  return result;
1668 }
1669 
1671 {
1673  int NewHelpKeys = 0;
1674  if (item) {
1675  if (item->timerMatch == tmFull)
1676  NewHelpKeys = 2;
1677  else
1678  NewHelpKeys = 1;
1679  }
1680  if (NewHelpKeys != helpKeys) {
1681  const char *Red[] = { NULL, tr("Button$Record"), tr("Button$Timer") };
1682  SetHelp(Red[NewHelpKeys], tr("Button$Now"), tr("Button$Next"));
1683  helpKeys = NewHelpKeys;
1684  }
1685 }
1686 
1688 {
1690  cMenuScheduleItem *CurrentItem = (cMenuScheduleItem *)Get(Current());
1691  const cChannel *Channel = NULL;
1692  const cEvent *Event = NULL;
1693  if (CurrentItem) {
1694  Event = CurrentItem->event;
1695  Channel = Channels.GetByChannelID(Event->ChannelID(), true);
1696  }
1697  else
1699  switch (cMenuScheduleItem::SortMode()) {
1700  case cMenuScheduleItem::ssmAllThis: PrepareScheduleAllThis(Event, Channel); break;
1701  case cMenuScheduleItem::ssmThisThis: PrepareScheduleThisThis(Event, Channel); break;
1702  case cMenuScheduleItem::ssmThisAll: PrepareScheduleThisAll(Event, Channel); break;
1703  case cMenuScheduleItem::ssmAllAll: PrepareScheduleAllAll(Event, Channel); break;
1704  default: esyslog("ERROR: unknown SortMode %d (%s %d)", cMenuScheduleItem::SortMode(), __FUNCTION__, __LINE__);
1705  }
1706  CurrentItem = (cMenuScheduleItem *)Get(Current());
1707  Sort();
1708  SetCurrent(CurrentItem);
1709  Display();
1710  return osContinue;
1711 }
1712 
1714 {
1716  if (item) {
1717  if (item->timerMatch == tmFull) {
1718  eTimerMatch tm = tmNone;
1719  cTimer *timer = Timers.GetMatch(item->event, &tm);
1720  if (timer)
1721  return AddSubMenu(new cMenuEditTimer(timer));
1722  }
1723  cTimer *timer = new cTimer(item->event);
1724  cTimer *t = Timers.GetTimer(timer);
1725  if (t) {
1726  delete timer;
1727  timer = t;
1728  return AddSubMenu(new cMenuEditTimer(timer));
1729  }
1730  else {
1731  Timers.Add(timer);
1732  Timers.SetModified();
1733  isyslog("timer %s added (active)", *timer->ToDescr());
1734  if (timer->Matches(0, false, NEWTIMERLIMIT))
1735  return AddSubMenu(new cMenuEditTimer(timer));
1736  if (HasSubMenu())
1737  CloseSubMenu();
1738  if (Update())
1739  Display();
1740  SetHelpKeys();
1741  }
1742  }
1743  return osContinue;
1744 }
1745 
1747 {
1748  if (otherChannel) {
1750  return osEnd;
1751  }
1752  Skins.Message(mtError, tr("Can't switch channel!"));
1753  return osContinue;
1754 }
1755 
1757 {
1758  bool HadSubMenu = HasSubMenu();
1759  eOSState state = cOsdMenu::ProcessKey(Key);
1760 
1761  if (state == osUnknown) {
1762  switch (Key) {
1763  case k0: return Number();
1764  case kRecord:
1765  case kRed: return Record();
1766  case kGreen: if (schedules) {
1767  if (!now && !next) {
1768  int ChannelNr = 0;
1769  if (Count()) {
1770  cChannel *channel = Channels.GetByChannelID(((cMenuScheduleItem *)Get(Current()))->event->ChannelID(), true);
1771  if (channel)
1772  ChannelNr = channel->Number();
1773  }
1774  now = true;
1775  return AddSubMenu(new cMenuWhatsOn(schedules, true, ChannelNr));
1776  }
1777  now = !now;
1778  next = !next;
1780  }
1781  case kYellow: if (schedules)
1783  break;
1784  case kBlue: if (Count() && otherChannel)
1785  return Switch();
1786  break;
1787  case kInfo:
1788  case kOk: if (Count())
1789  return AddSubMenu(new cMenuEvent(((cMenuScheduleItem *)Get(Current()))->event, otherChannel, true));
1790  break;
1791  default: break;
1792  }
1793  }
1794  else if (!HasSubMenu()) {
1795  now = next = false;
1796  const cEvent *ei = cMenuWhatsOn::ScheduleEvent();
1797  if (ei) {
1798  cChannel *channel = Channels.GetByChannelID(ei->ChannelID(), true);
1799  if (channel) {
1801  PrepareScheduleAllThis(NULL, channel);
1802  if (channel->Number() != cDevice::CurrentChannel()) {
1803  otherChannel = channel->Number();
1804  SetHelp(Count() ? tr("Button$Record") : NULL, tr("Button$Now"), tr("Button$Next"), tr("Button$Switch"));
1805  }
1806  Display();
1807  }
1808  }
1809  else if (HadSubMenu && Update())
1810  Display();
1811  if (Key != kNone)
1812  SetHelpKeys();
1813  }
1814  return state;
1815 }
1816 
1817 // --- cMenuCommands ---------------------------------------------------------
1818 
1819 cMenuCommands::cMenuCommands(const char *Title, cList<cNestedItem> *Commands, const char *Parameters)
1820 :cOsdMenu(Title)
1821 {
1823  result = NULL;
1824  SetHasHotkeys();
1825  commands = Commands;
1826  parameters = Parameters;
1827  for (cNestedItem *Command = commands->First(); Command; Command = commands->Next(Command)) {
1828  const char *s = Command->Text();
1829  if (Command->SubItems())
1830  Add(new cOsdItem(hk(cString::sprintf("%s...", s))));
1831  else if (Parse(s))
1832  Add(new cOsdItem(hk(title)));
1833  }
1834 }
1835 
1837 {
1838  free(result);
1839 }
1840 
1841 bool cMenuCommands::Parse(const char *s)
1842 {
1843  const char *p = strchr(s, ':');
1844  if (p) {
1845  int l = p - s;
1846  if (l > 0) {
1847  char t[l + 1];
1848  stripspace(strn0cpy(t, s, l + 1));
1849  l = strlen(t);
1850  if (l > 1 && t[l - 1] == '?') {
1851  t[l - 1] = 0;
1852  confirm = true;
1853  }
1854  else
1855  confirm = false;
1856  title = t;
1857  command = skipspace(p + 1);
1858  return true;
1859  }
1860  }
1861  return false;
1862 }
1863 
1865 {
1866  cNestedItem *Command = commands->Get(Current());
1867  if (Command) {
1868  if (Command->SubItems())
1869  return AddSubMenu(new cMenuCommands(Title(), Command->SubItems(), parameters));
1870  if (Parse(Command->Text())) {
1871  if (!confirm || Interface->Confirm(cString::sprintf("%s?", *title))) {
1873  free(result);
1874  result = NULL;
1875  cString cmdbuf;
1876  if (!isempty(parameters))
1877  cmdbuf = cString::sprintf("%s %s", *command, *parameters);
1878  const char *cmd = *cmdbuf ? *cmdbuf : *command;
1879  dsyslog("executing command '%s'", cmd);
1880  cPipe p;
1881  if (p.Open(cmd, "r")) {
1882  int l = 0;
1883  int c;
1884  while ((c = fgetc(p)) != EOF) {
1885  if (l % 20 == 0) {
1886  if (char *NewBuffer = (char *)realloc(result, l + 21))
1887  result = NewBuffer;
1888  else {
1889  esyslog("ERROR: out of memory");
1890  break;
1891  }
1892  }
1893  result[l++] = char(c);
1894  }
1895  if (result)
1896  result[l] = 0;
1897  p.Close();
1898  }
1899  else
1900  esyslog("ERROR: can't open pipe for command '%s'", cmd);
1901  Skins.Message(mtStatus, NULL);
1902  if (result)
1903  return AddSubMenu(new cMenuText(title, result, fontFix));
1904  return osEnd;
1905  }
1906  }
1907  }
1908  return osContinue;
1909 }
1910 
1912 {
1913  eOSState state = cOsdMenu::ProcessKey(Key);
1914 
1915  if (state == osUnknown) {
1916  switch (Key) {
1917  case kRed:
1918  case kGreen:
1919  case kYellow:
1920  case kBlue: return osContinue;
1921  case kOk: return Execute();
1922  default: break;
1923  }
1924  }
1925  return state;
1926 }
1927 
1928 // --- cMenuCam --------------------------------------------------------------
1929 
1930 static bool CamMenuIsOpen = false;
1931 
1932 class cMenuCam : public cOsdMenu {
1933 private:
1937  char *input;
1938  int offset;
1940  void GenerateTitle(const char *s = NULL);
1941  void QueryCam(void);
1942  void AddMultiLineItem(const char *s);
1943  void Set(void);
1944  eOSState Select(void);
1945 public:
1946  cMenuCam(cCamSlot *CamSlot);
1947  virtual ~cMenuCam();
1948  virtual eOSState ProcessKey(eKeys Key);
1949  };
1950 
1952 :cOsdMenu("", 1) // tab necessary for enquiry!
1953 {
1955  camSlot = CamSlot;
1956  ciMenu = NULL;
1957  ciEnquiry = NULL;
1958  input = NULL;
1959  offset = 0;
1960  lastCamExchange = time(NULL);
1961  SetNeedsFastResponse(true);
1962  QueryCam();
1963  CamMenuIsOpen = true;
1964 }
1965 
1967 {
1968  if (ciMenu)
1969  ciMenu->Abort();
1970  delete ciMenu;
1971  if (ciEnquiry)
1972  ciEnquiry->Abort();
1973  delete ciEnquiry;
1974  free(input);
1975  CamMenuIsOpen = false;
1976 }
1977 
1978 void cMenuCam::GenerateTitle(const char *s)
1979 {
1980  SetTitle(cString::sprintf("CAM %d - %s", camSlot->SlotNumber(), (s && *s) ? s : camSlot->GetCamName()));
1981 }
1982 
1984 {
1985  delete ciMenu;
1986  ciMenu = NULL;
1987  delete ciEnquiry;
1988  ciEnquiry = NULL;
1989  if (camSlot->HasUserIO()) {
1990  ciMenu = camSlot->GetMenu();
1992  }
1993  Set();
1994 }
1995 
1996 void cMenuCam::Set(void)
1997 {
1998  if (ciMenu) {
1999  Clear();
2000  free(input);
2001  input = NULL;
2002  dsyslog("CAM %d: Menu ------------------", camSlot->SlotNumber());
2003  offset = 0;
2006  dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciMenu->TitleText());
2007  if (*ciMenu->SubTitleText()) {
2008  dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciMenu->SubTitleText());
2010  offset = Count();
2011  }
2012  for (int i = 0; i < ciMenu->NumEntries(); i++) {
2014  dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciMenu->Entry(i));
2015  }
2016  if (*ciMenu->BottomText()) {
2018  dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciMenu->BottomText());
2019  }
2021  }
2022  else if (ciEnquiry) {
2023  Clear();
2024  int Length = ciEnquiry->ExpectedLength();
2025  free(input);
2026  input = MALLOC(char, Length + 1);
2027  *input = 0;
2028  GenerateTitle();
2029  Add(new cOsdItem(ciEnquiry->Text(), osUnknown, false));
2030  Add(new cOsdItem("", osUnknown, false));
2031  Add(new cMenuEditNumItem("", input, Length, ciEnquiry->Blind()));
2032  }
2033  Display();
2034 }
2035 
2036 void cMenuCam::AddMultiLineItem(const char *s)
2037 {
2038  while (s && *s) {
2039  const char *p = strchr(s, '\n');
2040  int l = p ? p - s : strlen(s);
2041  cOsdItem *item = new cOsdItem;
2042  item->SetSelectable(false);
2043  item->SetText(strndup(s, l), false);
2044  Add(item);
2045  s = p ? p + 1 : p;
2046  }
2047 }
2048 
2050 {
2051  if (ciMenu) {
2052  if (ciMenu->Selectable()) {
2053  ciMenu->Select(Current() - offset);
2054  dsyslog("CAM %d: select %d", camSlot->SlotNumber(), Current() - offset);
2055  }
2056  else
2057  ciMenu->Cancel();
2058  }
2059  else if (ciEnquiry) {
2060  if (ciEnquiry->ExpectedLength() < 0xFF && int(strlen(input)) != ciEnquiry->ExpectedLength()) {
2061  char buffer[64];
2062  snprintf(buffer, sizeof(buffer), tr("Please enter %d digits!"), ciEnquiry->ExpectedLength());
2063  Skins.Message(mtError, buffer);
2064  return osContinue;
2065  }
2066  ciEnquiry->Reply(input);
2067  dsyslog("CAM %d: entered '%s'", camSlot->SlotNumber(), ciEnquiry->Blind() ? "****" : input);
2068  }
2069  QueryCam();
2070  return osContinue;
2071 }
2072 
2074 {
2075  if (!camSlot->HasMMI())
2076  return osBack;
2077 
2078  eOSState state = cOsdMenu::ProcessKey(Key);
2079 
2080  if (ciMenu || ciEnquiry) {
2081  lastCamExchange = time(NULL);
2082  if (state == osUnknown) {
2083  switch (Key) {
2084  case kOk: return Select();
2085  default: break;
2086  }
2087  }
2088  else if (state == osBack) {
2089  if (ciMenu)
2090  ciMenu->Cancel();
2091  if (ciEnquiry)
2092  ciEnquiry->Cancel();
2093  QueryCam();
2094  return osContinue;
2095  }
2096  if (ciMenu && ciMenu->HasUpdate()) {
2097  QueryCam();
2098  return osContinue;
2099  }
2100  }
2101  else if (time(NULL) - lastCamExchange < CAMRESPONSETIMEOUT)
2102  QueryCam();
2103  else {
2104  Skins.Message(mtError, tr("CAM not responding!"));
2105  return osBack;
2106  }
2107  return state;
2108 }
2109 
2110 // --- CamControl ------------------------------------------------------------
2111 
2113 {
2114  for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
2115  if (CamSlot->HasUserIO())
2116  return new cMenuCam(CamSlot);
2117  }
2118  return NULL;
2119 }
2120 
2121 bool CamMenuActive(void)
2122 {
2123  return CamMenuIsOpen;
2124 }
2125 
2126 // --- cMenuRecording --------------------------------------------------------
2127 
2128 class cMenuRecording : public cOsdMenu {
2129 private:
2132 public:
2133  cMenuRecording(const cRecording *Recording, bool WithButtons = false);
2134  virtual void Display(void);
2135  virtual eOSState ProcessKey(eKeys Key);
2136 };
2137 
2138 cMenuRecording::cMenuRecording(const cRecording *Recording, bool WithButtons)
2139 :cOsdMenu(tr("Recording info"))
2140 {
2142  recording = Recording;
2143  withButtons = WithButtons;
2144  if (withButtons)
2145  SetHelp(tr("Button$Play"), tr("Button$Rewind"));
2146 }
2147 
2149 {
2152  if (recording->Info()->Description())
2154 }
2155 
2157 {
2158  switch (int(Key)) {
2159  case kUp|k_Repeat:
2160  case kUp:
2161  case kDown|k_Repeat:
2162  case kDown:
2163  case kLeft|k_Repeat:
2164  case kLeft:
2165  case kRight|k_Repeat:
2166  case kRight:
2167  DisplayMenu()->Scroll(NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft, NORMALKEY(Key) == kLeft || NORMALKEY(Key) == kRight);
2168  cStatus::MsgOsdTextItem(NULL, NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft);
2169  return osContinue;
2170  case kInfo: return osBack;
2171  default: break;
2172  }
2173 
2174  eOSState state = cOsdMenu::ProcessKey(Key);
2175 
2176  if (state == osUnknown) {
2177  switch (Key) {
2178  case kRed: if (withButtons)
2179  Key = kOk; // will play the recording, even if recording commands are defined
2180  case kGreen: if (!withButtons)
2181  break;
2182  cRemote::Put(Key, true);
2183  // continue with osBack to close the info menu and process the key
2184  case kOk: return osBack;
2185  default: break;
2186  }
2187  }
2188  return state;
2189 }
2190 
2191 // --- cMenuRecordingItem ----------------------------------------------------
2192 
2194 private:
2196  int level;
2197  char *name;
2199 public:
2202  void IncrementCounter(bool New);
2203  const char *Name(void) { return name; }
2204  cRecording *Recording(void) { return recording; }
2205  bool IsDirectory(void) { return name != NULL; }
2206  void SetRecording(cRecording *Recording) { recording = Recording; }
2207  virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable);
2208  };
2209 
2211 {
2212  recording = Recording;
2213  level = Level;
2214  name = NULL;
2215  totalEntries = newEntries = 0;
2216  SetText(Recording->Title('\t', true, Level));
2217  if (*Text() == '\t')
2218  name = strdup(Text() + 2); // 'Text() + 2' to skip the two '\t'
2219 }
2220 
2222 {
2223  free(name);
2224 }
2225 
2227 {
2228  totalEntries++;
2229  if (New)
2230  newEntries++;
2231  SetText(cString::sprintf("%d\t\t%d\t%s", totalEntries, newEntries, name));
2232 }
2233 
2234 void cMenuRecordingItem::SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
2235 {
2236  if (!DisplayMenu->SetItemRecording(recording, Index, Current, Selectable, level, totalEntries, newEntries))
2237  DisplayMenu->SetItem(Text(), Index, Current, Selectable);
2238 }
2239 
2240 // --- cMenuRecordings -------------------------------------------------------
2241 
2242 cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus)
2243 :cOsdMenu(Base ? Base : tr("Recordings"), 9, 6, 6)
2244 {
2246  base = Base ? strdup(Base) : NULL;
2247  level = Setup.RecordingDirs ? Level : -1;
2248  Recordings.StateChanged(recordingsState); // just to get the current state
2249  helpKeys = -1;
2250  Display(); // this keeps the higher level menus from showing up briefly when pressing 'Back' during replay
2251  Set();
2252  if (Current() < 0)
2253  SetCurrent(First());
2254  else if (OpenSubMenus && cReplayControl::LastReplayed() && Open(true))
2255  return;
2256  Display();
2257  SetHelpKeys();
2258 }
2259 
2261 {
2262  helpKeys = -1;
2263  free(base);
2264 }
2265 
2267 {
2269  int NewHelpKeys = 0;
2270  if (ri) {
2271  if (ri->IsDirectory())
2272  NewHelpKeys = 1;
2273  else {
2274  NewHelpKeys = 2;
2275  if (ri->Recording()->Info()->Title())
2276  NewHelpKeys = 3;
2277  }
2278  }
2279  if (NewHelpKeys != helpKeys) {
2280  switch (NewHelpKeys) {
2281  case 0: SetHelp(NULL); break;
2282  case 1: SetHelp(tr("Button$Open")); break;
2283  case 2:
2284  case 3: SetHelp(RecordingCommands.Count() ? tr("Commands") : tr("Button$Play"), tr("Button$Rewind"), tr("Button$Delete"), NewHelpKeys == 3 ? tr("Button$Info") : NULL);
2285  default: ;
2286  }
2287  helpKeys = NewHelpKeys;
2288  }
2289 }
2290 
2291 void cMenuRecordings::Set(bool Refresh)
2292 {
2293  const char *CurrentRecording = cReplayControl::LastReplayed();
2294  cMenuRecordingItem *LastItem = NULL;
2295  cThreadLock RecordingsLock(&Recordings);
2296  if (Refresh) {
2298  CurrentRecording = ri->Recording()->FileName();
2299  }
2300  Clear();
2302  Recordings.Sort();
2303  for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) {
2304  if (!base || (strstr(recording->Name(), base) == recording->Name() && recording->Name()[strlen(base)] == FOLDERDELIMCHAR)) {
2305  cMenuRecordingItem *Item = new cMenuRecordingItem(recording, level);
2306  cMenuRecordingItem *LastDir = NULL;
2307  if (Item->IsDirectory()) {
2308  // Sorting may ignore non-alphanumeric characters, so we need to explicitly handle directories in case they only differ in such characters:
2309  for (cMenuRecordingItem *p = LastItem; p; p = dynamic_cast<cMenuRecordingItem *>(p->Prev())) {
2310  if (p->Name() && strcmp(p->Name(), Item->Name()) == 0) {
2311  LastDir = p;
2312  break;
2313  }
2314  }
2315  }
2316  if (*Item->Text() && !LastDir) {
2317  Add(Item);
2318  LastItem = Item;
2319  if (Item->IsDirectory())
2320  LastDir = Item;
2321  }
2322  else
2323  delete Item;
2324  if (LastItem || LastDir) {
2325  if (CurrentRecording && strcmp(CurrentRecording, recording->FileName()) == 0)
2326  SetCurrent(LastDir ? LastDir : LastItem);
2327  }
2328  if (LastDir)
2329  LastDir->IncrementCounter(recording->IsNew());
2330  }
2331  }
2332  if (Refresh)
2333  Display();
2334 }
2335 
2337 {
2339  if (base) {
2340  char *s = ExchangeChars(strdup(base), true);
2341  d = AddDirectory(d, s);
2342  free(s);
2343  }
2344  return d;
2345 }
2346 
2347 bool cMenuRecordings::Open(bool OpenSubMenus)
2348 {
2350  if (ri && ri->IsDirectory()) {
2351  const char *t = ri->Name();
2352  cString buffer;
2353  if (base) {
2354  buffer = cString::sprintf("%s~%s", base, t);
2355  t = buffer;
2356  }
2357  AddSubMenu(new cMenuRecordings(t, level + 1, OpenSubMenus));
2358  return true;
2359  }
2360  return false;
2361 }
2362 
2364 {
2366  if (ri) {
2367  if (ri->IsDirectory())
2368  Open();
2369  else {
2371  return osReplay;
2372  }
2373  }
2374  return osContinue;
2375 }
2376 
2378 {
2379  if (HasSubMenu() || Count() == 0)
2380  return osContinue;
2382  if (ri && !ri->IsDirectory()) {
2383  cDevice::PrimaryDevice()->StopReplay(); // must do this first to be able to rewind the currently replayed recording
2384  cResumeFile ResumeFile(ri->Recording()->FileName(), ri->Recording()->IsPesRecording());
2385  ResumeFile.Delete();
2386  return Play();
2387  }
2388  return osContinue;
2389 }
2390 
2392 {
2393  if (HasSubMenu() || Count() == 0)
2394  return osContinue;
2396  if (ri && !ri->IsDirectory()) {
2397  if (Interface->Confirm(tr("Delete recording?"))) {
2399  if (rc) {
2400  if (Interface->Confirm(tr("Timer still recording - really delete?"))) {
2401  cTimer *timer = rc->Timer();
2402  if (timer) {
2403  timer->Skip();
2404  cRecordControls::Process(time(NULL));
2405  if (timer->IsSingleEvent()) {
2406  isyslog("deleting timer %s", *timer->ToDescr());
2407  Timers.Del(timer);
2408  }
2409  Timers.SetModified();
2410  }
2411  }
2412  else
2413  return osContinue;
2414  }
2415  cRecording *recording = ri->Recording();
2416  cString FileName = recording->FileName();
2417  if (cCutter::Active(ri->Recording()->FileName())) {
2418  if (Interface->Confirm(tr("Recording is being edited - really delete?"))) {
2419  cCutter::Stop();
2420  recording = Recordings.GetByName(FileName); // cCutter::Stop() might have deleted it if it was the edited version
2421  // we continue with the code below even if recording is NULL,
2422  // in order to have the menu updated etc.
2423  }
2424  else
2425  return osContinue;
2426  }
2427  if (cReplayControl::NowReplaying() && strcmp(cReplayControl::NowReplaying(), FileName) == 0)
2429  if (!recording || recording->Delete()) {
2431  Recordings.DelByName(FileName);
2433  SetHelpKeys();
2435  Display();
2436  if (!Count())
2437  return osBack;
2438  return osUser2;
2439  }
2440  else
2441  Skins.Message(mtError, tr("Error while deleting recording!"));
2442  }
2443  }
2444  return osContinue;
2445 }
2446 
2448 {
2449  if (HasSubMenu() || Count() == 0)
2450  return osContinue;
2452  if (ri && !ri->IsDirectory() && ri->Recording()->Info()->Title())
2453  return AddSubMenu(new cMenuRecording(ri->Recording(), true));
2454  return osContinue;
2455 }
2456 
2458 {
2459  if (HasSubMenu() || Count() == 0)
2460  return osContinue;
2462  if (ri && !ri->IsDirectory()) {
2463  cMenuCommands *menu;
2464  eOSState state = AddSubMenu(menu = new cMenuCommands(tr("Recording commands"), &RecordingCommands, cString::sprintf("\"%s\"", *strescape(ri->Recording()->FileName(), "\\\"$"))));
2465  if (Key != kNone)
2466  state = menu->ProcessKey(Key);
2467  return state;
2468  }
2469  return osContinue;
2470 }
2471 
2473 {
2474  if (HasSubMenu())
2475  return osContinue;
2477  Set(true);
2478  return osContinue;
2479 }
2480 
2482 {
2483  bool HadSubMenu = HasSubMenu();
2484  eOSState state = cOsdMenu::ProcessKey(Key);
2485 
2486  if (state == osUnknown) {
2487  switch (Key) {
2488  case kPlayPause:
2489  case kPlay:
2490  case kOk: return Play();
2491  case kRed: return (helpKeys > 1 && RecordingCommands.Count()) ? Commands() : Play();
2492  case kGreen: return Rewind();
2493  case kYellow: return Delete();
2494  case kInfo:
2495  case kBlue: return Info();
2496  case k0: return Sort();
2497  case k1...k9: return Commands(Key);
2499  Set(true);
2500  break;
2501  default: break;
2502  }
2503  }
2504  else if (state == osUser2) {
2505  // a recording in a sub folder was deleted, so update the current item
2506  cOsdMenu *m = HasSubMenu() ? SubMenu() : this;
2508  if (cMenuRecordingItem *riSub = (cMenuRecordingItem *)m->Get(m->Current()))
2509  ri->SetRecording(riSub->Recording());
2510  }
2511  }
2512  if (Key == kYellow && HadSubMenu && !HasSubMenu()) {
2513  // the last recording in a subdirectory was deleted, so let's go back up
2515  if (!Count())
2516  return osBack;
2517  Display();
2518  }
2519  if (!HasSubMenu()) {
2520  if (Key != kNone)
2521  SetHelpKeys();
2522  }
2523  return state;
2524 }
2525 
2526 // --- cMenuSetupBase --------------------------------------------------------
2527 
2529 protected:
2531  virtual void Store(void);
2532 public:
2533  cMenuSetupBase(void);
2534  };
2535 
2537 {
2538  data = Setup;
2539 }
2540 
2542 {
2543  Setup = data;
2545  Setup.Save();
2546 }
2547 
2548 // --- cMenuSetupOSD ---------------------------------------------------------
2549 
2551 private:
2552  const char *useSmallFontTexts[3];
2553  const char *keyColorTexts[4];
2558  const char **skinDescriptions;
2564  virtual void Set(void);
2565 public:
2566  cMenuSetupOSD(void);
2567  virtual ~cMenuSetupOSD();
2568  virtual eOSState ProcessKey(eKeys Key);
2569  };
2570 
2572 {
2575  numSkins = Skins.Count();
2577  skinDescriptions = new const char*[numSkins];
2578  themes.Load(Skins.Current()->Name());
2589  Set();
2590 }
2591 
2593 {
2594  delete[] skinDescriptions;
2595 }
2596 
2598 {
2599  int current = Current();
2600  for (cSkin *Skin = Skins.First(); Skin; Skin = Skins.Next(Skin))
2601  skinDescriptions[Skin->Index()] = Skin->Description();
2602  useSmallFontTexts[0] = tr("never");
2603  useSmallFontTexts[1] = tr("skin dependent");
2604  useSmallFontTexts[2] = tr("always");
2605  keyColorTexts[0] = tr("Key$Red");
2606  keyColorTexts[1] = tr("Key$Green");
2607  keyColorTexts[2] = tr("Key$Yellow");
2608  keyColorTexts[3] = tr("Key$Blue");
2609  Clear();
2610  SetSection(tr("OSD"));
2611  Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &osdLanguageIndex, I18nNumLanguagesWithLocale(), &I18nLanguages()->At(0)));
2612  Add(new cMenuEditStraItem(tr("Setup.OSD$Skin"), &skinIndex, numSkins, skinDescriptions));
2613  if (themes.NumThemes())
2614  Add(new cMenuEditStraItem(tr("Setup.OSD$Theme"), &themeIndex, themes.NumThemes(), themes.Descriptions()));
2615  Add(new cMenuEditBoolItem(tr("Setup.OSD$WarEagle icons"), &data.WarEagleIcons));
2616  Add(new cMenuEditPrcItem( tr("Setup.OSD$Left (%)"), &data.OSDLeftP, 0.0, 0.5));
2617  Add(new cMenuEditPrcItem( tr("Setup.OSD$Top (%)"), &data.OSDTopP, 0.0, 0.5));
2618  Add(new cMenuEditPrcItem( tr("Setup.OSD$Width (%)"), &data.OSDWidthP, 0.5, 1.0));
2619  Add(new cMenuEditPrcItem( tr("Setup.OSD$Height (%)"), &data.OSDHeightP, 0.5, 1.0));
2620  Add(new cMenuEditIntItem( tr("Setup.OSD$Message time (s)"), &data.OSDMessageTime, 1, 60));
2621  Add(new cMenuEditStraItem(tr("Setup.OSD$Use small font"), &data.UseSmallFont, 3, useSmallFontTexts));
2622  Add(new cMenuEditBoolItem(tr("Setup.OSD$Anti-alias"), &data.AntiAlias));
2623  Add(new cMenuEditStraItem(tr("Setup.OSD$Default font"), &fontOsdIndex, fontOsdNames.Size(), &fontOsdNames[0]));
2624  Add(new cMenuEditStraItem(tr("Setup.OSD$Small font"), &fontSmlIndex, fontSmlNames.Size(), &fontSmlNames[0]));
2625  Add(new cMenuEditStraItem(tr("Setup.OSD$Fixed font"), &fontFixIndex, fontFixNames.Size(), &fontFixNames[0]));
2626  Add(new cMenuEditPrcItem( tr("Setup.OSD$Default font size (%)"), &data.FontOsdSizeP, 0.01, 0.1, 1));
2627  Add(new cMenuEditPrcItem( tr("Setup.OSD$Small font size (%)"), &data.FontSmlSizeP, 0.01, 0.1, 1));
2628  Add(new cMenuEditPrcItem( tr("Setup.OSD$Fixed font size (%)"), &data.FontFixSizeP, 0.01, 0.1, 1));
2629  Add(new cMenuEditBoolItem(tr("Setup.OSD$Channel info position"), &data.ChannelInfoPos, tr("bottom"), tr("top")));
2630  Add(new cMenuEditIntItem( tr("Setup.OSD$Channel info time (s)"), &data.ChannelInfoTime, 1, 60));
2631  Add(new cMenuEditBoolItem(tr("Setup.OSD$Info on channel switch"), &data.ShowInfoOnChSwitch));
2632  Add(new cMenuEditBoolItem(tr("Setup.OSD$Timeout requested channel info"), &data.TimeoutRequChInfo));
2633  Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll pages"), &data.MenuScrollPage));
2634  Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll wraps"), &data.MenuScrollWrap));
2635  Add(new cMenuEditBoolItem(tr("Setup.OSD$Menu key closes"), &data.MenuKeyCloses));
2636  Add(new cMenuEditBoolItem(tr("Setup.OSD$Recording directories"), &data.RecordingDirs));
2637  Add(new cMenuEditBoolItem(tr("Setup.OSD$Folders in timer menu"), &data.FoldersInTimerMenu));
2638  Add(new cMenuEditBoolItem(tr("Setup.OSD$Always sort folders first"), &data.AlwaysSortFoldersFirst));
2639  Add(new cMenuEditBoolItem(tr("Setup.OSD$Number keys for characters"), &data.NumberKeysForChars));
2640  Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 0"), &data.ColorKey0, 4, keyColorTexts));
2641  Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 1"), &data.ColorKey1, 4, keyColorTexts));
2642  Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 2"), &data.ColorKey2, 4, keyColorTexts));
2643  Add(new cMenuEditStraItem(tr("Setup.OSD$Color key 3"), &data.ColorKey3, 4, keyColorTexts));
2644  SetCurrent(Get(current));
2645  Display();
2646 }
2647 
2649 {
2650  bool ModifiedAppearance = false;
2651 
2652  if (Key == kOk) {
2654  if (skinIndex != originalSkinIndex) {
2655  cSkin *Skin = Skins.Get(skinIndex);
2656  if (Skin) {
2657  Utf8Strn0Cpy(data.OSDSkin, Skin->Name(), sizeof(data.OSDSkin));
2658  Skins.SetCurrent(Skin->Name());
2659  ModifiedAppearance = true;
2660  }
2661  }
2662  if (themes.NumThemes() && Skins.Current()->Theme()) {
2665  ModifiedAppearance |= themeIndex != originalThemeIndex;
2666  }
2668  ModifiedAppearance = true;
2670  ModifiedAppearance = true;
2675  ModifiedAppearance = true;
2677  ModifiedAppearance = true;
2679  ModifiedAppearance = true;
2682  }
2683 
2684  int oldSkinIndex = skinIndex;
2685  int oldOsdLanguageIndex = osdLanguageIndex;
2686  eOSState state = cMenuSetupBase::ProcessKey(Key);
2687 
2688  if (ModifiedAppearance) {
2690  SetDisplayMenu();
2691  }
2692 
2693  if (osdLanguageIndex != oldOsdLanguageIndex || skinIndex != oldSkinIndex) {
2695  int OriginalOSDLanguage = I18nCurrentLanguage();
2697 
2698  cSkin *Skin = Skins.Get(skinIndex);
2699  if (Skin) {
2700  char *d = themes.NumThemes() ? strdup(themes.Descriptions()[themeIndex]) : NULL;
2701  themes.Load(Skin->Name());
2702  if (skinIndex != oldSkinIndex)
2703  themeIndex = d ? themes.GetThemeIndex(d) : 0;
2704  free(d);
2705  }
2706 
2707  Set();
2708  I18nSetLanguage(OriginalOSDLanguage);
2709  }
2710  return state;
2711 }
2712 
2713 // --- cMenuSetupEPG ---------------------------------------------------------
2714 
2716 private:
2719  void Setup(void);
2720 public:
2721  cMenuSetupEPG(void);
2722  virtual eOSState ProcessKey(eKeys Key);
2723  };
2724 
2726 {
2729  ;
2731  SetSection(tr("EPG"));
2732  SetHelp(tr("Button$Scan"));
2733  Setup();
2734 }
2735 
2737 {
2738  int current = Current();
2739 
2740  Clear();
2741 
2742  Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout (h)"), &data.EPGScanTimeout));
2743  Add(new cMenuEditIntItem( tr("Setup.EPG$EPG bugfix level"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL));
2744  Add(new cMenuEditIntItem( tr("Setup.EPG$EPG linger time (min)"), &data.EPGLinger, 0));
2745  Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"), &data.SetSystemTime));
2746  if (data.SetSystemTime)
2747  Add(new cMenuEditTranItem(tr("Setup.EPG$Use time from transponder"), &data.TimeTransponder, &data.TimeSource));
2748  // TRANSLATORS: note the plural!
2749  Add(new cMenuEditIntItem( tr("Setup.EPG$Preferred languages"), &numLanguages, 0, I18nLanguages()->Size()));
2750  for (int i = 0; i < numLanguages; i++)
2751  // TRANSLATORS: note the singular!
2752  Add(new cMenuEditStraItem(tr("Setup.EPG$Preferred language"), &data.EPGLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
2753 
2754  SetCurrent(Get(current));
2755  Display();
2756 }
2757 
2759 {
2760  if (Key == kOk) {
2761  bool Modified = numLanguages != originalNumLanguages;
2762  if (!Modified) {
2763  for (int i = 0; i < numLanguages; i++) {
2764  if (data.EPGLanguages[i] != ::Setup.EPGLanguages[i]) {
2765  Modified = true;
2766  break;
2767  }
2768  }
2769  }
2770  if (Modified)
2772  }
2773 
2774  int oldnumLanguages = numLanguages;
2775  int oldSetSystemTime = data.SetSystemTime;
2776 
2777  eOSState state = cMenuSetupBase::ProcessKey(Key);
2778  if (Key != kNone) {
2779  if (numLanguages != oldnumLanguages || data.SetSystemTime != oldSetSystemTime) {
2780  for (int i = oldnumLanguages; i < numLanguages; i++) {
2781  data.EPGLanguages[i] = 0;
2782  for (int l = 0; l < I18nLanguages()->Size(); l++) {
2783  int k;
2784  for (k = 0; k < oldnumLanguages; k++) {
2785  if (data.EPGLanguages[k] == l)
2786  break;
2787  }
2788  if (k >= oldnumLanguages) {
2789  data.EPGLanguages[i] = l;
2790  break;
2791  }
2792  }
2793  }
2795  Setup();
2796  }
2797  if (Key == kRed) {
2799  return osEnd;
2800  }
2801  }
2802  return state;
2803 }
2804 
2805 // --- cMenuSetupDVB ---------------------------------------------------------
2806 
2808 private:
2813  void Setup(void);
2814  const char *videoDisplayFormatTexts[3];
2815  const char *updateChannelsTexts[6];
2816  const char *standardComplianceTexts[2];
2817 public:
2818  cMenuSetupDVB(void);
2819  virtual eOSState ProcessKey(eKeys Key);
2820  };
2821 
2823 {
2826  ;
2828  ;
2831  videoDisplayFormatTexts[0] = tr("pan&scan");
2832  videoDisplayFormatTexts[1] = tr("letterbox");
2833  videoDisplayFormatTexts[2] = tr("center cut out");
2834  updateChannelsTexts[0] = tr("no");
2835  updateChannelsTexts[1] = tr("names only");
2836  updateChannelsTexts[2] = tr("PIDs only");
2837  updateChannelsTexts[3] = tr("names and PIDs");
2838  updateChannelsTexts[4] = tr("add new channels");
2839  updateChannelsTexts[5] = tr("add new transponders");
2840  standardComplianceTexts[0] = "DVB";
2841  standardComplianceTexts[1] = "ANSI/SCTE";
2842 
2843  SetSection(tr("DVB"));
2844  SetHelp(NULL, tr("Button$Audio"), tr("Button$Subtitles"), NULL);
2845  Setup();
2846 }
2847 
2849 {
2850  int current = Current();
2851 
2852  Clear();
2853 
2854  Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices()));
2855  Add(new cMenuEditStraItem(tr("Setup.DVB$Standard compliance"), &data.StandardCompliance, 2, standardComplianceTexts));
2856  Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9"));
2857  if (data.VideoFormat == 0)
2858  Add(new cMenuEditStraItem(tr("Setup.DVB$Video display format"), &data.VideoDisplayFormat, 3, videoDisplayFormatTexts));
2859  Add(new cMenuEditBoolItem(tr("Setup.DVB$Use Dolby Digital"), &data.UseDolbyDigital));
2860  Add(new cMenuEditStraItem(tr("Setup.DVB$Update channels"), &data.UpdateChannels, 6, updateChannelsTexts));
2861  Add(new cMenuEditIntItem( tr("Setup.DVB$Audio languages"), &numAudioLanguages, 0, I18nLanguages()->Size()));
2862  for (int i = 0; i < numAudioLanguages; i++)
2863  Add(new cMenuEditStraItem(tr("Setup.DVB$Audio language"), &data.AudioLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
2864  Add(new cMenuEditBoolItem(tr("Setup.DVB$Display subtitles"), &data.DisplaySubtitles));
2865  if (data.DisplaySubtitles) {
2866  Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle languages"), &numSubtitleLanguages, 0, I18nLanguages()->Size()));
2867  for (int i = 0; i < numSubtitleLanguages; i++)
2868  Add(new cMenuEditStraItem(tr("Setup.DVB$Subtitle language"), &data.SubtitleLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
2869  Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle offset"), &data.SubtitleOffset, -100, 100));
2870  Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle foreground transparency"), &data.SubtitleFgTransparency, 0, 9));
2871  Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle background transparency"), &data.SubtitleBgTransparency, 0, 10));
2872  }
2873 
2874  SetCurrent(Get(current));
2875  Display();
2876 }
2877 
2879 {
2880  int oldPrimaryDVB = ::Setup.PrimaryDVB;
2881  int oldVideoDisplayFormat = ::Setup.VideoDisplayFormat;
2882  bool oldVideoFormat = ::Setup.VideoFormat;
2883  bool newVideoFormat = data.VideoFormat;
2884  bool oldDisplaySubtitles = ::Setup.DisplaySubtitles;
2885  bool newDisplaySubtitles = data.DisplaySubtitles;
2886  int oldnumAudioLanguages = numAudioLanguages;
2887  int oldnumSubtitleLanguages = numSubtitleLanguages;
2888  eOSState state = cMenuSetupBase::ProcessKey(Key);
2889 
2890  if (Key != kNone) {
2891  switch (Key) {
2892  case kGreen: cRemote::Put(kAudio, true);
2893  state = osEnd;
2894  break;
2895  case kYellow: cRemote::Put(kSubtitles, true);
2896  state = osEnd;
2897  break;
2898  default: {
2899  bool DoSetup = data.VideoFormat != newVideoFormat;
2900  DoSetup |= data.DisplaySubtitles != newDisplaySubtitles;
2901  if (numAudioLanguages != oldnumAudioLanguages) {
2902  for (int i = oldnumAudioLanguages; i < numAudioLanguages; i++) {
2903  data.AudioLanguages[i] = 0;
2904  for (int l = 0; l < I18nLanguages()->Size(); l++) {
2905  int k;
2906  for (k = 0; k < oldnumAudioLanguages; k++) {
2907  if (data.AudioLanguages[k] == l)
2908  break;
2909  }
2910  if (k >= oldnumAudioLanguages) {
2911  data.AudioLanguages[i] = l;
2912  break;
2913  }
2914  }
2915  }
2917  DoSetup = true;
2918  }
2919  if (numSubtitleLanguages != oldnumSubtitleLanguages) {
2920  for (int i = oldnumSubtitleLanguages; i < numSubtitleLanguages; i++) {
2921  data.SubtitleLanguages[i] = 0;
2922  for (int l = 0; l < I18nLanguages()->Size(); l++) {
2923  int k;
2924  for (k = 0; k < oldnumSubtitleLanguages; k++) {
2925  if (data.SubtitleLanguages[k] == l)
2926  break;
2927  }
2928  if (k >= oldnumSubtitleLanguages) {
2929  data.SubtitleLanguages[i] = l;
2930  break;
2931  }
2932  }
2933  }
2935  DoSetup = true;
2936  }
2937  if (DoSetup)
2938  Setup();
2939  }
2940  }
2941  }
2942  if (state == osBack && Key == kOk) {
2943  if (::Setup.PrimaryDVB != oldPrimaryDVB)
2944  state = osSwitchDvb;
2945  if (::Setup.VideoDisplayFormat != oldVideoDisplayFormat)
2947  if (::Setup.VideoFormat != oldVideoFormat)
2948  cDevice::PrimaryDevice()->SetVideoFormat(::Setup.VideoFormat);
2949  if (::Setup.DisplaySubtitles != oldDisplaySubtitles)
2952  }
2953  return state;
2954 }
2955 
2956 // --- cMenuSetupLNB ---------------------------------------------------------
2957 
2959 private:
2961  void Setup(void);
2962 public:
2963  cMenuSetupLNB(void);
2964  virtual eOSState ProcessKey(eKeys Key);
2965  };
2966 
2968 :satCableNumbers(MAXDEVICES)
2969 {
2972  SetSection(tr("LNB"));
2973  Setup();
2974 }
2975 
2977 {
2978  int current = Current();
2979 
2980  Clear();
2981 
2982  Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC));
2983  if (!data.DiSEqC) {
2984  Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF));
2985  Add(new cMenuEditIntItem( tr("Setup.LNB$Low LNB frequency (MHz)"), &data.LnbFrequLo));
2986  Add(new cMenuEditIntItem( tr("Setup.LNB$High LNB frequency (MHz)"), &data.LnbFrequHi));
2987  }
2988 
2989  int NumSatDevices = 0;
2990  for (int i = 0; i < cDevice::NumDevices(); i++) {
2992  NumSatDevices++;
2993  }
2994  if (NumSatDevices > 1) {
2995  for (int i = 0; i < cDevice::NumDevices(); i++) {
2997  Add(new cMenuEditIntItem(cString::sprintf(tr("Setup.LNB$Device %d connected to sat cable"), i + 1), &satCableNumbers.Array()[i], 0, NumSatDevices, tr("Setup.LNB$own")));
2998  else
2999  satCableNumbers.Array()[i] = 0;
3000  }
3001  }
3002 
3003  SetCurrent(Get(current));
3004  Display();
3005 }
3006 
3008 {
3009  int oldDiSEqC = data.DiSEqC;
3010  bool DeviceBondingsChanged = false;
3011  if (Key == kOk) {
3012  cString NewDeviceBondings = satCableNumbers.ToString();
3013  DeviceBondingsChanged = strcmp(data.DeviceBondings, NewDeviceBondings) != 0;
3014  data.DeviceBondings = NewDeviceBondings;
3015  }
3016  eOSState state = cMenuSetupBase::ProcessKey(Key);
3017 
3018  if (Key != kNone && data.DiSEqC != oldDiSEqC)
3019  Setup();
3020  else if (DeviceBondingsChanged)
3022  return state;
3023 }
3024 
3025 // --- cMenuSetupCAM ---------------------------------------------------------
3026 
3027 class cMenuSetupCAMItem : public cOsdItem {
3028 private:
3030 public:
3032  cCamSlot *CamSlot(void) { return camSlot; }
3033  bool Changed(void);
3034  };
3035 
3037 {
3038  camSlot = CamSlot;
3039  SetText("");
3040  Changed();
3041 }
3042 
3044 {
3045  char buffer[32];
3046  const char *CamName = camSlot->GetCamName();
3047  if (!CamName) {
3048  switch (camSlot->ModuleStatus()) {
3049  case msReset: CamName = tr("CAM reset"); break;
3050  case msPresent: CamName = tr("CAM present"); break;
3051  case msReady: CamName = tr("CAM ready"); break;
3052  default: CamName = "-"; break;
3053  }
3054  }
3055  snprintf(buffer, sizeof(buffer), " %d %s", camSlot->SlotNumber(), CamName);
3056  if (strcmp(buffer, Text()) != 0) {
3057  SetText(buffer);
3058  return true;
3059  }
3060  return false;
3061 }
3062 
3064 private:
3065  eOSState Menu(void);
3066  eOSState Reset(void);
3067 public:
3068  cMenuSetupCAM(void);
3069  virtual eOSState ProcessKey(eKeys Key);
3070  };
3071 
3073 {
3075  SetSection(tr("CAM"));
3076  SetCols(15);
3077  SetHasHotkeys();
3078  for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot))
3079  Add(new cMenuSetupCAMItem(CamSlot));
3080  SetHelp(tr("Button$Menu"), tr("Button$Reset"));
3081 }
3082 
3084 {
3086  if (item) {
3087  if (item->CamSlot()->EnterMenu()) {
3088  Skins.Message(mtStatus, tr("Opening CAM menu..."));
3089  time_t t0 = time(NULL);
3090  time_t t1 = t0;
3091  while (time(NULL) - t0 <= MAXWAITFORCAMMENU) {
3092  if (item->CamSlot()->HasUserIO())
3093  break;
3094  if (time(NULL) - t1 >= CAMMENURETYTIMEOUT) {
3095  dsyslog("CAM %d: retrying to enter CAM menu...", item->CamSlot()->SlotNumber());
3096  item->CamSlot()->EnterMenu();
3097  t1 = time(NULL);
3098  }
3099  cCondWait::SleepMs(100);
3100  }
3101  Skins.Message(mtStatus, NULL);
3102  if (item->CamSlot()->HasUserIO())
3103  return AddSubMenu(new cMenuCam(item->CamSlot()));
3104  }
3105  Skins.Message(mtError, tr("Can't open CAM menu!"));
3106  }
3107  return osContinue;
3108 }
3109 
3111 {
3113  if (item) {
3114  if (!item->CamSlot()->Device() || Interface->Confirm(tr("CAM is in use - really reset?"))) {
3115  if (!item->CamSlot()->Reset())
3116  Skins.Message(mtError, tr("Can't reset CAM!"));
3117  }
3118  }
3119  return osContinue;
3120 }
3121 
3123 {
3125 
3126  if (!HasSubMenu()) {
3127  switch (Key) {
3128  case kOk:
3129  case kRed: return Menu();
3130  case kGreen: state = Reset(); break;
3131  default: break;
3132  }
3133  for (cMenuSetupCAMItem *ci = (cMenuSetupCAMItem *)First(); ci; ci = (cMenuSetupCAMItem *)ci->Next()) {
3134  if (ci->Changed())
3135  DisplayItem(ci);
3136  }
3137  }
3138  return state;
3139 }
3140 
3141 // --- cMenuSetupRecord ------------------------------------------------------
3142 
3144 private:
3145  const char *pauseKeyHandlingTexts[3];
3146  const char *delTimeshiftRecTexts[3];
3147 public:
3148  cMenuSetupRecord(void);
3149  };
3150 
3152 {
3154  pauseKeyHandlingTexts[0] = tr("do not pause live video");
3155  pauseKeyHandlingTexts[1] = tr("confirm pause live video");
3156  pauseKeyHandlingTexts[2] = tr("pause live video");
3157  delTimeshiftRecTexts[0] = tr("no");
3158  delTimeshiftRecTexts[1] = tr("confirm");
3159  delTimeshiftRecTexts[2] = tr("yes");
3160  SetSection(tr("Recording"));
3161  Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at start (min)"), &data.MarginStart));
3162  Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at stop (min)"), &data.MarginStop));
3163  Add(new cMenuEditIntItem( tr("Setup.Recording$Default priority"), &data.DefaultPriority, 0, MAXPRIORITY));
3164  Add(new cMenuEditIntItem( tr("Setup.Recording$Default lifetime (d)"), &data.DefaultLifetime, 0, MAXLIFETIME));
3165  Add(new cMenuEditStraItem(tr("Setup.Recording$Pause key handling"), &data.PauseKeyHandling, 3, pauseKeyHandlingTexts));
3166  Add(new cMenuEditIntItem( tr("Setup.Recording$Pause priority"), &data.PausePriority, 0, MAXPRIORITY));
3167  Add(new cMenuEditIntItem( tr("Setup.Recording$Pause lifetime (d)"), &data.PauseLifetime, 0, MAXLIFETIME));
3168  Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle));
3169  Add(new cMenuEditBoolItem(tr("Setup.Recording$Use VPS"), &data.UseVps));
3170  Add(new cMenuEditIntItem( tr("Setup.Recording$VPS margin (s)"), &data.VpsMargin, 0));
3171  Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord));
3172  Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord)));
3173  Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 0, MAXINSTANTRECTIME, tr("Setup.Recording$present event")));
3174  Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZETS));
3175  Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles));
3176  Add(new cMenuEditStraItem(tr("Setup.Recording$Delete timeshift recording"),&data.DelTimeshiftRec, 3, delTimeshiftRecTexts));
3177 }
3178 
3179 // --- cMenuSetupReplay ------------------------------------------------------
3180 
3182 protected:
3183  virtual void Store(void);
3184 public:
3185  cMenuSetupReplay(void);
3186  };
3187 
3189 {
3191  SetSection(tr("Replay"));
3192  Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode));
3193  Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode));
3194  Add(new cMenuEditBoolItem(tr("Setup.Replay$Show remaining time"), &data.ShowRemainingTime));
3195  Add(new cMenuEditIntItem( tr("Setup.Replay$Progress display time (s)"), &data.ProgressDisplayTime, 0, 60));
3196  Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause replay when setting mark"), &data.PauseOnMarkSet));
3197  Add(new cMenuEditIntItem(tr("Setup.Replay$Resume ID"), &data.ResumeID, 0, 99));
3198 }
3199 
3201 {
3202  if (Setup.ResumeID != data.ResumeID)
3205 }
3206 
3207 // --- cMenuSetupMisc --------------------------------------------------------
3208 
3210 public:
3211  cMenuSetupMisc(void);
3212  };
3213 
3215 {
3217  SetSection(tr("Miscellaneous"));
3218  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout));
3219  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity));
3220  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout));
3221  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Zap timeout (s)"), &data.ZapTimeout));
3222  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Channel entry timeout (ms)"), &data.ChannelEntryTimeout, 0));
3223  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Remote control repeat delay (ms)"), &data.RcRepeatDelay, 0));
3224  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Remote control repeat delta (ms)"), &data.RcRepeatDelta, 0));
3225  Add(new cMenuEditChanItem(tr("Setup.Miscellaneous$Initial channel"), &data.InitialChannel, tr("Setup.Miscellaneous$as before")));
3226  Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Initial volume"), &data.InitialVolume, -1, 255, tr("Setup.Miscellaneous$as before")));
3227  Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Channels wrap"), &data.ChannelsWrap));
3228  Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Show channel names with source"), &data.ShowChannelNamesWithSource));
3229  Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Emergency exit"), &data.EmergencyExit));
3230 }
3231 
3232 // --- cMenuSetupPluginItem --------------------------------------------------
3233 
3235 private:
3237 public:
3238  cMenuSetupPluginItem(const char *Name, int Index);
3239  int PluginIndex(void) { return pluginIndex; }
3240  };
3241 
3243 :cOsdItem(Name)
3244 {
3245  pluginIndex = Index;
3246 }
3247 
3248 // --- cMenuSetupPlugins -----------------------------------------------------
3249 
3251 public:
3252  cMenuSetupPlugins(void);
3253  virtual eOSState ProcessKey(eKeys Key);
3254  };
3255 
3257 {
3259  SetSection(tr("Plugins"));
3260  SetHasHotkeys();
3261  for (int i = 0; ; i++) {
3263  if (p)
3264  Add(new cMenuSetupPluginItem(hk(cString::sprintf("%s (%s) - %s", p->Name(), p->Version(), p->Description())), i));
3265  else
3266  break;
3267  }
3268 }
3269 
3271 {
3273 
3274  if (Key == kOk) {
3275  if (state == osUnknown) {
3277  if (item) {
3279  if (p) {
3280  cMenuSetupPage *menu = p->SetupMenu();
3281  if (menu) {
3282  menu->SetPlugin(p);
3283  return AddSubMenu(menu);
3284  }
3285  Skins.Message(mtInfo, tr("This plugin has no setup parameters!"));
3286  }
3287  }
3288  }
3289  else if (state == osContinue) {
3290  Store();
3291  // Reinitialize OSD and skin, in case any plugin setup change has an influence on these:
3293  SetDisplayMenu();
3294  Display();
3295  }
3296  }
3297  return state;
3298 }
3299 
3300 // --- cMenuSetup ------------------------------------------------------------
3301 
3302 class cMenuSetup : public cOsdMenu {
3303 private:
3304  virtual void Set(void);
3305  eOSState Restart(void);
3306 public:
3307  cMenuSetup(void);
3308  virtual eOSState ProcessKey(eKeys Key);
3309  };
3310 
3312 :cOsdMenu("")
3313 {
3315  Set();
3316 }
3317 
3319 {
3320  Clear();
3321  char buffer[64];
3322  snprintf(buffer, sizeof(buffer), "%s - VDR %s", tr("Setup"), VDRVERSION);
3323  SetTitle(buffer);
3324  SetHasHotkeys();
3325  Add(new cOsdItem(hk(tr("OSD")), osUser1));
3326  Add(new cOsdItem(hk(tr("EPG")), osUser2));
3327  Add(new cOsdItem(hk(tr("DVB")), osUser3));
3328  Add(new cOsdItem(hk(tr("LNB")), osUser4));
3329  Add(new cOsdItem(hk(tr("CAM")), osUser5));
3330  Add(new cOsdItem(hk(tr("Recording")), osUser6));
3331  Add(new cOsdItem(hk(tr("Replay")), osUser7));
3332  Add(new cOsdItem(hk(tr("Miscellaneous")), osUser8));
3334  Add(new cOsdItem(hk(tr("Plugins")), osUser9));
3335  Add(new cOsdItem(hk(tr("Restart")), osUser10));
3336 }
3337 
3339 {
3340  if (Interface->Confirm(tr("Really restart?")) && ShutdownHandler.ConfirmRestart(true)) {
3341  ShutdownHandler.Exit(1);
3342  return osEnd;
3343  }
3344  return osContinue;
3345 }
3346 
3348 {
3349  int osdLanguage = I18nCurrentLanguage();
3350  eOSState state = cOsdMenu::ProcessKey(Key);
3351 
3352  switch (state) {
3353  case osUser1: return AddSubMenu(new cMenuSetupOSD);
3354  case osUser2: return AddSubMenu(new cMenuSetupEPG);
3355  case osUser3: return AddSubMenu(new cMenuSetupDVB);
3356  case osUser4: return AddSubMenu(new cMenuSetupLNB);
3357  case osUser5: return AddSubMenu(new cMenuSetupCAM);
3358  case osUser6: return AddSubMenu(new cMenuSetupRecord);
3359  case osUser7: return AddSubMenu(new cMenuSetupReplay);
3360  case osUser8: return AddSubMenu(new cMenuSetupMisc);
3361  case osUser9: return AddSubMenu(new cMenuSetupPlugins);
3362  case osUser10: return Restart();
3363  default: ;
3364  }
3365  if (I18nCurrentLanguage() != osdLanguage) {
3366  Set();
3367  if (!HasSubMenu())
3368  Display();
3369  }
3370  return state;
3371 }
3372 
3373 // --- cMenuPluginItem -------------------------------------------------------
3374 
3375 class cMenuPluginItem : public cOsdItem {
3376 private:
3378 public:
3379  cMenuPluginItem(const char *Name, int Index);
3380  int PluginIndex(void) { return pluginIndex; }
3381  };
3382 
3383 cMenuPluginItem::cMenuPluginItem(const char *Name, int Index)
3384 :cOsdItem(Name, osPlugin)
3385 {
3386  pluginIndex = Index;
3387 }
3388 
3389 // --- cMenuMain -------------------------------------------------------------
3390 
3391 // TRANSLATORS: note the leading and trailing blanks!
3392 #define STOP_RECORDING trNOOP(" Stop recording ")
3393 
3395 
3396 cMenuMain::cMenuMain(eOSState State, bool OpenSubMenus)
3397 :cOsdMenu("")
3398 {
3400  replaying = false;
3401  stopReplayItem = NULL;
3402  cancelEditingItem = NULL;
3403  stopRecordingItem = NULL;
3404  recordControlsState = 0;
3405  Set();
3406 
3407  // Initial submenus:
3408 
3409  cOsdObject *menu = NULL;
3410  switch (State) {
3411  case osSchedule:
3412  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu))
3413  menu = new cMenuSchedule;
3414  break;
3415  case osChannels:
3416  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu))
3417  menu = new cMenuChannels;
3418  break;
3419  case osTimers:
3420  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu))
3421  menu = new cMenuTimers;
3422  break;
3423  case osRecordings:
3424  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu))
3425  menu = new cMenuRecordings(NULL, 0, OpenSubMenus);
3426  break;
3427  case osSetup: menu = new cMenuSetup; break;
3428  case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break;
3429  default: break;
3430  }
3431  if (menu)
3432  if (menu->IsMenu())
3433  AddSubMenu((cOsdMenu *) menu);
3434 }
3435 
3437 {
3439  pluginOsdObject = NULL;
3440  return o;
3441 }
3442 
3443 void cMenuMain::Set(void)
3444 {
3445  Clear();
3446  SetTitle("VDR");
3447  SetHasHotkeys();
3448 
3449  // Basic menu items:
3450 
3451  Add(new cOsdItem(hk(tr("Schedule")), osSchedule));
3452  Add(new cOsdItem(hk(tr("Channels")), osChannels));
3453  Add(new cOsdItem(hk(tr("Timers")), osTimers));
3454  Add(new cOsdItem(hk(tr("Recordings")), osRecordings));
3455 
3456  // Plugins:
3457 
3458  for (int i = 0; ; i++) {
3460  if (p) {
3461  const char *item = p->MainMenuEntry();
3462  if (item)
3463  Add(new cMenuPluginItem(hk(item), i));
3464  }
3465  else
3466  break;
3467  }
3468 
3469  // More basic menu items:
3470 
3471  Add(new cOsdItem(hk(tr("Setup")), osSetup));
3472  if (Commands.Count())
3473  Add(new cOsdItem(hk(tr("Commands")), osCommands));
3474 
3475  Update(true);
3476 
3477  Display();
3478 }
3479 
3480 bool cMenuMain::Update(bool Force)
3481 {
3482  bool result = false;
3483 
3484  bool NewReplaying = cControl::Control() != NULL;
3485  if (Force || NewReplaying != replaying) {
3486  replaying = NewReplaying;
3487  // Replay control:
3488  if (replaying && !stopReplayItem)
3489  // TRANSLATORS: note the leading blank!
3490  Add(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay));
3491  else if (stopReplayItem && !replaying) {
3492  Del(stopReplayItem->Index());
3493  stopReplayItem = NULL;
3494  }
3495  // Color buttons:
3496  SetHelp(!replaying ? tr("Button$Record") : NULL, tr("Button$Audio"), replaying || !Setup.PauseKeyHandling ? NULL : tr("Button$Pause"), replaying ? tr("Button$Stop") : cReplayControl::LastReplayed() ? tr("Button$Resume") : tr("Button$Play"));
3497  result = true;
3498  }
3499 
3500  // Editing control:
3501  bool CutterActive = cCutter::Active();
3502  if (CutterActive && !cancelEditingItem) {
3503  // TRANSLATORS: note the leading blank!
3504  Add(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit));
3505  result = true;
3506  }
3507  else if (cancelEditingItem && !CutterActive) {
3509  cancelEditingItem = NULL;
3510  result = true;
3511  }
3512 
3513  // Record control:
3515  while (stopRecordingItem) {
3518  stopRecordingItem = it;
3519  }
3520  const char *s = NULL;
3521  while ((s = cRecordControls::GetInstantId(s)) != NULL) {
3522  cOsdItem *item = new cOsdItem(osStopRecord);
3523  item->SetText(cString::sprintf("%s%s", tr(STOP_RECORDING), s));
3524  Add(item);
3525  if (!stopRecordingItem)
3526  stopRecordingItem = item;
3527  }
3528  result = true;
3529  }
3530 
3531  return result;
3532 }
3533 
3535 {
3536  bool HadSubMenu = HasSubMenu();
3537  int osdLanguage = I18nCurrentLanguage();
3538  eOSState state = cOsdMenu::ProcessKey(Key);
3539  HadSubMenu |= HasSubMenu();
3540 
3541  cOsdObject *menu = NULL;
3542  switch (state) {
3543  case osSchedule:
3544  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu))
3545  menu = new cMenuSchedule;
3546  else
3547  state = osContinue;
3548  break;
3549  case osChannels:
3550  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu))
3551  menu = new cMenuChannels;
3552  else
3553  state = osContinue;
3554  break;
3555  case osTimers:
3556  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu))
3557  menu = new cMenuTimers;
3558  else
3559  state = osContinue;
3560  break;
3561  case osRecordings:
3562  if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu))
3563  menu = new cMenuRecordings;
3564  else
3565  state = osContinue;
3566  break;
3567  case osSetup: menu = new cMenuSetup; break;
3568  case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break;
3569  case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) {
3570  cOsdItem *item = Get(Current());
3571  if (item) {
3572  cRecordControls::Stop(item->Text() + strlen(tr(STOP_RECORDING)));
3573  return osEnd;
3574  }
3575  }
3576  break;
3577  case osCancelEdit: if (Interface->Confirm(tr("Cancel editing?"))) {
3578  cCutter::Stop();
3579  return osEnd;
3580  }
3581  break;
3582  case osPlugin: {
3584  if (item) {
3586  if (p) {
3587  cOsdObject *menu = p->MainMenuAction();
3588  if (menu) {
3589  if (menu->IsMenu())
3590  return AddSubMenu((cOsdMenu *)menu);
3591  else {
3592  pluginOsdObject = menu;
3593  return osPlugin;
3594  }
3595  }
3596  }
3597  }
3598  state = osEnd;
3599  }
3600  break;
3601  default: switch (Key) {
3602  case kRecord:
3603  case kRed: if (!HadSubMenu)
3604  state = replaying ? osContinue : osRecord;
3605  break;
3606  case kGreen: if (!HadSubMenu) {
3607  cRemote::Put(kAudio, true);
3608  state = osEnd;
3609  }
3610  break;
3611  case kYellow: if (!HadSubMenu)
3613  break;
3614  case kBlue: if (!HadSubMenu)
3616  break;
3617  default: break;
3618  }
3619  }
3620  if (menu) {
3621  if (menu->IsMenu())
3622  return AddSubMenu((cOsdMenu *) menu);
3623  pluginOsdObject = menu;
3624  return osPlugin;
3625  }
3626  if (!HasSubMenu() && Update(HadSubMenu))
3627  Display();
3628  if (Key != kNone) {
3629  if (I18nCurrentLanguage() != osdLanguage) {
3630  Set();
3631  if (!HasSubMenu())
3632  Display();
3633  }
3634  }
3635  return state;
3636 }
3637 
3638 // --- SetTrackDescriptions --------------------------------------------------
3639 
3640 static void SetTrackDescriptions(int LiveChannel)
3641 {
3643  const cComponents *Components = NULL;
3644  cSchedulesLock SchedulesLock;
3645  if (LiveChannel) {
3646  cChannel *Channel = Channels.GetByNumber(LiveChannel);
3647  if (Channel) {
3648  const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
3649  if (Schedules) {
3650  const cSchedule *Schedule = Schedules->GetSchedule(Channel);
3651  if (Schedule) {
3652  const cEvent *Present = Schedule->GetPresentEvent();
3653  if (Present)
3654  Components = Present->Components();
3655  }
3656  }
3657  }
3658  }
3659  else if (cReplayControl::NowReplaying()) {
3660  cThreadLock RecordingsLock(&Recordings);
3662  if (Recording)
3663  Components = Recording->Info()->Components();
3664  }
3665  if (Components) {
3666  int indexAudio = 0;
3667  int indexDolby = 0;
3668  int indexSubtitle = 0;
3669  for (int i = 0; i < Components->NumComponents(); i++) {
3670  const tComponent *p = Components->Component(i);
3671  switch (p->stream) {
3672  case 2: if (p->type == 0x05)
3673  cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, LiveChannel ? NULL : p->language, p->description);
3674  else
3675  cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, indexAudio++, 0, LiveChannel ? NULL : p->language, p->description);
3676  break;
3677  case 3: cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, indexSubtitle++, 0, LiveChannel ? NULL : p->language, p->description);
3678  break;
3679  case 4: cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, LiveChannel ? NULL : p->language, p->description);
3680  break;
3681  default: ;
3682  }
3683  }
3684  }
3685 }
3686 
3687 // --- cDisplayChannel -------------------------------------------------------
3688 
3690 
3691 cDisplayChannel::cDisplayChannel(int Number, bool Switched)
3692 :cOsdObject(true)
3693 {
3694  currentDisplayChannel = this;
3695  group = -1;
3696  withInfo = !Switched || Setup.ShowInfoOnChSwitch;
3698  number = 0;
3699  timeout = Switched || Setup.TimeoutRequChInfo;
3700  channel = Channels.GetByNumber(Number);
3701  lastPresent = lastFollowing = NULL;
3702  if (channel) {
3703  DisplayChannel();
3704  DisplayInfo();
3705  displayChannel->Flush();
3706  }
3707  lastTime.Set();
3708 }
3709 
3711 :cOsdObject(true)
3712 {
3713  currentDisplayChannel = this;
3714  group = -1;
3715  number = 0;
3716  timeout = true;
3717  lastPresent = lastFollowing = NULL;
3718  lastTime.Set();
3722  ProcessKey(FirstKey);
3723 }
3724 
3726 {
3727  delete displayChannel;
3729  currentDisplayChannel = NULL;
3730 }
3731 
3733 {
3736  lastPresent = lastFollowing = NULL;
3737 }
3738 
3740 {
3741  if (withInfo && channel) {
3742  cSchedulesLock SchedulesLock;
3743  const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
3744  if (Schedules) {
3745  const cSchedule *Schedule = Schedules->GetSchedule(channel);
3746  if (Schedule) {
3747  const cEvent *Present = Schedule->GetPresentEvent();
3748  const cEvent *Following = Schedule->GetFollowingEvent();
3749  if (Present != lastPresent || Following != lastFollowing) {
3751  displayChannel->SetEvents(Present, Following);
3752  cStatus::MsgOsdProgramme(Present ? Present->StartTime() : 0, Present ? Present->Title() : NULL, Present ? Present->ShortText() : NULL, Following ? Following->StartTime() : 0, Following ? Following->Title() : NULL, Following ? Following->ShortText() : NULL);
3753  lastPresent = Present;
3754  lastFollowing = Following;
3755  }
3756  }
3757  }
3758  }
3759 }
3760 
3762 {
3763  DisplayChannel();
3764  displayChannel->SetEvents(NULL, NULL);
3765 }
3766 
3768 {
3769  if (Direction) {
3770  while (Channel) {
3771  Channel = Direction > 0 ? Channels.Next(Channel) : Channels.Prev(Channel);
3772  if (!Channel && Setup.ChannelsWrap)
3773  Channel = Direction > 0 ? Channels.First() : Channels.Last();
3774  if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, LIVEPRIORITY, true, true))
3775  return Channel;
3776  }
3777  }
3778  return NULL;
3779 }
3780 
3782 {
3783  cChannel *NewChannel = NULL;
3784  if (Key != kNone)
3785  lastTime.Set();
3786  switch (int(Key)) {
3787  case k0:
3788  if (number == 0) {
3789  // keep the "Toggle channels" function working
3790  cRemote::Put(Key);
3791  return osEnd;
3792  }
3793  case k1 ... k9:
3794  group = -1;
3795  if (number >= 0) {
3796  if (number > Channels.MaxNumber())
3797  number = Key - k0;
3798  else
3799  number = number * 10 + Key - k0;
3801  Refresh();
3802  withInfo = false;
3803  // Lets see if there can be any useful further input:
3804  int n = channel ? number * 10 : 0;
3805  int m = 10;
3806  cChannel *ch = channel;
3807  while (ch && (ch = Channels.Next(ch)) != NULL) {
3808  if (!ch->GroupSep()) {
3809  if (n <= ch->Number() && ch->Number() < n + m) {
3810  n = 0;
3811  break;
3812  }
3813  if (ch->Number() > n) {
3814  n *= 10;
3815  m *= 10;
3816  }
3817  }
3818  }
3819  if (n > 0) {
3820  // This channel is the only one that fits the input, so let's take it right away:
3821  NewChannel = channel;
3822  withInfo = true;
3823  number = 0;
3824  Refresh();
3825  }
3826  }
3827  break;
3828  case kLeft|k_Repeat:
3829  case kLeft:
3830  case kRight|k_Repeat:
3831  case kRight:
3832  case kNext|k_Repeat:
3833  case kNext:
3834  case kPrev|k_Repeat:
3835  case kPrev:
3836  withInfo = false;
3837  number = 0;
3838  if (group < 0) {
3840  if (channel)
3841  group = channel->Index();
3842  }
3843  if (group >= 0) {
3844  int SaveGroup = group;
3845  if (NORMALKEY(Key) == kRight || NORMALKEY(Key) == kNext)
3847  else
3848  group = Channels.GetPrevGroup(group < 1 ? 1 : group);
3849  if (group < 0)
3850  group = SaveGroup;
3852  if (channel) {
3853  Refresh();
3854  if (!channel->GroupSep())
3855  group = -1;
3856  }
3857  }
3858  break;
3859  case kUp|k_Repeat:
3860  case kUp:
3861  case kDown|k_Repeat:
3862  case kDown:
3863  case kChanUp|k_Repeat:
3864  case kChanUp:
3865  case kChanDn|k_Repeat:
3866  case kChanDn: {
3867  eKeys k = NORMALKEY(Key);
3868  cChannel *ch = NextAvailableChannel(channel, (k == kUp || k == kChanUp) ? 1 : -1);
3869  if (ch)
3870  channel = ch;
3871  else if (channel && channel->Number() != cDevice::CurrentChannel())
3872  Key = k; // immediately switches channel when hitting the beginning/end of the channel list with k_Repeat
3873  }
3874  // no break here
3875  case kUp|k_Release:
3876  case kDown|k_Release:
3877  case kChanUp|k_Release:
3878  case kChanDn|k_Release:
3879  case kNext|k_Release:
3880  case kPrev|k_Release:
3881  if (!(Key & k_Repeat) && channel && channel->Number() != cDevice::CurrentChannel())
3882  NewChannel = channel;
3883  withInfo = true;
3884  group = -1;
3885  number = 0;
3886  Refresh();
3887  break;
3888  case kNone:
3891  if (channel)
3892  NewChannel = channel;
3893  withInfo = true;
3894  number = 0;
3895  Refresh();
3896  lastTime.Set();
3897  }
3898  break;
3899  //TODO
3900  //XXX case kGreen: return osEventNow;
3901  //XXX case kYellow: return osEventNext;
3902  case kOk:
3903  if (group >= 0) {
3905  if (channel)
3906  NewChannel = channel;
3907  withInfo = true;
3908  group = -1;
3909  Refresh();
3910  }
3911  else if (number > 0) {
3913  if (channel)
3914  NewChannel = channel;
3915  withInfo = true;
3916  number = 0;
3917  Refresh();
3918  }
3919  else
3920  return osEnd;
3921  break;
3922  default:
3923  if ((Key & (k_Repeat | k_Release)) == 0) {
3924  cRemote::Put(Key);
3925  return osEnd;
3926  }
3927  };
3928  if (!timeout || lastTime.Elapsed() < (uint64_t)(Setup.ChannelInfoTime * 1000)) {
3929  if (Key == kNone && !number && group < 0 && !NewChannel && channel && channel->Number() != cDevice::CurrentChannel()) {
3930  // makes sure a channel switch through the SVDRP CHAN command is displayed
3932  Refresh();
3933  lastTime.Set();
3934  }
3935  DisplayInfo();
3936  displayChannel->Flush();
3937  if (NewChannel) {
3938  SetTrackDescriptions(NewChannel->Number()); // to make them immediately visible in the channel display
3939  Channels.SwitchTo(NewChannel->Number());
3940  SetTrackDescriptions(NewChannel->Number()); // switching the channel has cleared them
3941  channel = NewChannel;
3942  }
3943  return osContinue;
3944  }
3945  return osEnd;
3946 }
3947 
3948 // --- cDisplayVolume --------------------------------------------------------
3949 
3950 #define VOLUMETIMEOUT 1000 //ms
3951 #define MUTETIMEOUT 5000 //ms
3952 
3954 
3956 :cOsdObject(true)
3957 {
3958  currentDisplayVolume = this;
3961  Show();
3962 }
3963 
3965 {
3966  delete displayVolume;
3967  currentDisplayVolume = NULL;
3968 }
3969 
3971 {
3973 }
3974 
3976 {
3977  if (!currentDisplayVolume)
3978  new cDisplayVolume;
3979  return currentDisplayVolume;
3980 }
3981 
3983 {
3986 }
3987 
3989 {
3990  switch (int(Key)) {
3991  case kVolUp|k_Repeat:
3992  case kVolUp:
3993  case kVolDn|k_Repeat:
3994  case kVolDn:
3995  Show();
3997  break;
3998  case kMute:
3999  if (cDevice::PrimaryDevice()->IsMute()) {
4000  Show();
4002  }
4003  else
4004  timeout.Set();
4005  break;
4006  case kNone: break;
4007  default: if ((Key & k_Release) == 0) {
4008  cRemote::Put(Key);
4009  return osEnd;
4010  }
4011  }
4012  return timeout.TimedOut() ? osEnd : osContinue;
4013 }
4014 
4015 // --- cDisplayTracks --------------------------------------------------------
4016 
4017 #define TRACKTIMEOUT 5000 //ms
4018 
4020 
4022 :cOsdObject(true)
4023 {
4025  SetTrackDescriptions(!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring() ? cDevice::CurrentChannel() : 0);
4026  currentDisplayTracks = this;
4027  numTracks = track = 0;
4029  eTrackType CurrentAudioTrack = cDevice::PrimaryDevice()->GetCurrentAudioTrack();
4030  for (int i = ttAudioFirst; i <= ttDolbyLast; i++) {
4031  const tTrackId *TrackId = cDevice::PrimaryDevice()->GetTrack(eTrackType(i));
4032  if (TrackId && TrackId->id) {
4033  types[numTracks] = eTrackType(i);
4034  descriptions[numTracks] = strdup(*TrackId->description ? TrackId->description : *TrackId->language ? TrackId->language : *itoa(i));
4035  if (i == CurrentAudioTrack)
4036  track = numTracks;
4037  numTracks++;
4038  }
4039  }
4040  descriptions[numTracks] = NULL;
4043  Show();
4044 }
4045 
4047 {
4048  delete displayTracks;
4049  currentDisplayTracks = NULL;
4050  for (int i = 0; i < numTracks; i++)
4051  free(descriptions[i]);
4053 }
4054 
4056 {
4057  int ac = IS_AUDIO_TRACK(types[track]) ? audioChannel : -1;
4060  displayTracks->Flush();
4063 }
4064 
4066 {
4067  if (cDevice::PrimaryDevice()->NumAudioTracks() > 0) {
4068  if (!currentDisplayTracks)
4069  new cDisplayTracks;
4070  return currentDisplayTracks;
4071  }
4072  Skins.Message(mtWarning, tr("No audio available!"));
4073  return NULL;
4074 }
4075 
4077 {
4080 }
4081 
4083 {
4084  int oldTrack = track;
4085  int oldAudioChannel = audioChannel;
4086  switch (int(Key)) {
4087  case kUp|k_Repeat:
4088  case kUp:
4089  case kDown|k_Repeat:
4090  case kDown:
4091  if (NORMALKEY(Key) == kUp && track > 0)
4092  track--;
4093  else if (NORMALKEY(Key) == kDown && track < numTracks - 1)
4094  track++;
4096  break;
4097  case kLeft|k_Repeat:
4098  case kLeft:
4099  case kRight|k_Repeat:
4100  case kRight: if (IS_AUDIO_TRACK(types[track])) {
4101  static int ac[] = { 1, 0, 2 };
4103  if (NORMALKEY(Key) == kLeft && audioChannel > 0)
4104  audioChannel--;
4105  else if (NORMALKEY(Key) == kRight && audioChannel < 2)
4106  audioChannel++;
4107  audioChannel = ac[audioChannel];
4109  }
4110  break;
4111  case kAudio|k_Repeat:
4112  case kAudio:
4113  if (++track >= numTracks)
4114  track = 0;
4116  break;
4117  case kOk:
4118  if (types[track] != cDevice::PrimaryDevice()->GetCurrentAudioTrack())
4119  oldTrack = -1; // make sure we explicitly switch to that track
4120  timeout.Set();
4121  break;
4122  case kNone: break;
4123  default: if ((Key & k_Release) == 0)
4124  return osEnd;
4125  }
4126  if (track != oldTrack || audioChannel != oldAudioChannel)
4127  Show();
4128  if (track != oldTrack) {
4131  }
4132  if (audioChannel != oldAudioChannel)
4134  return timeout.TimedOut() ? osEnd : osContinue;
4135 }
4136 
4137 // --- cDisplaySubtitleTracks ------------------------------------------------
4138 
4140 
4142 :cOsdObject(true)
4143 {
4144  SetTrackDescriptions(!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring() ? cDevice::CurrentChannel() : 0);
4145  currentDisplayTracks = this;
4146  numTracks = track = 0;
4147  types[numTracks] = ttNone;
4148  descriptions[numTracks] = strdup(tr("No subtitles"));
4149  numTracks++;
4150  eTrackType CurrentSubtitleTrack = cDevice::PrimaryDevice()->GetCurrentSubtitleTrack();
4151  for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) {
4152  const tTrackId *TrackId = cDevice::PrimaryDevice()->GetTrack(eTrackType(i));
4153  if (TrackId && TrackId->id) {
4154  types[numTracks] = eTrackType(i);
4155  descriptions[numTracks] = strdup(*TrackId->description ? TrackId->description : *TrackId->language ? TrackId->language : *itoa(i));
4156  if (i == CurrentSubtitleTrack)
4157  track = numTracks;
4158  numTracks++;
4159  }
4160  }
4161  descriptions[numTracks] = NULL;
4163  displayTracks = Skins.Current()->DisplayTracks(tr("Button$Subtitles"), numTracks, descriptions);
4164  Show();
4165 }
4166 
4168 {
4169  delete displayTracks;
4170  currentDisplayTracks = NULL;
4171  for (int i = 0; i < numTracks; i++)
4172  free(descriptions[i]);
4174 }
4175 
4177 {
4179  displayTracks->Flush();
4181 }
4182 
4184 {
4185  if (cDevice::PrimaryDevice()->NumSubtitleTracks() > 0) {
4186  if (!currentDisplayTracks)
4188  return currentDisplayTracks;
4189  }
4190  Skins.Message(mtWarning, tr("No subtitles available!"));
4191  return NULL;
4192 }
4193 
4195 {
4198 }
4199 
4201 {
4202  int oldTrack = track;
4203  switch (int(Key)) {
4204  case kUp|k_Repeat:
4205  case kUp:
4206  case kDown|k_Repeat:
4207  case kDown:
4208  if (NORMALKEY(Key) == kUp && track > 0)
4209  track--;
4210  else if (NORMALKEY(Key) == kDown && track < numTracks - 1)
4211  track++;
4213  break;
4214  case kSubtitles|k_Repeat:
4215  case kSubtitles:
4216  if (++track >= numTracks)
4217  track = 0;
4219  break;
4220  case kOk:
4221  if (types[track] != cDevice::PrimaryDevice()->GetCurrentSubtitleTrack())
4222  oldTrack = -1; // make sure we explicitly switch to that track
4223  timeout.Set();
4224  break;
4225  case kNone: break;
4226  default: if ((Key & k_Release) == 0)
4227  return osEnd;
4228  }
4229  if (track != oldTrack) {
4230  Show();
4232  }
4233  return timeout.TimedOut() ? osEnd : osContinue;
4234 }
4235 
4236 // --- cRecordControl --------------------------------------------------------
4237 
4238 cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
4239 {
4240  // Whatever happens here, the timers will be modified in some way...
4241  Timers.SetModified();
4242  // We're going to manipulate an event here, so we need to prevent
4243  // others from modifying any EPG data:
4244  cSchedulesLock SchedulesLock;
4245  cSchedules::Schedules(SchedulesLock);
4246 
4247  event = NULL;
4248  fileName = NULL;
4249  recorder = NULL;
4250  device = Device;
4251  if (!device) device = cDevice::PrimaryDevice();//XXX
4252  timer = Timer;
4253  if (!timer) {
4254  timer = new cTimer(true, Pause);
4255  Timers.Add(timer);
4256  instantId = cString::sprintf(cDevice::NumDevices() > 1 ? "%s - %d" : "%s", timer->Channel()->Name(), device->CardIndex() + 1);
4257  }
4258  timer->SetPending(true);
4259  timer->SetRecording(true);
4260  event = timer->Event();
4261 
4262  if (event || GetEvent())
4263  dsyslog("Title: '%s' Subtitle: '%s'", event->Title(), event->ShortText());
4264  cRecording Recording(timer, event);
4265  fileName = strdup(Recording.FileName());
4266 
4267  // crude attempt to avoid duplicate recordings:
4269  isyslog("already recording: '%s'", fileName);
4270  if (Timer) {
4271  timer->SetPending(false);
4272  timer->SetRecording(false);
4273  timer->OnOff();
4274  }
4275  else {
4276  Timers.Del(timer);
4277  if (!cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
4279  }
4280  timer = NULL;
4281  return;
4282  }
4283 
4285  isyslog("record %s", fileName);
4286  if (MakeDirs(fileName, true)) {
4287  const cChannel *ch = timer->Channel();
4288  recorder = new cRecorder(fileName, ch, timer->Priority());
4289  if (device->AttachReceiver(recorder)) {
4290  Recording.WriteInfo();
4291  cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true);
4292  if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
4295  if (Timer && !Timer->IsSingleEvent()) {
4296  char *Directory = strdup(fileName);
4297  // going up two directory levels to get the series folder
4298  if (char *p = strrchr(Directory, '/')) {
4299  while (p > Directory && *--p != '/')
4300  ;
4301  *p = 0;
4302  if (!HasRecordingsSortMode(Directory)) {
4303  dsyslog("setting %s to be sorted by time", Directory);
4304  SetRecordingsSortMode(Directory, rsmTime);
4305  }
4306  }
4307  free(Directory);
4308  }
4309  return;
4310  }
4311  else
4313  }
4314  else
4316  if (!Timer) {
4317  Timers.Del(timer);
4318  timer = NULL;
4319  }
4320 }
4321 
4323 {
4324  Stop();
4325  free(fileName);
4326 }
4327 
4328 #define INSTANT_REC_EPG_LOOKAHEAD 300 // seconds to look into the EPG data for an instant recording
4329 
4331 {
4332  const cChannel *channel = timer->Channel();
4334  for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) {
4335  {
4336  cSchedulesLock SchedulesLock;
4337  const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
4338  if (Schedules) {
4339  const cSchedule *Schedule = Schedules->GetSchedule(channel);
4340  if (Schedule) {
4341  event = Schedule->GetEventAround(Time);
4342  if (event) {
4343  if (seconds > 0)
4344  dsyslog("got EPG info after %d seconds", seconds);
4345  return true;
4346  }
4347  }
4348  }
4349  }
4350  if (seconds == 0)
4351  dsyslog("waiting for EPG info...");
4352  cCondWait::SleepMs(1000);
4353  }
4354  dsyslog("no EPG info available");
4355  return false;
4356 }
4357 
4358 void cRecordControl::Stop(bool ExecuteUserCommand)
4359 {
4360  if (timer) {
4362  timer->SetRecording(false);
4363  timer = NULL;
4364  cStatus::MsgRecording(device, NULL, fileName, false);
4365  if (ExecuteUserCommand)
4367  Timers.SetModified();
4368  }
4369 }
4370 
4372 {
4373  if (!recorder || !recorder->IsAttached() || !timer || !timer->Matches(t)) {
4374  if (timer)
4375  timer->SetPending(false);
4376  return false;
4377  }
4379  return true;
4380 }
4381 
4382 // --- cRecordControls -------------------------------------------------------
4383 
4385 int cRecordControls::state = 0;
4386 
4387 bool cRecordControls::Start(cTimer *Timer, bool Pause)
4388 {
4389  static time_t LastNoDiskSpaceMessage = 0;
4390  int FreeMB = 0;
4391  if (Timer) {
4392  AssertFreeDiskSpace(Timer->Priority(), !Timer->Pending());
4393  Timer->SetPending(true);
4394  }
4395  VideoDiskSpace(&FreeMB);
4396  if (FreeMB < MINFREEDISK) {
4397  if (!Timer || time(NULL) - LastNoDiskSpaceMessage > NODISKSPACEDELTA) {
4398  isyslog("not enough disk space to start recording%s%s", Timer ? " timer " : "", Timer ? *Timer->ToDescr() : "");
4399  Skins.Message(mtWarning, tr("Not enough disk space to start recording!"));
4400  LastNoDiskSpaceMessage = time(NULL);
4401  }
4402  return false;
4403  }
4404  LastNoDiskSpaceMessage = 0;
4405 
4406  ChangeState();
4407  int ch = Timer ? Timer->Channel()->Number() : cDevice::CurrentChannel();
4408  cChannel *channel = Channels.GetByNumber(ch);
4409 
4410  if (channel) {
4411  int Priority = Timer ? Timer->Priority() : Pause ? Setup.PausePriority : Setup.DefaultPriority;
4412  cDevice *device = cDevice::GetDevice(channel, Priority, false);
4413  if (device) {
4414  dsyslog("switching device %d to channel %d", device->DeviceNumber() + 1, channel->Number());
4415  if (!device->SwitchChannel(channel, false)) {
4417  return false;
4418  }
4419  if (!Timer || Timer->Matches()) {
4420  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
4421  if (!RecordControls[i]) {
4422  RecordControls[i] = new cRecordControl(device, Timer, Pause);
4423  return RecordControls[i]->Process(time(NULL));
4424  }
4425  }
4426  }
4427  }
4428  else if (!Timer || !Timer->Pending()) {
4429  isyslog("no free DVB device to record channel %d!", ch);
4430  Skins.Message(mtError, tr("No free DVB device to record!"));
4431  }
4432  }
4433  else
4434  esyslog("ERROR: channel %d not defined!", ch);
4435  return false;
4436 }
4437 
4438 void cRecordControls::Stop(const char *InstantId)
4439 {
4440  ChangeState();
4441  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
4442  if (RecordControls[i]) {
4443  const char *id = RecordControls[i]->InstantId();
4444  if (id && strcmp(id, InstantId) == 0) {
4445  cTimer *timer = RecordControls[i]->Timer();
4446  RecordControls[i]->Stop();
4447  if (timer) {
4448  isyslog("deleting timer %s", *timer->ToDescr());
4449  Timers.Del(timer);
4450  Timers.SetModified();
4451  }
4452  break;
4453  }
4454  }
4455  }
4456 }
4457 
4459 {
4460  Skins.Message(mtStatus, tr("Pausing live video..."));
4461  cReplayControl::SetRecording(NULL); // make sure the new cRecordControl will set cReplayControl::LastReplayed()
4462  if (Start(NULL, true)) {
4463  cReplayControl *rc = new cReplayControl(true);
4464  cControl::Launch(rc);
4465  cControl::Attach();
4466  Skins.Message(mtStatus, NULL);
4467  return true;
4468  }
4469  Skins.Message(mtStatus, NULL);
4470  return false;
4471 }
4472 
4473 const char *cRecordControls::GetInstantId(const char *LastInstantId)
4474 {
4475  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
4476  if (RecordControls[i]) {
4477  if (!LastInstantId && RecordControls[i]->InstantId())
4478  return RecordControls[i]->InstantId();
4479  if (LastInstantId && LastInstantId == RecordControls[i]->InstantId())
4480  LastInstantId = NULL;
4481  }
4482  }
4483  return NULL;
4484 }
4485 
4487 {
4488  if (FileName) {
4489  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
4490  if (RecordControls[i] && strcmp(RecordControls[i]->FileName(), FileName) == 0)
4491  return RecordControls[i];
4492  }
4493  }
4494  return NULL;
4495 }
4496 
4498 {
4499  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
4500  if (RecordControls[i] && RecordControls[i]->Timer() == Timer)
4501  return RecordControls[i];
4502  }
4503  return NULL;
4504 }
4505 
4507 {
4508  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
4509  if (RecordControls[i]) {
4510  if (!RecordControls[i]->Process(t)) {
4512  ChangeState();
4513  }
4514  }
4515  }
4516 }
4517 
4519 {
4520  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
4521  if (RecordControls[i]) {
4522  if (RecordControls[i]->Timer() && RecordControls[i]->Timer()->Channel() == Channel) {
4523  if (RecordControls[i]->Device()->ProvidesTransponder(Channel)) { // avoids retune on devices that don't really access the transponder
4524  isyslog("stopping recording due to modification of channel %d", Channel->Number());
4525  RecordControls[i]->Stop();
4526  // This will restart the recording, maybe even from a different
4527  // device in case conditional access has changed.
4528  ChangeState();
4529  }
4530  }
4531  }
4532  }
4533 }
4534 
4536 {
4537  for (int i = 0; i < MAXRECORDCONTROLS; i++) {
4538  if (RecordControls[i])
4539  return true;
4540  }
4541  return false;
4542 }
4543 
4545 {
4546  for (int i = 0; i < MAXRECORDCONTROLS; i++)
4548  ChangeState();
4549 }
4550 
4552 {
4553  int NewState = state;
4554  bool Result = State != NewState;
4555  State = state;
4556  return Result;
4557 }
4558 
4559 // --- cReplayControl --------------------------------------------------------
4560 
4563 
4565 :cDvbPlayerControl(fileName, PauseLive)
4566 {
4567  cDevice::PrimaryDevice()->SetKeepTracks(PauseLive);
4568  currentReplayControl = this;
4569  displayReplay = NULL;
4570  marksModified = false;
4571  visible = modeOnly = shown = displayFrames = false;
4572  lastCurrent = lastTotal = -1;
4573  lastPlay = lastForward = false;
4574  lastSpeed = -2; // an invalid value
4575  timeoutShow = 0;
4576  timeSearchActive = false;
4577  cRecording Recording(fileName);
4578  cStatus::MsgReplaying(this, Recording.Name(), Recording.FileName(), true);
4579  marks.Load(fileName, Recording.FramesPerSecond(), Recording.IsPesRecording());
4580  SetTrackDescriptions(false);
4583 }
4584 
4586 {
4588  Hide();
4589  cStatus::MsgReplaying(this, NULL, fileName, false);
4590  Stop();
4591  if (currentReplayControl == this)
4592  currentReplayControl = NULL;
4593 }
4594 
4596 {
4597  if (Setup.DelTimeshiftRec && *fileName) {
4599  if (rc && rc->InstantId()) {
4600  if (Active()) {
4601  if (Setup.DelTimeshiftRec == 2 || Interface->Confirm(tr("Delete timeshift recording?"))) {
4602  cTimer *timer = rc->Timer();
4603  rc->Stop(false); // don't execute user command
4604  if (timer) {
4605  isyslog("deleting timer %s", *timer->ToDescr());
4606  Timers.Del(timer);
4607  Timers.SetModified();
4608  }
4610  cRecording *recording = Recordings.GetByName(fileName);
4611  if (recording) {
4612  if (recording->Delete()) {
4615  }
4616  else
4617  Skins.Message(mtError, tr("Error while deleting recording!"));
4618  }
4619  return;
4620  }
4621  }
4622  }
4623  }
4625 }
4626 
4627 void cReplayControl::SetRecording(const char *FileName)
4628 {
4629  fileName = FileName;
4630 }
4631 
4633 {
4634  return currentReplayControl ? *fileName : NULL;
4635 }
4636 
4638 {
4640  fileName = NULL;
4641  return fileName;
4642 }
4643 
4644 void cReplayControl::ClearLastReplayed(const char *FileName)
4645 {
4646  if (*fileName && FileName && strcmp(fileName, FileName) == 0)
4647  fileName = NULL;
4648 }
4649 
4650 void cReplayControl::ShowTimed(int Seconds)
4651 {
4652  if (modeOnly)
4653  Hide();
4654  if (!visible) {
4655  shown = ShowProgress(true);
4656  timeoutShow = (shown && Seconds > 0) ? time(NULL) + Seconds : 0;
4657  }
4658  else if (timeoutShow && Seconds > 0)
4659  timeoutShow = time(NULL) + Seconds;
4660 }
4661 
4663 {
4664  ShowTimed();
4665 }
4666 
4668 {
4669  if (visible) {
4670  delete displayReplay;
4671  displayReplay = NULL;
4672  SetNeedsFastResponse(false);
4673  visible = false;
4674  modeOnly = false;
4675  lastPlay = lastForward = false;
4676  lastSpeed = -2; // an invalid value
4677  timeSearchActive = false;
4678  timeoutShow = 0;
4679  }
4680  if (marksModified) {
4681  marks.Save();
4682  marksModified = false;
4683  }
4684 }
4685 
4687 {
4688  if (visible || Setup.ShowReplayMode && !cOsd::IsOpen()) {
4689  bool Play, Forward;
4690  int Speed;
4691  if (GetReplayMode(Play, Forward, Speed) && (!visible || Play != lastPlay || Forward != lastForward || Speed != lastSpeed)) {
4692  bool NormalPlay = (Play && Speed == -1);
4693 
4694  if (!visible) {
4695  if (NormalPlay)
4696  return; // no need to do indicate ">" unless there was a different mode displayed before
4697  visible = modeOnly = true;
4699  }
4700 
4701  if (modeOnly && !timeoutShow && NormalPlay)
4702  timeoutShow = time(NULL) + MODETIMEOUT;
4703  displayReplay->SetMode(Play, Forward, Speed);
4704  lastPlay = Play;
4705  lastForward = Forward;
4706  lastSpeed = Speed;
4707  }
4708  }
4709 }
4710 
4712 {
4713  int Current, Total;
4714 
4715  if (GetIndex(Current, Total) && Total > 0) {
4716  if (!visible) {
4719  SetNeedsFastResponse(true);
4720  visible = true;
4721  }
4722  if (Initial) {
4723  if (*fileName) {
4724  if (cRecording *Recording = Recordings.GetByName(fileName))
4725  displayReplay->SetRecording(Recording);
4726  }
4727  lastCurrent = lastTotal = -1;
4728  }
4729  if (Current != lastCurrent || Total != lastTotal) {
4730  if (Setup.ShowRemainingTime || Total != lastTotal) {
4731  int Index = Total;
4733  Index = Current - Index;
4735  if (!Initial)
4736  displayReplay->Flush();
4737  }
4738  displayReplay->SetProgress(Current, Total);
4739  if (!Initial)
4740  displayReplay->Flush();
4742  displayReplay->Flush();
4743  lastCurrent = Current;
4744  }
4745  lastTotal = Total;
4746  ShowMode();
4747  return true;
4748  }
4749  return false;
4750 }
4751 
4753 {
4754  char buf[64];
4755  // TRANSLATORS: note the trailing blank!
4756  strcpy(buf, tr("Jump: "));
4757  int len = strlen(buf);
4758  char h10 = '0' + (timeSearchTime >> 24);
4759  char h1 = '0' + ((timeSearchTime & 0x00FF0000) >> 16);
4760  char m10 = '0' + ((timeSearchTime & 0x0000FF00) >> 8);
4761  char m1 = '0' + (timeSearchTime & 0x000000FF);
4762  char ch10 = timeSearchPos > 3 ? h10 : '-';
4763  char ch1 = timeSearchPos > 2 ? h1 : '-';
4764  char cm10 = timeSearchPos > 1 ? m10 : '-';
4765  char cm1 = timeSearchPos > 0 ? m1 : '-';
4766  sprintf(buf + len, "%c%c:%c%c", ch10, ch1, cm10, cm1);
4767  displayReplay->SetJump(buf);
4768 }
4769 
4771 {
4772 #define STAY_SECONDS_OFF_END 10
4773  int Seconds = (timeSearchTime >> 24) * 36000 + ((timeSearchTime & 0x00FF0000) >> 16) * 3600 + ((timeSearchTime & 0x0000FF00) >> 8) * 600 + (timeSearchTime & 0x000000FF) * 60;
4774  int Current = int(round(lastCurrent / FramesPerSecond()));
4775  int Total = int(round(lastTotal / FramesPerSecond()));
4776  switch (Key) {
4777  case k0 ... k9:
4778  if (timeSearchPos < 4) {
4779  timeSearchTime <<= 8;
4780  timeSearchTime |= Key - k0;
4781  timeSearchPos++;
4783  }
4784  break;
4785  case kFastRew:
4786  case kLeft:
4787  case kFastFwd:
4788  case kRight: {
4789  int dir = ((Key == kRight || Key == kFastFwd) ? 1 : -1);
4790  if (dir > 0)
4791  Seconds = min(Total - Current - STAY_SECONDS_OFF_END, Seconds);
4792  SkipSeconds(Seconds * dir);
4793  timeSearchActive = false;
4794  }
4795  break;
4796  case kPlayPause:
4797  case kPlay:
4798  case kUp:
4799  case kPause:
4800  case kDown:
4801  case kOk:
4802  if (timeSearchPos > 0) {
4803  Seconds = min(Total - STAY_SECONDS_OFF_END, Seconds);
4804  Goto(SecondsToFrames(Seconds, FramesPerSecond()), Key == kDown || Key == kPause || Key == kOk);
4805  }
4806  timeSearchActive = false;
4807  break;
4808  default:
4809  if (!(Key & k_Flags)) // ignore repeat/release keys
4810  timeSearchActive = false;
4811  break;
4812  }
4813 
4814  if (!timeSearchActive) {
4815  if (timeSearchHide)
4816  Hide();
4817  else
4818  displayReplay->SetJump(NULL);
4819  ShowMode();
4820  }
4821 }
4822 
4824 {
4826  timeSearchHide = false;
4827  if (modeOnly)
4828  Hide();
4829  if (!visible) {
4830  Show();
4831  if (visible)
4832  timeSearchHide = true;
4833  else
4834  return;
4835  }
4836  timeoutShow = 0;
4838  timeSearchActive = true;
4839 }
4840 
4842 {
4843  int Current, Total;
4844  if (GetIndex(Current, Total, true)) {
4845  lastCurrent = -1; // triggers redisplay
4846  if (cMark *m = marks.Get(Current))
4847  marks.Del(m);
4848  else {
4849  marks.Add(Current);
4850  bool Play, Forward;
4851  int Speed;
4852  if (Setup.PauseOnMarkSet || GetReplayMode(Play, Forward, Speed) && !Play) {
4853  Goto(Current, true);
4854  displayFrames = true;
4855  }
4856  }
4857  ShowTimed(2);
4858  marksModified = true;
4859  }
4860 }
4861 
4862 void cReplayControl::MarkJump(bool Forward)
4863 {
4864  int Current, Total;
4865  if (GetIndex(Current, Total)) {
4866  if (marks.Count()) {
4867  if (cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current)) {
4868  Goto(m->Position(), true);
4869  displayFrames = true;
4870  return;
4871  }
4872  }
4873  // There are either no marks at all, or we already were at the first or last one,
4874  // so jump to the very beginning or end:
4875  Goto(Forward ? Total : 0, true);
4876  }
4877 }
4878 
4879 void cReplayControl::MarkMove(bool Forward)
4880 {
4881  int Current, Total;
4882  if (GetIndex(Current, Total)) {
4883  if (cMark *m = marks.Get(Current)) {
4884  displayFrames = true;
4885  int p = SkipFrames(Forward ? 1 : -1);
4886  cMark *m2;
4887  if (Forward) {
4888  while ((m2 = marks.Next(m)) != NULL && m2->Position() == m->Position())
4889  m = m2;
4890  }
4891  else {
4892  while ((m2 = marks.Prev(m)) != NULL && m2->Position() == m->Position())
4893  m = m2;
4894  }
4895  m->SetPosition(p);
4896  Goto(m->Position(), true);
4897  marksModified = true;
4898  }
4899  }
4900 }
4901 
4903 {
4904  if (*fileName) {
4905  Hide();
4906  if (!cCutter::Active()) {
4907  if (!marks.Count())
4908  Skins.Message(mtError, tr("No editing marks defined!"));
4909  else if (!marks.GetNumSequences())
4910  Skins.Message(mtError, tr("No editing sequences defined!"));
4911  else if (!cCutter::Start(fileName))
4912  Skins.Message(mtError, tr("Can't start editing process!"));
4913  else
4914  Skins.Message(mtInfo, tr("Editing process started"));
4915  }
4916  else
4917  Skins.Message(mtError, tr("Editing process already active!"));
4918  ShowMode();
4919  }
4920 }
4921 
4923 {
4924  int Current, Total;
4925  if (GetIndex(Current, Total)) {
4926  cMark *m = marks.Get(Current);
4927  if (!m)
4928  m = marks.GetNext(Current);
4929  if (m) {
4930  if ((m->Index() & 0x01) != 0)
4931  m = marks.Next(m);
4932  if (m) {
4934  Play();
4935  }
4936  }
4937  }
4938 }
4939 
4941 {
4943  if (Recording)
4944  return new cMenuRecording(Recording, false);
4945  return NULL;
4946 }
4947 
4949 {
4950  if (const cRecording *Recording = Recordings.GetByName(LastReplayed()))
4951  return Recording;
4952  return NULL;
4953 }
4954 
4956 {
4957  if (!Active())
4958  return osEnd;
4959  if (Key == kNone && !marksModified)
4960  marks.Update();
4961  if (visible) {
4962  if (timeoutShow && time(NULL) > timeoutShow) {
4963  Hide();
4964  ShowMode();
4965  timeoutShow = 0;
4966  }
4967  else if (modeOnly)
4968  ShowMode();
4969  else
4970  shown = ShowProgress(!shown) || shown;
4971  }
4972  bool DisplayedFrames = displayFrames;
4973  displayFrames = false;
4974  if (timeSearchActive && Key != kNone) {
4975  TimeSearchProcess(Key);
4976  return osContinue;
4977  }
4978  if (Key == kPlayPause) {
4979  bool Play, Forward;
4980  int Speed;
4981  GetReplayMode(Play, Forward, Speed);
4982  if (Speed >= 0)
4983  Key = Play ? kPlay : kPause;
4984  else
4985  Key = Play ? kPause : kPlay;
4986  }
4987  bool DoShowMode = true;
4988  switch (int(Key)) {
4989  // Positioning:
4990  case kPlay:
4991  case kUp: Play(); break;
4992  case kPause:
4993  case kDown: Pause(); break;
4994  case kFastRew|k_Release:
4995  case kLeft|k_Release:
4996  if (Setup.MultiSpeedMode) break;
4997  case kFastRew:
4998  case kLeft: Backward(); break;
4999  case kFastFwd|k_Release:
5000  case kRight|k_Release:
5001  if (Setup.MultiSpeedMode) break;
5002  case kFastFwd:
5003  case kRight: Forward(); break;
5004  case kRed: TimeSearch(); break;
5005  case kGreen|k_Repeat:
5006  case kGreen: SkipSeconds(-60); break;
5007  case kYellow|k_Repeat:
5008  case kYellow: SkipSeconds( 60); break;
5009  case kStop:
5010  case kBlue: Hide();
5011  Stop();
5012  return osEnd;
5013  default: {
5014  DoShowMode = false;
5015  switch (int(Key)) {
5016  // Editing:
5017  case kMarkToggle: MarkToggle(); break;
5018  case kPrev|k_Repeat:
5019  case kPrev:
5020  case kMarkJumpBack|k_Repeat:
5021  case kMarkJumpBack: MarkJump(false); break;
5022  case kNext|k_Repeat:
5023  case kNext:
5025  case kMarkJumpForward: MarkJump(true); break;
5026  case kMarkMoveBack|k_Repeat:
5027  case kMarkMoveBack: MarkMove(false); break;
5029  case kMarkMoveForward: MarkMove(true); break;
5030  case kEditCut: EditCut(); break;
5031  case kEditTest: EditTest(); break;
5032  default: {
5033  displayFrames = DisplayedFrames;
5034  switch (Key) {
5035  // Menu control:
5036  case kOk: if (visible && !modeOnly) {
5037  Hide();
5038  DoShowMode = true;
5039  }
5040  else
5041  Show();
5042  break;
5043  case kBack: Hide();
5044  Stop();
5045  return osRecordings;
5046  default: return osUnknown;
5047  }
5048  }
5049  }
5050  }
5051  }
5052  if (DoShowMode)
5053  ShowMode();
5054  return osContinue;
5055 }
int Find(const char *s) const
Definition: tools.c:1415
cDisplaySubtitleTracks(void)
Definition: menu.c:4141
void Setup(void)
Definition: menu.c:384
void ShowTimed(int Seconds=0)
Definition: menu.c:4650
const cEvent * GetPresentEvent(void) const
Definition: epg.c:921
static int currentChannel
Definition: menu.c:1381
bool Update(void)
Definition: menu.c:1658
static cString fileName
Definition: menu.h:275
cString itoa(int n)
Definition: tools.c:339
static cString ToString(int Code)
Definition: sources.c:40
void SetHelpKeys(void)
Definition: menu.c:1670
static int CurrentChannel(void)
Definition: menu.c:1387
Definition: keys.h:29
bool lastForward
Definition: menu.h:265
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:236
virtual void Scroll(bool Up, bool Page)
If this menu contains a text area that can be scrolled, this function will be called to actually scro...
Definition: skins.c:91
bool Replaying(void) const
Returns true if we are currently replaying.
Definition: device.c:1272
int AntiAlias
Definition: config.h:315
void SetModified(void)
Definition: timers.c:768
Definition: epg.h:71
bool now
Definition: menu.c:1376
int DeviceNumber(void) const
Returns the number of this device (0 ... numDevices).
Definition: device.c:196
double OSDHeightP
Definition: config.h:310
static unsigned char buf(long p)
Definition: vdr-genindex.c:63
virtual void SetTrack(int Index, const char *const *Tracks)=0
< This class implements the track display.
virtual void Show(void)
Definition: menu.c:4662
int helpKeys
Definition: menu.c:1544
int helpKeys
Definition: menu.h:199
cOsdItem * stopReplayItem
Definition: menu.h:102
int subFolder
Definition: menu.c:647
cTimer * CurrentTimer(void)
Definition: menu.c:1117
virtual bool SetItemEvent(const cEvent *Event, int Index, bool Current, bool Selectable, const cChannel *Channel, bool WithDate, eTimerMatch TimerMatch)
Sets the item at the given Index to Event.
Definition: skins.h:186
int Position(void) const
Definition: recording.h:220
Definition: skins.h:105
eOSState ProcessKey(eKeys Key)
Definition: menu.c:3988
void DisplayItem(cOsdItem *Item)
Definition: osdbase.c:298
int Vpid(void) const
Definition: channels.h:151
cList< cNestedItem > * commands
Definition: menu.h:58
int Number(void) const
Definition: channels.h:175
static eScheduleSortMode SortMode(void)
Definition: menu.c:1307
virtual void Set(void)
Definition: menuitems.c:82
int tid
Definition: channels.h:120
virtual void Del(int Index)
Definition: osdbase.c:189
int lastCurrent
Definition: menu.h:264
cString DirectoryName(void)
Definition: menu.c:2336
cString DeviceBondings
Definition: config.h:345
Definition: keys.h:37
cMenuFolderItem(cNestedItem *Folder)
Definition: menu.c:632
cChannels Channels
Definition: channels.c:792
Definition: device.h:66
bool isempty(const char *s)
Definition: tools.c:248
cString GetFolder(void)
Definition: menu.c:854
bool IsDirectory(void)
Definition: menu.c:2205
cStringList fontSmlNames
Definition: menu.c:2562
virtual cSkinDisplayVolume * DisplayVolume(void)=0
Creates and returns a new object for displaying the current volume.
const char * Text(void) const
Definition: config.h:196
virtual ~cMenuText()
Definition: menu.c:575
#define dsyslog(a...)
Definition: tools.h:36
cString AddDirectory(const char *DirName, const char *FileName)
Definition: tools.c:301
int Index(void) const
Definition: tools.c:1920
int StandardCompliance
Definition: config.h:277
void Setup(void)
Definition: menu.c:2736
int fontOsdIndex
Definition: menu.c:2563
cChannel * Channel(void)
Definition: menu.c:291
const char * videoDisplayFormatTexts[3]
Definition: menu.c:2814
#define CA_ENCRYPTED_MIN
Definition: channels.h:47
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:4955
int MultiSpeedMode
Definition: config.h:330
void OnOff(void)
Definition: timers.c:676
int originalNumAudioLanguages
Definition: menu.c:2809
eOSState Switch(void)
Definition: menu.c:1746
static void SetSortMode(eScheduleSortMode SortMode)
Definition: menu.c:1305
double OSDWidthP
Definition: config.h:310
Definition: font.h:23
Definition: keys.h:34
void TimeSearchDisplay(void)
Definition: menu.c:4752
void Set(int Ms=0)
Definition: tools.c:689
bool Confirm(const char *s, int Seconds=10, bool WaitForTimeout=false)
Definition: interface.c:64
time_t lastCamExchange
Definition: menu.c:1939
static void ResetVersions(void)
Definition: epg.c:1233
int GetPrevGroup(int Idx)
Definition: channels.c:849
int MaxNumber(void)
Definition: channels.h:230
int I18nCurrentLanguage(void)
Returns the index of the current language.
Definition: i18n.c:183
void SetRecording(bool Recording)
Definition: timers.c:585
virtual void Store(void)
Definition: menu.c:2541
cList< cNestedItem > * list
Definition: menu.c:644
void DisplayChannel(void)
Definition: menu.c:3732
eOSState Switch(void)
Definition: menu.c:1455
Definition: keys.h:23
void Add(cOsdItem *Item, bool Current=false, cOsdItem *After=NULL)
Definition: osdbase.c:203
int PluginIndex(void)
Definition: menu.c:3239
void MarkToggle(void)
Definition: menu.c:4841
eOSState Record(void)
Definition: menu.c:1713
char * text
Definition: menu.h:24
char file[NAME_MAX *2+1]
Definition: timers.h:42
cMark * GetPrev(int Position)
Definition: recording.c:1617
virtual void GetData(cChannel *Channel)=0
Copies all source specific parameters to the given Channel.
double FontFixSizeP
Definition: config.h:321
void SetRecordingsSortMode(const char *Directory, eRecordingsSortMode SortMode)
Definition: recording.c:2458
const cRecordingInfo * Info(void) const
Definition: recording.h:121
void ResetResume(const char *ResumeFileName=NULL)
Definition: recording.c:1467
bool Load(const char *SkinName)
Definition: themes.c:239
cRecordControl(cDevice *Device, cTimer *Timer=NULL, bool Pause=false)
Definition: menu.c:4238
virtual const cRecording * GetRecording(void)
Returns the cRecording that is currently being replayed, or NULL if this player is not playing a cRec...
Definition: menu.c:4948
bool modeOnly
Definition: menu.h:263
void Set(void)
Definition: menu.c:1996
cOsdItem * stopRecordingItem
Definition: menu.h:104
cEITScanner EITScanner
Definition: eitscan.c:90
cSetup data
Definition: menu.c:2530
bool HasUpdate(void)
Definition: ci.c:1143
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:1945
const char * Name(void)
Definition: plugin.h:34
cMenuRecordings(const char *Base=NULL, int Level=0, bool OpenSubMenus=false)
Definition: menu.c:2242
static cString ToText(const cChannel *Channel)
Definition: channels.c:501
double FramesPerSecond(void)
Definition: player.h:101
bool timeout
Definition: menu.h:122
void Play(void)
Definition: dvbplayer.c:889
int UseVps
Definition: config.h:297
char * stripspace(char *s)
Definition: tools.c:176
cSourceParam * Get(char Source) const
Definition: sourceparams.c:36
int stop
Definition: timers.h:39
double FontOsdSizeP
Definition: config.h:319
bool shown
Definition: menu.h:263
Definition: keys.h:43
char description[32]
Definition: device.h:85
virtual void SetVolume(int Current, int Total, bool Mute)=0
< This class implements the volume/mute display.
static void Shutdown(void)
Definition: menu.c:4544
cChannel * channel
Definition: menu.c:163
cDevice * Device(void)
Definition: menu.h:230
int WeekDays(void) const
Definition: timers.h:58
int Ca(int Index=0) const
Definition: channels.h:170
cSatCableNumbers satCableNumbers
Definition: menu.c:2960
static void InvokeCommand(const char *State, const char *RecordingFileName, const char *SourceFileName=NULL)
Definition: recording.c:1690
double FramesPerSecond(void) const
Definition: recording.h:125
bool visible
Definition: menu.h:263
cMenuSetupPlugins(void)
Definition: menu.c:3256
eOSState Edit(void)
Definition: menu.c:455
virtual const char * Version(void)=0
virtual int Compare(const cListObject &ListObject) const
Must return 0 if this object is equal to ListObject, a positive value if it is "greater", and a negative value if it is "smaller".
Definition: menu.c:1033
char language[MAXLANGCODE2]
Definition: epg.h:45
void Set(const char *CurrentFolder=NULL)
Definition: menu.c:759
virtual void SetRecording(const cRecording *Recording)=0
Sets the Recording that shall be displayed, using the entire central area of the menu.
static eChannelSortMode SortMode(void)
Definition: menu.c:288
const char * Title(char Delimiter= ' ', bool NewIndicator=false, int Level=-1) const
Definition: recording.c:1021
virtual void Show(void)
Definition: menu.c:4055
void QueryCam(void)
Definition: menu.c:1983
void Refresh(void)
Definition: menu.c:3761
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:594
#define RUC_BEFORERECORDING
Definition: recording.h:263
#define kEditTest
Definition: keys.h:73
bool now
Definition: menu.c:1542
int DefaultPriority
Definition: config.h:293
Definition: keys.h:46
cChannel * GetChannel(int Index)
Definition: menu.c:406
cMenuSchedule(void)
Definition: menu.c:1561
int number
Definition: menu.c:352
bool MakeDirs(const char *FileName, bool IsDirectory)
Definition: tools.c:396
eOSState ProcessKey(eKeys Key)
Definition: menu.c:123
int lastTotal
Definition: menu.h:264
virtual void Hide(void)
Definition: menu.c:4667
cTimers Timers
Definition: timers.c:694
bool lastPlay
Definition: menu.h:265
eOSState Edit(void)
Definition: menu.c:1158
#define TIMERMACRO_EPISODE
Definition: config.h:52
int start
Definition: timers.h:38
int ZapTimeout
Definition: config.h:289
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1011
eOSState Select(void)
Definition: menu.c:794
cMenuScheduleItem(const cEvent *Event, cChannel *Channel=NULL, bool WithDate=false)
Definition: menu.c:1315
int PausePriority
Definition: config.h:294
void AddMultiLineItem(const char *s)
Definition: menu.c:2036
cTimer * Timer(void)
Definition: menu.c:1023
int timeSearchPos
Definition: menu.h:269
const char * DefaultFontSml
Definition: font.c:25
const char * VideoDirectory
Definition: videodir.c:22
cStringList fontOsdNames
Definition: menu.c:2562
Definition: ci.h:54
virtual cOsdObject * MainMenuAction(void)
Definition: plugin.c:95
char * result
Definition: menu.h:63
static cDisplayVolume * Create(void)
Definition: menu.c:3975
int ppid
Definition: channels.h:104
cMenuMain(eOSState State=osUnknown, bool OpenSubMenus=false)
Definition: menu.c:3396
int numTracks
Definition: menu.h:159
int Code(void) const
Definition: sources.h:33
cString command
Definition: menu.h:61
Definition: plugin.h:20
cString PrintFirstDay(void) const
Definition: timers.c:282
cMenuChannels(void)
Definition: menu.c:370
Definition: keys.h:17
virtual int Compare(const cListObject &ListObject) const
Must return 0 if this object is equal to ListObject, a positive value if it is "greater", and a negative value if it is "smaller".
Definition: menu.c:305
cTimer * GetMatch(time_t t)
Definition: timers.c:716
eOSState Delete(void)
Definition: menu.c:472
const cEvent * Event(void) const
Definition: timers.h:69
eOSState Execute(void)
Definition: menu.c:1864
Definition: keys.h:61
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:3007
#define MAXDEVICES
Definition: device.h:28
#define esyslog(a...)
Definition: tools.h:34
cOsdMenu * SubMenu(void)
Definition: osdbase.h:126
static void SetupChanged(void)
Definition: dvbsubtitle.c:814
virtual void SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat)
Sets the video display format to the given one (only useful if this device has an MPEG decoder)...
Definition: device.c:446
cString title
Definition: menu.h:60
void Select(int Index)
Definition: ci.c:1149
int MinUserInactivity
Definition: config.h:328
virtual void Clear(void)
Definition: osdbase.c:312
cTimer * Timer(void)
Definition: menu.h:234
static void ChannelDataModified(cChannel *Channel)
Definition: menu.c:4518
cNestedItemList Commands
Definition: config.c:275
bool Parse(const char *s)
Definition: menu.c:1841
void Skip(void)
Definition: timers.c:669
virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
Definition: menu.c:340
char * strn0cpy(char *dest, const char *src, size_t n)
Definition: tools.c:131
bool Matches(time_t t=0, bool Directly=false, int Margin=0) const
Definition: timers.c:400
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
Definition: device.c:260
cOsdItem * Get(int Index) const
Definition: tools.h:481
bool TimedOut(void)
Definition: tools.c:694
Definition: ci.h:77
const char * ShortName(bool OrName=false) const
Definition: channels.c:131
static cControl * Control(bool Hidden=false)
Returns the current replay control (if any) in case it is currently visible.
Definition: player.c:73
void GenerateTitle(const char *s=NULL)
Definition: menu.c:1978
int helpKeys
Definition: menu.c:1083
static void Process(time_t t)
Definition: menu.c:4506
bool AttachReceiver(cReceiver *Receiver)
Attaches the given receiver to this device.
Definition: device.c:1709
Definition: menu.h:22
char * fileName
Definition: menu.h:224
bool confirm
Definition: menu.h:62
cChannel * channel
Definition: timers.h:35
char FontSml[MAXFONTNAME]
Definition: config.h:317
int AlwaysSortFoldersFirst
Definition: config.h:301
bool SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language=NULL, const char *Description=NULL)
Sets the track of the given Type and Index to the given values.
Definition: device.c:1013
virtual ~cMenuSetupOSD()
Definition: menu.c:2592
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:3122
eOSState New(void)
Definition: menu.c:465
Definition: keys.h:33
eOSState New(void)
Definition: menu.c:1166
bool Save(void)
Definition: config.c:690
void RefreshCurrent(void)
Definition: osdbase.c:273
cMenuEditFolder(const char *Dir, cList< cNestedItem > *List, cNestedItem *Folder=NULL)
Definition: menu.c:655
int EPGLanguages[I18N_MAX_LANGUAGES+1]
Definition: config.h:284
const char * Title(void)
Definition: osdbase.h:111
T max(T a, T b)
Definition: tools.h:55
int PauseLifetime
Definition: config.h:294
bool GroupSep(void) const
Definition: channels.h:177
static const cEvent * scheduleEvent
Definition: menu.c:1382
const cComponents * Components(void) const
Definition: recording.h:73
int MarkInstantRecord
Definition: config.h:267
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:1911
void Setup(void)
Definition: menu.c:197
eTrackType types[ttMaxTrackTypes]
Definition: menu.h:157
#define MAXVOLUME
Definition: device.h:31
tComponent * Component(int Index) const
Definition: epg.h:62
Definition: keys.h:27
void SetSubItems(bool On)
Definition: config.c:162
cSkinDisplayReplay * displayReplay
Definition: menu.h:260
eOSState ProcessKey(eKeys Key)
Definition: menu.c:4200
cDisplayTracks(void)
Definition: menu.c:4021
static void Process(eKeys Key)
Definition: menu.c:4194
int RecordingDirs
Definition: config.h:299
virtual void Show(void)
Definition: menu.c:4176
eOSState SetFolder(void)
Definition: menu.c:944
char * name
Definition: channels.h:95
Definition: device.h:65
int UseSubtitle
Definition: config.h:296
#define VDRVERSION
Definition: config.h:25
void ReNumber(void)
Definition: channels.c:873
cNestedItem * Folder(void)
Definition: menu.c:629
static cDisplayChannel * currentDisplayChannel
Definition: menu.h:126
int spids[MAXSPIDS+1]
Definition: channels.h:112
static int NumDevices(void)
Returns the total number of devices.
Definition: device.h:113
virtual void SetMode(bool Play, bool Forward, int Speed)=0
Sets the current replay mode, which can be used to display some indicator, showing the user whether w...
const cSource * source
Definition: menu.c:100
void SetPending(bool Pending)
Definition: timers.c:595
cChannel * channel
Definition: menu.h:123
eTrackType GetCurrentSubtitleTrack(void) const
Definition: device.h:522
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:1138
int EPGLinger
Definition: config.h:287
void SetDisplayMenu(void)
Definition: osdbase.c:118
time_t StartTime(void) const
Definition: timers.c:497
void Exit(int ExitCode)
Set VDR exit code and initiate end of VDR main loop.
Definition: shutdown.h:54
int weekdays
bitmask, lowest bits: SSFTWTM (the 'M' is the LSB)
Definition: timers.h:37
Definition: timers.h:25
void ForceScan(void)
Definition: eitscan.c:113
eTrackType
Definition: device.h:65
const char * Name(void)
Definition: skins.h:361
time_t StartTime(void) const
Definition: epg.h:106
int Current(void) const
Definition: osdbase.h:136
#define ICON_RUNNING
Definition: iconpatch.h:39
bool Selectable(void)
Definition: ci.h:47
virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
Definition: menu.c:1366
int ShowReplayMode
Definition: config.h:331
bool displayFrames
Definition: menu.h:263
int MenuKeyCloses
Definition: config.h:266
eOSState SetFolder(void)
Definition: menu.c:842
void SetPosition(int Position)
Definition: recording.h:222
void SetText(const char *Text)
Definition: config.c:156
virtual ~cMenuSchedule()
Definition: menu.c:1580
int Count(void) const
Definition: tools.h:475
virtual void SetEvent(const cEvent *Event)=0
Sets the Event that shall be displayed, using the entire central area of the menu.
Definition: keys.h:25
static bool StateChanged(int &State)
Definition: menu.c:4551
eOSState Reset(void)
Definition: menu.c:3110
int pluginIndex
Definition: menu.c:3377
bool timeSearchActive
Definition: menu.h:268
virtual void SetVideoFormat(bool VideoFormat16_9)
Sets the output video format to either 16:9 or 4:3 (only useful if this device has an MPEG decoder)...
Definition: device.c:469
int ColorKey2
Definition: config.h:303
#define ICON_ARROW
Definition: iconpatch.h:38
bool IsMenu(void) const
Definition: osdbase.h:81
T min(T a, T b)
Definition: tools.h:54
cString ChannelString(const cChannel *Channel, int Number)
Definition: channels.c:1026
cString ToString(void)
Definition: config.c:107
int nid
Definition: channels.h:119
int GetThemeIndex(const char *Description)
Definition: themes.c:283
int ShowInfoOnChSwitch
Definition: config.h:262
int timerState
Definition: menu.c:1545
Definition: keys.h:63
#define NORMALKEY(k)
Definition: keys.h:77
virtual void Set(void)
Definition: menu.c:3318
eOSState Number(void)
Definition: menu.c:1687
void Setup(void)
Definition: menu.c:2848
int channel
Definition: menu.h:76
cTimeMs timeout
Definition: menu.h:156
virtual void SetJump(const char *Jump)=0
Sets the prompt that allows the user to enter a jump point.
void Setup(void)
Definition: menu.c:2976
static int state
Definition: menu.h:240
int originalSkinIndex
Definition: menu.c:2556
void PrepareScheduleThisAll(const cEvent *Event, const cChannel *Channel)
Definition: menu.c:1620
void Add(cTimer *Timer, cTimer *After=NULL)
Definition: timers.c:774
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:3534
#define ICON_CLOCK_UH
Definition: iconpatch.h:41
char * provider
Definition: channels.h:97
int CurrentDolby
Definition: config.h:338
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:964
void SetNeedsFastResponse(bool NeedsFastResponse)
Definition: osdbase.h:76
void I18nSetLocale(const char *Locale)
Sets the current locale to Locale.
Definition: i18n.c:170
uint64_t Elapsed(void)
Definition: tools.c:699
virtual void SetText(const char *Text, bool FixedFont)=0
Sets the Text that shall be displayed, using the entire central area of the menu. ...
eModuleStatus ModuleStatus(void)
Returns the status of the CAM in this slot.
Definition: ci.c:1730
virtual void Set(void)
Definition: menu.c:115
int ChannelsWrap
Definition: config.h:340
virtual int Compare(const cListObject &ListObject) const
Must return 0 if this object is equal to ListObject, a positive value if it is "greater", and a negative value if it is "smaller".
Definition: menu.c:1324
virtual void SetItem(const char *Text, int Index, bool Current, bool Selectable)=0
Sets the item at the given Index to Text.
eOSState Switch(void)
Definition: menu.c:445
const char * standardComplianceTexts[2]
Definition: menu.c:2816
static const cSchedules * Schedules(cSchedulesLock &SchedulesLock)
Caller must provide a cSchedulesLock which has to survive the entire time the returned cSchedules is ...
Definition: epg.c:1201
virtual void SetRecording(const cRecording *Recording)
Sets the recording that is currently being played.
Definition: skins.c:175
Definition: keys.h:38
cNestedItemList RecordingCommands
Definition: config.c:276
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:532
char * input
Definition: menu.c:1937
cMenuTimerItem(cTimer *Timer)
Definition: menu.c:1027
Definition: keys.h:36
int tpid
Definition: channels.h:117
cTimer data
Definition: menu.h:75
cMenuRecording(const cRecording *Recording, bool WithButtons=false)
Definition: menu.c:2138
cString IndexToHMSF(int Index, bool WithFrame, double FramesPerSecond)
Definition: recording.c:2391
cNestedItemList * nestedItemList
Definition: menu.h:36
int timeSearchTime
Definition: menu.h:269
cMenuRecordingItem(cRecording *Recording, int Level)
Definition: menu.c:2210
#define MALLOC(type, size)
Definition: tools.h:46
cString instantId
Definition: menu.h:223
int ChannelEntryTimeout
Definition: config.h:290
const cChannel * Channel(void) const
Definition: timers.h:56
bool SetCurrentAudioTrack(eTrackType Type)
Sets the current audio track to the given Type.
Definition: device.c:1067
static void SetRecording(const char *FileName)
Definition: menu.c:4627
bool Update(bool Force=false)
Definition: menu.c:1342
bool replaying
Definition: menu.h:101
static eChannelSortMode sortMode
Definition: menu.c:282
eOSState Delete(void)
Definition: menu.c:1173
static int CurrentVolume(void)
Definition: device.h:570
const cChannel * channel
Definition: menu.c:1301
eOSState Select(void)
Definition: menu.c:2049
#define TIMERMACRO_TITLE
Definition: config.h:51
int LnbFrequLo
Definition: config.h:271
Definition: keys.h:55
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:868
Definition: timers.h:27
eOSState Number(eKeys Key)
Definition: menu.c:421
Definition: skins.h:91
int helpKeys
Definition: menu.c:1377
eTimerMatch
Definition: timers.h:25
int EmergencyExit
Definition: config.h:342
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
Definition: device.c:1146
int TimeTransponder
Definition: config.h:276
virtual bool SetItemRecording(const cRecording *Recording, int Index, bool Current, bool Selectable, int Level, int Total, int New)
Sets the item at the given Index to Recording.
Definition: skins.h:212
virtual int Compare(const cListObject &ListObject) const
Must return 0 if this object is equal to ListObject, a positive value if it is "greater", and a negative value if it is "smaller".
Definition: timers.c:160
virtual const char * Description(void)=0
T * Last(void) const
Definition: tools.h:483
char * shortName
Definition: channels.h:96
time_t timeoutShow
Definition: menu.h:267
#define ICON_BLANK
Definition: iconpatch.h:24
void SetEventFromSchedule(const cSchedules *Schedules=NULL)
Definition: timers.c:514
cDisplayChannel(int Number, bool Switched)
Definition: menu.c:3691
bool Transferring(void) const
Returns true if we are currently in Transfer Mode.
Definition: device.c:1277
eOSState
Definition: osdbase.h:18
virtual void SetMarks(const cMarks *Marks)
Sets the editing marks to Marks, which shall be used to display the progress bar through a cProgressB...
Definition: skins.c:180
cOsdItem * firstFolder
Definition: menu.h:39
const char * Text(void) const
Definition: osdbase.h:64
int fontSmlIndex
Definition: menu.c:2563
virtual void Show(void)
Definition: menu.c:3970
bool Recording(void) const
Definition: timers.h:52
cDevice * Device(void)
Returns the device this CAM slot is currently assigned to.
Definition: ci.c:1610
cTimer * GetTimer(cTimer *Timer)
Definition: timers.c:704
void SetHasHotkeys(bool HasHotkeys=true)
Definition: osdbase.c:151
cRecording * GetByName(const char *FileName)
Definition: recording.c:1380
Definition: skins.h:85
int fontFixIndex
Definition: menu.c:2563
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:2648
Definition: skins.h:103
static int CurrentChannel(void)
Returns the number of the current channel on the primary device.
Definition: device.h:309
int PluginIndex(void)
Definition: menu.c:3380
const char * Name(void) const
Definition: channels.c:121
bool Selectable(void) const
Definition: osdbase.h:60
const char * I18nLocale(int Language)
Returns the locale code of the given Language (which is an index as returned by I18nCurrentLanguage()...
Definition: i18n.c:218
#define CA_FTA
Definition: channels.h:42
bool Process(time_t t)
Definition: menu.c:4371
void IncrementCounter(bool New)
Definition: menu.c:2226
virtual eOSState ProcessKey(eKeys Key)
Definition: osdbase.c:555
int NumberKeysForChars
Definition: config.h:302
static cPlugin * CallFirstService(const char *Id, void *Data=NULL)
Definition: plugin.c:475
cMark * GetNext(int Position)
Definition: recording.c:1626
T * Next(const T *object) const
Definition: tools.h:485
int InitialVolume
Definition: config.h:339
static cDisplayTracks * currentDisplayTracks
Definition: menu.h:160
void SetCols(int c0, int c1=0, int c2=0, int c3=0, int c4=0)
Definition: osdbase.c:142
int themeIndex
Definition: menu.c:2561
eDvbFont
Definition: font.h:21
void SetPlugin(cPlugin *Plugin)
Definition: menuitems.c:1153
void GetRecordingsSortMode(const char *Directory)
Definition: recording.c:2448
const char * useSmallFontTexts[3]
Definition: menu.c:2552
cMenuCommands(const char *Title, cList< cNestedItem > *Commands, const char *Parameters=NULL)
Definition: menu.c:1819
virtual void Flush(void)
Actually draws the OSD display to the output device.
Definition: skins.h:45
static bool BondDevices(const char *Bondings)
Bonds the devices as defined in the given Bondings string.
Definition: dvbdevice.c:1318
virtual void Set(void)
Definition: menu.c:71
char * descriptions[ttMaxTrackTypes+1]
Definition: menu.h:158
virtual cOsdItem * GetOsdItem(void)=0
Returns all the OSD items necessary for editing the source specific parameters of the channel that wa...
bool Modified(int &State)
Returns true if any of the timers have been modified, which is detected by State being different than...
Definition: timers.c:792
void DecBeingEdited(void)
Definition: timers.h:123
#define ICON_BLANK_UTF8
Definition: iconpatch.h:48
Definition: keys.h:40
virtual void Insert(T Data, int Before=0)
Definition: tools.h:534
cMenuSetupLNB(void)
Definition: menu.c:2967
bool withButtons
Definition: menu.c:2131
void PrepareScheduleAllThis(const cEvent *Event, const cChannel *Channel)
Definition: menu.c:1585
cString WeekDayName(int WeekDay)
Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a three letter day name.
Definition: tools.c:1034
Definition: osdbase.h:35
eOSState Info(void)
Definition: menu.c:2447
cTheme * Theme(void)
Definition: skins.h:362
int SubtitleFgTransparency
Definition: config.h:283
void TimeSearch(void)
Definition: menu.c:4823
const char *const * Descriptions(void)
Definition: themes.h:76
cMenuSetup(void)
Definition: menu.c:3311
virtual ~cDisplayVolume()
Definition: menu.c:3964
int ChannelInfoPos
Definition: config.h:308
void SetFirstDayItem(void)
Definition: menu.c:931
const char * Text(void)
Definition: ci.h:66
bool HasUserIO(void)
Returns true if there is a pending user interaction, which shall be retrieved via GetMenu() or GetEnq...
Definition: ci.c:1761
void SetHelpKeys(void)
Definition: menu.c:1431
void SetMenuCategory(eMenuCategory MenuCategory)
Definition: osdbase.c:113
Definition: keys.h:44
int audioChannel
Definition: menu.h:159
const cRecording * recording
Definition: menu.c:2130
cListObject * Next(void) const
Definition: tools.h:458
double OSDLeftP
Definition: config.h:310
virtual cOsdObject * GetInfo(void)
Returns an OSD object that displays information about the currently played programme.
Definition: menu.c:4940
cCiMenu * GetMenu(void)
Gets a pending menu, or NULL if there is no menu.
Definition: ci.c:1774
int originalNumLanguages
Definition: menu.c:2717
bool GetEvent(void)
Definition: menu.c:4330
cSkinDisplayTracks * displayTracks
Definition: menu.h:155
bool FromString(const char *s)
Definition: config.c:81
int originalNumSubtitleLanguages
Definition: menu.c:2811
bool SwitchChannel(const cChannel *Channel, bool LiveView)
Switches the device to the given Channel, initiating transfer mode if necessary.
Definition: device.c:748
#define FOLDERDELIMCHAR
Definition: recording.h:21
cMenuEditChannel(cChannel *Channel, bool New=false)
Definition: menu.c:173
virtual cSkinDisplayReplay * DisplayReplay(bool ModeOnly)=0
Creates and returns a new object for displaying replay progress.
void IncBeingEdited(void)
Definition: channels.h:226
cString dir
Definition: menu.h:38
bool addIfConfirmed
Definition: menu.h:77
static void Stop(void)
Definition: cutter.c:690
char FontOsd[MAXFONTNAME]
Definition: config.h:316
cChannel data
Definition: menu.c:164
cTimeMs numberTimer
Definition: menu.c:353
int LnbSLOF
Definition: config.h:270
const char * Description(void)
Returns a user visible, single line description of this theme.
Definition: themes.c:75
uchar type
Definition: epg.h:44
void Pause(void)
Definition: dvbplayer.c:883
int GetNextNormal(int Idx)
Definition: channels.c:857
cDevice * device
Definition: menu.h:219
void Backward(void)
Definition: dvbplayer.c:901
~cMenuChannels()
Definition: menu.c:379
tChannelID ChannelID(void) const
Definition: epg.c:147
static int GetMDay(time_t t)
Definition: timers.c:351
int lifetime
Definition: timers.h:41
int SVDRPTimeout
Definition: config.h:288
bool HasFlags(uint Flags) const
Definition: timers.c:664
static void IncSortMode(void)
Definition: menu.c:287
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
Definition: thread.c:57
#define ICON_TV_CRYPTED
Definition: iconpatch.h:34
cOsdItem * cancelEditingItem
Definition: menu.h:103
cSources Sources
Definition: sources.c:105
void Cancel(void)
Definition: ci.c:1156
void SetText(const char *Text, bool Copy=true)
Definition: osdbase.c:42
cSkinDisplayVolume * displayVolume
Definition: menu.h:141
void SetSelectable(bool Selectable)
Definition: osdbase.c:48
virtual ~cMenuCam()
Definition: menu.c:1966
int GetPrevNormal(int Idx)
Definition: channels.c:865
const cList< cEvent > * Events(void) const
Definition: epg.h:171
Definition: keys.h:18
void Sort(void)
Definition: tools.c:2046
static void SetCurrentChannel(int ChannelNr)
Definition: menu.c:1388
bool Pending(void) const
Definition: timers.h:53
bool IsAttached(void)
Returns true if this receiver is (still) attached to a device.
Definition: receiver.h:68
void DescendPath(const char *Path)
Definition: menu.c:777
eOSState Confirm(void)
Definition: menu.c:684
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:1756
static void MsgSetAudioChannel(int AudioChannel)
Definition: status.c:62
bool Load(const char *FileName, bool OnlyDescriptions=false)
Loads the theme data from the given file.
Definition: themes.c:83
const char * Name(void)
Definition: menu.c:2203
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
Definition: device.c:990
static void UpdateOsdSize(bool Force=false)
Inquires the actual size of the video display and adjusts the OSD and font sizes accordingly.
Definition: osd.c:1992
const cEvent * GetEventAround(time_t Time) const
Definition: epg.c:961
cSourceParams SourceParams
Definition: sourceparams.c:34
cList< cNestedItem > * list
Definition: menu.h:37
void SetText(const char *Text)
Definition: menu.c:580
static const cCursesFont Font
Definition: skincurses.c:30
bool Open(const char *Command, const char *Mode)
Definition: thread.c:464
eVideoDisplayFormat
Definition: device.h:60
#define IS_AUDIO_TRACK(t)
Definition: device.h:78
void SetValue(const char *Value)
Definition: menuitems.c:37
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:2073
Definition: keys.h:28
Definition: skins.h:23
int SubtitleLanguages[I18N_MAX_LANGUAGES+1]
Definition: config.h:281
static bool Active(void)
Definition: menu.c:4535
virtual void Display(void)
Definition: osdbase.c:217
virtual cMenuSetupPage * SetupMenu(void)
Definition: plugin.c:100
virtual ~cDisplayChannel()
Definition: menu.c:3725
int FoldersInTimerMenu
Definition: config.h:300
int TimeSource
Definition: config.h:275
bool Delete(void)
Changes the file name so that it will no longer be visible in the "Recordings" menu Returns false in ...
Definition: recording.c:1146
#define MAXLIFETIME
Definition: config.h:48
int rid
Definition: channels.h:122
cList< cNestedItem > * SubItems(void)
Definition: config.h:197
int EPGScanTimeout
Definition: config.h:285
cSchedulesLock schedulesLock
Definition: menu.c:1540
int SubtitleOffset
Definition: config.h:282
int VideoFormat
Definition: config.h:305
#define ICON_ARROW_UTF8
Definition: iconpatch.h:62
Definition: skins.h:79
cSetup Setup
Definition: config.c:372
int PauseKeyHandling
Definition: config.h:295
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
cSkinDisplayMenu * DisplayMenu(void)
Definition: osdbase.h:106
Definition: config.h:244
#define kMarkJumpForward
Definition: keys.h:71
Definition: ci.h:127
void PrepareScheduleAllAll(const cEvent *Event, const cChannel *Channel)
Definition: menu.c:1639
const char ** skinDescriptions
Definition: menu.c:2558
cTimeMs timeout
Definition: menu.h:142
cShutdownHandler ShutdownHandler
Definition: shutdown.c:27
const char * InstantId(void)
Definition: menu.h:232
#define kMarkMoveForward
Definition: keys.h:69
cSkinDisplayTracks * displayTracks
Definition: menu.h:173
cCiEnquiry * ciEnquiry
Definition: menu.c:1936
cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr)
Definition: menu.c:1396
cRecording * recording
Definition: menu.c:2195
static int IsOpen(void)
Returns true if there is currently a level 0 OSD open.
Definition: osd.h:790
cMenuEditSrcItem(const char *Name, int *Value)
Definition: menu.c:108
int frequency
Definition: channels.h:100
virtual ~cReplayControl()
Definition: menu.c:4585
int recordingsState
Definition: menu.h:198
void SetModified(bool ByUser=false)
Definition: channels.c:998
int GetNextGroup(int Idx)
Definition: channels.c:841
void IncBeingEdited(void)
Definition: timers.h:122
cRecording * Recording(void)
Definition: menu.c:2204
#define ICON_CLOCK_UH_UTF8
Definition: iconpatch.h:65
static void Stop(const char *InstantId)
Definition: menu.c:4438
cMenuSetupBase(void)
Definition: menu.c:2536
int SplitEditedFiles
Definition: config.h:326
bool HasRecordingsSortMode(const char *Directory)
Definition: recording.c:2443
bool timeSearchHide
Definition: menu.h:268
const char * Provider(void) const
Definition: channels.h:144
Definition: keys.h:26
static cDisplaySubtitleTracks * Create(void)
Definition: menu.c:4183
char * description
Definition: epg.h:46
cMenuSetupDVB(void)
Definition: menu.c:2822
virtual ~cRecordControl()
Definition: menu.c:4322
int Size(void) const
Definition: tools.h:533
#define ICON_TV
Definition: iconpatch.h:36
time_t day
midnight of the day this timer shall hit, or of the first day it shall hit in case of a repeating tim...
Definition: timers.h:36
Definition: themes.h:61
cRecorder * recorder
Definition: menu.h:221
#define RUC_AFTERRECORDING
Definition: recording.h:264
int ColorKey3
Definition: config.h:303
Definition: keys.h:45
#define MINVIDEOFILESIZE
Definition: recording.h:286
int current
Definition: osdbase.h:93
cMenuEditStrItem * file
Definition: menu.h:78
int MinEventTimeout
Definition: config.h:328
Definition: skins.h:342
cString parameters
Definition: menu.h:59
int recordControlsState
Definition: menu.h:105
int LnbFrequHi
Definition: config.h:272
cChannel * GetByChannelID(tChannelID ChannelID, bool TryWithoutRid=false, bool TryWithoutPolarization=false)
Definition: channels.c:919
int otherChannel
Definition: menu.c:1543
cCamSlot * camSlot
Definition: menu.c:1934
int ProgressDisplayTime
Definition: config.h:333
void ToggleRepeating(void)
Definition: menuitems.c:890
int RcRepeatDelay
Definition: config.h:291
void Stop(bool ExecuteUserCommand=true)
Definition: menu.c:4358
int Close(void)
Definition: thread.c:521
bool GetIndex(int &Current, int &Total, bool SnapToIFrame=false)
Definition: dvbplayer.c:920
static void Launch(cControl *Control)
Definition: player.c:79
cNestedItem * folder
Definition: menu.c:645
void MarkJump(bool Forward)
Definition: menu.c:4862
static const char * LastReplayed(void)
Definition: menu.c:4637
int vpid
Definition: channels.h:103
eKeys Message(eMessageType Type, const char *s, int Seconds=0)
Displays the given message, either through a currently visible display object that is capable of doin...
Definition: skins.c:234
static void MsgOsdTextItem(const char *Text, bool Scroll=false)
Definition: status.c:110
Definition: skins.h:23
virtual eOSState ProcessKey(eKeys Key)
Definition: osdbase.c:63
cStringList fontFixNames
Definition: menu.c:2562
virtual ~cMenuEditTimer()
Definition: menu.c:919
virtual void Display(void)
Definition: menu.c:2148
int InstantRecordTime
Definition: config.h:269
bool HasTimer(void) const
Definition: channels.c:169
bool ShowProgress(bool Initial)
Definition: menu.c:4711
virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
Definition: menu.c:2234
bool Active(void)
Definition: dvbplayer.c:872
int MaxVideoFileSize
Definition: config.h:325
const char * Title(void) const
Definition: epg.h:100
#define ICON_TV_UTF8
Definition: iconpatch.h:60
bool Reset(void)
Resets the CAM in this slot.
Definition: ci.c:1712
eOSState Play(void)
Definition: menu.c:2363
static cDisplaySubtitleTracks * currentDisplayTracks
Definition: menu.h:178
cNestedItemList Folders
Definition: config.c:274
cTimer * timer
Definition: menu.h:74
eOSState ProcessKey(eKeys Key)
Definition: menu.c:4082
int ChannelInfoTime
Definition: config.h:309
bool Update(void)
Definition: menu.c:1419
bool GetReplayMode(bool &Play, bool &Forward, int &Speed)
Definition: dvbplayer.c:929
static const char * GetInstantId(const char *LastInstantId)
Definition: menu.c:4473
cThemes themes
Definition: menu.c:2559
Definition: keys.h:21
int numSkins
Definition: menu.c:2555
void SetSection(const char *Section)
Definition: menuitems.c:1133
int skinIndex
Definition: menu.c:2557
const char * DefaultFontFix
Definition: font.c:26
int CardIndex(void) const
Returns the card index of this device (0 ... MAXDEVICES - 1).
Definition: device.h:812
static bool HasPlugins(void)
Definition: plugin.c:452
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:1500
static void TriggerLastActivity(void)
Simulates user activity, for instance to keep the current menu open even if no remote control key has...
Definition: remote.c:204
static void MsgSetAudioTrack(int Index, const char *const *Tracks)
Definition: status.c:56
Definition: thread.h:189
Definition: device.h:69
Definition: epg.h:42
int lastSpeed
Definition: menu.h:266
int numSubtitleLanguages
Definition: menu.c:2812
int sid
Definition: channels.h:121
static void MsgOsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle)
Definition: status.c:122
int PrimaryDVB
Definition: config.h:261
const char * Description(void) const
Definition: sources.h:34
const char * Name(int Index)
Definition: themes.h:74
static cRecordControl * RecordControls[]
Definition: menu.h:239
cNestedItem * folder
Definition: menu.c:626
void SetCurrent(cOsdItem *Item)
Definition: osdbase.c:268
eTimerMatch timerMatch
Definition: menu.c:1303
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:2758
Definition: skins.h:23
virtual void SetProgress(int Current, int Total)=0
This function will be called whenever the position in or the total length of the recording has change...
int SetSystemTime
Definition: config.h:274
const cSchedule * GetSchedule(tChannelID ChannelID) const
Definition: epg.c:1328
int Stop(void) const
Definition: timers.h:60
int ExpectedLength(void)
Definition: ci.h:68
void TimeSearchProcess(eKeys Key)
Definition: menu.c:4770
static bool Active(const char *FileName=NULL)
Returns true if the cutter is currently active.
Definition: cutter.c:709
cString ToDescr(void) const
Definition: timers.c:179
uint flags
Definition: timers.h:34
int VpsMargin
Definition: config.h:298
cCiEnquiry * GetEnquiry(void)
Gets a pending enquiry, or NULL if there is no enquiry.
Definition: ci.c:1787
static void ClearLastReplayed(const char *FileName)
Definition: menu.c:4644
int UseDolbyDigital
Definition: config.h:307
#define kMarkMoveBack
Definition: keys.h:68
int GetNumSequences(void)
Returns the actual number of sequences to be cut from the recording.
Definition: recording.c:1669
static void MsgOsdChannel(const char *Text)
Definition: status.c:116
static void MsgSetSubtitleTrack(int Index, const char *const *Tracks)
Definition: status.c:68
#define ICON_RADIO
Definition: iconpatch.h:35
bool editing
Definition: menu.h:40
void DisplayCurrent(bool Current)
Definition: osdbase.c:280
void DecBeingEdited(void)
Definition: channels.h:227
const cEvent * lastFollowing
Definition: menu.h:125
virtual void Move(int From, int To)
Definition: menu.c:509
int VideoDiskSpace(int *FreeMB, int *UsedMB)
Definition: videodir.c:191
bool marksModified
Definition: menu.h:262
void SetHelpKeys(void)
Definition: menu.c:926
void EditTest(void)
Definition: menu.c:4922
bool HasUniqueChannelID(cChannel *NewChannel, cChannel *OldChannel=NULL)
Definition: channels.c:960
void Stop(void)
Definition: dvbplayer.c:877
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:3781
cListObject * Prev(void) const
Definition: tools.h:457
#define ICON_CLOCK
Definition: iconpatch.h:33
T * First(void) const
Definition: tools.h:482
virtual const char * MainMenuEntry(void)
Definition: plugin.c:90
Definition: timers.h:25
void Del(cListObject *Object, bool DeleteObject=true)
Definition: tools.c:1977
void ShowMode(void)
Definition: menu.c:4686
static void Attach(void)
Definition: player.c:87
static void Process(eKeys Key)
Definition: menu.c:3982
char FontFix[MAXFONTNAME]
Definition: config.h:318
~cMenuRecordings()
Definition: menu.c:2260
bool withInfo
Definition: menu.h:119
int MarginStop
Definition: config.h:278
int numAudioLanguages
Definition: menu.c:2810
int ShowChannelNamesWithSource
Definition: config.h:341
int dpids[MAXDPIDS+1]
Definition: channels.h:109
static void Process(eKeys Key)
Definition: menu.c:4076
eOSState Info(void)
Definition: menu.c:1197
static void MsgOsdClear(void)
Definition: status.c:74
time_t StopTime(void) const
Definition: timers.c:504
cMenuSetupCAM(void)
Definition: menu.c:3072
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:3270
int offset
Definition: menu.c:1938
cChannel * GetByNumber(int Number, int SkipGap=0)
Definition: channels.c:891
void EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
Definition: device.c:1113
const char * delTimeshiftRecTexts[3]
Definition: menu.c:3146
int WarEagleIcons
Definition: config.h:260
int AudioLanguages[I18N_MAX_LANGUAGES+1]
Definition: config.h:279
cMenuFolder(const char *Title, cList< cNestedItem > *List, cNestedItemList *NestedItemList, const char *Dir, const char *Path=NULL)
Definition: menu.c:740
static cOsdObject * pluginOsdObject
Definition: menu.h:106
void Reply(const char *s)
Definition: ci.c:1186
int ColorKey1
Definition: config.h:303
bool IsLangUtf8(void)
Definition: iconpatch.c:9
cMark * Get(int Position)
Definition: recording.c:1608
Definition: keys.h:35
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition: device.h:132
eOSState New(void)
Definition: menu.c:808
virtual void Display(void)
Definition: menu.c:586
void Propagate(void)
Definition: menu.c:412
#define kMarkToggle
Definition: keys.h:67
eOSState Edit(void)
Definition: menu.c:830
cTimeMs lastTime
Definition: menu.h:120
void SetFlags(uint Flags)
Definition: timers.c:649
virtual void SetTotal(const char *Total)=0
Sets the total length of the recording, as a user readable string if the form "h:mm:ss".
Definition: ci.h:25
cMenuText(const char *Title, const char *Text, eDvbFont Font=fontOsd)
Definition: menu.c:566
Definition: epg.h:143
virtual void Set(void)
Definition: menu.c:1038
static bool GetAvailableFontNames(cStringList *FontNames, bool Monospaced=false)
Queries the font configuration for a list of available font names, which is returned in FontNames...
Definition: font.c:432
#define MAXEPGBUGFIXLEVEL
Definition: epg.h:21
const cStringList * I18nLanguages(void)
Returns the list of available languages.
Definition: i18n.c:201
bool HasMMI(void)
Returns 'true' if the CAM in this slot has an active MMI.
Definition: ci.c:1756
virtual ~cMenuCommands()
Definition: menu.c:1836
cChannel * NextAvailableChannel(cChannel *Channel, int Direction)
Definition: menu.c:3767
#define ICON_REC
Definition: iconpatch.h:32
void SetDeferred(int Seconds)
Definition: timers.c:643
virtual ~cDisplayTracks()
Definition: menu.c:4046
void Forward(void)
Definition: dvbplayer.c:895
#define MAXPRIORITY
Definition: config.h:43
Definition: timers.h:21
void Cancel(void)
Definition: ci.c:1193
cMenuSetupMisc(void)
Definition: menu.c:3214
cMenuSetupOSD(void)
Definition: menu.c:2571
static const cEvent * ScheduleEvent(void)
Definition: menu.c:1448
cString GetFolder(void)
Definition: menu.c:679
const char * hk(const char *s)
Definition: osdbase.c:127
static cDisplayTracks * Create(void)
Definition: menu.c:4065
void StopReplay(void)
Stops the current replay session (if any).
Definition: device.c:1325
const tTrackId * GetTrack(eTrackType Type)
Returns a pointer to the given track id, or NULL if Type is not less than ttMaxTrackTypes.
Definition: device.c:1042
const char * GetCamName(void)
Returns the name of the CAM in this slot, or NULL if there is no ready CAM in this slot...
Definition: ci.c:1744
#define tr(s)
Definition: i18n.h:85
eOSState Commands(eKeys Key=kNone)
Definition: menu.c:2457
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:3347
cDisplayVolume(void)
Definition: menu.c:3955
cSkinDisplayChannel * displayChannel
Definition: menu.h:117
const char * Entry(int n)
Definition: ci.h:45
const char * File(void) const
Definition: timers.h:63
eDvbFont font
Definition: menu.h:25
int GetAudioChannel(void)
Gets the current audio channel, which is stereo (0), mono left (1) or mono right (2).
Definition: device.c:965
void Delete(void)
Definition: recording.c:322
bool IsSingleEvent(void) const
Definition: timers.c:346
cMenuSetupCAMItem(cCamSlot *CamSlot)
Definition: menu.c:3036
int I18nNumLanguagesWithLocale(void)
Returns the number of entries in the list returned by I18nLanguages() that actually have a locale...
Definition: i18n.c:196
const cSchedules * schedules
Definition: menu.c:1541
virtual void Move(int From, int To)
Definition: tools.c:1989
int PauseOnMarkSet
Definition: config.h:334
int UpdateChannels
Definition: config.h:306
const char * pauseKeyHandlingTexts[3]
Definition: menu.c:3145
cRecordings Recordings
Any access to Recordings that loops through the list of recordings needs to hold a thread lock on thi...
Definition: recording.c:1246
int source
Definition: channels.h:101
cMenuEditTimer(cTimer *Timer, bool New=false)
Definition: menu.c:891
cCamSlot * CamSlot(void)
Definition: menu.c:3032
bool ConfirmRestart(bool Ask)
Check for background activity that blocks restart.
Definition: shutdown.c:211
void DELETENULL(T *&p)
Definition: tools.h:48
cCamSlot * camSlot
Definition: menu.c:3029
eOSState CloseSubMenu()
Definition: osdbase.c:546
char * skipspace(const char *s)
Definition: tools.h:194
static cReplayControl * currentReplayControl
Definition: menu.h:274
void SetHelp(const char *Red, const char *Green=NULL, const char *Yellow=NULL, const char *Blue=NULL)
Definition: osdbase.c:179
cMenuEvent(const cEvent *Event, bool CanSwitch=false, bool Buttons=false)
Definition: menu.c:1236
static void SetCurrentChannel(const cChannel *Channel)
Sets the number of the current channel on the primary device, without actually switching to it...
Definition: device.h:311
void DisplayInfo(void)
Definition: menu.c:3739
void SetHelpKeys(void)
Definition: menu.c:754
#define kEditCut
Definition: keys.h:72
#define SECSINDAY
Definition: tools.h:41
bool next
Definition: menu.c:1542
void Add(int Position)
Definition: recording.c:1602
cString GetTimeString(void) const
Definition: epg.c:414
int NumEntries(void)
Definition: ci.h:46
void IncRecordingsSortMode(const char *Directory)
Definition: recording.c:2466
int NumComponents(void) const
Definition: epg.h:59
const char * Description(void) const
Definition: recording.h:72
int DelTimeshiftRec
Definition: config.h:327
int TimeoutRequChInfo
Definition: config.h:263
const char * Name(void) const
Definition: recording.h:118
#define isyslog(a...)
Definition: tools.h:35
char * strcpyrealloc(char *dest, const char *src)
Definition: tools.c:114
static void ChangeState(void)
Definition: menu.h:254
void AssertFreeDiskSpace(int Priority, bool Force)
The special Priority value -1 means that we shall get rid of any deleted recordings faster than norma...
Definition: recording.c:140
double FontSmlSizeP
Definition: config.h:320
#define ICON_REC_UTF8
Definition: iconpatch.h:56
virtual void SetAudioChannel(int AudioChannel)=0
Sets the audio channel indicator.
cMarks marks
Definition: menu.h:261
int EPGBugfixLevel
Definition: config.h:286
const cEvent * event
Definition: menu.h:222
eTrackType types[ttMaxTrackTypes]
Definition: menu.h:175
virtual void Display(void)
Definition: menu.c:1253
static cRecordControl * GetRecordControl(const char *FileName)
Definition: menu.c:4486
void DelByName(const char *FileName)
Definition: recording.c:1405
eOSState OnOff(void)
Definition: menu.c:1139
static cPlugin * GetPlugin(int Index)
Definition: plugin.c:457
const char * Title(void) const
Definition: recording.h:70
const cEvent * event
Definition: menu.c:1300
char * base
Definition: menu.h:196
bool Update(void)
Definition: recording.c:1538
virtual ~cDisplaySubtitleTracks()
Definition: menu.c:4167
cCiMenu * ciMenu
Definition: menu.c:1935
int UseSmallFont
Definition: config.h:314
const char * Description(void) const
Definition: epg.h:102
bool HasSubMenu(void)
Definition: osdbase.h:125
bool Changed(void)
Definition: menu.c:3043
Definition: keys.h:62
void ClearSortNames(void)
Definition: recording.c:1477
Definition: keys.h:32
int SecondsToFrames(int Seconds, double FramesPerSecond)
Definition: recording.c:2418
int ColorKey0
Definition: config.h:303
static void IncSortMode(void)
Definition: menu.c:1306
eOSState ProcessKey(eKeys Key)
Definition: menu.c:81
int caids[MAXCAIDS+1]
Definition: channels.h:118
bool StateChanged(int &State)
Definition: recording.c:1345
void SetKeepTracks(bool KeepTracks)
Controls whether the current audio and subtitle track settings shall be kept as they currently are...
Definition: device.h:536
eOSState Delete(void)
Definition: menu.c:2391
const cComponents * Components(void) const
Definition: epg.h:103
void SetHelpKeys(void)
Definition: menu.c:2266
int priority
Definition: timers.h:40
Definition: keys.h:31
const char * SubTitleText(void)
Definition: ci.h:43
char language[MAXLANGCODE2]
Definition: device.h:84
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:1261
time_t Day(void) const
Definition: timers.h:57
uchar stream
Definition: epg.h:43
eOSState Sort(void)
Definition: menu.c:2472
Definition: tools.h:323
#define ICON_RADIO_UTF8
Definition: iconpatch.h:59
void Abort(void)
Definition: ci.c:1198
void I18nSetLanguage(int Language)
Sets the current language index to Language.
Definition: i18n.c:188
int Priority(void) const
Definition: timers.h:61
bool Load(const char *RecordingFileName, double FramesPerSecond=DEFAULTFRAMESPERSECOND, bool IsPesRecording=false)
Definition: recording.c:1526
bool SwitchTo(int Number)
Definition: channels.c:970
time_t FirstDay(void) const
Definition: timers.h:64
Definition: keys.h:28
static cOsdObject * PluginOsdObject(void)
Definition: menu.c:3436
virtual bool ProvidesSource(int Source) const
Returns true if this device can provide the given source.
Definition: device.c:678
void Set(bool Refresh=false)
Definition: menu.c:2291
#define ICON_RUNNING_UTF8
Definition: iconpatch.h:63
virtual void SetCurrent(const char *Current)=0
Sets the current position within the recording, as a user readable string if the form "h:mm:ss...
int MenuScrollWrap
Definition: config.h:265
#define kMarkJumpBack
Definition: keys.h:70
void PrepareScheduleThisThis(const cEvent *Event, const cChannel *Channel)
Definition: menu.c:1603
cSourceParam * sourceParam
Definition: menu.c:165
int MenuScrollPage
Definition: config.h:264
#define ICON_VPS_UTF8
Definition: iconpatch.h:64
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:2481
char NameInstantRecord[NAME_MAX+1]
Definition: config.h:268
bool EnterMenu(void)
Requests the CAM in this slot to start its menu.
Definition: ci.c:1767
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:1207
void Set(void)
Definition: menu.c:3443
bool DoubleEqual(double a, double b)
Definition: tools.h:85
char name[256]
Definition: menu.c:166
int * Array(void)
Definition: config.h:94
virtual void SetEvents(const cEvent *Present, const cEvent *Following)=0
Sets the Present and Following EPG events.
eOSState Restart(void)
Definition: menu.c:3338
Definition: osdbase.h:34
virtual ~cMenuTimers()
Definition: menu.c:1112
virtual void Set(void)
Definition: menu.c:318
cMenuCam(cCamSlot *CamSlot)
Definition: menu.c:1951
const char * keyColorTexts[4]
Definition: menu.c:2553
void SetAudioChannel(int AudioChannel)
Sets the audio channel to stereo (0), mono left (1) or mono right (2).
Definition: device.c:971
cReplayControl(bool PauseLive=false)
Definition: menu.c:4564
virtual void Set(void)
Definition: menu.c:2597
void SetHelpKeys(void)
Definition: menu.c:1123
cString strescape(const char *s, const char *chars)
Definition: tools.c:205
cMenuSetupRecord(void)
Definition: menu.c:3151
void Goto(int Index, bool Still=false)
Definition: dvbplayer.c:934
Definition: keys.h:24
static void SetSortMode(eChannelSortMode SortMode)
Definition: menu.c:286
const char * updateChannelsTexts[6]
Definition: menu.c:2815
eOSState state
Definition: osdbase.h:52
cSource * Get(int Code)
Definition: sources.c:107
int SkipFrames(int Frames)
Definition: dvbplayer.c:913
#define IS_DOLBY_TRACK(t)
Definition: device.h:79
int DisplaySubtitles
Definition: config.h:280
char * ExchangeChars(char *s, bool ToFileSystem)
Definition: recording.c:566
int VideoDisplayFormat
Definition: config.h:304
cInterface * Interface
Definition: interface.c:17
char * Utf8Strn0Cpy(char *Dest, const char *Src, int n)
Copies at most n character bytes from Src to Dest, making sure that the resulting copy ends with a co...
Definition: tools.c:796
const char * FileName(int Index)
Definition: themes.h:75
eOSState Rewind(void)
Definition: menu.c:2377
void SetTitle(const char *Title)
Definition: osdbase.c:164
const char * ShortText(void) const
Definition: epg.h:101
int number
Definition: menu.h:121
int timerState
Definition: menu.c:1378
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:2156
char OSDTheme[MaxThemeName]
Definition: config.h:259
cString InitialChannel
Definition: config.h:344
bool SetCurrentSubtitleTrack(eTrackType Type, bool Manual=false)
Sets the current subtitle track to the given Type.
Definition: device.c:1085
const char * BottomText(void)
Definition: ci.h:44
cChannel * channel
Definition: menu.c:283
const char * DefaultFontOsd
Definition: font.c:24
#define MAXVIDEOFILESIZETS
Definition: recording.h:284
char OSDSkin[MaxSkinName]
Definition: config.h:258
bool Save(void)
Definition: config.c:258
int OSDMessageTime
Definition: config.h:313
virtual bool SetItemTimer(const cTimer *Timer, int Index, bool Current, bool Selectable)
Sets the item at the given Index to Timer.
Definition: skins.h:196
#define LIVEPRIORITY
Definition: config.h:45
void Abort(void)
Definition: ci.c:1161
static bool PauseLiveVideo(void)
Definition: menu.c:4458
cSkin * Current(void)
Returns a pointer to the current skin.
Definition: skins.h:408
bool Open(bool OpenSubMenus=false)
Definition: menu.c:2347
Definition: keys.h:28
const char * FileName(void) const
Definition: recording.c:1003
cTimer * timer
Definition: menu.h:220
cMenuEditDateItem * day
Definition: menu.h:79
eOSState AddSubMenu(cOsdMenu *SubMenu)
Definition: osdbase.c:538
int NumThemes(void)
Definition: themes.h:73
eOSState Menu(void)
Definition: menu.c:3083
int MarginStart
Definition: config.h:278
static void ForceCheck(void)
To avoid unnecessary load, the video disk usage is only actually checked every DISKSPACECHEK seconds...
Definition: videodir.h:43
char * portalName
Definition: channels.h:98
Definition: ci.h:77
void SetRecording(cRecording *Recording)
Definition: menu.c:2206
cMenuPluginItem(const char *Name, int Index)
Definition: menu.c:3383
void Del(cTimer *Timer, bool DeleteObject=true)
Definition: timers.c:786
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:2878
void SkipSeconds(int Seconds)
Definition: dvbplayer.c:907
bool Update(bool Force=false)
Definition: menu.c:3480
cMenuTimers(void)
Definition: menu.c:1097
eTrackType GetCurrentAudioTrack(void) const
Definition: device.h:518
int Utf8SymChars(const char *s, int Symbols)
Returns the number of character bytes at the beginning of the given string that form at most the give...
Definition: tools.c:771
eOSState Delete(void)
Definition: menu.c:814
bool Save(void)
Definition: recording.c:1569
const cEvent * lastPresent
Definition: menu.h:124
virtual cSkinDisplayTracks * DisplayTracks(const char *Title, int NumTracks, const char *const *Tracks)=0
Creates and returns a new object for displaying the available tracks.
T * Prev(const T *object) const
Definition: tools.h:484
bool SetCurrent(const char *Name=NULL)
Sets the current skin to the one indicated by name.
Definition: skins.c:215
virtual bool SetItemChannel(const cChannel *Channel, int Index, bool Current, bool Selectable, bool WithProvider)
Sets the item at the given Index to Channel.
Definition: skins.h:203
static bool Start(const char *FileName)
Definition: cutter.c:652
cMenuEditCaItem(const char *Name, int *Value)
Definition: menu.c:65
int track
Definition: menu.h:159
static void Shutdown(void)
Definition: player.c:100
#define ICON_VPS
Definition: iconpatch.h:40
virtual cSkinDisplayChannel * DisplayChannel(bool WithInfo)=0
Creates and returns a new object for displaying the current channel.
char name[PATH_MAX]
Definition: menu.c:646
#define ICON_CLOCK_UTF8
Definition: iconpatch.h:57
void AddByName(const char *FileName, bool TriggerUpdate=true)
Definition: recording.c:1392
eKeys
Definition: keys.h:16
virtual void Store(void)
Definition: menu.c:3200
const cEvent * event
Definition: menu.h:92
char OSDLanguage[I18N_MAX_LOCALE_LEN]
Definition: config.h:257
bool IsPesRecording(void) const
Definition: recording.h:136
void RequestEmergencyExit(void)
Requests an emergency exit of the VDR main loop.
Definition: shutdown.c:96
static cDisplayVolume * currentDisplayVolume
Definition: menu.h:143
cCamSlots CamSlots
Definition: ci.c:1552
int SubtitleBgTransparency
Definition: config.h:283
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:95
eOSState Record(void)
Definition: menu.c:1467
int numLanguages
Definition: menu.c:2718
int SlotNumber(void)
Returns the number of this CAM slot within the whole system.
Definition: ci.h:171
cMenuSetupPluginItem(const char *Name, int Index)
Definition: menu.c:3242
The cDevice class is the base from which actual devices can be derived.
Definition: device.h:104
static void MsgRecording(const cDevice *Device, const char *Name, const char *FileName, bool On)
Definition: status.c:38
int Start(void) const
Definition: timers.h:59
int ResumeID
Definition: config.h:335
int RcRepeatDelta
Definition: config.h:292
void EditCut(void)
Definition: menu.c:4902
cMenuChannelItem(cChannel *Channel)
Definition: menu.c:297
#define ICON_TV_CRYPTED_UTF8
Definition: iconpatch.h:58
Definition: tools.h:166
virtual void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable)
Definition: menu.c:1073
int DefaultLifetime
Definition: config.h:293
Definition: keys.h:41
virtual eOSState ProcessKey(eKeys Key)
Definition: menu.c:709
int originalThemeIndex
Definition: menu.c:2560
cMenuEditDateItem * firstday
Definition: menu.h:80
static const char * NowReplaying(void)
Definition: menu.c:4632
cTimer * timer
Definition: menu.c:1018
char * descriptions[ttMaxTrackTypes+1]
Definition: menu.h:176
int ShowRemainingTime
Definition: config.h:332
const char * TitleText(void)
Definition: ci.h:42
int osdLanguageIndex
Definition: menu.c:2554
cMenuSetupEPG(void)
Definition: menu.c:2725
virtual void SetData(cChannel *Channel)=0
Sets all source specific parameters to those of the given Channel.
int apids[MAXAPIDS+1]
Definition: channels.h:106
void MarkMove(bool Forward)
Definition: menu.c:4879
static void MsgReplaying(const cControl *Control, const char *Name, const char *FileName, bool On)
Definition: status.c:44
static cString PrintDay(time_t Day, int WeekDays, bool SingleByteChars)
Definition: timers.c:248
bool Blind(void)
Definition: ci.h:67
cMenuSetupReplay(void)
Definition: menu.c:3188
double OSDTopP
Definition: config.h:310
void Stop(void)
Definition: menu.c:4595
Definition: keys.h:22
virtual void SetChannel(const cChannel *Channel, int Number)=0
< This class is used to display the current channel, together with the present and following EPG even...
Definition: ci.h:77
cSkins Skins
Definition: skins.c:203
const cEvent * GetFollowingEvent(void) const
Definition: epg.c:936
uint16_t id
Definition: device.h:83
Definition: skins.h:102
static eScheduleSortMode sortMode
Definition: menu.c:1298
static bool Start(cTimer *Timer=NULL, bool Pause=false)
Definition: menu.c:4387
int DiSEqC
Definition: config.h:273