vdr  2.0.4
menuitems.c
Go to the documentation of this file.
1 /*
2  * menuitems.c: General purpose menu items
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: menuitems.c 2.16 2013/02/15 14:20:29 kls Exp $
8  */
9 
10 #include "menuitems.h"
11 #include <ctype.h>
12 #include <math.h>
13 #include <wctype.h>
14 #include "i18n.h"
15 #include "plugin.h"
16 #include "remote.h"
17 #include "skins.h"
18 #include "status.h"
19 
20 #define AUTO_ADVANCE_TIMEOUT 1500 // ms before auto advance when entering characters via numeric keys
21 
22 const char *FileNameChars = trNOOP("FileNameChars$ abcdefghijklmnopqrstuvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&");
23 
24 // --- cMenuEditItem ---------------------------------------------------------
25 
27 {
28  name = strdup(Name ? Name : "???");
29  SetHelp(NULL);
30 }
31 
33 {
34  free(name);
35 }
36 
37 void cMenuEditItem::SetValue(const char *Value)
38 {
39  cString buffer = cString::sprintf("%s:\t%s", name, Value);
40  SetText(buffer);
42 }
43 
44 void cMenuEditItem::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue)
45 {
46  // strings are NOT copied - must be constants!!!
47  helpRed = Red;
48  helpGreen = Green;
49  helpYellow = Yellow;
50  helpBlue = Blue;
51  helpDisplayed = false;
52 }
53 
55 {
56  bool HasHelp = helpRed || helpGreen || helpYellow || helpBlue;
57  if (HasHelp && !helpDisplayed) {
60  helpDisplayed = true;
61  }
62  return HasHelp;
63 }
64 
65 // --- cMenuEditIntItem ------------------------------------------------------
66 
67 cMenuEditIntItem::cMenuEditIntItem(const char *Name, int *Value, int Min, int Max, const char *MinString, const char *MaxString)
68 :cMenuEditItem(Name)
69 {
70  value = Value;
71  min = Min;
72  max = Max;
73  minString = MinString;
74  maxString = MaxString;
75  if (*value < min)
76  *value = min;
77  else if (*value > max)
78  *value = max;
79  Set();
80 }
81 
83 {
84  if (minString && *value == min)
86  else if (maxString && *value == max)
88  else {
89  char buf[16];
90  snprintf(buf, sizeof(buf), "%d", *value);
91  SetValue(buf);
92  }
93 }
94 
96 {
98 
99  if (state == osUnknown) {
100  int newValue = *value;
101  bool IsRepeat = Key & k_Repeat;
102  Key = NORMALKEY(Key);
103  switch (Key) {
104  case kNone: break;
105  case k0 ... k9:
106  if (fresh) {
107  newValue = 0;
108  fresh = false;
109  }
110  newValue = newValue * 10 + (Key - k0);
111  break;
112  case kLeft: // TODO might want to increase the delta if repeated quickly?
113  newValue = *value - 1;
114  fresh = true;
115  if (!IsRepeat && newValue < min && max != INT_MAX)
116  newValue = max;
117  break;
118  case kRight:
119  newValue = *value + 1;
120  fresh = true;
121  if (!IsRepeat && newValue > max && min != INT_MIN)
122  newValue = min;
123  break;
124  default:
125  if (*value < min) { *value = min; Set(); }
126  if (*value > max) { *value = max; Set(); }
127  return state;
128  }
129  if (newValue != *value && (!fresh || min <= newValue) && newValue <= max) {
130  *value = newValue;
131  Set();
132  }
133  state = osContinue;
134  }
135  return state;
136 }
137 
138 // --- cMenuEditBoolItem -----------------------------------------------------
139 
140 cMenuEditBoolItem::cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString, const char *TrueString)
141 :cMenuEditIntItem(Name, Value, 0, 1)
142 {
143  falseString = FalseString ? FalseString : tr("no");
144  trueString = TrueString ? TrueString : tr("yes");
145  Set();
146 }
147 
149 {
150  char buf[16];
151  snprintf(buf, sizeof(buf), "%s", *value ? trueString : falseString);
152  SetValue(buf);
153 }
154 
155 // --- cMenuEditBitItem ------------------------------------------------------
156 
157 cMenuEditBitItem::cMenuEditBitItem(const char *Name, uint *Value, uint Mask, const char *FalseString, const char *TrueString)
158 :cMenuEditBoolItem(Name, &bit, FalseString, TrueString)
159 {
160  value = Value;
161  bit = (*value & Mask) != 0;
162  mask = Mask;
163  Set();
164 }
165 
167 {
168  *value = bit ? *value | mask : *value & ~mask;
170 }
171 
172 // --- cMenuEditNumItem ------------------------------------------------------
173 
174 cMenuEditNumItem::cMenuEditNumItem(const char *Name, char *Value, int Length, bool Blind)
175 :cMenuEditItem(Name)
176 {
177  value = Value;
178  length = Length;
179  blind = Blind;
180  Set();
181 }
182 
184 {
185  if (blind) {
186  char buf[length + 1];
187  int i;
188  for (i = 0; i < length && value[i]; i++)
189  buf[i] = '*';
190  buf[i] = 0;
191  SetValue(buf);
192  }
193  else
194  SetValue(value);
195 }
196 
198 {
200 
201  if (state == osUnknown) {
202  Key = NORMALKEY(Key);
203  switch (Key) {
204  case kLeft: {
205  int l = strlen(value);
206  if (l > 0)
207  value[l - 1] = 0;
208  }
209  break;
210  case k0 ... k9: {
211  int l = strlen(value);
212  if (l < length) {
213  value[l] = Key - k0 + '0';
214  value[l + 1] = 0;
215  }
216  }
217  break;
218  default: return state;
219  }
220  Set();
221  state = osContinue;
222  }
223  return state;
224 }
225 
226 // --- cMenuEditPrcItem ------------------------------------------------------
227 
228 cMenuEditPrcItem::cMenuEditPrcItem(const char *Name, double *Value, double Min, double Max, int Decimals)
229 :cMenuEditItem(Name)
230 {
231  value = Value;
232  min = Min;
233  max = Max;
234  decimals = Decimals;
235  factor = 100;
236  while (Decimals-- > 0)
237  factor *= 10;
238  if (*value < min)
239  *value = min;
240  else if (*value > max)
241  *value = max;
242  Set();
243 }
244 
246 {
247  char buf[16];
248  snprintf(buf, sizeof(buf), "%.*f", decimals, *value * 100);
249  SetValue(buf);
250 }
251 
253 {
255 
256  if (state == osUnknown) {
257  double newValue = round(*value * factor); // avoids precision problems
258  Key = NORMALKEY(Key);
259  switch (Key) {
260  case kNone: break;
261  case k0 ... k9:
262  if (fresh) {
263  newValue = 0;
264  fresh = false;
265  }
266  newValue = newValue * 10 + (Key - k0);
267  break;
268  case kLeft: // TODO might want to increase the delta if repeated quickly?
269  newValue--;
270  fresh = true;
271  break;
272  case kRight:
273  newValue++;
274  fresh = true;
275  break;
276  default:
277  if (*value < min) { *value = min; Set(); }
278  if (*value > max) { *value = max; Set(); }
279  return state;
280  }
281  newValue /= factor;
282  if (!DoubleEqual(newValue, *value) && (!fresh || min <= newValue) && newValue <= max) {
283  *value = newValue;
284  Set();
285  }
286  state = osContinue;
287  }
288  return state;
289 }
290 
291 // --- cMenuEditChrItem ------------------------------------------------------
292 
293 cMenuEditChrItem::cMenuEditChrItem(const char *Name, char *Value, const char *Allowed)
294 :cMenuEditItem(Name)
295 {
296  value = Value;
297  allowed = strdup(Allowed ? Allowed : "");
298  current = strchr(allowed, *Value);
299  if (!current)
300  current = allowed;
301  Set();
302 }
303 
305 {
306  free(allowed);
307 }
308 
310 {
311  char buf[2];
312  buf[0] = *value;
313  buf[1] = '\0';
314  SetValue(buf);
315 }
316 
318 {
320 
321  if (state == osUnknown) {
322  if (NORMALKEY(Key) == kLeft) {
323  if (current > allowed)
324  current--;
325  }
326  else if (NORMALKEY(Key) == kRight) {
327  if (*(current + 1))
328  current++;
329  }
330  else
331  return state;
332  *value = *current;
333  Set();
334  state = osContinue;
335  }
336  return state;
337 }
338 
339 // --- cMenuEditStrItem ------------------------------------------------------
340 
341 cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed)
342 :cMenuEditItem(Name)
343 {
344  value = Value;
345  length = Length;
346  allowed = Allowed ? Allowed : tr(FileNameChars);
347  pos = -1;
348  offset = 0;
349  insert = uppercase = false;
350  newchar = true;
351  lengthUtf8 = 0;
352  valueUtf8 = NULL;
353  allowedUtf8 = NULL;
354  charMapUtf8 = NULL;
355  currentCharUtf8 = NULL;
356  lastKey = kNone;
357  Set();
358 }
359 
361 {
362  delete[] valueUtf8;
363  delete[] allowedUtf8;
364  delete[] charMapUtf8;
365 }
366 
368 {
369  if (!valueUtf8) {
370  valueUtf8 = new uint[length];
372  int l = strlen(allowed) + 1;
373  allowedUtf8 = new uint[l];
375  const char *charMap = tr("CharMap$ 0\t-.,1#~\\^$[]|()*+?{}/:%@&\tabc2\tdef3\tghi4\tjkl5\tmno6\tpqrs7\ttuv8\twxyz9");
376  l = strlen(charMap) + 1;
377  charMapUtf8 = new uint[l];
378  Utf8ToArray(charMap, charMapUtf8, l);
380  AdvancePos();
381  }
382 }
383 
385 {
386  if (valueUtf8) {
387  if (SaveValue) {
389  stripspace(value);
390  }
391  lengthUtf8 = 0;
392  delete[] valueUtf8;
393  valueUtf8 = NULL;
394  delete[] allowedUtf8;
395  allowedUtf8 = NULL;
396  delete[] charMapUtf8;
397  charMapUtf8 = NULL;
398  pos = -1;
399  offset = 0;
400  newchar = true;
401  }
402 }
403 
405 {
406  if (InEditMode())
407  SetHelp(tr("Button$ABC/abc"), insert ? tr("Button$Overwrite") : tr("Button$Insert"), tr("Button$Delete"));
408  else
409  SetHelp(NULL);
410 }
411 
413 {
414  if (allowedUtf8) {
415  for (uint *a = allowedUtf8; *a; a++) {
416  if (c == *a)
417  return a;
418  }
419  }
420  return NULL;
421 }
422 
424 {
425  if (pos < length - 2 && pos < lengthUtf8) {
426  if (++pos >= lengthUtf8) {
427  if (pos >= 2 && valueUtf8[pos - 1] == ' ' && valueUtf8[pos - 2] == ' ')
428  pos--; // allow only two blanks at the end
429  else {
430  valueUtf8[pos] = ' ';
431  valueUtf8[pos + 1] = 0;
432  lengthUtf8++;
433  }
434  }
435  }
436  newchar = true;
437  if (!insert && Utf8is(alpha, valueUtf8[pos]))
438  uppercase = Utf8is(upper, valueUtf8[pos]);
439 }
440 
442 {
443  if (InEditMode()) {
444  // This is an ugly hack to make editing strings work with the 'skincurses' plugin.
445  const cFont *font = dynamic_cast<cSkinDisplayMenu *>(cSkinDisplay::Current())->GetTextAreaFont(false);
446  if (!font || font->Width("W") != 1) // all characters have with == 1 in the font used by 'skincurses'
447  font = cFont::GetFont(fontOsd);
448 
449  int width = cSkinDisplay::Current()->EditableWidth();
450  width -= font->Width("[]");
451  width -= font->Width("<>"); // reserving this anyway make the whole thing simpler
452 
453  if (pos < offset)
454  offset = pos;
455  int WidthFromOffset = 0;
456  int EndPos = lengthUtf8;
457  for (int i = offset; i < lengthUtf8; i++) {
458  WidthFromOffset += font->Width(valueUtf8[i]);
459  if (WidthFromOffset > width) {
460  if (pos >= i) {
461  do {
462  WidthFromOffset -= font->Width(valueUtf8[offset]);
463  offset++;
464  } while (WidthFromOffset > width && offset < pos);
465  EndPos = pos + 1;
466  }
467  else {
468  EndPos = i;
469  break;
470  }
471  }
472  }
473 
474  char buf[1000];
475  char *p = buf;
476  if (offset)
477  *p++ = '<';
478  p += Utf8FromArray(valueUtf8 + offset, p, sizeof(buf) - (p - buf), pos - offset);
479  *p++ = '[';
480  if (insert && newchar)
481  *p++ = ']';
482  p += Utf8FromArray(&valueUtf8[pos], p, sizeof(buf) - (p - buf), 1);
483  if (!(insert && newchar))
484  *p++ = ']';
485  p += Utf8FromArray(&valueUtf8[pos + 1], p, sizeof(buf) - (p - buf), EndPos - pos - 1);
486  if (EndPos != lengthUtf8)
487  *p++ = '>';
488  *p = 0;
489 
490  SetValue(buf);
491  }
492  else
493  SetValue(value);
494 }
495 
496 uint cMenuEditStrItem::Inc(uint c, bool Up)
497 {
498  uint *p = IsAllowed(c);
499  if (!p)
500  p = allowedUtf8;
501  if (Up) {
502  if (!*++p)
503  p = allowedUtf8;
504  }
505  else if (--p < allowedUtf8) {
506  p = allowedUtf8;
507  while (*p && *(p + 1))
508  p++;
509  }
510  return *p;
511 }
512 
514 {
515  if (insert && lengthUtf8 < length - 1)
516  Insert();
517  valueUtf8[pos] = c;
518  if (pos < length - 2)
519  pos++;
520  if (pos >= lengthUtf8) {
521  valueUtf8[pos] = ' ';
522  valueUtf8[pos + 1] = 0;
523  lengthUtf8 = pos + 1;
524  }
525 }
526 
528 {
529  memmove(valueUtf8 + pos + 1, valueUtf8 + pos, (lengthUtf8 - pos + 1) * sizeof(*valueUtf8));
530  lengthUtf8++;
531  valueUtf8[pos] = ' ';
532 }
533 
535 {
536  memmove(valueUtf8 + pos, valueUtf8 + pos + 1, (lengthUtf8 - pos) * sizeof(*valueUtf8));
537  lengthUtf8--;
538 }
539 
541 {
542  bool SameKey = NORMALKEY(Key) == lastKey;
543  if (Key != kNone)
544  lastKey = NORMALKEY(Key);
545  else if (!newchar && k0 <= lastKey && lastKey <= k9 && autoAdvanceTimeout.TimedOut()) {
546  AdvancePos();
547  newchar = true;
548  currentCharUtf8 = NULL;
549  Set();
550  return osContinue;
551  }
552  switch (int(Key)) {
553  case kRed: // Switch between upper- and lowercase characters
554  if (InEditMode()) {
555  if (!insert || !newchar) {
556  uppercase = !uppercase;
557  valueUtf8[pos] = uppercase ? Utf8to(upper, valueUtf8[pos]) : Utf8to(lower, valueUtf8[pos]);
558  }
559  }
560  else
561  return osUnknown;
562  break;
563  case kGreen: // Toggle insert/overwrite modes
564  if (InEditMode()) {
565  insert = !insert;
566  newchar = true;
567  SetHelpKeys();
568  }
569  else
570  return osUnknown;
571  break;
572  case kYellow|k_Repeat:
573  case kYellow: // Remove the character at the current position; in insert mode it is the character to the right of the cursor
574  if (InEditMode()) {
575  if (lengthUtf8 > 1) {
576  if (!insert || pos < lengthUtf8 - 1)
577  Delete();
578  else if (insert && pos == lengthUtf8 - 1)
579  valueUtf8[pos] = ' '; // in insert mode, deleting the last character replaces it with a blank to keep the cursor position
580  // reduce position, if we removed the last character
581  if (pos == lengthUtf8)
582  pos--;
583  }
584  else if (lengthUtf8 == 1)
585  valueUtf8[0] = ' '; // This is the last character in the string, replace it with a blank
586  if (Utf8is(alpha, valueUtf8[pos]))
587  uppercase = Utf8is(upper, valueUtf8[pos]);
588  newchar = true;
589  }
590  else
591  return osUnknown;
592  break;
593  case kBlue|k_Repeat:
594  case kBlue: // consume the key only if in edit-mode
595  if (!InEditMode())
596  return osUnknown;
597  break;
598  case kLeft|k_Repeat:
599  case kLeft: if (pos > 0) {
600  if (!insert || newchar)
601  pos--;
602  newchar = true;
603  if (!insert && Utf8is(alpha, valueUtf8[pos]))
604  uppercase = Utf8is(upper, valueUtf8[pos]);
605  }
606  break;
607  case kRight|k_Repeat:
608  case kRight: if (InEditMode())
609  AdvancePos();
610  else {
611  EnterEditMode();
612  SetHelpKeys();
613  }
614  break;
615  case kUp|k_Repeat:
616  case kUp:
617  case kDown|k_Repeat:
618  case kDown: if (InEditMode()) {
619  if (insert && newchar) {
620  // create a new character in insert mode
621  if (lengthUtf8 < length - 1)
622  Insert();
623  }
624  if (uppercase)
625  valueUtf8[pos] = Utf8to(upper, Inc(Utf8to(lower, valueUtf8[pos]), NORMALKEY(Key) == kUp));
626  else
627  valueUtf8[pos] = Inc( valueUtf8[pos], NORMALKEY(Key) == kUp);
628  newchar = false;
629  }
630  else
631  return cMenuEditItem::ProcessKey(Key);
632  break;
633  case k0|k_Repeat ... k9|k_Repeat:
634  case k0 ... k9: {
635  if (InEditMode()) {
637  if (!SameKey) {
638  if (!newchar)
639  AdvancePos();
640  currentCharUtf8 = NULL;
641  }
642  if (!currentCharUtf8 || !*currentCharUtf8 || *currentCharUtf8 == '\t') {
643  // find the beginning of the character map entry for Key
644  int n = NORMALKEY(Key) - k0;
646  while (n > 0 && *currentCharUtf8) {
647  if (*currentCharUtf8++ == '\t')
648  n--;
649  }
650  // find first allowed character
651  while (*currentCharUtf8 && *currentCharUtf8 != '\t' && !IsAllowed(*currentCharUtf8))
652  currentCharUtf8++;
653  }
654  if (*currentCharUtf8 && *currentCharUtf8 != '\t') {
655  if (insert && newchar) {
656  // create a new character in insert mode
657  if (lengthUtf8 < length - 1)
658  Insert();
659  }
661  if (uppercase)
662  valueUtf8[pos] = Utf8to(upper, valueUtf8[pos]);
663  // find next allowed character
664  do {
665  currentCharUtf8++;
666  } while (*currentCharUtf8 && *currentCharUtf8 != '\t' && !IsAllowed(*currentCharUtf8));
667  newchar = false;
669  }
670  }
671  else
672  Type('0' + NORMALKEY(Key) - k0);
673  }
674  else
675  return cMenuEditItem::ProcessKey(Key);
676  }
677  break;
678  case kBack:
679  case kOk: if (InEditMode()) {
680  LeaveEditMode(Key == kOk);
681  SetHelpKeys();
682  break;
683  }
684  // run into default
685  default: if (InEditMode() && BASICKEY(Key) == kKbd) {
686  int c = KEYKBD(Key);
687  if (c <= 0xFF) { // FIXME what about other UTF-8 characters?
688  if (IsAllowed(Utf8to(lower, c)))
689  Type(c);
690  else {
691  switch (c) {
692  case 0x7F: // backspace
693  if (pos > 0) {
694  pos--;
695  return ProcessKey(kYellow);
696  }
697  break;
698  default: ;
699  }
700  }
701  }
702  else {
703  switch (c) {
704  case kfHome: pos = 0; break;
705  case kfEnd: pos = lengthUtf8 - 1; break;
706  case kfIns: return ProcessKey(kGreen);
707  case kfDel: return ProcessKey(kYellow);
708  default: ;
709  }
710  }
711  }
712  else
713  return cMenuEditItem::ProcessKey(Key);
714  }
715  Set();
716  return osContinue;
717 }
718 
719 // --- cMenuEditStraItem -----------------------------------------------------
720 
721 cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings)
722 :cMenuEditIntItem(Name, Value, 0, NumStrings - 1)
723 {
724  strings = Strings;
725  Set();
726 }
727 
729 {
731 }
732 
733 // --- cMenuEditChanItem -----------------------------------------------------
734 
735 cMenuEditChanItem::cMenuEditChanItem(const char *Name, int *Value, const char *NoneString)
736 :cMenuEditIntItem(Name, Value, NoneString ? 0 : 1, Channels.MaxNumber())
737 {
738  channelID = NULL;
739  noneString = NoneString;
740  dummyValue = 0;
741  Set();
742 }
743 
744 cMenuEditChanItem::cMenuEditChanItem(const char *Name, cString *ChannelID, const char *NoneString)
745 :cMenuEditIntItem(Name, &dummyValue, NoneString ? 0 : 1, Channels.MaxNumber())
746 {
747  channelID = ChannelID;
748  noneString = NoneString;
749  cChannel *channel = Channels.GetByChannelID(tChannelID::FromString(*ChannelID));
750  dummyValue = channel ? channel->Number() : 0;
751  Set();
752 }
753 
755 {
756  if (*value > 0) {
757  char buf[255];
758  cChannel *channel = Channels.GetByNumber(*value);
759  snprintf(buf, sizeof(buf), "%d %s", *value, channel ? channel->Name() : "");
760  SetValue(buf);
761  if (channelID)
762  *channelID = channel ? channel->GetChannelID().ToString() : "";
763  }
764  else if (noneString) {
766  if (channelID)
767  *channelID = "";
768  }
769 }
770 
772 {
773  int delta = 1;
774 
775  switch (int(Key)) {
776  case kLeft|k_Repeat:
777  case kLeft: delta = -1;
778  case kRight|k_Repeat:
779  case kRight:
780  {
781  cChannel *channel = Channels.GetByNumber(*value + delta, delta);
782  if (channel)
783  *value = channel->Number();
784  else if (delta < 0 && noneString)
785  *value = 0;
786  if (channelID)
787  *channelID = channel ? channel->GetChannelID().ToString() : "";
788  Set();
789  }
790  break;
791  default: return cMenuEditIntItem::ProcessKey(Key);
792  }
793  return osContinue;
794 }
795 
796 // --- cMenuEditTranItem -----------------------------------------------------
797 
798 cMenuEditTranItem::cMenuEditTranItem(const char *Name, int *Value, int *Source)
799 :cMenuEditChanItem(Name, &number, "-")
800 {
801  number = 0;
802  source = Source;
803  transponder = Value;
804  cChannel *channel = Channels.First();
805  while (channel) {
806  if (!channel->GroupSep() && *source == channel->Source() && ISTRANSPONDER(channel->Transponder(), *Value)) {
807  number = channel->Number();
808  break;
809  }
810  channel = (cChannel *)channel->Next();
811  }
812  Set();
813 }
814 
816 {
818  cChannel *channel = Channels.GetByNumber(number);
819  if (channel) {
820  *source = channel->Source();
821  *transponder = channel->Transponder();
822  }
823  else {
824  *source = 0;
825  *transponder = 0;
826  }
827  return state;
828 }
829 
830 // --- cMenuEditDateItem -----------------------------------------------------
831 
832 static int ParseWeekDays(const char *s)
833 {
834  time_t day;
835  int weekdays;
836  return cTimer::ParseDay(s, day, weekdays) ? weekdays : 0;
837 }
838 
839 int cMenuEditDateItem::days[] = { ParseWeekDays("M------"),
840  ParseWeekDays("-T-----"),
841  ParseWeekDays("--W----"),
842  ParseWeekDays("---T---"),
843  ParseWeekDays("----F--"),
844  ParseWeekDays("-----S-"),
845  ParseWeekDays("------S"),
846  ParseWeekDays("MTWTF--"),
847  ParseWeekDays("MTWTFS-"),
848  ParseWeekDays("MTWTFSS"),
849  ParseWeekDays("-----SS"),
850  0 };
851 
852 cMenuEditDateItem::cMenuEditDateItem(const char *Name, time_t *Value, int *WeekDays)
853 :cMenuEditItem(Name)
854 {
855  value = Value;
856  weekdays = WeekDays;
857  oldvalue = 0;
858  oldweekdays = 0;
860  Set();
861 }
862 
864 {
865  for (unsigned int i = 0; i < sizeof(days) / sizeof(int); i++)
866  if (WeekDays == days[i])
867  return i;
868  return 0;
869 }
870 
872 {
873 #define DATEBUFFERSIZE 32
874  char buf[DATEBUFFERSIZE];
875  if (weekdays && *weekdays) {
876  SetValue(cTimer::PrintDay(0, *weekdays, false));
877  return;
878  }
879  else if (*value) {
880  struct tm tm_r;
881  localtime_r(value, &tm_r);
882  strftime(buf, DATEBUFFERSIZE, "%Y-%m-%d ", &tm_r);
883  strcat(buf, WeekDayName(tm_r.tm_wday));
884  }
885  else
886  *buf = 0;
887  SetValue(buf);
888 }
889 
891 {
892  if (weekdays) {
893  if (*weekdays) {
894  *value = cTimer::SetTime(oldvalue ? oldvalue : time(NULL), 0);
895  oldvalue = 0;
897  *weekdays = 0;
898  }
899  else {
901  oldweekdays = 0;
903  oldvalue = *value;
904  *value = 0;
905  }
906  Set();
907  }
908 }
909 
911 {
913 
914  if (state == osUnknown) {
915  time_t now = time(NULL);
916  if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
917  if (!weekdays || !*weekdays) {
918  // Decrement single day:
919  time_t v = *value;
920  v -= SECSINDAY;
921  if (v < now) {
922  if (now <= v + SECSINDAY) { // switched from tomorrow to today
923  if (!weekdays)
924  v = 0;
925  }
926  else if (weekdays) { // switched from today to yesterday, so enter weekdays mode
927  v = 0;
928  dayindex = sizeof(days) / sizeof(int) - 2;
929  *weekdays = days[dayindex];
930  }
931  else // don't go before today
932  v = *value;
933  }
934  *value = v;
935  }
936  else {
937  // Decrement weekday index:
938  if (dayindex > 0)
939  *weekdays = days[--dayindex];
940  }
941  }
942  else if (NORMALKEY(Key) == kRight) {
943  if (!weekdays || !*weekdays) {
944  // Increment single day:
945  if (!*value)
946  *value = cTimer::SetTime(now, 0);
947  *value += SECSINDAY;
948  }
949  else {
950  // Increment weekday index:
951  *weekdays = days[++dayindex];
952  if (!*weekdays) { // was last weekday entry, so switch to today
953  *value = cTimer::SetTime(now, 0);
954  dayindex = 0;
955  }
956  }
957  }
958  else if (weekdays) {
959  if (Key == k0) {
960  // Toggle between weekdays and single day:
961  ToggleRepeating();
962  return osContinue; // ToggleRepeating) has already called Set()
963  }
964  else if (k1 <= Key && Key <= k7) {
965  // Toggle individual weekdays:
966  if (*weekdays) {
967  int v = *weekdays ^ (1 << (Key - k1));
968  if (v != 0)
969  *weekdays = v; // can't let this become all 0
970  }
971  }
972  else
973  return state;
974  }
975  else
976  return state;
977  Set();
978  state = osContinue;
979  }
980  return state;
981 }
982 
983 // --- cMenuEditTimeItem -----------------------------------------------------
984 
985 cMenuEditTimeItem::cMenuEditTimeItem(const char *Name, int *Value)
986 :cMenuEditItem(Name)
987 {
988  value = Value;
989  hh = *value / 100;
990  mm = *value % 100;
991  pos = 0;
992  Set();
993 }
994 
996 {
997  char buf[10];
998  switch (pos) {
999  case 1: snprintf(buf, sizeof(buf), "%01d-:--", hh / 10); break;
1000  case 2: snprintf(buf, sizeof(buf), "%02d:--", hh); break;
1001  case 3: snprintf(buf, sizeof(buf), "%02d:%01d-", hh, mm / 10); break;
1002  default: snprintf(buf, sizeof(buf), "%02d:%02d", hh, mm);
1003  }
1004  SetValue(buf);
1005 }
1006 
1008 {
1010 
1011  if (state == osUnknown) {
1012  if (k0 <= Key && Key <= k9) {
1013  if (fresh || pos > 3) {
1014  pos = 0;
1015  fresh = false;
1016  }
1017  int n = Key - k0;
1018  switch (pos) {
1019  case 0: if (n <= 2) {
1020  hh = n * 10;
1021  mm = 0;
1022  pos++;
1023  }
1024  break;
1025  case 1: if (hh + n <= 23) {
1026  hh += n;
1027  pos++;
1028  }
1029  break;
1030  case 2: if (n <= 5) {
1031  mm += n * 10;
1032  pos++;
1033  }
1034  break;
1035  case 3: if (mm + n <= 59) {
1036  mm += n;
1037  pos++;
1038  }
1039  break;
1040  default: ;
1041  }
1042  }
1043  else if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
1044  if (--mm < 0) {
1045  mm = 59;
1046  if (--hh < 0)
1047  hh = 23;
1048  }
1049  fresh = true;
1050  }
1051  else if (NORMALKEY(Key) == kRight) {
1052  if (++mm > 59) {
1053  mm = 0;
1054  if (++hh > 23)
1055  hh = 0;
1056  }
1057  fresh = true;
1058  }
1059  else
1060  return state;
1061  *value = hh * 100 + mm;
1062  Set();
1063  state = osContinue;
1064  }
1065  return state;
1066 }
1067 
1068 // --- cMenuEditMapItem ------------------------------------------------------
1069 
1070 cMenuEditMapItem::cMenuEditMapItem(const char *Name, int *Value, const tDvbParameterMap *Map, const char *ZeroString)
1071 :cMenuEditItem(Name)
1072 {
1073  value = Value;
1074  map = Map;
1075  zeroString = ZeroString;
1076  Set();
1077 }
1078 
1080 {
1081  const char *s = NULL;
1082  int n = MapToUser(*value, map, &s);
1083  if (n == 0 && zeroString)
1085  else if (n >= 0) {
1086  if (s)
1087  SetValue(s);
1088  else {
1089  char buf[16];
1090  snprintf(buf, sizeof(buf), "%d", n);
1091  SetValue(buf);
1092  }
1093  }
1094  else
1095  SetValue("???");
1096 }
1097 
1099 {
1101 
1102  if (state == osUnknown) {
1103  int newValue = *value;
1104  int n = DriverIndex(*value, map);
1105  if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
1106  if (n-- > 0)
1107  newValue = map[n].driverValue;
1108  }
1109  else if (NORMALKEY(Key) == kRight) {
1110  if (map[++n].userValue >= 0)
1111  newValue = map[n].driverValue;
1112  }
1113  else
1114  return state;
1115  if (newValue != *value) {
1116  *value = newValue;
1117  Set();
1118  }
1119  state = osContinue;
1120  }
1121  return state;
1122 }
1123 
1124 // --- cMenuSetupPage --------------------------------------------------------
1125 
1127 :cOsdMenu("", 33)
1128 {
1130  plugin = NULL;
1131 }
1132 
1133 void cMenuSetupPage::SetSection(const char *Section)
1134 {
1135  SetTitle(cString::sprintf("%s - %s", tr("Setup"), Section));
1136 }
1137 
1139 {
1140  eOSState state = cOsdMenu::ProcessKey(Key);
1141 
1142  if (state == osUnknown) {
1143  switch (Key) {
1144  case kOk: Store();
1145  state = osBack;
1146  break;
1147  default: break;
1148  }
1149  }
1150  return state;
1151 }
1152 
1154 {
1156  plugin = Plugin;
1157  SetSection(cString::sprintf("%s '%s'", tr("Plugin"), plugin->Name()));
1158 }
1159 
1160 void cMenuSetupPage::SetupStore(const char *Name, const char *Value)
1161 {
1162  if (plugin)
1163  plugin->SetupStore(Name, Value);
1164 }
1165 
1166 void cMenuSetupPage::SetupStore(const char *Name, int Value)
1167 {
1168  if (plugin)
1169  plugin->SetupStore(Name, Value);
1170 }
cMenuEditIntItem(const char *Name, int *Value, int Min=0, int Max=INT_MAX, const char *MinString=NULL, const char *MaxString=NULL)
Definition: menuitems.c:67
cTimeMs autoAdvanceTimeout
Definition: menuitems.h:110
int Number(void) const
Definition: channels.h:191
cMenuSetupPage(void)
Definition: menuitems.c:1126
static void MsgOsdCurrentItem(const char *Text)
Definition: status.c:104
virtual void Set(void)
Definition: menuitems.c:82
cChannels Channels
Definition: channels.c:845
cPlugin * plugin
Definition: menuitems.h:202
cString * channelID
Definition: menuitems.h:142
Definition: remote.h:98
static tChannelID FromString(const char *s)
Definition: channels.c:25
int EditableWidth(void)
Definition: skins.h:34
virtual void Set(void)
Definition: menuitems.c:441
cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char *const *Strings)
Definition: menuitems.c:721
void Set(int Ms=0)
Definition: tools.c:689
const char * helpRed
Definition: menuitems.h:22
void LeaveEditMode(bool SaveValue=false)
Definition: menuitems.c:384
Definition: keys.h:23
const char * Name(void)
Definition: plugin.h:34
char * stripspace(char *s)
Definition: tools.c:176
#define BASICKEY(k)
Definition: keys.h:81
Definition: keys.h:28
virtual void Set(void)
Definition: menuitems.c:148
static int days[]
Definition: menuitems.h:162
int FindDayIndex(int WeekDays)
Definition: menuitems.c:863
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1011
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:197
void SetupStore(const char *Name, const char *Value=NULL)
Definition: plugin.c:110
Definition: plugin.h:20
time_t * value
Definition: menuitems.h:163
Definition: keys.h:17
Definition: keys.h:61
bool DisplayHelp(void)
Definition: menuitems.c:54
cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString=NULL, const char *TrueString=NULL)
Definition: menuitems.c:140
bool TimedOut(void)
Definition: tools.c:694
bool GroupSep(void) const
Definition: channels.h:193
const char * helpGreen
Definition: menuitems.h:22
cMenuEditPrcItem(const char *Name, double *Value, double Min=0.0, double Max=1.0, int Decimals=0)
Definition: menuitems.c:228
void SetupStore(const char *Name, const char *Value=NULL)
Definition: menuitems.c:1160
#define KEYKBD(k)
Definition: keys.h:83
Definition: keys.h:27
const char * helpBlue
Definition: menuitems.h:22
char * name
Definition: menuitems.h:21
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:1098
bool fresh
Definition: osdbase.h:56
virtual void Set(void)
Definition: menuitems.c:871
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:815
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:1138
static cSkinDisplay * Current(void)
Returns the currently active cSkinDisplay.
Definition: skins.h:47
Definition: keys.h:25
const tDvbParameterMap * map
Definition: menuitems.h:190
int Transponder(void) const
Returns the transponder frequency in MHz, plus the polarization in case of sat.
Definition: channels.c:156
#define NORMALKEY(k)
Definition: keys.h:77
static void MsgOsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue)
Definition: status.c:92
virtual void SetButtons(const char *Red, const char *Green=NULL, const char *Yellow=NULL, const char *Blue=NULL)
Sets the color buttons to the given strings, provided this cSkinDisplay actually has a color button d...
Definition: skins.h:39
const char * maxString
Definition: menuitems.h:37
#define Utf8to(conv, c)
Definition: tools.h:136
const char * falseString
Definition: menuitems.h:46
const char *const * strings
Definition: menuitems.h:131
Definition: keys.h:55
Definition: skins.h:91
virtual void Store(void)=0
static time_t SetTime(time_t t, int SecondsFromMidnight)
Definition: timers.c:381
eOSState
Definition: osdbase.h:18
virtual void Set(void)
Definition: menuitems.c:995
double * value
Definition: menuitems.h:75
const char * Name(void) const
Definition: channels.c:121
virtual eOSState ProcessKey(eKeys Key)
Definition: osdbase.c:559
int NumberKeysForChars
Definition: config.h:303
const char * noneString
Definition: menuitems.h:140
void SetPlugin(cPlugin *Plugin)
Definition: menuitems.c:1153
int Source(void) const
Definition: channels.h:163
virtual void Set(void)
Definition: menuitems.c:245
#define trNOOP(s)
Definition: i18n.h:88
#define ISTRANSPONDER(f1, f2)
Definition: channels.h:18
Definition: font.h:22
cString WeekDayName(int WeekDay)
Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a three letter day name.
Definition: tools.c:1034
virtual void Set(void)
Definition: menuitems.c:166
cMenuEditTranItem(const char *Name, int *Value, int *Source)
Definition: menuitems.c:798
void SetMenuCategory(eMenuCategory MenuCategory)
Definition: osdbase.c:113
cListObject * Next(void) const
Definition: tools.h:458
uint * allowedUtf8
Definition: menuitems.h:106
int MapToUser(int Value, const tDvbParameterMap *Map, const char **String)
Definition: dvbdevice.c:166
cMenuEditBitItem(const char *Name, uint *Value, uint Mask, const char *FalseString=NULL, const char *TrueString=NULL)
Definition: menuitems.c:157
void SetText(const char *Text, bool Copy=true)
Definition: osdbase.c:42
Definition: keys.h:18
uint Inc(uint c, bool Up)
Definition: menuitems.c:496
void SetValue(const char *Value)
Definition: menuitems.c:37
Definition: keys.h:28
const char * minString
Definition: menuitems.h:37
cMenuEditChrItem(const char *Name, char *Value, const char *Allowed)
Definition: menuitems.c:293
cSetup Setup
Definition: config.c:373
int DriverIndex(int Value, const tDvbParameterMap *Map)
Definition: dvbdevice.c:155
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:317
Definition: keys.h:20
tChannelID GetChannelID(void) const
Definition: channels.h:202
const char * allowed
Definition: menuitems.h:101
#define Utf8is(ccls, c)
Definition: tools.h:137
Definition: keys.h:26
cChannel * GetByChannelID(tChannelID ChannelID, bool TryWithoutRid=false, bool TryWithoutPolarization=false)
Definition: channels.c:972
void ToggleRepeating(void)
Definition: menuitems.c:890
static int GetWDay(time_t t)
Definition: timers.c:357
virtual eOSState ProcessKey(eKeys Key)
Definition: osdbase.c:63
void EnterEditMode(void)
Definition: menuitems.c:367
cMenuEditNumItem(const char *Name, char *Value, int Length, bool Blind=false)
Definition: menuitems.c:174
uint * currentCharUtf8
Definition: menuitems.h:108
Definition: keys.h:21
void SetSection(const char *Section)
Definition: menuitems.c:1133
uint * valueUtf8
Definition: menuitems.h:105
bool InEditMode(void)
Definition: menuitems.h:122
void Insert(void)
Definition: menuitems.c:527
virtual void Set(void)
Definition: menuitems.c:754
cMenuEditDateItem(const char *Name, time_t *Value, int *WeekDays=NULL)
Definition: menuitems.c:852
T * First(void) const
Definition: tools.h:482
cString ToString(void) const
Definition: channels.c:42
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:1007
cChannel * GetByNumber(int Number, int SkipGap=0)
Definition: channels.c:944
virtual void Set(void)
Definition: menuitems.c:1079
bool helpDisplayed
Definition: menuitems.h:23
int Utf8ToArray(const char *s, uint *a, int Size)
Converts the given character bytes (including the terminating 0) into an array of UTF-8 symbols of th...
Definition: tools.c:815
uint * IsAllowed(uint c)
Definition: menuitems.c:412
void AdvancePos(void)
Definition: menuitems.c:423
#define tr(s)
Definition: i18n.h:85
Definition: keys.h:56
void Type(uint c)
Definition: menuitems.c:513
#define SECSINDAY
Definition: tools.h:41
int Utf8FromArray(const uint *a, char *s, int Size, int Max)
Converts the given array of UTF-8 symbols (including the terminating 0) into a sequence of character ...
Definition: tools.c:833
const char * zeroString
Definition: menuitems.h:191
const char * current
Definition: menuitems.h:89
static bool ParseDay(const char *s, time_t &Day, int &WeekDays)
Definition: timers.c:189
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:252
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:540
virtual int Width(uint c) const =0
Returns the width of the given character in pixel.
virtual void Set(void)
Definition: menuitems.c:728
const char * trueString
Definition: menuitems.h:46
Definition: keys.h:28
uint * charMapUtf8
Definition: menuitems.h:107
Definition: remote.h:102
cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed=NULL)
Definition: menuitems.c:341
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:910
cMenuEditTimeItem(const char *Name, int *Value)
Definition: menuitems.c:985
virtual void Set(void)
Definition: menuitems.c:309
bool DoubleEqual(double a, double b)
Definition: tools.h:85
virtual void Set(void)
Definition: menuitems.c:183
Definition: osdbase.h:35
cMenuEditItem(const char *Name)
Definition: menuitems.c:26
Definition: keys.h:24
eOSState state
Definition: osdbase.h:53
void SetTitle(const char *Title)
Definition: osdbase.c:164
Definition: remote.h:101
char * allowed
Definition: menuitems.h:88
const char * helpYellow
Definition: menuitems.h:22
Definition: keys.h:28
void SetHelp(const char *Red, const char *Green=NULL, const char *Yellow=NULL, const char *Blue=NULL)
Definition: menuitems.c:44
Definition: remote.h:97
eKeys
Definition: keys.h:16
cMenuEditChanItem(const char *Name, int *Value, const char *NoneString=NULL)
Definition: menuitems.c:735
void Delete(void)
Definition: menuitems.c:534
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:95
Definition: font.h:37
void SetHelpKeys(void)
Definition: menuitems.c:404
Definition: tools.h:166
static const cFont * GetFont(eDvbFont Font)
Gets the given Font, which was previously set by a call to SetFont().
Definition: font.c:406
cMenuEditMapItem(const char *Name, int *Value, const tDvbParameterMap *Map, const char *ZeroString=NULL)
Definition: menuitems.c:1070
static cString PrintDay(time_t Day, int WeekDays, bool SingleByteChars)
Definition: timers.c:248
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:771
Definition: keys.h:22