vdr
1.7.27
|
00001 /* 00002 * menuitems.c: General purpose menu items 00003 * 00004 * See the main source file 'vdr.c' for copyright information and 00005 * how to reach the author. 00006 * 00007 * $Id: menuitems.c 2.13 2012/03/13 11:21:57 kls Exp $ 00008 */ 00009 00010 #include "menuitems.h" 00011 #include <ctype.h> 00012 #include <math.h> 00013 #include <wctype.h> 00014 #include "i18n.h" 00015 #include "plugin.h" 00016 #include "remote.h" 00017 #include "skins.h" 00018 #include "status.h" 00019 00020 #define AUTO_ADVANCE_TIMEOUT 1500 // ms before auto advance when entering characters via numeric keys 00021 00022 const char *FileNameChars = trNOOP("FileNameChars$ abcdefghijklmnopqrstuvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&"); 00023 00024 // --- cMenuEditItem --------------------------------------------------------- 00025 00026 cMenuEditItem::cMenuEditItem(const char *Name) 00027 { 00028 name = strdup(Name ? Name : "???"); 00029 SetHelp(NULL); 00030 } 00031 00032 cMenuEditItem::~cMenuEditItem() 00033 { 00034 free(name); 00035 } 00036 00037 void cMenuEditItem::SetValue(const char *Value) 00038 { 00039 cString buffer = cString::sprintf("%s:\t%s", name, Value); 00040 SetText(buffer); 00041 cStatus::MsgOsdCurrentItem(buffer); 00042 } 00043 00044 void cMenuEditItem::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue) 00045 { 00046 // strings are NOT copied - must be constants!!! 00047 helpRed = Red; 00048 helpGreen = Green; 00049 helpYellow = Yellow; 00050 helpBlue = Blue; 00051 helpDisplayed = false; 00052 } 00053 00054 bool cMenuEditItem::DisplayHelp(void) 00055 { 00056 bool HasHelp = helpRed || helpGreen || helpYellow || helpBlue; 00057 if (HasHelp && !helpDisplayed) { 00058 cSkinDisplay::Current()->SetButtons(helpRed, helpGreen, helpYellow, helpBlue); 00059 cStatus::MsgOsdHelpKeys(helpRed, helpGreen, helpYellow, helpBlue); 00060 helpDisplayed = true; 00061 } 00062 return HasHelp; 00063 } 00064 00065 // --- cMenuEditIntItem ------------------------------------------------------ 00066 00067 cMenuEditIntItem::cMenuEditIntItem(const char *Name, int *Value, int Min, int Max, const char *MinString, const char *MaxString) 00068 :cMenuEditItem(Name) 00069 { 00070 value = Value; 00071 min = Min; 00072 max = Max; 00073 minString = MinString; 00074 maxString = MaxString; 00075 if (*value < min) 00076 *value = min; 00077 else if (*value > max) 00078 *value = max; 00079 Set(); 00080 } 00081 00082 void cMenuEditIntItem::Set(void) 00083 { 00084 if (minString && *value == min) 00085 SetValue(minString); 00086 else if (maxString && *value == max) 00087 SetValue(maxString); 00088 else { 00089 char buf[16]; 00090 snprintf(buf, sizeof(buf), "%d", *value); 00091 SetValue(buf); 00092 } 00093 } 00094 00095 eOSState cMenuEditIntItem::ProcessKey(eKeys Key) 00096 { 00097 eOSState state = cMenuEditItem::ProcessKey(Key); 00098 00099 if (state == osUnknown) { 00100 int newValue = *value; 00101 bool IsRepeat = Key & k_Repeat; 00102 Key = NORMALKEY(Key); 00103 switch (Key) { 00104 case kNone: break; 00105 case k0 ... k9: 00106 if (fresh) { 00107 newValue = 0; 00108 fresh = false; 00109 } 00110 newValue = newValue * 10 + (Key - k0); 00111 break; 00112 case kLeft: // TODO might want to increase the delta if repeated quickly? 00113 newValue = *value - 1; 00114 fresh = true; 00115 if (!IsRepeat && newValue < min && max != INT_MAX) 00116 newValue = max; 00117 break; 00118 case kRight: 00119 newValue = *value + 1; 00120 fresh = true; 00121 if (!IsRepeat && newValue > max && min != INT_MIN) 00122 newValue = min; 00123 break; 00124 default: 00125 if (*value < min) { *value = min; Set(); } 00126 if (*value > max) { *value = max; Set(); } 00127 return state; 00128 } 00129 if (newValue != *value && (!fresh || min <= newValue) && newValue <= max) { 00130 *value = newValue; 00131 Set(); 00132 } 00133 state = osContinue; 00134 } 00135 return state; 00136 } 00137 00138 // --- cMenuEditBoolItem ----------------------------------------------------- 00139 00140 cMenuEditBoolItem::cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString, const char *TrueString) 00141 :cMenuEditIntItem(Name, Value, 0, 1) 00142 { 00143 falseString = FalseString ? FalseString : tr("no"); 00144 trueString = TrueString ? TrueString : tr("yes"); 00145 Set(); 00146 } 00147 00148 void cMenuEditBoolItem::Set(void) 00149 { 00150 char buf[16]; 00151 snprintf(buf, sizeof(buf), "%s", *value ? trueString : falseString); 00152 SetValue(buf); 00153 } 00154 00155 // --- cMenuEditBitItem ------------------------------------------------------ 00156 00157 cMenuEditBitItem::cMenuEditBitItem(const char *Name, uint *Value, uint Mask, const char *FalseString, const char *TrueString) 00158 :cMenuEditBoolItem(Name, &bit, FalseString, TrueString) 00159 { 00160 value = Value; 00161 bit = (*value & Mask) != 0; 00162 mask = Mask; 00163 Set(); 00164 } 00165 00166 void cMenuEditBitItem::Set(void) 00167 { 00168 *value = bit ? *value | mask : *value & ~mask; 00169 cMenuEditBoolItem::Set(); 00170 } 00171 00172 // --- cMenuEditNumItem ------------------------------------------------------ 00173 00174 cMenuEditNumItem::cMenuEditNumItem(const char *Name, char *Value, int Length, bool Blind) 00175 :cMenuEditItem(Name) 00176 { 00177 value = Value; 00178 length = Length; 00179 blind = Blind; 00180 Set(); 00181 } 00182 00183 void cMenuEditNumItem::Set(void) 00184 { 00185 if (blind) { 00186 char buf[length + 1]; 00187 int i; 00188 for (i = 0; i < length && value[i]; i++) 00189 buf[i] = '*'; 00190 buf[i] = 0; 00191 SetValue(buf); 00192 } 00193 else 00194 SetValue(value); 00195 } 00196 00197 eOSState cMenuEditNumItem::ProcessKey(eKeys Key) 00198 { 00199 eOSState state = cMenuEditItem::ProcessKey(Key); 00200 00201 if (state == osUnknown) { 00202 Key = NORMALKEY(Key); 00203 switch (Key) { 00204 case kLeft: { 00205 int l = strlen(value); 00206 if (l > 0) 00207 value[l - 1] = 0; 00208 } 00209 break; 00210 case k0 ... k9: { 00211 int l = strlen(value); 00212 if (l < length) { 00213 value[l] = Key - k0 + '0'; 00214 value[l + 1] = 0; 00215 } 00216 } 00217 break; 00218 default: return state; 00219 } 00220 Set(); 00221 state = osContinue; 00222 } 00223 return state; 00224 } 00225 00226 // --- cMenuEditPrcItem ------------------------------------------------------ 00227 00228 cMenuEditPrcItem::cMenuEditPrcItem(const char *Name, double *Value, double Min, double Max, int Decimals) 00229 :cMenuEditItem(Name) 00230 { 00231 value = Value; 00232 min = Min; 00233 max = Max; 00234 decimals = Decimals; 00235 factor = 100; 00236 while (Decimals-- > 0) 00237 factor *= 10; 00238 if (*value < min) 00239 *value = min; 00240 else if (*value > max) 00241 *value = max; 00242 Set(); 00243 } 00244 00245 void cMenuEditPrcItem::Set(void) 00246 { 00247 char buf[16]; 00248 snprintf(buf, sizeof(buf), "%.*f", decimals, *value * 100); 00249 SetValue(buf); 00250 } 00251 00252 eOSState cMenuEditPrcItem::ProcessKey(eKeys Key) 00253 { 00254 eOSState state = cMenuEditItem::ProcessKey(Key); 00255 00256 if (state == osUnknown) { 00257 double newValue = round(*value * factor); // avoids precision problems 00258 Key = NORMALKEY(Key); 00259 switch (Key) { 00260 case kNone: break; 00261 case k0 ... k9: 00262 if (fresh) { 00263 newValue = 0; 00264 fresh = false; 00265 } 00266 newValue = newValue * 10 + (Key - k0); 00267 break; 00268 case kLeft: // TODO might want to increase the delta if repeated quickly? 00269 newValue--; 00270 fresh = true; 00271 break; 00272 case kRight: 00273 newValue++; 00274 fresh = true; 00275 break; 00276 default: 00277 if (*value < min) { *value = min; Set(); } 00278 if (*value > max) { *value = max; Set(); } 00279 return state; 00280 } 00281 newValue /= factor; 00282 if (!DoubleEqual(newValue, *value) && (!fresh || min <= newValue) && newValue <= max) { 00283 *value = newValue; 00284 Set(); 00285 } 00286 state = osContinue; 00287 } 00288 return state; 00289 } 00290 00291 // --- cMenuEditChrItem ------------------------------------------------------ 00292 00293 cMenuEditChrItem::cMenuEditChrItem(const char *Name, char *Value, const char *Allowed) 00294 :cMenuEditItem(Name) 00295 { 00296 value = Value; 00297 allowed = strdup(Allowed ? Allowed : ""); 00298 current = strchr(allowed, *Value); 00299 if (!current) 00300 current = allowed; 00301 Set(); 00302 } 00303 00304 cMenuEditChrItem::~cMenuEditChrItem() 00305 { 00306 free(allowed); 00307 } 00308 00309 void cMenuEditChrItem::Set(void) 00310 { 00311 char buf[2]; 00312 buf[0] = *value; 00313 buf[1] = '\0'; 00314 SetValue(buf); 00315 } 00316 00317 eOSState cMenuEditChrItem::ProcessKey(eKeys Key) 00318 { 00319 eOSState state = cMenuEditItem::ProcessKey(Key); 00320 00321 if (state == osUnknown) { 00322 if (NORMALKEY(Key) == kLeft) { 00323 if (current > allowed) 00324 current--; 00325 } 00326 else if (NORMALKEY(Key) == kRight) { 00327 if (*(current + 1)) 00328 current++; 00329 } 00330 else 00331 return state; 00332 *value = *current; 00333 Set(); 00334 state = osContinue; 00335 } 00336 return state; 00337 } 00338 00339 // --- cMenuEditStrItem ------------------------------------------------------ 00340 00341 cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed) 00342 :cMenuEditItem(Name) 00343 { 00344 value = Value; 00345 length = Length; 00346 allowed = Allowed ? Allowed : tr(FileNameChars); 00347 pos = -1; 00348 offset = 0; 00349 insert = uppercase = false; 00350 newchar = true; 00351 lengthUtf8 = 0; 00352 valueUtf8 = NULL; 00353 allowedUtf8 = NULL; 00354 charMapUtf8 = NULL; 00355 currentCharUtf8 = NULL; 00356 lastKey = kNone; 00357 Set(); 00358 } 00359 00360 cMenuEditStrItem::~cMenuEditStrItem() 00361 { 00362 delete[] valueUtf8; 00363 delete[] allowedUtf8; 00364 delete[] charMapUtf8; 00365 } 00366 00367 void cMenuEditStrItem::EnterEditMode(void) 00368 { 00369 if (!valueUtf8) { 00370 valueUtf8 = new uint[length]; 00371 lengthUtf8 = Utf8ToArray(value, valueUtf8, length); 00372 int l = strlen(allowed) + 1; 00373 allowedUtf8 = new uint[l]; 00374 Utf8ToArray(allowed, allowedUtf8, l); 00375 const char *charMap = tr("CharMap$ 0\t-.,1#~\\^$[]|()*+?{}/:%@&\tabc2\tdef3\tghi4\tjkl5\tmno6\tpqrs7\ttuv8\twxyz9"); 00376 l = strlen(charMap) + 1; 00377 charMapUtf8 = new uint[l]; 00378 Utf8ToArray(charMap, charMapUtf8, l); 00379 currentCharUtf8 = charMapUtf8; 00380 AdvancePos(); 00381 } 00382 } 00383 00384 void cMenuEditStrItem::LeaveEditMode(bool SaveValue) 00385 { 00386 if (valueUtf8) { 00387 if (SaveValue) { 00388 Utf8FromArray(valueUtf8, value, length); 00389 stripspace(value); 00390 } 00391 lengthUtf8 = 0; 00392 delete[] valueUtf8; 00393 valueUtf8 = NULL; 00394 delete[] allowedUtf8; 00395 allowedUtf8 = NULL; 00396 delete[] charMapUtf8; 00397 charMapUtf8 = NULL; 00398 pos = -1; 00399 offset = 0; 00400 newchar = true; 00401 } 00402 } 00403 00404 void cMenuEditStrItem::SetHelpKeys(void) 00405 { 00406 if (InEditMode()) 00407 SetHelp(tr("Button$ABC/abc"), insert ? tr("Button$Overwrite") : tr("Button$Insert"), tr("Button$Delete")); 00408 else 00409 SetHelp(NULL); 00410 } 00411 00412 uint *cMenuEditStrItem::IsAllowed(uint c) 00413 { 00414 if (allowedUtf8) { 00415 for (uint *a = allowedUtf8; *a; a++) { 00416 if (c == *a) 00417 return a; 00418 } 00419 } 00420 return NULL; 00421 } 00422 00423 void cMenuEditStrItem::AdvancePos(void) 00424 { 00425 if (pos < length - 2 && pos < lengthUtf8) { 00426 if (++pos >= lengthUtf8) { 00427 if (pos >= 2 && valueUtf8[pos - 1] == ' ' && valueUtf8[pos - 2] == ' ') 00428 pos--; // allow only two blanks at the end 00429 else { 00430 valueUtf8[pos] = ' '; 00431 valueUtf8[pos + 1] = 0; 00432 lengthUtf8++; 00433 } 00434 } 00435 } 00436 newchar = true; 00437 if (!insert && Utf8is(alpha, valueUtf8[pos])) 00438 uppercase = Utf8is(upper, valueUtf8[pos]); 00439 } 00440 00441 void cMenuEditStrItem::Set(void) 00442 { 00443 if (InEditMode()) { 00444 // This is an ugly hack to make editing strings work with the 'skincurses' plugin. 00445 const cFont *font = dynamic_cast<cSkinDisplayMenu *>(cSkinDisplay::Current())->GetTextAreaFont(false); 00446 if (!font || font->Width("W") != 1) // all characters have with == 1 in the font used by 'skincurses' 00447 font = cFont::GetFont(fontOsd); 00448 00449 int width = cSkinDisplay::Current()->EditableWidth(); 00450 width -= font->Width("[]"); 00451 width -= font->Width("<>"); // reserving this anyway make the whole thing simpler 00452 00453 if (pos < offset) 00454 offset = pos; 00455 int WidthFromOffset = 0; 00456 int EndPos = lengthUtf8; 00457 for (int i = offset; i < lengthUtf8; i++) { 00458 WidthFromOffset += font->Width(valueUtf8[i]); 00459 if (WidthFromOffset > width) { 00460 if (pos >= i) { 00461 do { 00462 WidthFromOffset -= font->Width(valueUtf8[offset]); 00463 offset++; 00464 } while (WidthFromOffset > width && offset < pos); 00465 EndPos = pos + 1; 00466 } 00467 else { 00468 EndPos = i; 00469 break; 00470 } 00471 } 00472 } 00473 00474 char buf[1000]; 00475 char *p = buf; 00476 if (offset) 00477 *p++ = '<'; 00478 p += Utf8FromArray(valueUtf8 + offset, p, sizeof(buf) - (p - buf), pos - offset); 00479 *p++ = '['; 00480 if (insert && newchar) 00481 *p++ = ']'; 00482 p += Utf8FromArray(&valueUtf8[pos], p, sizeof(buf) - (p - buf), 1); 00483 if (!(insert && newchar)) 00484 *p++ = ']'; 00485 p += Utf8FromArray(&valueUtf8[pos + 1], p, sizeof(buf) - (p - buf), EndPos - pos - 1); 00486 if (EndPos != lengthUtf8) 00487 *p++ = '>'; 00488 *p = 0; 00489 00490 SetValue(buf); 00491 } 00492 else 00493 SetValue(value); 00494 } 00495 00496 uint cMenuEditStrItem::Inc(uint c, bool Up) 00497 { 00498 uint *p = IsAllowed(c); 00499 if (!p) 00500 p = allowedUtf8; 00501 if (Up) { 00502 if (!*++p) 00503 p = allowedUtf8; 00504 } 00505 else if (--p < allowedUtf8) { 00506 p = allowedUtf8; 00507 while (*p && *(p + 1)) 00508 p++; 00509 } 00510 return *p; 00511 } 00512 00513 void cMenuEditStrItem::Type(uint c) 00514 { 00515 if (insert && lengthUtf8 < length - 1) 00516 Insert(); 00517 valueUtf8[pos] = c; 00518 if (pos < length - 2) 00519 pos++; 00520 if (pos >= lengthUtf8) { 00521 valueUtf8[pos] = ' '; 00522 valueUtf8[pos + 1] = 0; 00523 lengthUtf8 = pos + 1; 00524 } 00525 } 00526 00527 void cMenuEditStrItem::Insert(void) 00528 { 00529 memmove(valueUtf8 + pos + 1, valueUtf8 + pos, (lengthUtf8 - pos + 1) * sizeof(*valueUtf8)); 00530 lengthUtf8++; 00531 valueUtf8[pos] = ' '; 00532 } 00533 00534 void cMenuEditStrItem::Delete(void) 00535 { 00536 memmove(valueUtf8 + pos, valueUtf8 + pos + 1, (lengthUtf8 - pos) * sizeof(*valueUtf8)); 00537 lengthUtf8--; 00538 } 00539 00540 eOSState cMenuEditStrItem::ProcessKey(eKeys Key) 00541 { 00542 bool SameKey = NORMALKEY(Key) == lastKey; 00543 if (Key != kNone) 00544 lastKey = NORMALKEY(Key); 00545 else if (!newchar && k0 <= lastKey && lastKey <= k9 && autoAdvanceTimeout.TimedOut()) { 00546 AdvancePos(); 00547 newchar = true; 00548 currentCharUtf8 = NULL; 00549 Set(); 00550 return osContinue; 00551 } 00552 switch (int(Key)) { 00553 case kRed: // Switch between upper- and lowercase characters 00554 if (InEditMode()) { 00555 if (!insert || !newchar) { 00556 uppercase = !uppercase; 00557 valueUtf8[pos] = uppercase ? Utf8to(upper, valueUtf8[pos]) : Utf8to(lower, valueUtf8[pos]); 00558 } 00559 } 00560 else 00561 return osUnknown; 00562 break; 00563 case kGreen: // Toggle insert/overwrite modes 00564 if (InEditMode()) { 00565 insert = !insert; 00566 newchar = true; 00567 SetHelpKeys(); 00568 } 00569 else 00570 return osUnknown; 00571 break; 00572 case kYellow|k_Repeat: 00573 case kYellow: // Remove the character at the current position; in insert mode it is the character to the right of the cursor 00574 if (InEditMode()) { 00575 if (lengthUtf8 > 1) { 00576 if (!insert || pos < lengthUtf8 - 1) 00577 Delete(); 00578 else if (insert && pos == lengthUtf8 - 1) 00579 valueUtf8[pos] = ' '; // in insert mode, deleting the last character replaces it with a blank to keep the cursor position 00580 // reduce position, if we removed the last character 00581 if (pos == lengthUtf8) 00582 pos--; 00583 } 00584 else if (lengthUtf8 == 1) 00585 valueUtf8[0] = ' '; // This is the last character in the string, replace it with a blank 00586 if (Utf8is(alpha, valueUtf8[pos])) 00587 uppercase = Utf8is(upper, valueUtf8[pos]); 00588 newchar = true; 00589 } 00590 else 00591 return osUnknown; 00592 break; 00593 case kBlue|k_Repeat: 00594 case kBlue: // consume the key only if in edit-mode 00595 if (!InEditMode()) 00596 return osUnknown; 00597 break; 00598 case kLeft|k_Repeat: 00599 case kLeft: if (pos > 0) { 00600 if (!insert || newchar) 00601 pos--; 00602 newchar = true; 00603 if (!insert && Utf8is(alpha, valueUtf8[pos])) 00604 uppercase = Utf8is(upper, valueUtf8[pos]); 00605 } 00606 break; 00607 case kRight|k_Repeat: 00608 case kRight: if (InEditMode()) 00609 AdvancePos(); 00610 else { 00611 EnterEditMode(); 00612 SetHelpKeys(); 00613 } 00614 break; 00615 case kUp|k_Repeat: 00616 case kUp: 00617 case kDown|k_Repeat: 00618 case kDown: if (InEditMode()) { 00619 if (insert && newchar) { 00620 // create a new character in insert mode 00621 if (lengthUtf8 < length - 1) 00622 Insert(); 00623 } 00624 if (uppercase) 00625 valueUtf8[pos] = Utf8to(upper, Inc(Utf8to(lower, valueUtf8[pos]), NORMALKEY(Key) == kUp)); 00626 else 00627 valueUtf8[pos] = Inc( valueUtf8[pos], NORMALKEY(Key) == kUp); 00628 newchar = false; 00629 } 00630 else 00631 return cMenuEditItem::ProcessKey(Key); 00632 break; 00633 case k0|k_Repeat ... k9|k_Repeat: 00634 case k0 ... k9: { 00635 if (InEditMode()) { 00636 if (Setup.NumberKeysForChars) { 00637 if (!SameKey) { 00638 if (!newchar) 00639 AdvancePos(); 00640 currentCharUtf8 = NULL; 00641 } 00642 if (!currentCharUtf8 || !*currentCharUtf8 || *currentCharUtf8 == '\t') { 00643 // find the beginning of the character map entry for Key 00644 int n = NORMALKEY(Key) - k0; 00645 currentCharUtf8 = charMapUtf8; 00646 while (n > 0 && *currentCharUtf8) { 00647 if (*currentCharUtf8++ == '\t') 00648 n--; 00649 } 00650 // find first allowed character 00651 while (*currentCharUtf8 && *currentCharUtf8 != '\t' && !IsAllowed(*currentCharUtf8)) 00652 currentCharUtf8++; 00653 } 00654 if (*currentCharUtf8 && *currentCharUtf8 != '\t') { 00655 if (insert && newchar) { 00656 // create a new character in insert mode 00657 if (lengthUtf8 < length - 1) 00658 Insert(); 00659 } 00660 valueUtf8[pos] = *currentCharUtf8; 00661 if (uppercase) 00662 valueUtf8[pos] = Utf8to(upper, valueUtf8[pos]); 00663 // find next allowed character 00664 do { 00665 currentCharUtf8++; 00666 } while (*currentCharUtf8 && *currentCharUtf8 != '\t' && !IsAllowed(*currentCharUtf8)); 00667 newchar = false; 00668 autoAdvanceTimeout.Set(AUTO_ADVANCE_TIMEOUT); 00669 } 00670 } 00671 else 00672 Type('0' + NORMALKEY(Key) - k0); 00673 } 00674 else 00675 return cMenuEditItem::ProcessKey(Key); 00676 } 00677 break; 00678 case kBack: 00679 case kOk: if (InEditMode()) { 00680 LeaveEditMode(Key == kOk); 00681 SetHelpKeys(); 00682 break; 00683 } 00684 // run into default 00685 default: if (InEditMode() && BASICKEY(Key) == kKbd) { 00686 int c = KEYKBD(Key); 00687 if (c <= 0xFF) { // FIXME what about other UTF-8 characters? 00688 if (IsAllowed(Utf8to(lower, c))) 00689 Type(c); 00690 else { 00691 switch (c) { 00692 case 0x7F: // backspace 00693 if (pos > 0) { 00694 pos--; 00695 return ProcessKey(kYellow); 00696 } 00697 break; 00698 default: ; 00699 } 00700 } 00701 } 00702 else { 00703 switch (c) { 00704 case kfHome: pos = 0; break; 00705 case kfEnd: pos = lengthUtf8 - 1; break; 00706 case kfIns: return ProcessKey(kGreen); 00707 case kfDel: return ProcessKey(kYellow); 00708 default: ; 00709 } 00710 } 00711 } 00712 else 00713 return cMenuEditItem::ProcessKey(Key); 00714 } 00715 Set(); 00716 return osContinue; 00717 } 00718 00719 // --- cMenuEditStraItem ----------------------------------------------------- 00720 00721 cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings) 00722 :cMenuEditIntItem(Name, Value, 0, NumStrings - 1) 00723 { 00724 strings = Strings; 00725 Set(); 00726 } 00727 00728 void cMenuEditStraItem::Set(void) 00729 { 00730 SetValue(strings[*value]); 00731 } 00732 00733 // --- cMenuEditChanItem ----------------------------------------------------- 00734 00735 cMenuEditChanItem::cMenuEditChanItem(const char *Name, int *Value, const char *NoneString) 00736 :cMenuEditIntItem(Name, Value, NoneString ? 0 : 1, Channels.MaxNumber()) 00737 { 00738 channelID = NULL; 00739 noneString = NoneString; 00740 dummyValue = 0; 00741 Set(); 00742 } 00743 00744 cMenuEditChanItem::cMenuEditChanItem(const char *Name, cString *ChannelID, const char *NoneString) 00745 :cMenuEditIntItem(Name, &dummyValue, NoneString ? 0 : 1, Channels.MaxNumber()) 00746 { 00747 channelID = ChannelID; 00748 noneString = NoneString; 00749 cChannel *channel = Channels.GetByChannelID(tChannelID::FromString(*ChannelID)); 00750 dummyValue = channel ? channel->Number() : 0; 00751 Set(); 00752 } 00753 00754 void cMenuEditChanItem::Set(void) 00755 { 00756 if (*value > 0) { 00757 char buf[255]; 00758 cChannel *channel = Channels.GetByNumber(*value); 00759 snprintf(buf, sizeof(buf), "%d %s", *value, channel ? channel->Name() : ""); 00760 SetValue(buf); 00761 if (channelID) 00762 *channelID = channel->GetChannelID().ToString(); 00763 } 00764 else if (noneString) { 00765 SetValue(noneString); 00766 if (channelID) 00767 *channelID = ""; 00768 } 00769 } 00770 00771 eOSState cMenuEditChanItem::ProcessKey(eKeys Key) 00772 { 00773 int delta = 1; 00774 00775 switch (int(Key)) { 00776 case kLeft|k_Repeat: 00777 case kLeft: delta = -1; 00778 case kRight|k_Repeat: 00779 case kRight: 00780 { 00781 cChannel *channel = Channels.GetByNumber(*value + delta, delta); 00782 if (channel) 00783 *value = channel->Number(); 00784 else if (delta < 0 && noneString) 00785 *value = 0; 00786 if (channelID) 00787 *channelID = channel ? channel->GetChannelID().ToString() : ""; 00788 Set(); 00789 } 00790 break; 00791 default: return cMenuEditIntItem::ProcessKey(Key); 00792 } 00793 return osContinue; 00794 } 00795 00796 // --- cMenuEditTranItem ----------------------------------------------------- 00797 00798 cMenuEditTranItem::cMenuEditTranItem(const char *Name, int *Value, int *Source) 00799 :cMenuEditChanItem(Name, &number, "-") 00800 { 00801 number = 0; 00802 source = Source; 00803 transponder = Value; 00804 cChannel *channel = Channels.First(); 00805 while (channel) { 00806 if (!channel->GroupSep() && *source == channel->Source() && ISTRANSPONDER(channel->Transponder(), *Value)) { 00807 number = channel->Number(); 00808 break; 00809 } 00810 channel = (cChannel *)channel->Next(); 00811 } 00812 Set(); 00813 } 00814 00815 eOSState cMenuEditTranItem::ProcessKey(eKeys Key) 00816 { 00817 eOSState state = cMenuEditChanItem::ProcessKey(Key); 00818 cChannel *channel = Channels.GetByNumber(number); 00819 if (channel) { 00820 *source = channel->Source(); 00821 *transponder = channel->Transponder(); 00822 } 00823 else { 00824 *source = 0; 00825 *transponder = 0; 00826 } 00827 return state; 00828 } 00829 00830 // --- cMenuEditDateItem ----------------------------------------------------- 00831 00832 static int ParseWeekDays(const char *s) 00833 { 00834 time_t day; 00835 int weekdays; 00836 return cTimer::ParseDay(s, day, weekdays) ? weekdays : 0; 00837 } 00838 00839 int cMenuEditDateItem::days[] = { ParseWeekDays("M------"), 00840 ParseWeekDays("-T-----"), 00841 ParseWeekDays("--W----"), 00842 ParseWeekDays("---T---"), 00843 ParseWeekDays("----F--"), 00844 ParseWeekDays("-----S-"), 00845 ParseWeekDays("------S"), 00846 ParseWeekDays("MTWTF--"), 00847 ParseWeekDays("MTWTFS-"), 00848 ParseWeekDays("MTWTFSS"), 00849 ParseWeekDays("-----SS"), 00850 0 }; 00851 00852 cMenuEditDateItem::cMenuEditDateItem(const char *Name, time_t *Value, int *WeekDays) 00853 :cMenuEditItem(Name) 00854 { 00855 value = Value; 00856 weekdays = WeekDays; 00857 oldvalue = 0; 00858 oldweekdays = 0; 00859 dayindex = weekdays ? FindDayIndex(*weekdays) : 0; 00860 Set(); 00861 } 00862 00863 int cMenuEditDateItem::FindDayIndex(int WeekDays) 00864 { 00865 for (unsigned int i = 0; i < sizeof(days) / sizeof(int); i++) 00866 if (WeekDays == days[i]) 00867 return i; 00868 return 0; 00869 } 00870 00871 void cMenuEditDateItem::Set(void) 00872 { 00873 #define DATEBUFFERSIZE 32 00874 char buf[DATEBUFFERSIZE]; 00875 if (weekdays && *weekdays) { 00876 SetValue(cTimer::PrintDay(0, *weekdays, false)); 00877 return; 00878 } 00879 else if (*value) { 00880 struct tm tm_r; 00881 localtime_r(value, &tm_r); 00882 strftime(buf, DATEBUFFERSIZE, "%Y-%m-%d ", &tm_r); 00883 strcat(buf, WeekDayName(tm_r.tm_wday)); 00884 } 00885 else 00886 *buf = 0; 00887 SetValue(buf); 00888 } 00889 00890 void cMenuEditDateItem::ToggleRepeating(void) 00891 { 00892 if (weekdays) { 00893 if (*weekdays) { 00894 *value = cTimer::SetTime(oldvalue ? oldvalue : time(NULL), 0); 00895 oldvalue = 0; 00896 oldweekdays = *weekdays; 00897 *weekdays = 0; 00898 } 00899 else { 00900 *weekdays = oldweekdays ? oldweekdays : days[cTimer::GetWDay(*value)]; 00901 oldweekdays = 0; 00902 dayindex = FindDayIndex(*weekdays); 00903 oldvalue = *value; 00904 *value = 0; 00905 } 00906 Set(); 00907 } 00908 } 00909 00910 eOSState cMenuEditDateItem::ProcessKey(eKeys Key) 00911 { 00912 eOSState state = cMenuEditItem::ProcessKey(Key); 00913 00914 if (state == osUnknown) { 00915 time_t now = time(NULL); 00916 if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly? 00917 if (!weekdays || !*weekdays) { 00918 // Decrement single day: 00919 time_t v = *value; 00920 v -= SECSINDAY; 00921 if (v < now) { 00922 if (now <= v + SECSINDAY) { // switched from tomorrow to today 00923 if (!weekdays) 00924 v = 0; 00925 } 00926 else if (weekdays) { // switched from today to yesterday, so enter weekdays mode 00927 v = 0; 00928 dayindex = sizeof(days) / sizeof(int) - 2; 00929 *weekdays = days[dayindex]; 00930 } 00931 else // don't go before today 00932 v = *value; 00933 } 00934 *value = v; 00935 } 00936 else { 00937 // Decrement weekday index: 00938 if (dayindex > 0) 00939 *weekdays = days[--dayindex]; 00940 } 00941 } 00942 else if (NORMALKEY(Key) == kRight) { 00943 if (!weekdays || !*weekdays) { 00944 // Increment single day: 00945 if (!*value) 00946 *value = cTimer::SetTime(now, 0); 00947 *value += SECSINDAY; 00948 } 00949 else { 00950 // Increment weekday index: 00951 *weekdays = days[++dayindex]; 00952 if (!*weekdays) { // was last weekday entry, so switch to today 00953 *value = cTimer::SetTime(now, 0); 00954 dayindex = 0; 00955 } 00956 } 00957 } 00958 else if (weekdays) { 00959 if (Key == k0) { 00960 // Toggle between weekdays and single day: 00961 ToggleRepeating(); 00962 return osContinue; // ToggleRepeating) has already called Set() 00963 } 00964 else if (k1 <= Key && Key <= k7) { 00965 // Toggle individual weekdays: 00966 if (*weekdays) { 00967 int v = *weekdays ^ (1 << (Key - k1)); 00968 if (v != 0) 00969 *weekdays = v; // can't let this become all 0 00970 } 00971 } 00972 else 00973 return state; 00974 } 00975 else 00976 return state; 00977 Set(); 00978 state = osContinue; 00979 } 00980 return state; 00981 } 00982 00983 // --- cMenuEditTimeItem ----------------------------------------------------- 00984 00985 cMenuEditTimeItem::cMenuEditTimeItem(const char *Name, int *Value) 00986 :cMenuEditItem(Name) 00987 { 00988 value = Value; 00989 hh = *value / 100; 00990 mm = *value % 100; 00991 pos = 0; 00992 Set(); 00993 } 00994 00995 void cMenuEditTimeItem::Set(void) 00996 { 00997 char buf[10]; 00998 switch (pos) { 00999 case 1: snprintf(buf, sizeof(buf), "%01d-:--", hh / 10); break; 01000 case 2: snprintf(buf, sizeof(buf), "%02d:--", hh); break; 01001 case 3: snprintf(buf, sizeof(buf), "%02d:%01d-", hh, mm / 10); break; 01002 default: snprintf(buf, sizeof(buf), "%02d:%02d", hh, mm); 01003 } 01004 SetValue(buf); 01005 } 01006 01007 eOSState cMenuEditTimeItem::ProcessKey(eKeys Key) 01008 { 01009 eOSState state = cMenuEditItem::ProcessKey(Key); 01010 01011 if (state == osUnknown) { 01012 if (k0 <= Key && Key <= k9) { 01013 if (fresh || pos > 3) { 01014 pos = 0; 01015 fresh = false; 01016 } 01017 int n = Key - k0; 01018 switch (pos) { 01019 case 0: if (n <= 2) { 01020 hh = n * 10; 01021 mm = 0; 01022 pos++; 01023 } 01024 break; 01025 case 1: if (hh + n <= 23) { 01026 hh += n; 01027 pos++; 01028 } 01029 break; 01030 case 2: if (n <= 5) { 01031 mm += n * 10; 01032 pos++; 01033 } 01034 break; 01035 case 3: if (mm + n <= 59) { 01036 mm += n; 01037 pos++; 01038 } 01039 break; 01040 default: ; 01041 } 01042 } 01043 else if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly? 01044 if (--mm < 0) { 01045 mm = 59; 01046 if (--hh < 0) 01047 hh = 23; 01048 } 01049 fresh = true; 01050 } 01051 else if (NORMALKEY(Key) == kRight) { 01052 if (++mm > 59) { 01053 mm = 0; 01054 if (++hh > 23) 01055 hh = 0; 01056 } 01057 fresh = true; 01058 } 01059 else 01060 return state; 01061 *value = hh * 100 + mm; 01062 Set(); 01063 state = osContinue; 01064 } 01065 return state; 01066 } 01067 01068 // --- cMenuEditMapItem ------------------------------------------------------ 01069 01070 cMenuEditMapItem::cMenuEditMapItem(const char *Name, int *Value, const tDvbParameterMap *Map, const char *ZeroString) 01071 :cMenuEditItem(Name) 01072 { 01073 value = Value; 01074 map = Map; 01075 zeroString = ZeroString; 01076 Set(); 01077 } 01078 01079 void cMenuEditMapItem::Set(void) 01080 { 01081 const char *s = NULL; 01082 int n = MapToUser(*value, map, &s); 01083 if (n == 0 && zeroString) 01084 SetValue(zeroString); 01085 else if (n >= 0) { 01086 if (s) 01087 SetValue(s); 01088 else { 01089 char buf[16]; 01090 snprintf(buf, sizeof(buf), "%d", n); 01091 SetValue(buf); 01092 } 01093 } 01094 else 01095 SetValue("???"); 01096 } 01097 01098 eOSState cMenuEditMapItem::ProcessKey(eKeys Key) 01099 { 01100 eOSState state = cMenuEditItem::ProcessKey(Key); 01101 01102 if (state == osUnknown) { 01103 int newValue = *value; 01104 int n = DriverIndex(*value, map); 01105 if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly? 01106 if (n-- > 0) 01107 newValue = map[n].driverValue; 01108 } 01109 else if (NORMALKEY(Key) == kRight) { 01110 if (map[++n].userValue >= 0) 01111 newValue = map[n].driverValue; 01112 } 01113 else 01114 return state; 01115 if (newValue != *value) { 01116 *value = newValue; 01117 Set(); 01118 } 01119 state = osContinue; 01120 } 01121 return state; 01122 } 01123 01124 // --- cMenuSetupPage -------------------------------------------------------- 01125 01126 cMenuSetupPage::cMenuSetupPage(void) 01127 :cOsdMenu("", 33) 01128 { 01129 plugin = NULL; 01130 } 01131 01132 void cMenuSetupPage::SetSection(const char *Section) 01133 { 01134 SetTitle(cString::sprintf("%s - %s", tr("Setup"), Section)); 01135 } 01136 01137 eOSState cMenuSetupPage::ProcessKey(eKeys Key) 01138 { 01139 eOSState state = cOsdMenu::ProcessKey(Key); 01140 01141 if (state == osUnknown) { 01142 switch (Key) { 01143 case kOk: Store(); 01144 state = osBack; 01145 break; 01146 default: break; 01147 } 01148 } 01149 return state; 01150 } 01151 01152 void cMenuSetupPage::SetPlugin(cPlugin *Plugin) 01153 { 01154 plugin = Plugin; 01155 SetSection(cString::sprintf("%s '%s'", tr("Plugin"), plugin->Name())); 01156 } 01157 01158 void cMenuSetupPage::SetupStore(const char *Name, const char *Value) 01159 { 01160 if (plugin) 01161 plugin->SetupStore(Name, Value); 01162 } 01163 01164 void cMenuSetupPage::SetupStore(const char *Name, int Value) 01165 { 01166 if (plugin) 01167 plugin->SetupStore(Name, Value); 01168 }