Home

Dokumentation

Impressum

Dokumentation VDR
 

Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

menuitems.c

Go to the documentation of this file.
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 1.11 2002/12/15 11:05:19 kls Exp $
00008  */
00009 
00010 #include "menuitems.h"
00011 #include <ctype.h>
00012 #include "i18n.h"
00013 #include "plugin.h"
00014 #include "status.h"
00015 
00016 const char *FileNameChars = " abcdefghijklmnopqrstuvwxyz0123456789-.#~";
00017 
00018 // --- cMenuEditItem ---------------------------------------------------------
00019 
00020 cMenuEditItem::cMenuEditItem(const char *Name)
00021 {
00022   name = strdup(Name);
00023   value = NULL;
00024 }
00025 
00026 cMenuEditItem::~cMenuEditItem()
00027 {
00028   free(name);
00029   free(value);
00030 }
00031 
00032 void cMenuEditItem::SetValue(const char *Value)
00033 {
00034   free(value);
00035   value = strdup(Value);
00036   char *buffer = NULL;
00037   asprintf(&buffer, "%s:\t%s", name, value);
00038   SetText(buffer, false);
00039   Display();
00040 }
00041 
00042 // --- cMenuEditIntItem ------------------------------------------------------
00043 
00044 cMenuEditIntItem::cMenuEditIntItem(const char *Name, int *Value, int Min, int Max)
00045 :cMenuEditItem(Name)
00046 {
00047   value = Value;
00048   min = Min;
00049   max = Max;
00050   Set();
00051 }
00052 
00053 void cMenuEditIntItem::Set(void)
00054 {
00055   char buf[16];
00056   snprintf(buf, sizeof(buf), "%d", *value);
00057   SetValue(buf);
00058 }
00059 
00060 eOSState cMenuEditIntItem::ProcessKey(eKeys Key)
00061 {
00062   eOSState state = cMenuEditItem::ProcessKey(Key);
00063 
00064   if (state == osUnknown) {
00065      int newValue;
00066      if (k0 <= Key && Key <= k9) {
00067         if (fresh) {
00068            *value = 0;
00069            fresh = false;
00070            }
00071         newValue = *value * 10 + (Key - k0);
00072         }
00073      else if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
00074         newValue = *value - 1;
00075         fresh = true;
00076         }
00077      else if (NORMALKEY(Key) == kRight) {
00078         newValue = *value + 1;
00079         fresh = true;
00080         }
00081      else {
00082         if (*value < min) { *value = min; Set(); }
00083         if (*value > max) { *value = max; Set(); }
00084         return state;
00085         }
00086      if ((!fresh || min <= newValue) && newValue <= max) {
00087         *value = newValue;
00088         Set();
00089         }
00090      state = osContinue;
00091      }
00092   return state;
00093 }
00094 
00095 // --- cMenuEditBoolItem -----------------------------------------------------
00096 
00097 cMenuEditBoolItem::cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString, const char *TrueString)
00098 :cMenuEditIntItem(Name, Value, 0, 1)
00099 {
00100   falseString = FalseString ? FalseString : tr("no");
00101   trueString = TrueString ? TrueString : tr("yes");
00102   Set();
00103 }
00104 
00105 void cMenuEditBoolItem::Set(void)
00106 {
00107   char buf[16];
00108   snprintf(buf, sizeof(buf), "%s", *value ? trueString : falseString);
00109   SetValue(buf);
00110 }
00111 
00112 // --- cMenuEditChrItem ------------------------------------------------------
00113 
00114 cMenuEditChrItem::cMenuEditChrItem(const char *Name, char *Value, const char *Allowed)
00115 :cMenuEditItem(Name)
00116 {
00117   value = Value;
00118   allowed = strdup(Allowed);
00119   current = strchr(allowed, *Value);
00120   if (!current)
00121      current = allowed;
00122   Set();
00123 }
00124 
00125 cMenuEditChrItem::~cMenuEditChrItem()
00126 {
00127   free(allowed);
00128 }
00129 
00130 void cMenuEditChrItem::Set(void)
00131 {
00132   char buf[2];
00133   snprintf(buf, sizeof(buf), "%c", *value);
00134   SetValue(buf);
00135 }
00136 
00137 eOSState cMenuEditChrItem::ProcessKey(eKeys Key)
00138 {
00139   eOSState state = cMenuEditItem::ProcessKey(Key);
00140 
00141   if (state == osUnknown) {
00142      if (NORMALKEY(Key) == kLeft) {
00143         if (current > allowed)
00144            current--;
00145         }
00146      else if (NORMALKEY(Key) == kRight) {
00147         if (*(current + 1))
00148            current++;
00149         }
00150      else
00151         return state;
00152      *value = *current;
00153      Set();
00154      state = osContinue;
00155      }
00156   return state;
00157 }
00158 
00159 // --- cMenuEditStrItem ------------------------------------------------------
00160 
00161 cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed)
00162 :cMenuEditItem(Name)
00163 {
00164   value = Value;
00165   length = Length;
00166   allowed = strdup(Allowed);
00167   pos = -1;
00168   insert = uppercase = false;
00169   newchar = true;
00170   Set();
00171 }
00172 
00173 cMenuEditStrItem::~cMenuEditStrItem()
00174 {
00175   free(allowed);
00176 }
00177 
00178 void cMenuEditStrItem::SetHelpKeys(void)
00179 {
00180   if (pos >= 0)
00181      Interface->Help(tr("ABC/abc"), tr(insert ? "Overwrite" : "Insert"), tr("Delete"));
00182   else
00183      Interface->Help(NULL);
00184 }
00185 
00186 void cMenuEditStrItem::Set(void)
00187 {
00188   char buf[1000];
00189   const char *fmt = insert && newchar ? "[]%c%s" : "[%c]%s";
00190 
00191   if (pos >= 0) {
00192      strncpy(buf, value, pos);
00193      snprintf(buf + pos, sizeof(buf) - pos - 2, fmt, *(value + pos), value + pos + 1);
00194      int width = Interface->Width() - Interface->GetCols()[0];
00195      if (cOsd::WidthInCells(buf) <= width) {
00196         // the whole buffer fits on the screen
00197         SetValue(buf);
00198         return;
00199         }
00200      width *= cOsd::CellWidth();
00201      width -= cOsd::Width('>'); // assuming '<' and '>' have the same with
00202      int w = 0;
00203      int i = 0;
00204      int l = strlen(buf);
00205      while (i < l && w <= width)
00206            w += cOsd::Width(buf[i++]);
00207      if (i >= pos + 4) {
00208         // the cursor fits on the screen
00209         buf[i - 1] = '>';
00210         buf[i] = 0;
00211         SetValue(buf);
00212         return;
00213         }
00214      // the cursor doesn't fit on the screen
00215      w = 0;
00216      if (buf[i = pos + 3]) {
00217         buf[i] = '>';
00218         buf[i + 1] = 0;
00219         }
00220      else
00221         i--;
00222      while (i >= 0 && w <= width)
00223            w += cOsd::Width(buf[i--]);
00224      buf[++i] = '<';
00225      SetValue(buf + i);
00226      }
00227   else
00228      SetValue(value);
00229 }
00230 
00231 char cMenuEditStrItem::Inc(char c, bool Up)
00232 {
00233   const char *p = strchr(allowed, c);
00234   if (!p)
00235      p = allowed;
00236   if (Up) {
00237      if (!*++p)
00238         p = allowed;
00239      }
00240   else if (--p < allowed)
00241      p = allowed + strlen(allowed) - 1;
00242   return *p;
00243 }
00244 
00245 eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
00246 {
00247   switch (Key) {
00248     case kRed:   // Switch between upper- and lowercase characters
00249                  if (pos >= 0 && (!insert || !newchar)) {
00250                     uppercase = !uppercase;
00251                     value[pos] = uppercase ? toupper(value[pos]) : tolower(value[pos]);
00252                     }
00253                  break;
00254     case kGreen: // Toggle insert/overwrite modes
00255                  if (pos >= 0) {
00256                     insert = !insert;
00257                     newchar = true;
00258                     }
00259                  SetHelpKeys();
00260                  break;
00261     case kYellow|k_Repeat:
00262     case kYellow: // Remove the character at current position; in insert mode it is the character to the right of cursor
00263                  if (pos >= 0) {
00264                     if (strlen(value) > 1) {
00265                        if (!insert || pos < int(strlen(value)) - 1)
00266                           memmove(value + pos, value + pos + 1, strlen(value) - pos);
00267                        // reduce position, if we removed the last character
00268                        if (pos == int(strlen(value)))
00269                           pos--;
00270                        }
00271                     else if (strlen(value) == 1)
00272                        value[0] = ' '; // This is the last character in the string, replace it with a blank
00273                     if (isalpha(value[pos]))
00274                        uppercase = isupper(value[pos]);
00275                     newchar = true;
00276                     }
00277                  break;
00278     case kLeft|k_Repeat:
00279     case kLeft:  if (pos > 0) {
00280                     if (!insert || newchar)
00281                        pos--;
00282                     newchar = true;
00283                     }
00284                  if (!insert && isalpha(value[pos]))
00285                     uppercase = isupper(value[pos]);
00286                  break;
00287     case kRight|k_Repeat:
00288     case kRight: if (pos < length - 2 && pos < int(strlen(value)) ) {
00289                     if (++pos >= int(strlen(value))) {
00290                        if (pos >= 2 && value[pos - 1] == ' ' && value[pos - 2] == ' ')
00291                           pos--; // allow only two blanks at the end
00292                        else {
00293                           value[pos] = ' ';
00294                           value[pos + 1] = 0;
00295                           }
00296                        }
00297                     }
00298                  newchar = true;
00299                  if (!insert && isalpha(value[pos]))
00300                     uppercase = isupper(value[pos]);
00301                  if (pos == 0)
00302                     SetHelpKeys();
00303                  break;
00304     case kUp|k_Repeat:
00305     case kUp:
00306     case kDown|k_Repeat:
00307     case kDown:  if (pos >= 0) {
00308                     if (insert && newchar) {
00309                        // create a new character in insert mode
00310                        if (int(strlen(value)) < length - 1) {
00311                           memmove(value + pos + 1, value + pos, strlen(value) - pos + 1);
00312                           value[pos] = ' ';
00313                           }
00314                        }
00315                     if (uppercase)
00316                        value[pos] = toupper(Inc(tolower(value[pos]), NORMALKEY(Key) == kUp));
00317                     else
00318                        value[pos] =         Inc(        value[pos],  NORMALKEY(Key) == kUp);
00319                     newchar = false;
00320                     }
00321                  else
00322                     return cMenuEditItem::ProcessKey(Key);
00323                  break;
00324     case kOk:    if (pos >= 0) {
00325                     pos = -1;
00326                     newchar = true;
00327                     stripspace(value);
00328                     SetHelpKeys();
00329                     break;
00330                     }
00331                  // run into default
00332     default:     if (pos >= 0 && BASICKEY(Key) == kKbd) {
00333                     int c = KEYKBD(Key);
00334                     if (c <= 0xFF) {
00335                        const char *p = strchr(allowed, tolower(c));
00336                        if (p) {
00337                           int l = strlen(value);
00338                           if (insert && l < length - 1)
00339                              memmove(value + pos + 1, value + pos, l - pos + 1);
00340                           value[pos] = c;
00341                           if (pos < length - 2)
00342                              pos++;
00343                           if (pos >= l) {
00344                              value[pos] = ' ';
00345                              value[pos + 1] = 0;
00346                              }
00347                           }
00348                        else {
00349                           switch (c) {
00350                             case 0x7F: // backspace
00351                                        if (pos > 0) {
00352                                           pos--;
00353                                           return ProcessKey(kYellow);
00354                                           }
00355                                        break;
00356                             }
00357                           }
00358                        }
00359                     else {
00360                        switch (c) {
00361                          case kfHome: pos = 0; break;
00362                          case kfEnd:  pos = strlen(value) - 1; break;
00363                          case kfIns:  return ProcessKey(kGreen);
00364                          case kfDel:  return ProcessKey(kYellow);
00365                          }
00366                        }
00367                     }
00368                  else
00369                     return cMenuEditItem::ProcessKey(Key);
00370     }
00371   Set();
00372   return osContinue;
00373 }
00374 
00375 // --- cMenuEditStraItem -----------------------------------------------------
00376 
00377 cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings)
00378 :cMenuEditIntItem(Name, Value, 0, NumStrings - 1)
00379 {
00380   strings = Strings;
00381   Set();
00382 }
00383 
00384 void cMenuEditStraItem::Set(void)
00385 {
00386   SetValue(strings[*value]);
00387 }
00388 
00389 // --- cMenuTextItem ---------------------------------------------------------
00390 
00391 cMenuTextItem::cMenuTextItem(const char *Text, int X, int Y, int W, int H, eDvbColor FgColor, eDvbColor BgColor, eDvbFont Font)
00392 {
00393   x = X;
00394   y = Y;
00395   w = W;
00396   h = H;
00397   fgColor = FgColor;
00398   bgColor = BgColor;
00399   font = Font;
00400   offset = 0;
00401   eDvbFont oldFont = Interface->SetFont(font);
00402   text = Interface->WrapText(Text, w - 1, &lines);
00403   Interface->SetFont(oldFont);
00404   if (h < 0)
00405      h = lines;
00406 }
00407 
00408 cMenuTextItem::~cMenuTextItem()
00409 {
00410   free(text);
00411 }
00412 
00413 void cMenuTextItem::Clear(void)
00414 {
00415   Interface->Fill(x, y, w, h, bgColor);
00416 }
00417 
00418 void cMenuTextItem::Display(int Offset, eDvbColor FgColor, eDvbColor BgColor)
00419 {
00420   int l = 0;
00421   char *t = text;
00422   eDvbFont oldFont = Interface->SetFont(font);
00423   while (*t) {
00424         char *n = strchr(t, '\n');
00425         if (l >= offset) {
00426            if (n)
00427               *n = 0;
00428            Interface->Write(x, y + l - offset, t, fgColor, bgColor);
00429            if (n)
00430               *n = '\n';
00431            else
00432               break;
00433            }
00434         if (!n)
00435            break;
00436         t = n + 1;
00437         if (++l >= h + offset)
00438            break;
00439         }
00440   Interface->SetFont(oldFont);
00441   // scroll indicators use inverted color scheme!
00442   if (CanScrollUp())   Interface->Write(x + w - 1, y,         "^", bgColor, fgColor);
00443   if (CanScrollDown()) Interface->Write(x + w - 1, y + h - 1, "v", bgColor, fgColor);
00444   cStatus::MsgOsdTextItem(text);
00445 }
00446 
00447 void cMenuTextItem::ScrollUp(bool Page)
00448 {
00449   if (CanScrollUp()) {
00450      Clear();
00451      offset = max(offset - (Page ? h : 1), 0);
00452      Display();
00453      }
00454   cStatus::MsgOsdTextItem(NULL, true);
00455 }
00456 
00457 void cMenuTextItem::ScrollDown(bool Page)
00458 {
00459   if (CanScrollDown()) {
00460      Clear();
00461      offset = min(offset + (Page ? h : 1), lines - h);
00462      Display();
00463      }
00464   cStatus::MsgOsdTextItem(NULL, false);
00465 }
00466 
00467 eOSState cMenuTextItem::ProcessKey(eKeys Key)
00468 {
00469   switch (Key) {
00470     case kLeft|k_Repeat:
00471     case kLeft:
00472     case kUp|k_Repeat:
00473     case kUp:            ScrollUp(NORMALKEY(Key) == kLeft);    break;
00474     case kRight|k_Repeat:
00475     case kRight:
00476     case kDown|k_Repeat:
00477     case kDown:          ScrollDown(NORMALKEY(Key) == kRight); break;
00478     default:             return osUnknown;
00479     }
00480   return osContinue;
00481 }
00482 
00483 // --- cMenuSetupPage --------------------------------------------------------
00484 
00485 cMenuSetupPage::cMenuSetupPage(void)
00486 :cOsdMenu("", 33)
00487 {
00488   plugin = NULL;
00489 }
00490 
00491 void cMenuSetupPage::SetSection(const char *Section)
00492 {
00493   char buf[40];
00494   snprintf(buf, sizeof(buf), "%s - %s", tr("Setup"), Section);
00495   SetTitle(buf);
00496 }
00497 
00498 eOSState cMenuSetupPage::ProcessKey(eKeys Key)
00499 {
00500   eOSState state = cOsdMenu::ProcessKey(Key);
00501 
00502   if (state == osUnknown) {
00503      switch (Key) {
00504        case kOk: Store();
00505                  state = osBack;
00506                  break;
00507        default: break;
00508        }
00509      }
00510   return state;
00511 }
00512 
00513 void cMenuSetupPage::SetPlugin(cPlugin *Plugin)
00514 {
00515   plugin = Plugin;
00516   char buf[40];
00517   snprintf(buf, sizeof(buf), "%s '%s'", tr("Plugin"), plugin->Name());
00518   SetSection(buf);
00519 }
00520 
00521 void cMenuSetupPage::SetupStore(const char *Name, const char *Value)
00522 {
00523   if (plugin)
00524      plugin->SetupStore(Name, Value);
00525 }
00526 
00527 void cMenuSetupPage::SetupStore(const char *Name, int Value)
00528 {
00529   if (plugin)
00530      plugin->SetupStore(Name, Value);
00531 }

Generated on Wed Feb 5 23:30:10 2003 for VDR by doxygen1.3-rc2