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