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