vdr 2.7.2
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.2 2024/07/13 09:12:18 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 const cFont *font = dynamic_cast<cSkinDisplayMenu *>(cSkinDisplay::Current())->GetTextAreaFont(false);
501
502 int width = cSkinDisplay::Current()->EditableWidth();
503 width -= font->Width("[]");
504 width -= font->Width("<>"); // reserving this anyway makes the whole thing simpler
505
506 if (pos < offset)
507 offset = pos;
508 int WidthFromOffset = 0;
509 int EndPos = lengthUtf8;
510 for (int i = offset; i < lengthUtf8; i++) {
511 WidthFromOffset += font->Width(valueUtf8[i]);
512 if (WidthFromOffset > width) {
513 if (pos >= i) {
514 do {
515 WidthFromOffset -= font->Width(valueUtf8[offset]);
516 offset++;
517 } while (WidthFromOffset > width && offset < pos);
518 EndPos = pos + 1;
519 }
520 else {
521 EndPos = i;
522 break;
523 }
524 }
525 }
526
527 char buf[1000];
528 char *p = buf;
529 if (offset)
530 *p++ = '<';
531 p += Utf8FromArray(valueUtf8 + offset, p, sizeof(buf) - (p - buf), pos - offset);
532 *p++ = '[';
533 if (insert && newchar)
534 *p++ = ']';
535 p += Utf8FromArray(&valueUtf8[pos], p, sizeof(buf) - (p - buf), 1);
536 if (!(insert && newchar))
537 *p++ = ']';
538 p += Utf8FromArray(&valueUtf8[pos + 1], p, sizeof(buf) - (p - buf), EndPos - pos - 1);
539 if (EndPos != lengthUtf8)
540 *p++ = '>';
541 *p = 0;
542
543 SetValue(buf);
544 }
545 else
547}
548
549uint cMenuEditStrItem::Inc(uint c, bool Up)
550{
551 uint *p = IsAllowed(c);
552 if (!p)
553 p = allowedUtf8;
554 if (Up) {
555 if (!*++p)
556 p = allowedUtf8;
557 }
558 else if (--p < allowedUtf8) {
559 p = allowedUtf8;
560 while (*p && *(p + 1))
561 p++;
562 }
563 return *p;
564}
565
567{
568 if (insert && lengthUtf8 < length - 1)
569 Insert();
570 valueUtf8[pos] = c;
571 if (pos < length - 2)
572 pos++;
573 if (pos >= lengthUtf8) {
574 valueUtf8[pos] = ' ';
575 valueUtf8[pos + 1] = 0;
576 lengthUtf8 = pos + 1;
577 }
578}
579
581{
582 memmove(valueUtf8 + pos + 1, valueUtf8 + pos, (lengthUtf8 - pos + 1) * sizeof(*valueUtf8));
583 lengthUtf8++;
584 valueUtf8[pos] = ' ';
585}
586
588{
589 memmove(valueUtf8 + pos, valueUtf8 + pos + 1, (lengthUtf8 - pos) * sizeof(*valueUtf8));
590 lengthUtf8--;
591}
592
594{
595 if (!macros)
596 return;
597 if (lastMacro >= 0) {
598 int l = strlen(macros[lastMacro]);
599 while (l-- > 0)
600 Delete();
601 }
602 const char *p = macros[macro];
603 int oldPos = pos;
604 bool oldInsert = insert;
605 insert = true;
606 newchar = true;
607 while (*p) {
608 Type(*p);
609 p++;
610 }
611 insert = oldInsert;
612 pos = oldPos;
614 if (!macros[++macro])
615 macro = 0;
616}
617
619{
620 bool SameKey = NORMALKEY(Key) == lastKey;
621 if (Key != kNone) {
622 lastKey = NORMALKEY(Key);
623 if (Key != kBlue)
624 lastMacro = -1;
625 }
626 else if (!newchar && k0 <= lastKey && lastKey <= k9 && autoAdvanceTimeout.TimedOut()) {
627 AdvancePos();
628 newchar = true;
629 currentCharUtf8 = NULL;
630 Set();
631 return osContinue;
632 }
633 switch (int(Key)) {
634 case kRed: // Switch between upper- and lowercase characters
635 if (InEditMode()) {
636 if (!insert || !newchar) {
638 valueUtf8[pos] = uppercase ? Utf8to(upper, valueUtf8[pos]) : Utf8to(lower, valueUtf8[pos]);
639 }
640 }
641 else
642 return osUnknown;
643 break;
644 case kGreen: // Toggle insert/overwrite modes
645 if (InEditMode()) {
646 insert = !insert;
647 newchar = true;
648 SetHelpKeys();
649 }
650 else
651 return osUnknown;
652 break;
653 case kYellow|k_Repeat:
654 case kYellow: // Remove the character at the current position; in insert mode it is the character to the right of the cursor
655 if (InEditMode()) {
656 if (lengthUtf8 > 1) {
657 if (!insert || pos < lengthUtf8 - 1)
658 Delete();
659 else if (insert && pos == lengthUtf8 - 1)
660 valueUtf8[pos] = ' '; // in insert mode, deleting the last character replaces it with a blank to keep the cursor position
661 // reduce position, if we removed the last character
662 if (pos == lengthUtf8)
663 pos--;
664 }
665 else if (lengthUtf8 == 1)
666 valueUtf8[0] = ' '; // This is the last character in the string, replace it with a blank
667 if (Utf8is(alpha, valueUtf8[pos]))
668 uppercase = Utf8is(upper, valueUtf8[pos]);
669 newchar = true;
670 }
671 else
672 return osUnknown;
673 break;
674 case kBlue|k_Repeat:
675 case kBlue: if (InEditMode())
676 InsertMacro();
677 else
678 return osUnknown;
679 break;
680 case kLeft|k_Repeat:
681 case kLeft: if (pos > 0) {
682 if (!insert || newchar)
683 pos--;
684 newchar = true;
685 if (!insert && Utf8is(alpha, valueUtf8[pos]))
686 uppercase = Utf8is(upper, valueUtf8[pos]);
687 }
688 break;
689 case kRight|k_Repeat:
690 case kRight: if (InEditMode())
691 AdvancePos();
692 else {
694 SetHelpKeys();
695 }
696 break;
697 case kUp|k_Repeat:
698 case kUp:
699 case kDown|k_Repeat:
700 case kDown: if (InEditMode()) {
701 if (insert && newchar) {
702 // create a new character in insert mode
703 if (lengthUtf8 < length - 1)
704 Insert();
705 }
706 if (uppercase)
707 valueUtf8[pos] = Utf8to(upper, Inc(Utf8to(lower, valueUtf8[pos]), NORMALKEY(Key) == kUp));
708 else
709 valueUtf8[pos] = Inc( valueUtf8[pos], NORMALKEY(Key) == kUp);
710 newchar = false;
711 }
712 else
713 return cMenuEditItem::ProcessKey(Key);
714 break;
715 case k0|k_Repeat ... k9|k_Repeat:
716 case k0 ... k9: {
717 if (InEditMode()) {
719 if (!SameKey) {
720 if (!newchar)
721 AdvancePos();
722 currentCharUtf8 = NULL;
723 }
724 if (!currentCharUtf8 || !*currentCharUtf8 || *currentCharUtf8 == '\t') {
725 // find the beginning of the character map entry for Key
726 int n = NORMALKEY(Key) - k0;
728 while (n > 0 && *currentCharUtf8) {
729 if (*currentCharUtf8++ == '\t')
730 n--;
731 }
732 // find first allowed character
735 }
736 if (*currentCharUtf8 && *currentCharUtf8 != '\t') {
737 if (insert && newchar) {
738 // create a new character in insert mode
739 if (lengthUtf8 < length - 1)
740 Insert();
741 }
743 if (uppercase)
744 valueUtf8[pos] = Utf8to(upper, valueUtf8[pos]);
745 // find next allowed character
746 do {
748 } while (*currentCharUtf8 && *currentCharUtf8 != '\t' && !IsAllowed(*currentCharUtf8));
749 newchar = false;
751 }
752 }
753 else
754 Type('0' + NORMALKEY(Key) - k0);
755 }
756 else
757 return cMenuEditItem::ProcessKey(Key);
758 }
759 break;
760 case kBack:
761 case kOk: if (InEditMode()) {
762 LeaveEditMode(Key == kOk);
763 SetHelpKeys();
764 break;
765 }
766 // run into default
767 default: if (InEditMode() && BASICKEY(Key) == kKbd) {
768 int c = KEYKBD(Key);
769 if (c <= 0xFF) { // FIXME what about other UTF-8 characters?
770 if (IsAllowed(Utf8to(lower, c)))
771 Type(c);
772 else {
773 switch (c) {
774 case 0x7F: // backspace
775 if (pos > 0) {
776 pos--;
777 return ProcessKey(kYellow);
778 }
779 break;
780 default: ;
781 }
782 }
783 }
784 else {
785 switch (c) {
786 case kfHome: pos = 0; break;
787 case kfEnd: pos = lengthUtf8 - 1; break;
788 case kfIns: return ProcessKey(kGreen);
789 case kfDel: return ProcessKey(kYellow);
790 default: ;
791 }
792 }
793 }
794 else
795 return cMenuEditItem::ProcessKey(Key);
796 }
797 Set();
798 return osContinue;
799}
800
801// --- cMenuEditStraItem -----------------------------------------------------
802
803cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings)
804:cMenuEditIntItem(Name, Value, 0, NumStrings - 1)
805{
806 strings = Strings;
807 Set();
808}
809
811{
813}
814
815// --- cMenuEditStrlItem -----------------------------------------------------
816
817cMenuEditStrlItem::cMenuEditStrlItem(const char *Name, char *Value, int Length, const cStringList *Strings)
818:cMenuEditIntItem(Name, &index, 0, Strings->Size() - 1)
819{
820 strings = Strings;
821 value = Value;
822 length = Length;
824 if (index < 0)
825 index = 0;
826 Set();
827}
828
834
835// --- cMenuEditChanItem -----------------------------------------------------
836
837cMenuEditChanItem::cMenuEditChanItem(const char *Name, int *Value, const char *NoneString)
838:cMenuEditIntItem(Name, Value, NoneString ? 0 : 1, cChannels::MaxNumber())
839{
840 channelID = NULL;
841 noneString = NoneString;
842 dummyValue = 0;
843 Set();
844}
845
846cMenuEditChanItem::cMenuEditChanItem(const char *Name, cString *ChannelID, const char *NoneString)
847:cMenuEditIntItem(Name, &dummyValue, NoneString ? 0 : 1, cChannels::MaxNumber())
848{
849 channelID = ChannelID;
850 noneString = NoneString;
852 const cChannel *Channel = Channels->GetByChannelID(tChannelID::FromString(*ChannelID));
853 dummyValue = Channel ? Channel->Number() : 0;
854 Set();
855}
856
858{
859 if (*value > 0) {
860 char buf[255];
862 const cChannel *Channel = Channels->GetByNumber(*value);
863 snprintf(buf, sizeof(buf), "%d %s", *value, Channel ? Channel->Name() : "");
864 SetValue(buf);
865 if (channelID)
866 *channelID = Channel ? Channel->GetChannelID().ToString() : "";
867 }
868 else if (noneString) {
870 if (channelID)
871 *channelID = "";
872 }
873}
874
876{
877 int delta = 1;
878
879 switch (int(Key)) {
880 case kLeft|k_Repeat:
881 case kLeft: delta = -1;
882 case kRight|k_Repeat:
883 case kRight:
884 {
886 const cChannel *Channel = Channels->GetByNumber(*value + delta, delta);
887 if (Channel)
888 *value = Channel->Number();
889 else if (delta < 0 && noneString)
890 *value = 0;
891 if (channelID)
892 *channelID = Channel ? Channel->GetChannelID().ToString() : "";
893 Set();
894 }
895 break;
896 default: return cMenuEditIntItem::ProcessKey(Key);
897 }
898 return osContinue;
899}
900
901// --- cMenuEditTranItem -----------------------------------------------------
902
903cMenuEditTranItem::cMenuEditTranItem(const char *Name, int *Value, int *Source)
904:cMenuEditChanItem(Name, &number, "-")
905{
906 number = 0;
907 source = Source;
908 transponder = Value;
910 const cChannel *Channel = Channels->First();
911 while (Channel) {
912 if (!Channel->GroupSep() && *source == Channel->Source() && ISTRANSPONDER(Channel->Transponder(), *Value)) {
913 number = Channel->Number();
914 break;
915 }
916 Channel = Channels->Next(Channel);
917 }
918 Set();
919}
920
922{
925 if (const cChannel *Channel = Channels->GetByNumber(number)) {
926 *source = Channel->Source();
927 *transponder = Channel->Transponder();
928 }
929 else {
930 *source = 0;
931 *transponder = 0;
932 }
933 return state;
934}
935
936// --- cMenuEditDateItem -----------------------------------------------------
937
938static int ParseWeekDays(const char *s)
939{
940 time_t day;
941 int weekdays;
942 return cTimer::ParseDay(s, day, weekdays) ? weekdays : 0;
943}
944
945int cMenuEditDateItem::days[] = { ParseWeekDays("M------"),
946 ParseWeekDays("-T-----"),
947 ParseWeekDays("--W----"),
948 ParseWeekDays("---T---"),
949 ParseWeekDays("----F--"),
950 ParseWeekDays("-----S-"),
951 ParseWeekDays("------S"),
952 ParseWeekDays("MTWTF--"),
953 ParseWeekDays("MTWTFS-"),
954 ParseWeekDays("MTWTFSS"),
955 ParseWeekDays("-----SS"),
956 0 };
957
958cMenuEditDateItem::cMenuEditDateItem(const char *Name, time_t *Value, int *WeekDays)
959:cMenuEditItem(Name)
960{
961 value = Value;
962 weekdays = WeekDays;
963 oldvalue = 0;
964 oldweekdays = 0;
966 Set();
967}
968
970{
971 for (unsigned int i = 0; i < sizeof(days) / sizeof(int); i++)
972 if (WeekDays == days[i])
973 return i;
974 return 0;
975}
976
978{
979#define DATEBUFFERSIZE 32
980 char buf[DATEBUFFERSIZE];
981 if (weekdays && *weekdays) {
983 return;
984 }
985 else if (*value) {
986 struct tm tm_r;
987 localtime_r(value, &tm_r);
988 strftime(buf, DATEBUFFERSIZE, "%Y-%m-%d ", &tm_r);
989 strcat(buf, WeekDayName(tm_r.tm_wday));
990 }
991 else
992 *buf = 0;
993 SetValue(buf);
994}
995
997{
998 if (weekdays) {
999 if (*weekdays) {
1000 *value = cTimer::SetTime(oldvalue ? oldvalue : time(NULL), 0);
1001 oldvalue = 0;
1003 *weekdays = 0;
1004 }
1005 else {
1007 oldweekdays = 0;
1009 oldvalue = *value;
1010 *value = 0;
1011 }
1012 Set();
1013 }
1014}
1015
1017{
1019
1020 if (state == osUnknown) {
1021 time_t now = time(NULL);
1022 if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
1023 if (!weekdays || !*weekdays) {
1024 // Decrement single day:
1025 time_t v = *value;
1026 v -= SECSINDAY;
1027 if (v < now) {
1028 if (now <= v + SECSINDAY) { // switched from tomorrow to today
1029 if (!weekdays)
1030 v = 0;
1031 }
1032 else if (weekdays) { // switched from today to yesterday, so enter weekdays mode
1033 v = 0;
1034 dayindex = sizeof(days) / sizeof(int) - 2;
1036 }
1037 else // don't go before today
1038 v = *value;
1039 }
1040 *value = v;
1041 }
1042 else {
1043 // Decrement weekday index:
1044 if (dayindex > 0)
1045 *weekdays = days[--dayindex];
1046 }
1047 }
1048 else if (NORMALKEY(Key) == kRight) {
1049 if (!weekdays || !*weekdays) {
1050 // Increment single day:
1051 if (!*value)
1052 *value = cTimer::SetTime(now, 0);
1053 *value += SECSINDAY;
1054 }
1055 else {
1056 // Increment weekday index:
1057 *weekdays = days[++dayindex];
1058 if (!*weekdays) { // was last weekday entry, so switch to today
1059 *value = cTimer::SetTime(now, 0);
1060 dayindex = 0;
1061 }
1062 }
1063 }
1064 else if (weekdays) {
1065 if (Key == k0) {
1066 // Toggle between weekdays and single day:
1068 return osContinue; // ToggleRepeating) has already called Set()
1069 }
1070 else if (k1 <= Key && Key <= k7) {
1071 // Toggle individual weekdays:
1072 if (*weekdays) {
1073 int v = *weekdays ^ (1 << (Key - k1));
1074 if (v != 0)
1075 *weekdays = v; // can't let this become all 0
1076 }
1077 }
1078 else
1079 return state;
1080 }
1081 else
1082 return state;
1083 Set();
1084 state = osContinue;
1085 }
1086 return state;
1087}
1088
1089// --- cMenuEditTimeItem -----------------------------------------------------
1090
1091cMenuEditTimeItem::cMenuEditTimeItem(const char *Name, int *Value)
1092:cMenuEditItem(Name)
1093{
1094 value = Value;
1095 hh = *value / 100;
1096 mm = *value % 100;
1097 pos = 0;
1098 Set();
1099}
1100
1102{
1103 switch (pos) {
1104 case 1: SetValue(cString::sprintf("%01d-:--", hh / 10)); break;
1105 case 2: SetValue(cString::sprintf("%02d:--", hh)); break;
1106 case 3: SetValue(cString::sprintf("%02d:%01d-", hh, mm / 10)); break;
1107 default: SetValue(cString::sprintf("%02d:%02d", hh, mm));
1108 }
1109}
1110
1112{
1114
1115 if (state == osUnknown) {
1116 if (k0 <= Key && Key <= k9) {
1117 if (fresh || pos > 3) {
1118 pos = 0;
1119 fresh = false;
1120 }
1121 int n = Key - k0;
1122 switch (pos) {
1123 case 0: if (n <= 2) {
1124 hh = n * 10;
1125 mm = 0;
1126 pos++;
1127 }
1128 break;
1129 case 1: if (hh + n <= 23) {
1130 hh += n;
1131 pos++;
1132 }
1133 break;
1134 case 2: if (n <= 5) {
1135 mm += n * 10;
1136 pos++;
1137 }
1138 break;
1139 case 3: if (mm + n <= 59) {
1140 mm += n;
1141 pos++;
1142 }
1143 break;
1144 default: ;
1145 }
1146 }
1147 else if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
1148 if (--mm < 0) {
1149 mm = 59;
1150 if (--hh < 0)
1151 hh = 23;
1152 }
1153 fresh = true;
1154 }
1155 else if (NORMALKEY(Key) == kRight) {
1156 if (++mm > 59) {
1157 mm = 0;
1158 if (++hh > 23)
1159 hh = 0;
1160 }
1161 fresh = true;
1162 }
1163 else
1164 return state;
1165 *value = hh * 100 + mm;
1166 Set();
1167 state = osContinue;
1168 }
1169 return state;
1170}
1171
1172// --- cMenuEditMapItem ------------------------------------------------------
1173
1174cMenuEditMapItem::cMenuEditMapItem(const char *Name, int *Value, const tDvbParameterMap *Map, const char *ZeroString)
1175:cMenuEditItem(Name)
1176{
1177 value = Value;
1178 map = Map;
1179 zeroString = ZeroString;
1180 Set();
1181}
1182
1184{
1185 const char *s = NULL;
1186 int n = MapToUser(*value, map, &s);
1187 if (n == 0 && zeroString)
1189 else if (n >= 0) {
1190 if (s)
1191 SetValue(s);
1192 else {
1193 char buf[16];
1194 snprintf(buf, sizeof(buf), "%d", n);
1195 SetValue(buf);
1196 }
1197 }
1198 else
1199 SetValue("???");
1200}
1201
1203{
1205
1206 if (state == osUnknown) {
1207 int newValue = *value;
1208 int n = DriverIndex(*value, map);
1209 if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
1210 if (n-- > 0)
1211 newValue = map[n].driverValue;
1212 }
1213 else if (NORMALKEY(Key) == kRight) {
1214 if (map[++n].userValue >= 0)
1215 newValue = map[n].driverValue;
1216 }
1217 else
1218 return state;
1219 if (newValue != *value) {
1220 *value = newValue;
1221 Set();
1222 }
1223 state = osContinue;
1224 }
1225 return state;
1226}
1227
1228// --- cMenuSetupPage --------------------------------------------------------
1229
1231:cOsdMenu("", 36)
1232{
1234 plugin = NULL;
1235}
1236
1237void cMenuSetupPage::SetSection(const char *Section)
1238{
1239 SetTitle(cString::sprintf("%s - %s", tr("Setup"), Section));
1240}
1241
1243{
1244 eOSState state = cOsdMenu::ProcessKey(Key);
1245
1246 if (state == osUnknown) {
1247 switch (Key) {
1248 case kOk: Store();
1249 state = osBack;
1250 break;
1251 default: break;
1252 }
1253 }
1254 return state;
1255}
1256
1258{
1260 plugin = Plugin;
1261 SetSection(cString::sprintf("%s '%s'", tr("Plugin"), plugin->Name()));
1262}
1263
1264void cMenuSetupPage::SetupStore(const char *Name, const char *Value)
1265{
1266 if (plugin)
1267 plugin->SetupStore(Name, Value);
1268}
1269
1270void cMenuSetupPage::SetupStore(const char *Name, int Value)
1271{
1272 if (plugin)
1273 plugin->SetupStore(Name, Value);
1274}
#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...
cListObject * Next(void) const
Definition tools.h:547
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:857
cString * channelID
Definition menuitems.h:171
cMenuEditChanItem(const char *Name, int *Value, const char *NoneString=NULL)
Definition menuitems.c:837
const char * noneString
Definition menuitems.h:169
virtual eOSState ProcessKey(eKeys Key)
Definition menuitems.c:875
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:969
void ToggleRepeating(void)
Definition menuitems.c:996
static int days[]
Definition menuitems.h:945
virtual eOSState ProcessKey(eKeys Key)
Definition menuitems.c:1016
virtual void Set(void)
Definition menuitems.c:977
cMenuEditDateItem(const char *Name, time_t *Value, int *WeekDays=NULL)
Definition menuitems.c:958
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:1183
const char * zeroString
Definition menuitems.h:220
virtual eOSState ProcessKey(eKeys Key)
Definition menuitems.c:1202
cMenuEditMapItem(const char *Name, int *Value, const tDvbParameterMap *Map, const char *ZeroString=NULL)
Definition menuitems.c:1174
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:549
virtual eOSState ProcessKey(eKeys Key)
Definition menuitems.c:618
void Insert(void)
Definition menuitems.c:580
void Delete(void)
Definition menuitems.c:587
void LeaveEditMode(bool SaveValue=false)
Definition menuitems.c:439
void Type(uint c)
Definition menuitems.c:566
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:593
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:810
cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char *const *Strings)
Definition menuitems.c:803
const cStringList * strings
Definition menuitems.h:157
virtual void Set(void)
Definition menuitems.c:829
cMenuEditStrlItem(const char *Name, char *Value, int Length, const cStringList *Strings)
Definition menuitems.c:817
cMenuEditTimeItem(const char *Name, int *Value)
Definition menuitems.c:1091
virtual void Set(void)
Definition menuitems.c:1101
virtual eOSState ProcessKey(eKeys Key)
Definition menuitems.c:1111
virtual eOSState ProcessKey(eKeys Key)
Definition menuitems.c:921
cMenuEditTranItem(const char *Name, int *Value, int *Source)
Definition menuitems.c:903
virtual eOSState ProcessKey(eKeys Key)
Definition menuitems.c:1242
virtual void Store(void)=0
cMenuSetupPage(void)
Definition menuitems.c:1230
void SetSection(const char *Section)
Definition menuitems.c:1237
void SetupStore(const char *Name, const char *Value=NULL)
Definition menuitems.c:1264
cPlugin * plugin
Definition menuitems.h:231
void SetPlugin(cPlugin *Plugin)
Definition menuitems.c:1257
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: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:1623
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition tools.c:1188
void Set(int Ms=0)
Sets the timer.
Definition tools.c:805
bool TimedOut(void) const
Definition tools.c:810
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:731
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
#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:938
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:931
cString WeekDayName(int WeekDay)
Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a three letter day name.
Definition tools.c:1211
char * stripspace(char *s)
Definition tools.c:224
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:949
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