vdr 2.7.6
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.4 2025/06/18 20:22:10 kls Exp $
8 */
9
10#include "menuitems.h"
11#include <ctype.h>
12#include <math.h>
13#include <wctype.h>
14#include "i18n.h"
15#include "plugin.h"
16#include "remote.h"
17#include "skins.h"
18#include "status.h"
19
20#define AUTO_ADVANCE_TIMEOUT 1500 // ms before auto advance when entering characters via numeric keys
21
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);
41}
42
43void cMenuEditItem::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue)
44{
45 // strings are NOT copied - must be constants!!!
46 helpRed = Red;
47 helpGreen = Green;
48 helpYellow = Yellow;
49 helpBlue = Blue;
50 helpDisplayed = false;
51}
52
54{
55 bool HasHelp = helpRed || helpGreen || helpYellow || helpBlue;
56 if (HasHelp && !helpDisplayed && Current) {
59 }
60 helpDisplayed = Current;
61 return HasHelp;
62}
63
64// --- cMenuEditIntItem ------------------------------------------------------
65
66cMenuEditIntItem::cMenuEditIntItem(const char *Name, int *Value, int Min, int Max, const char *MinString, const char *MaxString)
67:cMenuEditItem(Name)
68{
69 value = Value;
70 min = Min;
71 max = Max;
72 minString = MinString;
73 maxString = MaxString;
74 if (*value < min)
75 *value = min;
76 else if (*value > max)
77 *value = max;
78 Set();
79}
80
82{
83 if (minString && *value == min)
85 else if (maxString && *value == max)
87 else {
88 char buf[16];
89 snprintf(buf, sizeof(buf), "%d", *value);
90 SetValue(buf);
91 }
92}
93
95{
97
98 if (state == osUnknown) {
99 int newValue = *value;
100 bool IsRepeat = Key & k_Repeat;
101 Key = NORMALKEY(Key);
102 switch (Key) {
103 case kNone: return state;
104 case k0 ... k9:
105 if (fresh) {
106 newValue = 0;
107 fresh = false;
108 }
109 newValue = newValue * 10 + (Key - k0);
110 break;
111 case kLeft: // TODO might want to increase the delta if repeated quickly?
112 newValue = *value - 1;
113 fresh = true;
114 if (!IsRepeat && newValue < min && max != INT_MAX)
115 newValue = max;
116 break;
117 case kRight:
118 newValue = *value + 1;
119 fresh = true;
120 if (!IsRepeat && newValue > max && min != INT_MIN)
121 newValue = min;
122 break;
123 default:
124 if (*value < min) { *value = min; Set(); }
125 if (*value > max) { *value = max; Set(); }
126 return state;
127 }
128 if (newValue != *value && (!fresh || min <= newValue) && newValue <= max) {
129 *value = newValue;
130 Set();
131 }
133 }
134 return state;
135}
136
137// --- cMenuEditBoolItem -----------------------------------------------------
138
139cMenuEditBoolItem::cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString, const char *TrueString)
140:cMenuEditIntItem(Name, Value, 0, 1)
141{
142 falseString = FalseString ? FalseString : tr("no");
143 trueString = TrueString ? TrueString : tr("yes");
144 Set();
145}
146
148{
149 char buf[16];
150 snprintf(buf, sizeof(buf), "%s", *value ? trueString : falseString);
151 SetValue(buf);
152}
153
154// --- cMenuEditBitItem ------------------------------------------------------
155
156cMenuEditBitItem::cMenuEditBitItem(const char *Name, uint *Value, uint Mask, const char *FalseString, const char *TrueString)
157:cMenuEditBoolItem(Name, &bit, FalseString, TrueString)
158{
159 value = Value;
160 bit = (*value & Mask) != 0;
161 mask = Mask;
162 Set();
163}
164
166{
167 *value = bit ? *value | mask : *value & ~mask;
169}
170
171// --- cMenuEditNumItem ------------------------------------------------------
172
173cMenuEditNumItem::cMenuEditNumItem(const char *Name, char *Value, int Length, bool Blind)
174:cMenuEditItem(Name)
175{
176 value = Value;
177 length = Length;
178 blind = Blind;
179 Set();
180}
181
183{
184 if (blind) {
185 char buf[length + 1];
186 int i;
187 for (i = 0; i < length && value[i]; i++)
188 buf[i] = '*';
189 buf[i] = 0;
190 SetValue(buf);
191 }
192 else
194}
195
197{
199
200 if (state == osUnknown) {
201 Key = NORMALKEY(Key);
202 switch (Key) {
203 case kLeft: {
204 int l = strlen(value);
205 if (l > 0)
206 value[l - 1] = 0;
207 }
208 break;
209 case k0 ... k9: {
210 int l = strlen(value);
211 if (l < length) {
212 value[l] = Key - k0 + '0';
213 value[l + 1] = 0;
214 }
215 }
216 break;
217 default: return state;
218 }
219 Set();
221 }
222 return state;
223}
224
225// --- cMenuEditIntxItem -----------------------------------------------------
226
227cMenuEditIntxItem::cMenuEditIntxItem(const char *Name, int *Value, int Min, int Max, int Factor, const char *NegString, const char *PosString)
228:cMenuEditIntItem(Name, Value, Min, Max)
229{
230 factor = ::max(Factor, 1);
231 negString = NegString;
232 posString = PosString;
233 Set();
234}
235
237{
238 if (negString && posString)
239 SetHelp(NULL, (*value < 0) ? posString : negString);
240}
241
243{
244 const char *s = (*value < 0) ? negString : posString;
245 int v = *value;
246 if (negString && posString)
247 v = abs(v);
248 SetValue(cString::sprintf(s ? "%.*f %s" : "%.*f", factor / 10, double(v) / factor, s));
249 SetHelpKeys();
250}
251
253{
255 if (state == osUnknown) {
256 switch (Key) {
257 case kGreen: if (negString && posString) {
258 *value = -*value;
259 Set();
261 }
262 break;
263 default: ;
264 }
265 }
266 return state;
267}
268
269// --- cMenuEditPrcItem ------------------------------------------------------
270
271cMenuEditPrcItem::cMenuEditPrcItem(const char *Name, double *Value, double Min, double Max, int Decimals)
272:cMenuEditItem(Name)
273{
274 value = Value;
275 min = Min;
276 max = Max;
277 decimals = Decimals;
278 factor = 100;
279 while (Decimals-- > 0)
280 factor *= 10;
281 if (*value < min)
282 *value = min;
283 else if (*value > max)
284 *value = max;
285 Set();
286}
287
289{
290 char buf[16];
291 snprintf(buf, sizeof(buf), "%.*f", decimals, *value * 100);
292 SetValue(buf);
293}
294
296{
298
299 if (state == osUnknown) {
300 double newValue = round(*value * factor); // avoids precision problems
301 Key = NORMALKEY(Key);
302 switch (Key) {
303 case kNone: return state;
304 case k0 ... k9:
305 if (fresh) {
306 newValue = 0;
307 fresh = false;
308 }
309 newValue = newValue * 10 + (Key - k0);
310 break;
311 case kLeft: // TODO might want to increase the delta if repeated quickly?
312 newValue--;
313 fresh = true;
314 break;
315 case kRight:
316 newValue++;
317 fresh = true;
318 break;
319 default:
320 if (*value < min) { *value = min; Set(); }
321 if (*value > max) { *value = max; Set(); }
322 return state;
323 }
324 newValue /= factor;
325 if (!DoubleEqual(newValue, *value) && (!fresh || min <= newValue) && newValue <= max) {
326 *value = newValue;
327 Set();
328 }
330 }
331 return state;
332}
333
334// --- cMenuEditChrItem ------------------------------------------------------
335
336cMenuEditChrItem::cMenuEditChrItem(const char *Name, char *Value, const char *Allowed)
337:cMenuEditItem(Name)
338{
339 value = Value;
340 allowed = strdup(Allowed ? Allowed : "");
341 current = strchr(allowed, *Value);
342 if (!current)
344 Set();
345}
346
351
353{
354 char buf[2];
355 buf[0] = *value;
356 buf[1] = '\0';
357 SetValue(buf);
358}
359
361{
363
364 if (state == osUnknown) {
365 if (NORMALKEY(Key) == kLeft) {
366 if (current > allowed)
367 current--;
368 }
369 else if (NORMALKEY(Key) == kRight) {
370 if (*(current + 1))
371 current++;
372 }
373 else
374 return state;
375 *value = *current;
376 Set();
378 }
379 return state;
380}
381
382// --- cMenuEditStrItem ------------------------------------------------------
383
384cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed)
385:cMenuEditItem(Name)
386{
387 value = Value;
388 length = Length;
389 allowed = Allowed ? Allowed : tr(FileNameChars);
390 pos = -1;
391 offset = 0;
392 keepSpace = false;
393 macro = -1;
394 lastMacro = -1;
395 macros = NULL;
396 insert = uppercase = false;
397 newchar = true;
398 lengthUtf8 = 0;
399 valueUtf8 = NULL;
400 allowedUtf8 = NULL;
401 charMapUtf8 = NULL;
402 currentCharUtf8 = NULL;
403 lastKey = kNone;
404 Set();
405}
406
408{
409 delete[] valueUtf8;
410 delete[] allowedUtf8;
411 delete[] charMapUtf8;
412}
413
414void cMenuEditStrItem::SetMacros(const char **Macros)
415{
416 macros = Macros;
417 macro = 0;
418 lastMacro = -1;
419}
420
422{
423 if (!valueUtf8) {
424 valueUtf8 = new uint[length];
426 int l = strlen(allowed) + 1;
427 allowedUtf8 = new uint[l];
429 const char *charMap = tr("CharMap$ 0\t-.,1#~\\^$[]|()*+?{}/:%@&\tabc2\tdef3\tghi4\tjkl5\tmno6\tpqrs7\ttuv8\twxyz9");
430 l = strlen(charMap) + 1;
431 charMapUtf8 = new uint[l];
432 Utf8ToArray(charMap, charMapUtf8, l);
434 AdvancePos();
435 }
436}
437
439{
440 if (valueUtf8) {
441 if (SaveValue) {
443 if (!keepSpace)
445 }
446 lengthUtf8 = 0;
447 delete[] valueUtf8;
448 valueUtf8 = NULL;
449 delete[] allowedUtf8;
450 allowedUtf8 = NULL;
451 delete[] charMapUtf8;
452 charMapUtf8 = NULL;
453 pos = -1;
454 offset = 0;
455 newchar = true;
456 }
457}
458
460{
461 if (InEditMode())
462 SetHelp(tr("Button$ABC/abc"), insert ? tr("Button$Overwrite") : tr("Button$Insert"), tr("Button$Delete"), macros ? tr("Button$Macro") : NULL);
463 else
464 SetHelp(NULL);
465}
466
468{
469 if (allowedUtf8) {
470 for (uint *a = allowedUtf8; *a; a++) {
471 if (c == *a)
472 return a;
473 }
474 }
475 return NULL;
476}
477
479{
480 if (pos < length - 2 && pos < lengthUtf8) {
481 if (++pos >= lengthUtf8) {
482 if (pos >= 2 && valueUtf8[pos - 1] == ' ' && valueUtf8[pos - 2] == ' ')
483 pos--; // allow only two blanks at the end
484 else {
485 valueUtf8[pos] = ' ';
486 valueUtf8[pos + 1] = 0;
487 lengthUtf8++;
488 }
489 }
490 }
491 newchar = true;
492 if (!insert && Utf8is(alpha, valueUtf8[pos]))
493 uppercase = Utf8is(upper, valueUtf8[pos]);
494}
495
497{
498 if (InEditMode()) {
499 const cFont *font = dynamic_cast<cSkinDisplayMenu *>(cSkinDisplay::Current())->GetTextAreaFont(false);
500
501 int width = cSkinDisplay::Current()->EditableWidth();
502 width -= font->Width("[]");
503 width -= font->Width("<>"); // reserving this anyway makes the whole thing simpler
504
505 if (pos < offset)
506 offset = pos;
507 int WidthFromOffset = 0;
508 int EndPos = lengthUtf8;
509 for (int i = offset; i < lengthUtf8; i++) {
510 WidthFromOffset += font->Width(valueUtf8[i]);
511 if (WidthFromOffset > width) {
512 if (pos >= i) {
513 do {
514 WidthFromOffset -= font->Width(valueUtf8[offset]);
515 offset++;
516 } while (WidthFromOffset > width && offset < pos);
517 EndPos = pos + 1;
518 }
519 else {
520 EndPos = i;
521 break;
522 }
523 }
524 }
525
526 char buf[1000];
527 char *p = buf;
528 if (offset)
529 *p++ = '<';
530 p += Utf8FromArray(valueUtf8 + offset, p, sizeof(buf) - (p - buf), pos - offset);
531 *p++ = '[';
532 if (insert && newchar)
533 *p++ = ']';
534 p += Utf8FromArray(&valueUtf8[pos], p, sizeof(buf) - (p - buf), 1);
535 if (!(insert && newchar))
536 *p++ = ']';
537 p += Utf8FromArray(&valueUtf8[pos + 1], p, sizeof(buf) - (p - buf), EndPos - pos - 1);
538 if (EndPos != lengthUtf8)
539 *p++ = '>';
540 *p = 0;
541
542 SetValue(buf);
543 }
544 else
546}
547
548uint cMenuEditStrItem::Inc(uint c, bool Up)
549{
550 uint *p = IsAllowed(c);
551 if (!p)
552 p = allowedUtf8;
553 if (Up) {
554 if (!*++p)
555 p = allowedUtf8;
556 }
557 else if (--p < allowedUtf8) {
558 p = allowedUtf8;
559 while (*p && *(p + 1))
560 p++;
561 }
562 return *p;
563}
564
566{
567 if (insert && lengthUtf8 < length - 1)
568 Insert();
569 valueUtf8[pos] = c;
570 if (pos < length - 2)
571 pos++;
572 if (pos >= lengthUtf8) {
573 valueUtf8[pos] = ' ';
574 valueUtf8[pos + 1] = 0;
575 lengthUtf8 = pos + 1;
576 }
577}
578
580{
581 memmove(valueUtf8 + pos + 1, valueUtf8 + pos, (lengthUtf8 - pos + 1) * sizeof(*valueUtf8));
582 lengthUtf8++;
583 valueUtf8[pos] = ' ';
584}
585
587{
588 memmove(valueUtf8 + pos, valueUtf8 + pos + 1, (lengthUtf8 - pos) * sizeof(*valueUtf8));
589 lengthUtf8--;
590}
591
593{
594 if (!macros)
595 return;
596 if (lastMacro >= 0) {
597 int l = strlen(macros[lastMacro]);
598 while (l-- > 0)
599 Delete();
600 }
601 const char *p = macros[macro];
602 int oldPos = pos;
603 bool oldInsert = insert;
604 insert = true;
605 newchar = true;
606 while (*p) {
607 Type(*p);
608 p++;
609 }
610 insert = oldInsert;
611 pos = oldPos;
613 if (!macros[++macro])
614 macro = 0;
615}
616
618{
619 bool SameKey = NORMALKEY(Key) == lastKey;
620 if (Key != kNone) {
621 lastKey = NORMALKEY(Key);
622 if (Key != kBlue)
623 lastMacro = -1;
624 }
625 else if (!newchar && k0 <= lastKey && lastKey <= k9 && autoAdvanceTimeout.TimedOut()) {
626 AdvancePos();
627 newchar = true;
628 currentCharUtf8 = NULL;
629 Set();
630 return osContinue;
631 }
632 switch (int(Key)) {
633 case kRed: // Switch between upper- and lowercase characters
634 if (InEditMode()) {
635 if (!insert || !newchar) {
637 valueUtf8[pos] = uppercase ? Utf8to(upper, valueUtf8[pos]) : Utf8to(lower, valueUtf8[pos]);
638 }
639 }
640 else
641 return osUnknown;
642 break;
643 case kGreen: // Toggle insert/overwrite modes
644 if (InEditMode()) {
645 insert = !insert;
646 newchar = true;
647 SetHelpKeys();
648 }
649 else
650 return osUnknown;
651 break;
652 case kYellow|k_Repeat:
653 case kYellow: // Remove the character at the current position; in insert mode it is the character to the right of the cursor
654 if (InEditMode()) {
655 if (lengthUtf8 > 1) {
656 if (!insert || pos < lengthUtf8 - 1)
657 Delete();
658 else if (insert && pos == lengthUtf8 - 1)
659 valueUtf8[pos] = ' '; // in insert mode, deleting the last character replaces it with a blank to keep the cursor position
660 // reduce position, if we removed the last character
661 if (pos == lengthUtf8)
662 pos--;
663 }
664 else if (lengthUtf8 == 1)
665 valueUtf8[0] = ' '; // This is the last character in the string, replace it with a blank
666 if (Utf8is(alpha, valueUtf8[pos]))
667 uppercase = Utf8is(upper, valueUtf8[pos]);
668 newchar = true;
669 }
670 else
671 return osUnknown;
672 break;
673 case kBlue|k_Repeat:
674 case kBlue: if (InEditMode())
675 InsertMacro();
676 else
677 return osUnknown;
678 break;
679 case kLeft|k_Repeat:
680 case kLeft: if (pos > 0) {
681 if (!insert || newchar)
682 pos--;
683 newchar = true;
684 if (!insert && Utf8is(alpha, valueUtf8[pos]))
685 uppercase = Utf8is(upper, valueUtf8[pos]);
686 }
687 break;
688 case kRight|k_Repeat:
689 case kRight: if (InEditMode())
690 AdvancePos();
691 else {
693 SetHelpKeys();
694 }
695 break;
696 case kUp|k_Repeat:
697 case kUp:
698 case kDown|k_Repeat:
699 case kDown: if (InEditMode()) {
700 if (insert && newchar) {
701 // create a new character in insert mode
702 if (lengthUtf8 < length - 1)
703 Insert();
704 }
705 if (uppercase)
706 valueUtf8[pos] = Utf8to(upper, Inc(Utf8to(lower, valueUtf8[pos]), NORMALKEY(Key) == kUp));
707 else
708 valueUtf8[pos] = Inc( valueUtf8[pos], NORMALKEY(Key) == kUp);
709 newchar = false;
710 }
711 else
712 return cMenuEditItem::ProcessKey(Key);
713 break;
714 case k0|k_Repeat ... k9|k_Repeat:
715 case k0 ... k9: {
716 if (InEditMode()) {
717 if (Setup.NumberKeysForChars) {
718 if (!SameKey) {
719 if (!newchar)
720 AdvancePos();
721 currentCharUtf8 = NULL;
722 }
723 if (!currentCharUtf8 || !*currentCharUtf8 || *currentCharUtf8 == '\t') {
724 // find the beginning of the character map entry for Key
725 int n = NORMALKEY(Key) - k0;
727 while (n > 0 && *currentCharUtf8) {
728 if (*currentCharUtf8++ == '\t')
729 n--;
730 }
731 // find first allowed character
734 }
735 if (*currentCharUtf8 && *currentCharUtf8 != '\t') {
736 if (insert && newchar) {
737 // create a new character in insert mode
738 if (lengthUtf8 < length - 1)
739 Insert();
740 }
742 if (uppercase)
743 valueUtf8[pos] = Utf8to(upper, valueUtf8[pos]);
744 // find next allowed character
745 do {
747 } while (*currentCharUtf8 && *currentCharUtf8 != '\t' && !IsAllowed(*currentCharUtf8));
748 newchar = false;
750 }
751 }
752 else
753 Type('0' + NORMALKEY(Key) - k0);
754 }
755 else
756 return cMenuEditItem::ProcessKey(Key);
757 }
758 break;
759 case kBack:
760 case kOk: if (InEditMode()) {
761 LeaveEditMode(Key == kOk);
762 SetHelpKeys();
763 break;
764 }
765 // run into default
766 default: if (InEditMode() && BASICKEY(Key) == kKbd) {
767 int c = KEYKBD(Key);
768 if (c <= 0xFF) { // FIXME what about other UTF-8 characters?
769 if (IsAllowed(Utf8to(lower, c)))
770 Type(c);
771 else {
772 switch (c) {
773 case 0x7F: // backspace
774 if (pos > 0) {
775 pos--;
776 return ProcessKey(kYellow);
777 }
778 break;
779 default: ;
780 }
781 }
782 }
783 else {
784 switch (c) {
785 case kfHome: pos = 0; break;
786 case kfEnd: pos = lengthUtf8 - 1; break;
787 case kfIns: return ProcessKey(kGreen);
788 case kfDel: return ProcessKey(kYellow);
789 default: ;
790 }
791 }
792 }
793 else
794 return cMenuEditItem::ProcessKey(Key);
795 }
796 Set();
797 return osContinue;
798}
799
800// --- cMenuEditStraItem -----------------------------------------------------
801
802cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings)
803:cMenuEditIntItem(Name, Value, 0, NumStrings - 1)
804{
805 strings = Strings;
806 Set();
807}
808
810{
812}
813
814// --- cMenuEditStrlItem -----------------------------------------------------
815
816cMenuEditStrlItem::cMenuEditStrlItem(const char *Name, char *Value, int Length, const cStringList *Strings)
817:cMenuEditIntItem(Name, &index, 0, Strings->Size() - 1)
818{
819 strings = Strings;
820 value = Value;
821 length = Length;
822 index = strings->Find(value);
823 if (index < 0)
824 index = 0;
825 Set();
826}
827
829{
832}
833
834// --- cMenuEditChanItem -----------------------------------------------------
835
836cMenuEditChanItem::cMenuEditChanItem(const char *Name, int *Value, const char *NoneString)
837:cMenuEditIntItem(Name, Value, NoneString ? 0 : 1, cChannels::MaxNumber())
838{
839 channelID = NULL;
840 noneString = NoneString;
841 dummyValue = 0;
842 Set();
843}
844
845cMenuEditChanItem::cMenuEditChanItem(const char *Name, cString *ChannelID, const char *NoneString)
846:cMenuEditIntItem(Name, &dummyValue, NoneString ? 0 : 1, cChannels::MaxNumber())
847{
848 channelID = ChannelID;
849 noneString = NoneString;
851 const cChannel *Channel = Channels->GetByChannelID(tChannelID::FromString(*ChannelID));
852 dummyValue = Channel ? Channel->Number() : 0;
853 Set();
854}
855
857{
858 if (*value > 0) {
859 char buf[255];
861 const cChannel *Channel = Channels->GetByNumber(*value);
862 snprintf(buf, sizeof(buf), "%d %s", *value, Channel ? Channel->Name() : "");
863 SetValue(buf);
864 if (channelID)
865 *channelID = Channel ? Channel->GetChannelID().ToString() : "";
866 }
867 else if (noneString) {
869 if (channelID)
870 *channelID = "";
871 }
872}
873
875{
876 int delta = 1;
877
878 switch (int(Key)) {
879 case kLeft|k_Repeat:
880 case kLeft: delta = -1;
881 case kRight|k_Repeat:
882 case kRight:
883 {
885 const cChannel *Channel = Channels->GetByNumber(*value + delta, delta);
886 if (Channel)
887 *value = Channel->Number();
888 else if (delta < 0 && noneString)
889 *value = 0;
890 if (channelID)
891 *channelID = Channel ? Channel->GetChannelID().ToString() : "";
892 Set();
893 }
894 break;
895 default: return cMenuEditIntItem::ProcessKey(Key);
896 }
897 return osContinue;
898}
899
900// --- cMenuEditTranItem -----------------------------------------------------
901
902cMenuEditTranItem::cMenuEditTranItem(const char *Name, int *Value, int *Source)
903:cMenuEditChanItem(Name, &number, "-")
904{
905 number = 0;
906 source = Source;
907 transponder = Value;
909 const cChannel *Channel = Channels->First();
910 while (Channel) {
911 if (!Channel->GroupSep() && *source == Channel->Source() && ISTRANSPONDER(Channel->Transponder(), *Value)) {
912 number = Channel->Number();
913 break;
914 }
915 Channel = Channels->Next(Channel);
916 }
917 Set();
918}
919
921{
924 if (const cChannel *Channel = Channels->GetByNumber(number)) {
925 *source = Channel->Source();
926 *transponder = Channel->Transponder();
927 }
928 else {
929 *source = 0;
930 *transponder = 0;
931 }
932 return state;
933}
934
935// --- cMenuEditDateItem -----------------------------------------------------
936
937static int ParseWeekDays(const char *s)
938{
939 time_t day;
940 int weekdays;
941 return cTimer::ParseDay(s, day, weekdays) ? weekdays : 0;
942}
943
944int cMenuEditDateItem::days[] = { ParseWeekDays("M------"),
945 ParseWeekDays("-T-----"),
946 ParseWeekDays("--W----"),
947 ParseWeekDays("---T---"),
948 ParseWeekDays("----F--"),
949 ParseWeekDays("-----S-"),
950 ParseWeekDays("------S"),
951 ParseWeekDays("MTWTF--"),
952 ParseWeekDays("MTWTFS-"),
953 ParseWeekDays("MTWTFSS"),
954 ParseWeekDays("-----SS"),
955 0 };
956
957cMenuEditDateItem::cMenuEditDateItem(const char *Name, time_t *Value, int *WeekDays)
958:cMenuEditItem(Name)
959{
960 value = Value;
961 weekdays = WeekDays;
962 oldvalue = 0;
963 oldweekdays = 0;
965 Set();
966}
967
969{
970 for (unsigned int i = 0; i < sizeof(days) / sizeof(int); i++)
971 if (WeekDays == days[i])
972 return i;
973 return 0;
974}
975
977{
978#define DATEBUFFERSIZE 32
979 char buf[DATEBUFFERSIZE];
980 if (weekdays && *weekdays) {
982 return;
983 }
984 else if (*value) {
985 struct tm tm_r;
986 localtime_r(value, &tm_r);
987 strftime(buf, DATEBUFFERSIZE, "%Y-%m-%d ", &tm_r);
988 strcat(buf, WeekDayName(tm_r.tm_wday));
989 }
990 else
991 *buf = 0;
992 SetValue(buf);
993}
994
996{
997 if (weekdays) {
998 if (*weekdays) {
999 *value = cTimer::SetTime(oldvalue ? oldvalue : time(NULL), 0);
1000 oldvalue = 0;
1002 *weekdays = 0;
1003 }
1004 else {
1006 oldweekdays = 0;
1008 oldvalue = *value;
1009 *value = 0;
1010 }
1011 Set();
1012 }
1013}
1014
1016{
1018
1019 if (state == osUnknown) {
1020 time_t now = time(NULL);
1021 if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
1022 if (!weekdays || !*weekdays) {
1023 // Decrement single day:
1024 time_t v = *value;
1025 v -= SECSINDAY;
1026 if (v < now) {
1027 if (now <= v + SECSINDAY) { // switched from tomorrow to today
1028 if (!weekdays)
1029 v = 0;
1030 }
1031 else if (weekdays) { // switched from today to yesterday, so enter weekdays mode
1032 v = 0;
1033 dayindex = sizeof(days) / sizeof(int) - 2;
1035 }
1036 else // don't go before today
1037 v = *value;
1038 }
1039 *value = v;
1040 }
1041 else {
1042 // Decrement weekday index:
1043 if (dayindex > 0)
1044 *weekdays = days[--dayindex];
1045 }
1046 }
1047 else if (NORMALKEY(Key) == kRight) {
1048 if (!weekdays || !*weekdays) {
1049 // Increment single day:
1050 if (!*value)
1051 *value = cTimer::SetTime(now, 0);
1052 *value += SECSINDAY;
1053 }
1054 else {
1055 // Increment weekday index:
1056 *weekdays = days[++dayindex];
1057 if (!*weekdays) { // was last weekday entry, so switch to today
1058 *value = cTimer::SetTime(now, 0);
1059 dayindex = 0;
1060 }
1061 }
1062 }
1063 else if (weekdays) {
1064 if (Key == k0) {
1065 // Toggle between weekdays and single day:
1067 return osContinue; // ToggleRepeating) has already called Set()
1068 }
1069 else if (k1 <= Key && Key <= k7) {
1070 // Toggle individual weekdays:
1071 if (*weekdays) {
1072 int v = *weekdays ^ (1 << (Key - k1));
1073 if (v != 0)
1074 *weekdays = v; // can't let this become all 0
1075 }
1076 }
1077 else
1078 return state;
1079 }
1080 else
1081 return state;
1082 Set();
1083 state = osContinue;
1084 }
1085 return state;
1086}
1087
1088// --- cMenuEditTimeItem -----------------------------------------------------
1089
1090cMenuEditTimeItem::cMenuEditTimeItem(const char *Name, int *Value)
1091:cMenuEditItem(Name)
1092{
1093 value = Value;
1094 hh = *value / 100;
1095 mm = *value % 100;
1096 pos = 0;
1097 Set();
1098}
1099
1101{
1102 switch (pos) {
1103 case 1: SetValue(cString::sprintf("%01d-:--", hh / 10)); break;
1104 case 2: SetValue(cString::sprintf("%02d:--", hh)); break;
1105 case 3: SetValue(cString::sprintf("%02d:%01d-", hh, mm / 10)); break;
1106 default: SetValue(cString::sprintf("%02d:%02d", hh, mm));
1107 }
1108}
1109
1111{
1113
1114 if (state == osUnknown) {
1115 if (k0 <= Key && Key <= k9) {
1116 if (fresh || pos > 3) {
1117 pos = 0;
1118 fresh = false;
1119 }
1120 int n = Key - k0;
1121 switch (pos) {
1122 case 0: if (n <= 2) {
1123 hh = n * 10;
1124 mm = 0;
1125 pos++;
1126 }
1127 break;
1128 case 1: if (hh + n <= 23) {
1129 hh += n;
1130 pos++;
1131 }
1132 break;
1133 case 2: if (n <= 5) {
1134 mm += n * 10;
1135 pos++;
1136 }
1137 break;
1138 case 3: if (mm + n <= 59) {
1139 mm += n;
1140 pos++;
1141 }
1142 break;
1143 default: ;
1144 }
1145 }
1146 else if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
1147 if (--mm < 0) {
1148 mm = 59;
1149 if (--hh < 0)
1150 hh = 23;
1151 }
1152 fresh = true;
1153 }
1154 else if (NORMALKEY(Key) == kRight) {
1155 if (++mm > 59) {
1156 mm = 0;
1157 if (++hh > 23)
1158 hh = 0;
1159 }
1160 fresh = true;
1161 }
1162 else
1163 return state;
1164 *value = hh * 100 + mm;
1165 Set();
1166 state = osContinue;
1167 }
1168 return state;
1169}
1170
1171// --- cMenuEditMapItem ------------------------------------------------------
1172
1173cMenuEditMapItem::cMenuEditMapItem(const char *Name, int *Value, const tDvbParameterMap *Map, const char *ZeroString)
1174:cMenuEditItem(Name)
1175{
1176 value = Value;
1177 map = Map;
1178 zeroString = ZeroString;
1179 Set();
1180}
1181
1183{
1184 const char *s = NULL;
1185 int n = MapToUser(*value, map, &s);
1186 if (n == 0 && zeroString)
1188 else if (n >= 0) {
1189 if (s)
1190 SetValue(s);
1191 else {
1192 char buf[16];
1193 snprintf(buf, sizeof(buf), "%d", n);
1194 SetValue(buf);
1195 }
1196 }
1197 else
1198 SetValue("???");
1199}
1200
1202{
1204
1205 if (state == osUnknown) {
1206 int newValue = *value;
1207 int n = DriverIndex(*value, map);
1208 if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
1209 if (n-- > 0)
1210 newValue = map[n].driverValue;
1211 }
1212 else if (NORMALKEY(Key) == kRight) {
1213 if (map[++n].userValue >= 0)
1214 newValue = map[n].driverValue;
1215 }
1216 else
1217 return state;
1218 if (newValue != *value) {
1219 *value = newValue;
1220 Set();
1221 }
1222 state = osContinue;
1223 }
1224 return state;
1225}
1226
1227// --- cMenuSetupPage --------------------------------------------------------
1228
1230:cOsdMenu("", 36)
1231{
1233 plugin = NULL;
1234}
1235
1236void cMenuSetupPage::SetSection(const char *Section)
1237{
1238 SetTitle(cString::sprintf("%s - %s", tr("Setup"), Section));
1239}
1240
1242{
1243 eOSState state = cOsdMenu::ProcessKey(Key);
1244
1245 if (state == osUnknown) {
1246 switch (Key) {
1247 case kOk: Store();
1248 state = osBack;
1249 break;
1250 default: break;
1251 }
1252 }
1253 return state;
1254}
1255
1257{
1259 plugin = Plugin;
1260 SetSection(cString::sprintf("%s '%s'", tr("Plugin"), plugin->Name()));
1261}
1262
1263void cMenuSetupPage::SetupStore(const char *Name, const char *Value)
1264{
1265 if (plugin)
1266 plugin->SetupStore(Name, Value);
1267}
1268
1269void cMenuSetupPage::SetupStore(const char *Name, int Value)
1270{
1271 if (plugin)
1272 plugin->SetupStore(Name, Value);
1273}
#define LOCK_CHANNELS_READ
Definition channels.h:273
#define ISTRANSPONDER(f1, f2)
Definition channels.h:18
int Source(void) const
Definition channels.h:154
int Number(void) const
Definition channels.h:181
const char * Name(void) const
Definition channels.c:122
tChannelID GetChannelID(void) const
Definition channels.h:194
bool GroupSep(void) const
Definition channels.h:183
int Transponder(void) const
Returns the transponder frequency in MHz, plus the polarization in case of sat.
Definition channels.c:155
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
virtual void Set(void) override
Definition menuitems.c:165
cMenuEditBitItem(const char *Name, uint *Value, uint Mask, const char *FalseString=NULL, const char *TrueString=NULL)
Definition menuitems.c:156
virtual void Set(void) override
Definition menuitems.c:147
cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString=NULL, const char *TrueString=NULL)
Definition menuitems.c:139
const char * falseString
Definition menuitems.h:46
const char * trueString
Definition menuitems.h:46
cString * channelID
Definition menuitems.h:171
cMenuEditChanItem(const char *Name, int *Value, const char *NoneString=NULL)
Definition menuitems.c:836
const char * noneString
Definition menuitems.h:169
virtual void Set(void) override
Definition menuitems.c:856
virtual eOSState ProcessKey(eKeys Key) override
Definition menuitems.c:874
virtual eOSState ProcessKey(eKeys Key) override
Definition menuitems.c:360
const char * current
Definition menuitems.h:100
cMenuEditChrItem(const char *Name, char *Value, const char *Allowed)
Definition menuitems.c:336
virtual void Set(void) override
Definition menuitems.c:352
int FindDayIndex(int WeekDays)
Definition menuitems.c:968
void ToggleRepeating(void)
Definition menuitems.c:995
static int days[]
Definition menuitems.h:944
virtual void Set(void) override
Definition menuitems.c:976
virtual eOSState ProcessKey(eKeys Key) override
Definition menuitems.c:1015
cMenuEditDateItem(const char *Name, time_t *Value, int *WeekDays=NULL)
Definition menuitems.c:957
cMenuEditIntItem(const char *Name, int *Value, int Min=0, int Max=INT_MAX, const char *MinString=NULL, const char *MaxString=NULL)
Definition menuitems.c:66
const char * maxString
Definition menuitems.h:37
virtual void Set(void) override
Definition menuitems.c:81
virtual eOSState ProcessKey(eKeys Key) override
Definition menuitems.c:94
const char * minString
Definition menuitems.h:37
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:227
void SetHelpKeys(void)
Definition menuitems.c:236
const char * negString
Definition menuitems.h:76
const char * posString
Definition menuitems.h:76
virtual eOSState ProcessKey(eKeys Key) override
Definition menuitems.c:252
virtual void Set(void) override
Definition menuitems.c:242
const char * helpYellow
Definition menuitems.h:22
bool DisplayHelp(bool Current)
Definition menuitems.c:53
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:43
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 eOSState ProcessKey(eKeys Key) override
Definition menuitems.c:1201
virtual void Set(void) override
Definition menuitems.c:1182
const char * zeroString
Definition menuitems.h:220
cMenuEditMapItem(const char *Name, int *Value, const tDvbParameterMap *Map, const char *ZeroString=NULL)
Definition menuitems.c:1173
virtual void Set(void) override
Definition menuitems.c:182
virtual eOSState ProcessKey(eKeys Key) override
Definition menuitems.c:196
cMenuEditNumItem(const char *Name, char *Value, int Length, bool Blind=false)
Definition menuitems.c:173
virtual void Set(void) override
Definition menuitems.c:288
cMenuEditPrcItem(const char *Name, double *Value, double Min=0.0, double Max=1.0, int Decimals=0)
Definition menuitems.c:271
double * value
Definition menuitems.h:86
virtual eOSState ProcessKey(eKeys Key) override
Definition menuitems.c:295
const char * allowed
Definition menuitems.h:112
uint Inc(uint c, bool Up)
Definition menuitems.c:548
void Insert(void)
Definition menuitems.c:579
void Delete(void)
Definition menuitems.c:586
void LeaveEditMode(bool SaveValue=false)
Definition menuitems.c:438
void Type(uint c)
Definition menuitems.c:565
cTimeMs autoAdvanceTimeout
Definition menuitems.h:124
uint * currentCharUtf8
Definition menuitems.h:122
virtual void Set(void) override
Definition menuitems.c:496
cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed=NULL)
Definition menuitems.c:384
virtual eOSState ProcessKey(eKeys Key) override
Definition menuitems.c:617
void InsertMacro(void)
Definition menuitems.c:592
const char ** macros
Definition menuitems.h:115
bool InEditMode(void)
Definition menuitems.h:137
void AdvancePos(void)
Definition menuitems.c:478
void SetMacros(const char **Macros)
Definition menuitems.c:414
void SetHelpKeys(void)
Definition menuitems.c:459
void EnterEditMode(void)
Definition menuitems.c:421
uint * IsAllowed(uint c)
Definition menuitems.c:467
virtual void Set(void) override
Definition menuitems.c:809
const char *const * strings
Definition menuitems.h:148
cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char *const *Strings)
Definition menuitems.c:802
const cStringList * strings
Definition menuitems.h:157
virtual void Set(void) override
Definition menuitems.c:828
cMenuEditStrlItem(const char *Name, char *Value, int Length, const cStringList *Strings)
Definition menuitems.c:816
cMenuEditTimeItem(const char *Name, int *Value)
Definition menuitems.c:1090
virtual void Set(void) override
Definition menuitems.c:1100
virtual eOSState ProcessKey(eKeys Key) override
Definition menuitems.c:1110
virtual eOSState ProcessKey(eKeys Key) override
Definition menuitems.c:920
cMenuEditTranItem(const char *Name, int *Value, int *Source)
Definition menuitems.c:902
virtual eOSState ProcessKey(eKeys Key) override
Definition menuitems.c:1241
virtual void Store(void)=0
cMenuSetupPage(void)
Definition menuitems.c:1229
void SetSection(const char *Section)
Definition menuitems.c:1236
void SetupStore(const char *Name, const char *Value=NULL)
Definition menuitems.c:1263
cPlugin * plugin
Definition menuitems.h:231
void SetPlugin(cPlugin *Plugin)
Definition menuitems.c:1256
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
virtual eOSState ProcessKey(eKeys Key) override
Definition osdbase.c:573
void SetTitle(const char *Title)
Definition osdbase.c:187
cOsdMenu(const char *Title, int c0=0, int c1=0, int c2=0, int c3=0, int c4=0)
Definition osdbase.c:83
void SetMenuCategory(eMenuCategory MenuCategory)
Definition osdbase.c:125
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:111
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition tools.c:1195
static time_t SetTime(time_t t, int SecondsFromMidnight)
Definition timers.c:548
static int GetWDay(time_t t)
Definition timers.c:524
static cString PrintDay(time_t Day, int WeekDays, bool SingleByteChars)
Definition timers.c:402
static bool ParseDay(const char *s, time_t &Day, int &WeekDays)
Definition timers.c:343
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:937
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:24
cString ToString(void) const
Definition channels.c:41
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:938
cString WeekDayName(int WeekDay)
Converts the given WeekDay (0=Sunday, 1=Monday, ...) to a three letter day name.
Definition tools.c:1218
char * stripspace(char *s)
Definition tools.c:227
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:956
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