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