vdr  2.4.1
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 4.3 2018/03/23 15:37:02 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 // --- cMenuEditStrlItem -----------------------------------------------------
778 
779 cMenuEditStrlItem::cMenuEditStrlItem(const char *Name, char *Value, int Length, const cStringList *Strings)
780 :cMenuEditIntItem(Name, &index, 0, Strings->Size() - 1)
781 {
782  strings = Strings;
783  value = Value;
784  length = Length;
785  index = strings->Find(value);
786  if (index < 0)
787  index = 0;
788  Set();
789 }
790 
792 {
794  SetValue(value);
795 }
796 
797 // --- cMenuEditChanItem -----------------------------------------------------
798 
799 cMenuEditChanItem::cMenuEditChanItem(const char *Name, int *Value, const char *NoneString)
800 :cMenuEditIntItem(Name, Value, NoneString ? 0 : 1, cChannels::MaxNumber())
801 {
802  channelID = NULL;
803  noneString = NoneString;
804  dummyValue = 0;
805  Set();
806 }
807 
808 cMenuEditChanItem::cMenuEditChanItem(const char *Name, cString *ChannelID, const char *NoneString)
809 :cMenuEditIntItem(Name, &dummyValue, NoneString ? 0 : 1, cChannels::MaxNumber())
810 {
811  channelID = ChannelID;
812  noneString = NoneString;
814  const cChannel *Channel = Channels->GetByChannelID(tChannelID::FromString(*ChannelID));
815  dummyValue = Channel ? Channel->Number() : 0;
816  Set();
817 }
818 
820 {
821  if (*value > 0) {
822  char buf[255];
824  const cChannel *Channel = Channels->GetByNumber(*value);
825  snprintf(buf, sizeof(buf), "%d %s", *value, Channel ? Channel->Name() : "");
826  SetValue(buf);
827  if (channelID)
828  *channelID = Channel ? Channel->GetChannelID().ToString() : "";
829  }
830  else if (noneString) {
832  if (channelID)
833  *channelID = "";
834  }
835 }
836 
838 {
839  int delta = 1;
840 
841  switch (int(Key)) {
842  case kLeft|k_Repeat:
843  case kLeft: delta = -1;
844  case kRight|k_Repeat:
845  case kRight:
846  {
848  const cChannel *Channel = Channels->GetByNumber(*value + delta, delta);
849  if (Channel)
850  *value = Channel->Number();
851  else if (delta < 0 && noneString)
852  *value = 0;
853  if (channelID)
854  *channelID = Channel ? Channel->GetChannelID().ToString() : "";
855  Set();
856  }
857  break;
858  default: return cMenuEditIntItem::ProcessKey(Key);
859  }
860  return osContinue;
861 }
862 
863 // --- cMenuEditTranItem -----------------------------------------------------
864 
865 cMenuEditTranItem::cMenuEditTranItem(const char *Name, int *Value, int *Source)
866 :cMenuEditChanItem(Name, &number, "-")
867 {
868  number = 0;
869  source = Source;
870  transponder = Value;
872  const cChannel *Channel = Channels->First();
873  while (Channel) {
874  if (!Channel->GroupSep() && *source == Channel->Source() && ISTRANSPONDER(Channel->Transponder(), *Value)) {
875  number = Channel->Number();
876  break;
877  }
878  Channel = Channels->Next(Channel);
879  }
880  Set();
881 }
882 
884 {
887  if (const cChannel *Channel = Channels->GetByNumber(number)) {
888  *source = Channel->Source();
889  *transponder = Channel->Transponder();
890  }
891  else {
892  *source = 0;
893  *transponder = 0;
894  }
895  return state;
896 }
897 
898 // --- cMenuEditDateItem -----------------------------------------------------
899 
900 static int ParseWeekDays(const char *s)
901 {
902  time_t day;
903  int weekdays;
904  return cTimer::ParseDay(s, day, weekdays) ? weekdays : 0;
905 }
906 
907 int cMenuEditDateItem::days[] = { ParseWeekDays("M------"),
908  ParseWeekDays("-T-----"),
909  ParseWeekDays("--W----"),
910  ParseWeekDays("---T---"),
911  ParseWeekDays("----F--"),
912  ParseWeekDays("-----S-"),
913  ParseWeekDays("------S"),
914  ParseWeekDays("MTWTF--"),
915  ParseWeekDays("MTWTFS-"),
916  ParseWeekDays("MTWTFSS"),
917  ParseWeekDays("-----SS"),
918  0 };
919 
920 cMenuEditDateItem::cMenuEditDateItem(const char *Name, time_t *Value, int *WeekDays)
921 :cMenuEditItem(Name)
922 {
923  value = Value;
924  weekdays = WeekDays;
925  oldvalue = 0;
926  oldweekdays = 0;
928  Set();
929 }
930 
932 {
933  for (unsigned int i = 0; i < sizeof(days) / sizeof(int); i++)
934  if (WeekDays == days[i])
935  return i;
936  return 0;
937 }
938 
940 {
941 #define DATEBUFFERSIZE 32
942  char buf[DATEBUFFERSIZE];
943  if (weekdays && *weekdays) {
944  SetValue(cTimer::PrintDay(0, *weekdays, false));
945  return;
946  }
947  else if (*value) {
948  struct tm tm_r;
949  localtime_r(value, &tm_r);
950  strftime(buf, DATEBUFFERSIZE, "%Y-%m-%d ", &tm_r);
951  strcat(buf, WeekDayName(tm_r.tm_wday));
952  }
953  else
954  *buf = 0;
955  SetValue(buf);
956 }
957 
959 {
960  if (weekdays) {
961  if (*weekdays) {
962  *value = cTimer::SetTime(oldvalue ? oldvalue : time(NULL), 0);
963  oldvalue = 0;
965  *weekdays = 0;
966  }
967  else {
969  oldweekdays = 0;
971  oldvalue = *value;
972  *value = 0;
973  }
974  Set();
975  }
976 }
977 
979 {
981 
982  if (state == osUnknown) {
983  time_t now = time(NULL);
984  if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
985  if (!weekdays || !*weekdays) {
986  // Decrement single day:
987  time_t v = *value;
988  v -= SECSINDAY;
989  if (v < now) {
990  if (now <= v + SECSINDAY) { // switched from tomorrow to today
991  if (!weekdays)
992  v = 0;
993  }
994  else if (weekdays) { // switched from today to yesterday, so enter weekdays mode
995  v = 0;
996  dayindex = sizeof(days) / sizeof(int) - 2;
997  *weekdays = days[dayindex];
998  }
999  else // don't go before today
1000  v = *value;
1001  }
1002  *value = v;
1003  }
1004  else {
1005  // Decrement weekday index:
1006  if (dayindex > 0)
1007  *weekdays = days[--dayindex];
1008  }
1009  }
1010  else if (NORMALKEY(Key) == kRight) {
1011  if (!weekdays || !*weekdays) {
1012  // Increment single day:
1013  if (!*value)
1014  *value = cTimer::SetTime(now, 0);
1015  *value += SECSINDAY;
1016  }
1017  else {
1018  // Increment weekday index:
1019  *weekdays = days[++dayindex];
1020  if (!*weekdays) { // was last weekday entry, so switch to today
1021  *value = cTimer::SetTime(now, 0);
1022  dayindex = 0;
1023  }
1024  }
1025  }
1026  else if (weekdays) {
1027  if (Key == k0) {
1028  // Toggle between weekdays and single day:
1029  ToggleRepeating();
1030  return osContinue; // ToggleRepeating) has already called Set()
1031  }
1032  else if (k1 <= Key && Key <= k7) {
1033  // Toggle individual weekdays:
1034  if (*weekdays) {
1035  int v = *weekdays ^ (1 << (Key - k1));
1036  if (v != 0)
1037  *weekdays = v; // can't let this become all 0
1038  }
1039  }
1040  else
1041  return state;
1042  }
1043  else
1044  return state;
1045  Set();
1046  state = osContinue;
1047  }
1048  return state;
1049 }
1050 
1051 // --- cMenuEditTimeItem -----------------------------------------------------
1052 
1053 cMenuEditTimeItem::cMenuEditTimeItem(const char *Name, int *Value)
1054 :cMenuEditItem(Name)
1055 {
1056  value = Value;
1057  hh = *value / 100;
1058  mm = *value % 100;
1059  pos = 0;
1060  Set();
1061 }
1062 
1064 {
1065  switch (pos) {
1066  case 1: SetValue(cString::sprintf("%01d-:--", hh / 10)); break;
1067  case 2: SetValue(cString::sprintf("%02d:--", hh)); break;
1068  case 3: SetValue(cString::sprintf("%02d:%01d-", hh, mm / 10)); break;
1069  default: SetValue(cString::sprintf("%02d:%02d", hh, mm));
1070  }
1071 }
1072 
1074 {
1076 
1077  if (state == osUnknown) {
1078  if (k0 <= Key && Key <= k9) {
1079  if (fresh || pos > 3) {
1080  pos = 0;
1081  fresh = false;
1082  }
1083  int n = Key - k0;
1084  switch (pos) {
1085  case 0: if (n <= 2) {
1086  hh = n * 10;
1087  mm = 0;
1088  pos++;
1089  }
1090  break;
1091  case 1: if (hh + n <= 23) {
1092  hh += n;
1093  pos++;
1094  }
1095  break;
1096  case 2: if (n <= 5) {
1097  mm += n * 10;
1098  pos++;
1099  }
1100  break;
1101  case 3: if (mm + n <= 59) {
1102  mm += n;
1103  pos++;
1104  }
1105  break;
1106  default: ;
1107  }
1108  }
1109  else if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
1110  if (--mm < 0) {
1111  mm = 59;
1112  if (--hh < 0)
1113  hh = 23;
1114  }
1115  fresh = true;
1116  }
1117  else if (NORMALKEY(Key) == kRight) {
1118  if (++mm > 59) {
1119  mm = 0;
1120  if (++hh > 23)
1121  hh = 0;
1122  }
1123  fresh = true;
1124  }
1125  else
1126  return state;
1127  *value = hh * 100 + mm;
1128  Set();
1129  state = osContinue;
1130  }
1131  return state;
1132 }
1133 
1134 // --- cMenuEditMapItem ------------------------------------------------------
1135 
1136 cMenuEditMapItem::cMenuEditMapItem(const char *Name, int *Value, const tDvbParameterMap *Map, const char *ZeroString)
1137 :cMenuEditItem(Name)
1138 {
1139  value = Value;
1140  map = Map;
1141  zeroString = ZeroString;
1142  Set();
1143 }
1144 
1146 {
1147  const char *s = NULL;
1148  int n = MapToUser(*value, map, &s);
1149  if (n == 0 && zeroString)
1151  else if (n >= 0) {
1152  if (s)
1153  SetValue(s);
1154  else {
1155  char buf[16];
1156  snprintf(buf, sizeof(buf), "%d", n);
1157  SetValue(buf);
1158  }
1159  }
1160  else
1161  SetValue("???");
1162 }
1163 
1165 {
1167 
1168  if (state == osUnknown) {
1169  int newValue = *value;
1170  int n = DriverIndex(*value, map);
1171  if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
1172  if (n-- > 0)
1173  newValue = map[n].driverValue;
1174  }
1175  else if (NORMALKEY(Key) == kRight) {
1176  if (map[++n].userValue >= 0)
1177  newValue = map[n].driverValue;
1178  }
1179  else
1180  return state;
1181  if (newValue != *value) {
1182  *value = newValue;
1183  Set();
1184  }
1185  state = osContinue;
1186  }
1187  return state;
1188 }
1189 
1190 // --- cMenuSetupPage --------------------------------------------------------
1191 
1193 :cOsdMenu("", 36)
1194 {
1196  plugin = NULL;
1197 }
1198 
1199 void cMenuSetupPage::SetSection(const char *Section)
1200 {
1201  SetTitle(cString::sprintf("%s - %s", tr("Setup"), Section));
1202 }
1203 
1205 {
1206  eOSState state = cOsdMenu::ProcessKey(Key);
1207 
1208  if (state == osUnknown) {
1209  switch (Key) {
1210  case kOk: Store();
1211  state = osBack;
1212  break;
1213  default: break;
1214  }
1215  }
1216  return state;
1217 }
1218 
1220 {
1222  plugin = Plugin;
1223  SetSection(cString::sprintf("%s '%s'", tr("Plugin"), plugin->Name()));
1224 }
1225 
1226 void cMenuSetupPage::SetupStore(const char *Name, const char *Value)
1227 {
1228  if (plugin)
1229  plugin->SetupStore(Name, Value);
1230 }
1231 
1232 void cMenuSetupPage::SetupStore(const char *Name, int Value)
1233 {
1234  if (plugin)
1235  plugin->SetupStore(Name, Value);
1236 }
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
T & At(int Index) const
Definition: tools.h:694
cMenuSetupPage(void)
Definition: menuitems.c:1192
static void MsgOsdCurrentItem(const char *Text)
Definition: status.c:116
virtual void Set(void)
Definition: menuitems.c:82
cPlugin * plugin
Definition: menuitems.h:225
cString * channelID
Definition: menuitems.h:165
Definition: remote.h:98
static tChannelID FromString(const char *s)
Definition: channels.c:24
int EditableWidth(void)
Definition: skins.h:48
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:774
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
#define BASICKEY(k)
Definition: keys.h:83
Definition: keys.h:28
virtual void Set(void)
Definition: menuitems.c:148
static int days[]
Definition: menuitems.h:185
int FindDayIndex(int WeekDays)
Definition: menuitems.c:931
virtual void Set(void)
Definition: menuitems.c:243
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1127
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:197
void SetupStore(const char *Name, const char *Value=NULL)
Definition: plugin.c:110
int Source(void) const
Definition: channels.h:152
Definition: plugin.h:20
time_t * value
Definition: menuitems.h:186
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
char * strn0cpy(char *dest, const char *src, size_t n)
Definition: tools.c:131
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:1226
#define KEYKBD(k)
Definition: keys.h:85
const cStringList * strings
Definition: menuitems.h:151
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:1164
bool fresh
Definition: osdbase.h:54
virtual void Set(void)
Definition: menuitems.c:939
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:883
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:1204
static cSkinDisplay * Current(void)
Returns the currently active cSkinDisplay.
Definition: skins.h:61
Definition: keys.h:25
const tDvbParameterMap * map
Definition: menuitems.h:213
#define NORMALKEY(k)
Definition: keys.h:79
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:104
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:53
const char * maxString
Definition: menuitems.h:37
#define Utf8to(conv, c)
Definition: tools.h:146
const char * falseString
Definition: menuitems.h:46
const char *const * strings
Definition: menuitems.h:142
Definition: keys.h:55
Definition: skins.h:120
virtual void Store(void)=0
static time_t SetTime(time_t t, int SecondsFromMidnight)
Definition: timers.c:396
eOSState
Definition: osdbase.h:18
virtual void Set(void)
Definition: menuitems.c:1063
int Transponder(void) const
Returns the transponder frequency in MHz, plus the polarization in case of sat.
Definition: channels.c:147
double * value
Definition: menuitems.h:86
virtual eOSState ProcessKey(eKeys Key)
Definition: osdbase.c:540
int NumberKeysForChars
Definition: config.h:314
const char * noneString
Definition: menuitems.h:163
void SetPlugin(cPlugin *Plugin)
Definition: menuitems.c:1219
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:1150
virtual void Set(void)
Definition: menuitems.c:166
cMenuEditTranItem(const char *Name, int *Value, int *Source)
Definition: menuitems.c:865
cString ToString(void) const
Definition: channels.c:41
void SetMenuCategory(eMenuCategory MenuCategory)
Definition: osdbase.c:118
uint * allowedUtf8
Definition: menuitems.h:117
virtual void Set(void)
Definition: menuitems.c:791
#define LOCK_CHANNELS_READ
Definition: channels.h:267
int MapToUser(int Value, const tDvbParameterMap *Map, const char **String)
Definition: dvbdevice.c:173
bool GroupSep(void) const
Definition: channels.h:181
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:372
int DriverIndex(int Value, const tDvbParameterMap *Map)
Definition: dvbdevice.c:162
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:361
Definition: keys.h:20
const char * allowed
Definition: menuitems.h:112
#define Utf8is(ccls, c)
Definition: tools.h:147
int Find(const char *s) const
Definition: tools.c:1562
Definition: keys.h:26
void ToggleRepeating(void)
Definition: menuitems.c:958
static int GetWDay(time_t t)
Definition: timers.c:372
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
const char * Name(void) const
Definition: channels.c:108
uint * currentCharUtf8
Definition: menuitems.h:119
Definition: keys.h:21
void SetSection(const char *Section)
Definition: menuitems.c:1199
uint * valueUtf8
Definition: menuitems.h:116
bool InEditMode(void)
Definition: menuitems.h:133
void Insert(void)
Definition: menuitems.c:571
virtual int Width(void) const =0
Returns the original character width as requested when the font was created, or 0 if the default widt...
virtual void Set(void)
Definition: menuitems.c:819
cMenuEditDateItem(const char *Name, time_t *Value, int *WeekDays=NULL)
Definition: menuitems.c:920
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:1073
virtual void Set(void)
Definition: menuitems.c:1145
tChannelID GetChannelID(void) const
Definition: channels.h:190
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:900
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
cListObject * Next(void) const
Definition: tools.h:510
#define SECSINDAY
Definition: tools.h:42
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:918
const char * zeroString
Definition: menuitems.h:214
const char * current
Definition: menuitems.h:100
static bool ParseDay(const char *s, time_t &Day, int &WeekDays)
Definition: timers.c:202
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:978
cMenuEditTimeItem(const char *Name, int *Value)
Definition: menuitems.c:1053
virtual void Set(void)
Definition: menuitems.c:353
bool DoubleEqual(double a, double b)
Definition: tools.h:95
virtual void Set(void)
Definition: menuitems.c:183
Definition: osdbase.h:33
cMenuEditItem(const char *Name)
Definition: menuitems.c:26
void SetHelpKeys(void)
Definition: menuitems.c:237
Definition: keys.h:24
eOSState state
Definition: osdbase.h:51
void SetTitle(const char *Title)
Definition: osdbase.c:174
cMenuEditStrlItem(const char *Name, char *Value, int Length, const cStringList *Strings)
Definition: menuitems.c:779
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:799
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:176
int Number(void) const
Definition: channels.h:179
static const cFont * GetFont(eDvbFont Font)
Gets the given Font, which was previously set by a call to SetFont().
Definition: font.c:411
cMenuEditMapItem(const char *Name, int *Value, const tDvbParameterMap *Map, const char *ZeroString=NULL)
Definition: menuitems.c:1136
static cString PrintDay(time_t Day, int WeekDays, bool SingleByteChars)
Definition: timers.c:261
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:837
Definition: keys.h:22
bool TimedOut(void) const
Definition: tools.c:779