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