vdr  2.6.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 5.1 2020/12/26 15:49:01 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  keepSpace = false;
394  macro = -1;
395  lastMacro = -1;
396  macros = NULL;
397  insert = uppercase = false;
398  newchar = true;
399  lengthUtf8 = 0;
400  valueUtf8 = NULL;
401  allowedUtf8 = NULL;
402  charMapUtf8 = NULL;
403  currentCharUtf8 = NULL;
404  lastKey = kNone;
405  Set();
406 }
407 
409 {
410  delete[] valueUtf8;
411  delete[] allowedUtf8;
412  delete[] charMapUtf8;
413 }
414 
415 void cMenuEditStrItem::SetMacros(const char **Macros)
416 {
417  macros = Macros;
418  macro = 0;
419  lastMacro = -1;
420 }
421 
423 {
424  if (!valueUtf8) {
425  valueUtf8 = new uint[length];
427  int l = strlen(allowed) + 1;
428  allowedUtf8 = new uint[l];
430  const char *charMap = tr("CharMap$ 0\t-.,1#~\\^$[]|()*+?{}/:%@&\tabc2\tdef3\tghi4\tjkl5\tmno6\tpqrs7\ttuv8\twxyz9");
431  l = strlen(charMap) + 1;
432  charMapUtf8 = new uint[l];
433  Utf8ToArray(charMap, charMapUtf8, l);
435  AdvancePos();
436  }
437 }
438 
440 {
441  if (valueUtf8) {
442  if (SaveValue) {
444  if (!keepSpace)
445  stripspace(value);
446  }
447  lengthUtf8 = 0;
448  delete[] valueUtf8;
449  valueUtf8 = NULL;
450  delete[] allowedUtf8;
451  allowedUtf8 = NULL;
452  delete[] charMapUtf8;
453  charMapUtf8 = NULL;
454  pos = -1;
455  offset = 0;
456  newchar = true;
457  }
458 }
459 
461 {
462  if (InEditMode())
463  SetHelp(tr("Button$ABC/abc"), insert ? tr("Button$Overwrite") : tr("Button$Insert"), tr("Button$Delete"), macros ? tr("Button$Macro") : NULL);
464  else
465  SetHelp(NULL);
466 }
467 
469 {
470  if (allowedUtf8) {
471  for (uint *a = allowedUtf8; *a; a++) {
472  if (c == *a)
473  return a;
474  }
475  }
476  return NULL;
477 }
478 
480 {
481  if (pos < length - 2 && pos < lengthUtf8) {
482  if (++pos >= lengthUtf8) {
483  if (pos >= 2 && valueUtf8[pos - 1] == ' ' && valueUtf8[pos - 2] == ' ')
484  pos--; // allow only two blanks at the end
485  else {
486  valueUtf8[pos] = ' ';
487  valueUtf8[pos + 1] = 0;
488  lengthUtf8++;
489  }
490  }
491  }
492  newchar = true;
493  if (!insert && Utf8is(alpha, valueUtf8[pos]))
494  uppercase = Utf8is(upper, valueUtf8[pos]);
495 }
496 
498 {
499  if (InEditMode()) {
500  // This is an ugly hack to make editing strings work with the 'skincurses' plugin.
501  const cFont *font = dynamic_cast<cSkinDisplayMenu *>(cSkinDisplay::Current())->GetTextAreaFont(false);
502  if (!font || font->Width("W") != 1) // all characters have width == 1 in the font used by 'skincurses'
503  font = cFont::GetFont(fontOsd);
504 
505  int width = cSkinDisplay::Current()->EditableWidth();
506  width -= font->Width("[]");
507  width -= font->Width("<>"); // reserving this anyway makes the whole thing simpler
508 
509  if (pos < offset)
510  offset = pos;
511  int WidthFromOffset = 0;
512  int EndPos = lengthUtf8;
513  for (int i = offset; i < lengthUtf8; i++) {
514  WidthFromOffset += font->Width(valueUtf8[i]);
515  if (WidthFromOffset > width) {
516  if (pos >= i) {
517  do {
518  WidthFromOffset -= font->Width(valueUtf8[offset]);
519  offset++;
520  } while (WidthFromOffset > width && offset < pos);
521  EndPos = pos + 1;
522  }
523  else {
524  EndPos = i;
525  break;
526  }
527  }
528  }
529 
530  char buf[1000];
531  char *p = buf;
532  if (offset)
533  *p++ = '<';
534  p += Utf8FromArray(valueUtf8 + offset, p, sizeof(buf) - (p - buf), pos - offset);
535  *p++ = '[';
536  if (insert && newchar)
537  *p++ = ']';
538  p += Utf8FromArray(&valueUtf8[pos], p, sizeof(buf) - (p - buf), 1);
539  if (!(insert && newchar))
540  *p++ = ']';
541  p += Utf8FromArray(&valueUtf8[pos + 1], p, sizeof(buf) - (p - buf), EndPos - pos - 1);
542  if (EndPos != lengthUtf8)
543  *p++ = '>';
544  *p = 0;
545 
546  SetValue(buf);
547  }
548  else
549  SetValue(value);
550 }
551 
552 uint cMenuEditStrItem::Inc(uint c, bool Up)
553 {
554  uint *p = IsAllowed(c);
555  if (!p)
556  p = allowedUtf8;
557  if (Up) {
558  if (!*++p)
559  p = allowedUtf8;
560  }
561  else if (--p < allowedUtf8) {
562  p = allowedUtf8;
563  while (*p && *(p + 1))
564  p++;
565  }
566  return *p;
567 }
568 
570 {
571  if (insert && lengthUtf8 < length - 1)
572  Insert();
573  valueUtf8[pos] = c;
574  if (pos < length - 2)
575  pos++;
576  if (pos >= lengthUtf8) {
577  valueUtf8[pos] = ' ';
578  valueUtf8[pos + 1] = 0;
579  lengthUtf8 = pos + 1;
580  }
581 }
582 
584 {
585  memmove(valueUtf8 + pos + 1, valueUtf8 + pos, (lengthUtf8 - pos + 1) * sizeof(*valueUtf8));
586  lengthUtf8++;
587  valueUtf8[pos] = ' ';
588 }
589 
591 {
592  memmove(valueUtf8 + pos, valueUtf8 + pos + 1, (lengthUtf8 - pos) * sizeof(*valueUtf8));
593  lengthUtf8--;
594 }
595 
597 {
598  if (!macros)
599  return;
600  if (lastMacro >= 0) {
601  int l = strlen(macros[lastMacro]);
602  while (l-- > 0)
603  Delete();
604  }
605  const char *p = macros[macro];
606  int oldPos = pos;
607  bool oldInsert = insert;
608  insert = true;
609  newchar = true;
610  while (*p) {
611  Type(*p);
612  p++;
613  }
614  insert = oldInsert;
615  pos = oldPos;
616  lastMacro = macro;
617  if (!macros[++macro])
618  macro = 0;
619 }
620 
622 {
623  bool SameKey = NORMALKEY(Key) == lastKey;
624  if (Key != kNone) {
625  lastKey = NORMALKEY(Key);
626  if (Key != kBlue)
627  lastMacro = -1;
628  }
629  else if (!newchar && k0 <= lastKey && lastKey <= k9 && autoAdvanceTimeout.TimedOut()) {
630  AdvancePos();
631  newchar = true;
632  currentCharUtf8 = NULL;
633  Set();
634  return osContinue;
635  }
636  switch (int(Key)) {
637  case kRed: // Switch between upper- and lowercase characters
638  if (InEditMode()) {
639  if (!insert || !newchar) {
640  uppercase = !uppercase;
641  valueUtf8[pos] = uppercase ? Utf8to(upper, valueUtf8[pos]) : Utf8to(lower, valueUtf8[pos]);
642  }
643  }
644  else
645  return osUnknown;
646  break;
647  case kGreen: // Toggle insert/overwrite modes
648  if (InEditMode()) {
649  insert = !insert;
650  newchar = true;
651  SetHelpKeys();
652  }
653  else
654  return osUnknown;
655  break;
656  case kYellow|k_Repeat:
657  case kYellow: // Remove the character at the current position; in insert mode it is the character to the right of the cursor
658  if (InEditMode()) {
659  if (lengthUtf8 > 1) {
660  if (!insert || pos < lengthUtf8 - 1)
661  Delete();
662  else if (insert && pos == lengthUtf8 - 1)
663  valueUtf8[pos] = ' '; // in insert mode, deleting the last character replaces it with a blank to keep the cursor position
664  // reduce position, if we removed the last character
665  if (pos == lengthUtf8)
666  pos--;
667  }
668  else if (lengthUtf8 == 1)
669  valueUtf8[0] = ' '; // This is the last character in the string, replace it with a blank
670  if (Utf8is(alpha, valueUtf8[pos]))
671  uppercase = Utf8is(upper, valueUtf8[pos]);
672  newchar = true;
673  }
674  else
675  return osUnknown;
676  break;
677  case kBlue|k_Repeat:
678  case kBlue: if (InEditMode())
679  InsertMacro();
680  else
681  return osUnknown;
682  break;
683  case kLeft|k_Repeat:
684  case kLeft: if (pos > 0) {
685  if (!insert || newchar)
686  pos--;
687  newchar = true;
688  if (!insert && Utf8is(alpha, valueUtf8[pos]))
689  uppercase = Utf8is(upper, valueUtf8[pos]);
690  }
691  break;
692  case kRight|k_Repeat:
693  case kRight: if (InEditMode())
694  AdvancePos();
695  else {
696  EnterEditMode();
697  SetHelpKeys();
698  }
699  break;
700  case kUp|k_Repeat:
701  case kUp:
702  case kDown|k_Repeat:
703  case kDown: if (InEditMode()) {
704  if (insert && newchar) {
705  // create a new character in insert mode
706  if (lengthUtf8 < length - 1)
707  Insert();
708  }
709  if (uppercase)
710  valueUtf8[pos] = Utf8to(upper, Inc(Utf8to(lower, valueUtf8[pos]), NORMALKEY(Key) == kUp));
711  else
712  valueUtf8[pos] = Inc( valueUtf8[pos], NORMALKEY(Key) == kUp);
713  newchar = false;
714  }
715  else
716  return cMenuEditItem::ProcessKey(Key);
717  break;
718  case k0|k_Repeat ... k9|k_Repeat:
719  case k0 ... k9: {
720  if (InEditMode()) {
722  if (!SameKey) {
723  if (!newchar)
724  AdvancePos();
725  currentCharUtf8 = NULL;
726  }
727  if (!currentCharUtf8 || !*currentCharUtf8 || *currentCharUtf8 == '\t') {
728  // find the beginning of the character map entry for Key
729  int n = NORMALKEY(Key) - k0;
731  while (n > 0 && *currentCharUtf8) {
732  if (*currentCharUtf8++ == '\t')
733  n--;
734  }
735  // find first allowed character
736  while (*currentCharUtf8 && *currentCharUtf8 != '\t' && !IsAllowed(*currentCharUtf8))
737  currentCharUtf8++;
738  }
739  if (*currentCharUtf8 && *currentCharUtf8 != '\t') {
740  if (insert && newchar) {
741  // create a new character in insert mode
742  if (lengthUtf8 < length - 1)
743  Insert();
744  }
746  if (uppercase)
747  valueUtf8[pos] = Utf8to(upper, valueUtf8[pos]);
748  // find next allowed character
749  do {
750  currentCharUtf8++;
751  } while (*currentCharUtf8 && *currentCharUtf8 != '\t' && !IsAllowed(*currentCharUtf8));
752  newchar = false;
754  }
755  }
756  else
757  Type('0' + NORMALKEY(Key) - k0);
758  }
759  else
760  return cMenuEditItem::ProcessKey(Key);
761  }
762  break;
763  case kBack:
764  case kOk: if (InEditMode()) {
765  LeaveEditMode(Key == kOk);
766  SetHelpKeys();
767  break;
768  }
769  // run into default
770  default: if (InEditMode() && BASICKEY(Key) == kKbd) {
771  int c = KEYKBD(Key);
772  if (c <= 0xFF) { // FIXME what about other UTF-8 characters?
773  if (IsAllowed(Utf8to(lower, c)))
774  Type(c);
775  else {
776  switch (c) {
777  case 0x7F: // backspace
778  if (pos > 0) {
779  pos--;
780  return ProcessKey(kYellow);
781  }
782  break;
783  default: ;
784  }
785  }
786  }
787  else {
788  switch (c) {
789  case kfHome: pos = 0; break;
790  case kfEnd: pos = lengthUtf8 - 1; break;
791  case kfIns: return ProcessKey(kGreen);
792  case kfDel: return ProcessKey(kYellow);
793  default: ;
794  }
795  }
796  }
797  else
798  return cMenuEditItem::ProcessKey(Key);
799  }
800  Set();
801  return osContinue;
802 }
803 
804 // --- cMenuEditStraItem -----------------------------------------------------
805 
806 cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings)
807 :cMenuEditIntItem(Name, Value, 0, NumStrings - 1)
808 {
809  strings = Strings;
810  Set();
811 }
812 
814 {
816 }
817 
818 // --- cMenuEditStrlItem -----------------------------------------------------
819 
820 cMenuEditStrlItem::cMenuEditStrlItem(const char *Name, char *Value, int Length, const cStringList *Strings)
821 :cMenuEditIntItem(Name, &index, 0, Strings->Size() - 1)
822 {
823  strings = Strings;
824  value = Value;
825  length = Length;
826  index = strings->Find(value);
827  if (index < 0)
828  index = 0;
829  Set();
830 }
831 
833 {
835  SetValue(value);
836 }
837 
838 // --- cMenuEditChanItem -----------------------------------------------------
839 
840 cMenuEditChanItem::cMenuEditChanItem(const char *Name, int *Value, const char *NoneString)
841 :cMenuEditIntItem(Name, Value, NoneString ? 0 : 1, cChannels::MaxNumber())
842 {
843  channelID = NULL;
844  noneString = NoneString;
845  dummyValue = 0;
846  Set();
847 }
848 
849 cMenuEditChanItem::cMenuEditChanItem(const char *Name, cString *ChannelID, const char *NoneString)
850 :cMenuEditIntItem(Name, &dummyValue, NoneString ? 0 : 1, cChannels::MaxNumber())
851 {
852  channelID = ChannelID;
853  noneString = NoneString;
855  const cChannel *Channel = Channels->GetByChannelID(tChannelID::FromString(*ChannelID));
856  dummyValue = Channel ? Channel->Number() : 0;
857  Set();
858 }
859 
861 {
862  if (*value > 0) {
863  char buf[255];
865  const cChannel *Channel = Channels->GetByNumber(*value);
866  snprintf(buf, sizeof(buf), "%d %s", *value, Channel ? Channel->Name() : "");
867  SetValue(buf);
868  if (channelID)
869  *channelID = Channel ? Channel->GetChannelID().ToString() : "";
870  }
871  else if (noneString) {
873  if (channelID)
874  *channelID = "";
875  }
876 }
877 
879 {
880  int delta = 1;
881 
882  switch (int(Key)) {
883  case kLeft|k_Repeat:
884  case kLeft: delta = -1;
885  case kRight|k_Repeat:
886  case kRight:
887  {
889  const cChannel *Channel = Channels->GetByNumber(*value + delta, delta);
890  if (Channel)
891  *value = Channel->Number();
892  else if (delta < 0 && noneString)
893  *value = 0;
894  if (channelID)
895  *channelID = Channel ? Channel->GetChannelID().ToString() : "";
896  Set();
897  }
898  break;
899  default: return cMenuEditIntItem::ProcessKey(Key);
900  }
901  return osContinue;
902 }
903 
904 // --- cMenuEditTranItem -----------------------------------------------------
905 
906 cMenuEditTranItem::cMenuEditTranItem(const char *Name, int *Value, int *Source)
907 :cMenuEditChanItem(Name, &number, "-")
908 {
909  number = 0;
910  source = Source;
911  transponder = Value;
913  const cChannel *Channel = Channels->First();
914  while (Channel) {
915  if (!Channel->GroupSep() && *source == Channel->Source() && ISTRANSPONDER(Channel->Transponder(), *Value)) {
916  number = Channel->Number();
917  break;
918  }
919  Channel = Channels->Next(Channel);
920  }
921  Set();
922 }
923 
925 {
928  if (const cChannel *Channel = Channels->GetByNumber(number)) {
929  *source = Channel->Source();
930  *transponder = Channel->Transponder();
931  }
932  else {
933  *source = 0;
934  *transponder = 0;
935  }
936  return state;
937 }
938 
939 // --- cMenuEditDateItem -----------------------------------------------------
940 
941 static int ParseWeekDays(const char *s)
942 {
943  time_t day;
944  int weekdays;
945  return cTimer::ParseDay(s, day, weekdays) ? weekdays : 0;
946 }
947 
948 int cMenuEditDateItem::days[] = { ParseWeekDays("M------"),
949  ParseWeekDays("-T-----"),
950  ParseWeekDays("--W----"),
951  ParseWeekDays("---T---"),
952  ParseWeekDays("----F--"),
953  ParseWeekDays("-----S-"),
954  ParseWeekDays("------S"),
955  ParseWeekDays("MTWTF--"),
956  ParseWeekDays("MTWTFS-"),
957  ParseWeekDays("MTWTFSS"),
958  ParseWeekDays("-----SS"),
959  0 };
960 
961 cMenuEditDateItem::cMenuEditDateItem(const char *Name, time_t *Value, int *WeekDays)
962 :cMenuEditItem(Name)
963 {
964  value = Value;
965  weekdays = WeekDays;
966  oldvalue = 0;
967  oldweekdays = 0;
969  Set();
970 }
971 
973 {
974  for (unsigned int i = 0; i < sizeof(days) / sizeof(int); i++)
975  if (WeekDays == days[i])
976  return i;
977  return 0;
978 }
979 
981 {
982 #define DATEBUFFERSIZE 32
983  char buf[DATEBUFFERSIZE];
984  if (weekdays && *weekdays) {
985  SetValue(cTimer::PrintDay(0, *weekdays, false));
986  return;
987  }
988  else if (*value) {
989  struct tm tm_r;
990  localtime_r(value, &tm_r);
991  strftime(buf, DATEBUFFERSIZE, "%Y-%m-%d ", &tm_r);
992  strcat(buf, WeekDayName(tm_r.tm_wday));
993  }
994  else
995  *buf = 0;
996  SetValue(buf);
997 }
998 
1000 {
1001  if (weekdays) {
1002  if (*weekdays) {
1003  *value = cTimer::SetTime(oldvalue ? oldvalue : time(NULL), 0);
1004  oldvalue = 0;
1005  oldweekdays = *weekdays;
1006  *weekdays = 0;
1007  }
1008  else {
1010  oldweekdays = 0;
1012  oldvalue = *value;
1013  *value = 0;
1014  }
1015  Set();
1016  }
1017 }
1018 
1020 {
1022 
1023  if (state == osUnknown) {
1024  time_t now = time(NULL);
1025  if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
1026  if (!weekdays || !*weekdays) {
1027  // Decrement single day:
1028  time_t v = *value;
1029  v -= SECSINDAY;
1030  if (v < now) {
1031  if (now <= v + SECSINDAY) { // switched from tomorrow to today
1032  if (!weekdays)
1033  v = 0;
1034  }
1035  else if (weekdays) { // switched from today to yesterday, so enter weekdays mode
1036  v = 0;
1037  dayindex = sizeof(days) / sizeof(int) - 2;
1038  *weekdays = days[dayindex];
1039  }
1040  else // don't go before today
1041  v = *value;
1042  }
1043  *value = v;
1044  }
1045  else {
1046  // Decrement weekday index:
1047  if (dayindex > 0)
1048  *weekdays = days[--dayindex];
1049  }
1050  }
1051  else if (NORMALKEY(Key) == kRight) {
1052  if (!weekdays || !*weekdays) {
1053  // Increment single day:
1054  if (!*value)
1055  *value = cTimer::SetTime(now, 0);
1056  *value += SECSINDAY;
1057  }
1058  else {
1059  // Increment weekday index:
1060  *weekdays = days[++dayindex];
1061  if (!*weekdays) { // was last weekday entry, so switch to today
1062  *value = cTimer::SetTime(now, 0);
1063  dayindex = 0;
1064  }
1065  }
1066  }
1067  else if (weekdays) {
1068  if (Key == k0) {
1069  // Toggle between weekdays and single day:
1070  ToggleRepeating();
1071  return osContinue; // ToggleRepeating) has already called Set()
1072  }
1073  else if (k1 <= Key && Key <= k7) {
1074  // Toggle individual weekdays:
1075  if (*weekdays) {
1076  int v = *weekdays ^ (1 << (Key - k1));
1077  if (v != 0)
1078  *weekdays = v; // can't let this become all 0
1079  }
1080  }
1081  else
1082  return state;
1083  }
1084  else
1085  return state;
1086  Set();
1087  state = osContinue;
1088  }
1089  return state;
1090 }
1091 
1092 // --- cMenuEditTimeItem -----------------------------------------------------
1093 
1094 cMenuEditTimeItem::cMenuEditTimeItem(const char *Name, int *Value)
1095 :cMenuEditItem(Name)
1096 {
1097  value = Value;
1098  hh = *value / 100;
1099  mm = *value % 100;
1100  pos = 0;
1101  Set();
1102 }
1103 
1105 {
1106  switch (pos) {
1107  case 1: SetValue(cString::sprintf("%01d-:--", hh / 10)); break;
1108  case 2: SetValue(cString::sprintf("%02d:--", hh)); break;
1109  case 3: SetValue(cString::sprintf("%02d:%01d-", hh, mm / 10)); break;
1110  default: SetValue(cString::sprintf("%02d:%02d", hh, mm));
1111  }
1112 }
1113 
1115 {
1117 
1118  if (state == osUnknown) {
1119  if (k0 <= Key && Key <= k9) {
1120  if (fresh || pos > 3) {
1121  pos = 0;
1122  fresh = false;
1123  }
1124  int n = Key - k0;
1125  switch (pos) {
1126  case 0: if (n <= 2) {
1127  hh = n * 10;
1128  mm = 0;
1129  pos++;
1130  }
1131  break;
1132  case 1: if (hh + n <= 23) {
1133  hh += n;
1134  pos++;
1135  }
1136  break;
1137  case 2: if (n <= 5) {
1138  mm += n * 10;
1139  pos++;
1140  }
1141  break;
1142  case 3: if (mm + n <= 59) {
1143  mm += n;
1144  pos++;
1145  }
1146  break;
1147  default: ;
1148  }
1149  }
1150  else if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
1151  if (--mm < 0) {
1152  mm = 59;
1153  if (--hh < 0)
1154  hh = 23;
1155  }
1156  fresh = true;
1157  }
1158  else if (NORMALKEY(Key) == kRight) {
1159  if (++mm > 59) {
1160  mm = 0;
1161  if (++hh > 23)
1162  hh = 0;
1163  }
1164  fresh = true;
1165  }
1166  else
1167  return state;
1168  *value = hh * 100 + mm;
1169  Set();
1170  state = osContinue;
1171  }
1172  return state;
1173 }
1174 
1175 // --- cMenuEditMapItem ------------------------------------------------------
1176 
1177 cMenuEditMapItem::cMenuEditMapItem(const char *Name, int *Value, const tDvbParameterMap *Map, const char *ZeroString)
1178 :cMenuEditItem(Name)
1179 {
1180  value = Value;
1181  map = Map;
1182  zeroString = ZeroString;
1183  Set();
1184 }
1185 
1187 {
1188  const char *s = NULL;
1189  int n = MapToUser(*value, map, &s);
1190  if (n == 0 && zeroString)
1192  else if (n >= 0) {
1193  if (s)
1194  SetValue(s);
1195  else {
1196  char buf[16];
1197  snprintf(buf, sizeof(buf), "%d", n);
1198  SetValue(buf);
1199  }
1200  }
1201  else
1202  SetValue("???");
1203 }
1204 
1206 {
1208 
1209  if (state == osUnknown) {
1210  int newValue = *value;
1211  int n = DriverIndex(*value, map);
1212  if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
1213  if (n-- > 0)
1214  newValue = map[n].driverValue;
1215  }
1216  else if (NORMALKEY(Key) == kRight) {
1217  if (map[++n].userValue >= 0)
1218  newValue = map[n].driverValue;
1219  }
1220  else
1221  return state;
1222  if (newValue != *value) {
1223  *value = newValue;
1224  Set();
1225  }
1226  state = osContinue;
1227  }
1228  return state;
1229 }
1230 
1231 // --- cMenuSetupPage --------------------------------------------------------
1232 
1234 :cOsdMenu("", 36)
1235 {
1237  plugin = NULL;
1238 }
1239 
1240 void cMenuSetupPage::SetSection(const char *Section)
1241 {
1242  SetTitle(cString::sprintf("%s - %s", tr("Setup"), Section));
1243 }
1244 
1246 {
1247  eOSState state = cOsdMenu::ProcessKey(Key);
1248 
1249  if (state == osUnknown) {
1250  switch (Key) {
1251  case kOk: Store();
1252  state = osBack;
1253  break;
1254  default: break;
1255  }
1256  }
1257  return state;
1258 }
1259 
1261 {
1263  plugin = Plugin;
1264  SetSection(cString::sprintf("%s '%s'", tr("Plugin"), plugin->Name()));
1265 }
1266 
1267 void cMenuSetupPage::SetupStore(const char *Name, const char *Value)
1268 {
1269  if (plugin)
1270  plugin->SetupStore(Name, Value);
1271 }
1272 
1273 void cMenuSetupPage::SetupStore(const char *Name, int Value)
1274 {
1275  if (plugin)
1276  plugin->SetupStore(Name, Value);
1277 }
#define LOCK_CHANNELS_READ
Definition: channels.h:269
#define ISTRANSPONDER(f1, f2)
Definition: channels.h:18
int Source(void) const
Definition: channels.h:151
int Number(void) const
Definition: channels.h:178
const char * Name(void) const
Definition: channels.c:107
tChannelID GetChannelID(void) const
Definition: channels.h:190
bool GroupSep(void) const
Definition: channels.h:180
int Transponder(void) const
Returns the transponder frequency in MHz, plus the polarization in case of sat.
Definition: channels.c:146
Definition: font.h:37
virtual int Width(void) const =0
Returns the original character width as requested when the font was created, or 0 if the default widt...
static const cFont * GetFont(eDvbFont Font)
Gets the given Font, which was previously set by a call to SetFont().
Definition: font.c:411
cListObject * Next(void) const
Definition: tools.h:557
cMenuEditBitItem(const char *Name, uint *Value, uint Mask, const char *FalseString=NULL, const char *TrueString=NULL)
Definition: menuitems.c:157
virtual void Set(void)
Definition: menuitems.c:166
virtual void Set(void)
Definition: menuitems.c:148
cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString=NULL, const char *TrueString=NULL)
Definition: menuitems.c:140
const char * falseString
Definition: menuitems.h:46
const char * trueString
Definition: menuitems.h:46
virtual void Set(void)
Definition: menuitems.c:860
cString * channelID
Definition: menuitems.h:171
cMenuEditChanItem(const char *Name, int *Value, const char *NoneString=NULL)
Definition: menuitems.c:840
const char * noneString
Definition: menuitems.h:169
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:878
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:361
const char * current
Definition: menuitems.h:100
cMenuEditChrItem(const char *Name, char *Value, const char *Allowed)
Definition: menuitems.c:337
virtual void Set(void)
Definition: menuitems.c:353
char * allowed
Definition: menuitems.h:99
int FindDayIndex(int WeekDays)
Definition: menuitems.c:972
void ToggleRepeating(void)
Definition: menuitems.c:999
static int days[]
Definition: menuitems.h:191
time_t * value
Definition: menuitems.h:192
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:1019
virtual void Set(void)
Definition: menuitems.c:980
cMenuEditDateItem(const char *Name, time_t *Value, int *WeekDays=NULL)
Definition: menuitems.c:961
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
virtual void Set(void)
Definition: menuitems.c:82
const char * maxString
Definition: menuitems.h:37
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:95
const char * minString
Definition: menuitems.h:37
virtual void Set(void)
Definition: menuitems.c:243
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 SetHelpKeys(void)
Definition: menuitems.c:237
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:253
const char * negString
Definition: menuitems.h:76
const char * posString
Definition: menuitems.h:76
const char * helpYellow
Definition: menuitems.h:22
bool DisplayHelp(bool Current)
Definition: menuitems.c:54
char * name
Definition: menuitems.h:21
const char * helpRed
Definition: menuitems.h:22
void SetHelp(const char *Red, const char *Green=NULL, const char *Yellow=NULL, const char *Blue=NULL)
Definition: menuitems.c:44
const char * helpGreen
Definition: menuitems.h:22
void SetValue(const char *Value)
Definition: menuitems.c:37
bool helpDisplayed
Definition: menuitems.h:23
cMenuEditItem(const char *Name)
Definition: menuitems.c:26
const char * helpBlue
Definition: menuitems.h:22
const tDvbParameterMap * map
Definition: menuitems.h:219
virtual void Set(void)
Definition: menuitems.c:1186
const char * zeroString
Definition: menuitems.h:220
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:1205
cMenuEditMapItem(const char *Name, int *Value, const tDvbParameterMap *Map, const char *ZeroString=NULL)
Definition: menuitems.c:1177
virtual void Set(void)
Definition: menuitems.c:183
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:197
cMenuEditNumItem(const char *Name, char *Value, int Length, bool Blind=false)
Definition: menuitems.c:174
cMenuEditPrcItem(const char *Name, double *Value, double Min=0.0, double Max=1.0, int Decimals=0)
Definition: menuitems.c:272
virtual void Set(void)
Definition: menuitems.c:289
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:296
double * value
Definition: menuitems.h:86
const char * allowed
Definition: menuitems.h:112
uint Inc(uint c, bool Up)
Definition: menuitems.c:552
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:621
uint * valueUtf8
Definition: menuitems.h:119
void Insert(void)
Definition: menuitems.c:583
void Delete(void)
Definition: menuitems.c:590
void LeaveEditMode(bool SaveValue=false)
Definition: menuitems.c:439
uint * allowedUtf8
Definition: menuitems.h:120
void Type(uint c)
Definition: menuitems.c:569
cTimeMs autoAdvanceTimeout
Definition: menuitems.h:124
uint * currentCharUtf8
Definition: menuitems.h:122
cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed=NULL)
Definition: menuitems.c:385
void InsertMacro(void)
Definition: menuitems.c:596
virtual void Set(void)
Definition: menuitems.c:497
const char ** macros
Definition: menuitems.h:115
bool InEditMode(void)
Definition: menuitems.h:137
void AdvancePos(void)
Definition: menuitems.c:479
void SetMacros(const char **Macros)
Definition: menuitems.c:415
void SetHelpKeys(void)
Definition: menuitems.c:460
void EnterEditMode(void)
Definition: menuitems.c:422
uint * charMapUtf8
Definition: menuitems.h:121
uint * IsAllowed(uint c)
Definition: menuitems.c:468
const char *const * strings
Definition: menuitems.h:148
virtual void Set(void)
Definition: menuitems.c:813
cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char *const *Strings)
Definition: menuitems.c:806
const cStringList * strings
Definition: menuitems.h:157
virtual void Set(void)
Definition: menuitems.c:832
cMenuEditStrlItem(const char *Name, char *Value, int Length, const cStringList *Strings)
Definition: menuitems.c:820
cMenuEditTimeItem(const char *Name, int *Value)
Definition: menuitems.c:1094
virtual void Set(void)
Definition: menuitems.c:1104
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:1114
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:924
cMenuEditTranItem(const char *Name, int *Value, int *Source)
Definition: menuitems.c:906
virtual eOSState ProcessKey(eKeys Key)
Definition: menuitems.c:1245
virtual void Store(void)=0
cMenuSetupPage(void)
Definition: menuitems.c:1233
void SetSection(const char *Section)
Definition: menuitems.c:1240
void SetupStore(const char *Name, const char *Value=NULL)
Definition: menuitems.c:1267
cPlugin * plugin
Definition: menuitems.h:231
void SetPlugin(cPlugin *Plugin)
Definition: menuitems.c:1260
virtual eOSState ProcessKey(eKeys Key)
Definition: osdbase.c:63
eOSState state
Definition: osdbase.h:51
bool fresh
Definition: osdbase.h:54
void SetText(const char *Text, bool Copy=true)
Definition: osdbase.c:42
void SetTitle(const char *Title)
Definition: osdbase.c:174
void SetMenuCategory(eMenuCategory MenuCategory)
Definition: osdbase.c:118
virtual eOSState ProcessKey(eKeys Key)
Definition: osdbase.c:540
Definition: plugin.h:22
const char * Name(void)
Definition: plugin.h:36
void SetupStore(const char *Name, const char *Value=NULL)
Definition: plugin.c:110
int NumberKeysForChars
Definition: config.h:321
int EditableWidth(void)
Definition: skins.h:48
static cSkinDisplay * Current(void)
Returns the currently active cSkinDisplay.
Definition: skins.h:61
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
static void MsgOsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue)
Definition: status.c:104
static void MsgOsdCurrentItem(const char *Text)
Definition: status.c:116
int Find(const char *s) const
Definition: tools.c:1584
Definition: tools.h:178
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1149
void Set(int Ms=0)
Sets the timer.
Definition: tools.c:792
bool TimedOut(void) const
Definition: tools.c:797
static time_t SetTime(time_t t, int SecondsFromMidnight)
Definition: timers.c:536
static int GetWDay(time_t t)
Definition: timers.c:512
static cString PrintDay(time_t Day, int WeekDays, bool SingleByteChars)
Definition: timers.c:390
static bool ParseDay(const char *s, time_t &Day, int &WeekDays)
Definition: timers.c:331
T & At(int Index) const
Definition: tools.h:741
cSetup Setup
Definition: config.c:372
int DriverIndex(int Value, const tDvbParameterMap *Map)
Definition: dvbdevice.c:164
int MapToUser(int Value, const tDvbParameterMap *Map, const char **String)
Definition: dvbdevice.c:175
@ fontOsd
Definition: font.h:22
#define tr(s)
Definition: i18n.h:85
#define trNOOP(s)
Definition: i18n.h:88
#define BASICKEY(k)
Definition: keys.h:83
#define KEYKBD(k)
Definition: keys.h:85
#define NORMALKEY(k)
Definition: keys.h:79
eKeys
Definition: keys.h:16
@ kRight
Definition: keys.h:23
@ k9
Definition: keys.h:28
@ kRed
Definition: keys.h:24
@ kUp
Definition: keys.h:17
@ kNone
Definition: keys.h:55
@ k7
Definition: keys.h:28
@ kDown
Definition: keys.h:18
@ kGreen
Definition: keys.h:25
@ k1
Definition: keys.h:28
@ kLeft
Definition: keys.h:22
@ kBlue
Definition: keys.h:27
@ kKbd
Definition: keys.h:56
@ k0
Definition: keys.h:28
@ kYellow
Definition: keys.h:26
@ kBack
Definition: keys.h:21
@ k_Repeat
Definition: keys.h:61
@ kOk
Definition: keys.h:20
#define AUTO_ADVANCE_TIMEOUT
Definition: menuitems.c:20
static int ParseWeekDays(const char *s)
Definition: menuitems.c:941
const char * FileNameChars
Definition: menuitems.c:22
#define DATEBUFFERSIZE
eOSState
Definition: osdbase.h:18
@ osContinue
Definition: osdbase.h:19
@ osUnknown
Definition: osdbase.h:18
@ osBack
Definition: osdbase.h:33
@ kfIns
Definition: remote.h:101
@ kfDel
Definition: remote.h:102
@ kfEnd
Definition: remote.h:98
@ kfHome
Definition: remote.h:97
@ mcSetup
Definition: skins.h:120
@ mcPluginSetup
Definition: skins.h:119
static tChannelID FromString(const char *s)
Definition: channels.c:23
cString ToString(void) const
Definition: channels.c:40
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:918
cString WeekDayName(int WeekDay)
Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a three letter day name.
Definition: tools.c:1172
char * stripspace(char *s)
Definition: tools.c:219
char * strn0cpy(char *dest, const char *src, size_t n)
Definition: tools.c:131
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:936
#define SECSINDAY
Definition: tools.h:42
#define Utf8to(conv, c)
Definition: tools.h:148
bool DoubleEqual(double a, double b)
Definition: tools.h:97
#define Utf8is(ccls, c)
Definition: tools.h:149