vdr 2.6.7
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
22const char *FileNameChars = trNOOP("FileNameChars$ abcdefghijklmnopqrstuvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&");
23
24// --- cMenuEditItem ---------------------------------------------------------
25
27{
28 name = strdup(Name ? Name : "???");
29 SetHelp(NULL);
30}
31
36
37void cMenuEditItem::SetValue(const char *Value)
38{
39 cString buffer = cString::sprintf("%s:\t%s", name, Value);
40 SetText(buffer);
42}
43
44void cMenuEditItem::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue)
45{
46 // strings are NOT copied - must be constants!!!
47 helpRed = Red;
48 helpGreen = Green;
49 helpYellow = Yellow;
50 helpBlue = Blue;
51 helpDisplayed = false;
52}
53
55{
56 bool HasHelp = helpRed || helpGreen || helpYellow || helpBlue;
57 if (HasHelp && !helpDisplayed && Current) {
60 }
61 helpDisplayed = Current;
62 return HasHelp;
63}
64
65// --- cMenuEditIntItem ------------------------------------------------------
66
67cMenuEditIntItem::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 }
134 }
135 return state;
136}
137
138// --- cMenuEditBoolItem -----------------------------------------------------
139
140cMenuEditBoolItem::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
157cMenuEditBitItem::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
174cMenuEditNumItem::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
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();
222 }
223 return state;
224}
225
226// --- cMenuEditIntxItem -----------------------------------------------------
227
228cMenuEditIntxItem::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();
262 }
263 break;
264 default: ;
265 }
266 }
267 return state;
268}
269
270// --- cMenuEditPrcItem ------------------------------------------------------
271
272cMenuEditPrcItem::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 }
331 }
332 return state;
333}
334
335// --- cMenuEditChrItem ------------------------------------------------------
336
337cMenuEditChrItem::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)
345 Set();
346}
347
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();
379 }
380 return state;
381}
382
383// --- cMenuEditStrItem ------------------------------------------------------
384
385cMenuEditStrItem::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
415void 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)
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
550}
551
552uint 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;
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) {
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 {
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
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 {
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
806cMenuEditStraItem::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
820cMenuEditStrlItem::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;
827 if (index < 0)
828 index = 0;
829 Set();
830}
831
837
838// --- cMenuEditChanItem -----------------------------------------------------
839
840cMenuEditChanItem::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
849cMenuEditChanItem::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
906cMenuEditTranItem::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
941static int ParseWeekDays(const char *s)
942{
943 time_t day;
944 int weekdays;
945 return cTimer::ParseDay(s, day, weekdays) ? weekdays : 0;
946}
947
948int 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
961cMenuEditDateItem::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) {
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;
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;
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:
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
1094cMenuEditTimeItem::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
1177cMenuEditMapItem::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
1240void 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
1267void cMenuSetupPage::SetupStore(const char *Name, const char *Value)
1268{
1269 if (plugin)
1270 plugin->SetupStore(Name, Value);
1271}
1272
1273void cMenuSetupPage::SetupStore(const char *Name, int Value)
1274{
1275 if (plugin)
1276 plugin->SetupStore(Name, Value);
1277}
#define LOCK_CHANNELS_READ
Definition channels.h:270
#define ISTRANSPONDER(f1, f2)
Definition channels.h:18
int Source(void) const
Definition channels.h:152
int Number(void) const
Definition channels.h:179
const char * Name(void) const
Definition channels.c:121
tChannelID GetChannelID(void) const
Definition channels.h:191
bool GroupSep(void) const
Definition channels.h:181
int Transponder(void) const
Returns the transponder frequency in MHz, plus the polarization in case of sat.
Definition channels.c:154
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:412
cListObject * Next(void) const
Definition tools.h:560
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
int FindDayIndex(int WeekDays)
Definition menuitems.c:972
void ToggleRepeating(void)
Definition menuitems.c:999
static int days[]
Definition menuitems.h:948
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
void Insert(void)
Definition menuitems.c:583
void Delete(void)
Definition menuitems.c:590
void LeaveEditMode(bool SaveValue=false)
Definition menuitems.c:439
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 * 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:536
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:323
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:1610
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition tools.c:1175
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:544
static int GetWDay(time_t t)
Definition timers.c:520
static cString PrintDay(time_t Day, int WeekDays, bool SingleByteChars)
Definition timers.c:398
static bool ParseDay(const char *s, time_t &Day, int &WeekDays)
Definition timers.c:339
T & At(int Index) const
Definition tools.h:744
cSetup Setup
Definition config.c:372
int DriverIndex(int Value, const tDvbParameterMap *Map)
Definition dvbdevice.c:167
int MapToUser(int Value, const tDvbParameterMap *Map, const char **String)
Definition dvbdevice.c:178
@ 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
const char * FileNameChars
Definition menuitems.c:22
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:1198
char * stripspace(char *s)
Definition tools.c:219
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
char * strn0cpy(char *dest, const char *src, size_t n)
Definition tools.c:131
#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