Vinícius Alves / Mbed 2 deprecated MenuLCD_copy

Dependencies:   MenuLCD mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers menbedNavigator.cpp Source File

menbedNavigator.cpp

00001 #include "mbed.h"
00002 #include "include/menbedNavigator.h"
00003 #include "include/menbedButtonEvent.h"
00004 #include "include/menbedMenuMessage.h"
00005 #include "include/menbedMenu.h"
00006 #include <cstdio>
00007 
00008 extern void toggleLed3();
00009 
00010 MenbedNavigator::MenbedNavigator(MenbedMenu *rootMenu,  
00011         MenbedDisplayer *displayer) :
00012     activeMenu(rootMenu), displayer(displayer)
00013 {
00014     selectedItemIndex = -1;
00015     topOfScreenItemIndex = 0;
00016     paramEditMode = false;
00017     
00018     numLines = displayer->getDisplay()->getLines();
00019     lineLength = displayer->getDisplay()->getLineLength();
00020 }
00021 
00022 void MenbedNavigator::updateDisplay()
00023 {
00024     MenbedMenuMessage menuMsg (numLines, lineLength);
00025 
00026     printMenu (menuMsg.text);
00027     menuMsg.showUpArrow = (topOfScreenItemIndex >= 1);
00028     menuMsg.showDownArrow = (topOfScreenItemIndex + numLines < (int)(activeMenu->menuItems.size()));
00029     
00030     displayer->update (&menuMsg);
00031 }
00032 
00033 
00034 void MenbedNavigator::handleButtonEvent (MenbedButtonEvent buttonEvent)
00035 {
00036     numButtons = buttonEvent.numButtons;
00037 
00038     switch (buttonEvent.name)
00039     {
00040     case MenbedButtonEvent::ButtonSelect: // Select
00041         if (!paramEditMode && (buttonEvent.action == 
00042                 MenbedButtonEvent::BUTTON_ACTION_RELEASED_SHORT))
00043             selectItem();
00044         else if (paramEditMode && (buttonEvent.action ==
00045                 MenbedButtonEvent::BUTTON_ACTION_RELEASED_SHORT))
00046             saveParam();
00047         else if ((numButtons < 4) && 
00048             paramEditMode && (buttonEvent.action == 
00049                 MenbedButtonEvent::BUTTON_ACTION_HELD_LONG))
00050             restoreParam();
00051         else if ((numButtons < 4) && !paramEditMode && 
00052             (buttonEvent.action ==
00053                 MenbedButtonEvent::BUTTON_ACTION_HELD_LONG))
00054             gotoParent();
00055         break;
00056         
00057     case MenbedButtonEvent::ButtonDown:
00058         if (paramEditMode && 
00059                 (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED))
00060             decParam();
00061         else if (!paramEditMode && 
00062                 (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED))
00063             moveDown();
00064         break;
00065         
00066     case MenbedButtonEvent::ButtonUp:
00067         if (numButtons > 2)
00068         {
00069             if (paramEditMode && 
00070                     (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED))
00071                 incParam();
00072             else if (!paramEditMode &&
00073                     (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED))
00074                 moveUp();
00075         }
00076         break;
00077         
00078     case MenbedButtonEvent::ButtonCancel:
00079         if (numButtons > 3)
00080         {
00081             if (paramEditMode && 
00082                     (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED))
00083                 restoreParam();
00084             else if (!paramEditMode && 
00085                     (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED))
00086                 gotoParent();
00087         }
00088         break;
00089     }
00090 
00091     updateDisplay();
00092     //menuRefresh_refreshed();
00093 }
00094 
00095 
00096 void MenbedNavigator::selectItem()
00097 {
00098     MenbedMenu **childMenuPtr;
00099     MenbedMenu *childMenu;
00100 
00101     if ((selectedItemIndex < 0) || 
00102             (selectedItemIndex >= (int)(activeMenu->menuItems.size())))
00103          return;
00104 
00105     // If it exists, execute the function associated with the menu item
00106     if (activeMenu->menuItems[selectedItemIndex]->selFcn != NULL)
00107         activeMenu->menuItems[selectedItemIndex]->selFcn();
00108 
00109     // Show the child menu associated with the menu item.  Initially, the first
00110     // item in the child menu is placed at the top of the screen, but is it
00111     // left unselected.
00112     childMenuPtr = activeMenu->menuItems[selectedItemIndex]->childMenu;
00113     if (childMenuPtr != NULL)
00114     {
00115         childMenu = *(activeMenu->menuItems[selectedItemIndex]->childMenu);
00116     
00117         if (!activeMenu->menuItems[selectedItemIndex]->childMenuIsAncestor)
00118         {
00119             childMenu->parentMenu = activeMenu;
00120             childMenu->parentSelectedItemIndex = selectedItemIndex;
00121             childMenu->parentTopOfScreenItemIndex = topOfScreenItemIndex;
00122         }
00123         else
00124             childMenu->parentMenu = NULL;
00125 
00126         activeMenu = childMenu;
00127         topOfScreenItemIndex = 0;
00128         selectedItemIndex = -1;       
00129     }
00130     // Otherwise, if the current menu item has a parameter that can be modified,
00131     // we switch to the parameter editing mode.
00132     else if ((activeMenu->menuItems[selectedItemIndex]->param != NULL) &&
00133             (activeMenu->menuItems[selectedItemIndex]->param->inc() != 0))
00134     {
00135         // All incrementing and decrementing of the parameter actually happens
00136         // to a shadow variable in the param structure named tempValue.  The
00137         // parameter value used by the other parts of the system is not updated
00138         // until the user is done editing the parameter.
00139         activeMenu->menuItems[selectedItemIndex]->param->initVal =
00140                 activeMenu->menuItems[selectedItemIndex]->param->getVal();
00141         activeMenu->menuItems[selectedItemIndex]->param->tempVal =
00142                 activeMenu->menuItems[selectedItemIndex]->param->initVal;
00143         paramEditMode = true;
00144     }
00145 }
00146 
00147 
00148 void MenbedNavigator::gotoParent()
00149 {
00150     if (activeMenu->parentMenu == NULL)
00151         return;
00152 
00153     selectedItemIndex = activeMenu->parentSelectedItemIndex;
00154     topOfScreenItemIndex = activeMenu->parentTopOfScreenItemIndex;
00155     activeMenu = activeMenu->parentMenu;
00156 }
00157 
00158 
00159 void MenbedNavigator::moveUp()
00160 {
00161     // If we're already at the top of the menu, do nothing
00162     if (selectedItemIndex <= -1)
00163         return;
00164     // If the top item of the menu is already selected, we send a NOP message
00165     // which deselects the top line and displays the down arrow if the menu
00166     // contains more items than can fit on the screen.  In effect, this allows
00167     // the user to deselect all menu items which adds a nice look to the system.
00168     else if (selectedItemIndex == 0)
00169         selectedItemIndex = -1;
00170     // If the currently selected menu item is the also the one at the top of the
00171     // screen, we need to scroll the screen down and add the item above the
00172     // currently selected one to the top of the screen.
00173     else if (selectedItemIndex == topOfScreenItemIndex)
00174     {
00175         selectedItemIndex--;
00176         topOfScreenItemIndex--;
00177     }
00178     // The selected item is not the top item on the screen.  All we need to do
00179     // is select the item above the currently selected item.
00180     else
00181         selectedItemIndex--;
00182 }
00183 
00184 
00185 
00186 void MenbedNavigator::moveDown()
00187 {
00188     // If the last item of the menu is already selected, our behavior depends
00189     // on how many buttons are present.  If there is no up button, we cycle
00190     // back to the top of the menu.  Otherwise, if an up button is present,
00191     // we do nothing.
00192     if (selectedItemIndex >= ((int)(activeMenu->menuItems.size()) - 1))
00193     {
00194         if (numButtons < 3)
00195         {
00196             selectedItemIndex = -1;
00197             topOfScreenItemIndex = 0;
00198         }
00199         else
00200             ;
00201     }
00202     // If the menu item displayed at the bottom of the screen is already
00203     // selected, we will need to scroll the screen up to make room for a new
00204     // line at the bottom of the screen.
00205     else if (selectedItemIndex ==
00206             (topOfScreenItemIndex + numLines - 1))
00207     {
00208         selectedItemIndex++;
00209         topOfScreenItemIndex++;
00210     }
00211     // Otherwise, if the currently selected menu item is now the one displayed
00212     // at the bottom of the screen, we simply change which of the visible items
00213     // is highlighted.
00214     else
00215         selectedItemIndex++;
00216         
00217 }
00218 
00219 
00220 void MenbedNavigator::incParam()
00221 {
00222     float inc;
00223     float tempVal;
00224 
00225     if (paramEditMode != true)
00226         return;
00227 
00228     inc = activeMenu->menuItems[selectedItemIndex]->param->inc();
00229 
00230     // Initialize our own local copy of the parameter's temporary value.  We do
00231     // this so that we can more easily check for violations of the allowed min
00232     // and max values.
00233     tempVal = activeMenu->menuItems[selectedItemIndex]->param->tempVal;
00234     tempVal += inc;
00235 
00236     // Check the bounds on the parameter.
00237     if (tempVal > activeMenu->menuItems[selectedItemIndex]->param->max())
00238         tempVal = activeMenu->menuItems[selectedItemIndex]->param->max();
00239     else if (tempVal < activeMenu->menuItems[selectedItemIndex]->param->min())
00240         tempVal = activeMenu->menuItems[selectedItemIndex]->param->min();
00241 
00242     // Assign the local temp. value back to the temporary value in the active
00243     // parameter structue.
00244     activeMenu->menuItems[selectedItemIndex]->param->tempVal = tempVal;
00245 
00246     // If the parameter is configured to produce live updates, call the
00247     // finalValFcn.
00248     if (activeMenu->menuItems[selectedItemIndex]->param->liveUpdate())
00249         activeMenu->menuItems[selectedItemIndex]->param->setVal(tempVal);
00250 }
00251 
00252 
00253 void MenbedNavigator::decParam()
00254 {
00255     float inc;
00256     float tempVal;
00257 
00258     if (paramEditMode != true)
00259         return;
00260 
00261     inc = activeMenu->menuItems[selectedItemIndex]->param->inc();
00262 
00263     // Initialize our own local copy of the parameter's temporary value.  We do
00264     // this so that we can more easily check for violations of the allowed min
00265     // and max values.
00266     tempVal = activeMenu->menuItems[selectedItemIndex]->param->tempVal;
00267     tempVal -= inc;
00268 
00269     // Check the bounds on the parameter.
00270     if (tempVal > activeMenu->menuItems[selectedItemIndex]->param->max())
00271         tempVal = activeMenu->menuItems[selectedItemIndex]->param->max();
00272     // If we reach the minimum parameter value when we only have a down button
00273     // and not an up button connected to the system, we wrap the parameter
00274     // value back around to its maximum.  Otherwise, if there is an up button
00275     // present, we peg the parameter at its minimum value.
00276     else if (tempVal < activeMenu->menuItems[selectedItemIndex]->param->min())
00277     {
00278         if (numButtons >= 3)
00279             tempVal = activeMenu->menuItems[selectedItemIndex]->param->min();
00280         else
00281             tempVal = activeMenu->menuItems[selectedItemIndex]->param->max();
00282     }
00283 
00284     // Assign the local temp. value back to the temporary value in the active
00285     // parameter structue.
00286     activeMenu->menuItems[selectedItemIndex]->param->tempVal = tempVal;
00287 
00288     // If the parameter is configured to produce live updates, call the
00289     // finalValFcn.
00290     if (activeMenu->menuItems[selectedItemIndex]->param->liveUpdate())
00291         activeMenu->menuItems[selectedItemIndex]->param->setVal(tempVal);
00292 }
00293 
00294 
00295 void MenbedNavigator::saveParam()
00296 {
00297     // Save the changes made the shadow variable tempValue to the real parameter
00298     // value that is used by the rest of the application.
00299     activeMenu->menuItems[selectedItemIndex]->param->setVal (
00300             activeMenu->menuItems[selectedItemIndex]->param->tempVal
00301             );
00302     paramEditMode = false;
00303 }
00304 
00305 
00306 void MenbedNavigator::restoreParam()
00307 {
00308     // Revert any changes made the parameter by calling the finalValFcn with
00309     // the initVal that was stored when we first began editing this parameter.
00310     activeMenu->menuItems[selectedItemIndex]->param->setVal(
00311             activeMenu->menuItems[selectedItemIndex]->param->initVal
00312             );
00313     paramEditMode = false;
00314 }
00315 
00316 
00317 void MenbedNavigator::printMenu (char *menuStr)
00318 {
00319     uint8_t i;
00320     char *lineStr = new char[lineLength];
00321     bool itemSel;
00322 
00323     menuStr[0] = '\0';
00324 
00325     for (i=topOfScreenItemIndex; i<topOfScreenItemIndex + numLines; i++)
00326     {
00327         // Make sure we don't try to print more menu items than exist in the
00328         // active menu.
00329         if (i > ((int)activeMenu->menuItems.size() - 1))
00330         {
00331             strcat (menuStr, "\n");
00332             continue;
00333         }
00334 
00335         itemSel = (i == selectedItemIndex);
00336 
00337         printItem (activeMenu->menuItems[i], lineStr, itemSel,
00338                 paramEditMode && itemSel);
00339 
00340         strncat (menuStr, lineStr, lineLength);
00341         strcat (menuStr, "\n");
00342     }
00343     
00344     delete[] lineStr;
00345 }
00346 
00347 
00348 void MenbedNavigator::printItem (MenbedMenuItem *item, char *line, bool itemSel,
00349         bool paramSel)
00350 {
00351     uint8_t i = 0;
00352     int8_t j;
00353     char *tempStr = new char[lineLength];
00354     char *frontTab, *backTab;
00355     char *subStr = new char[lineLength];
00356     uint8_t copySize;
00357 
00358     // Clear the line of text
00359     line[0] = '\0';
00360 
00361     // Iterate over the element in the array of text strings in the provided
00362     // menu item until an empty string is found indicating the end of the text
00363     // that should be printed for the current line.  For safety, we assume there
00364     // are a maximum of three element in the array: 1) text before the
00365     // parameter, 2) the parameter, and 3) text after the parameter.
00366     
00367     frontTab = item->text;
00368     while ((strlen (frontTab) > 0) && (i < 3))
00369     {
00370         backTab = strchr (frontTab, '\t');
00371         if (backTab == NULL)
00372         {
00373             backTab = frontTab + strlen(frontTab);
00374             i = 3; // force our way out of the while loop
00375         }
00376          
00377         copySize = backTab - frontTab;
00378         if (copySize >= lineLength)
00379             copySize = lineLength - 1;
00380             
00381         strncpy (subStr, frontTab, copySize);
00382         subStr[copySize] = '\0';
00383         
00384         // If the current string in the array is a printf-style conversion
00385         // specifier for a float, we replace it with the parameter value.
00386         if (checkConvSpec (subStr))
00387         {
00388             // If the user is currently editing the parameter, print the value
00389             // of the shadow variable tempValue instead of the parameters actual
00390             // value.  The tempValue is not copied over to the value field of
00391             // the structure until the user is done editing the parameter.  To
00392             // show that the parameter is being edited, we highlight the value
00393             // by inverting the text.
00394             if (paramSel)
00395             {
00396                 snprintf (tempStr, lineLength, subStr, item->param->tempVal);
00397 
00398                 // We highlight the parameter by inverting the characters on the
00399                 // screen.  The menu system only allows the standard (0-127)
00400                 // ASCII character, so we use the MSB/7th bit of each character
00401                 // to indicate that it should be inverted when printed on the
00402                 // screen.
00403                 for (j=strlen(tempStr) - 1; j>=0; j--)
00404                     tempStr[j] |= 0x80;
00405 
00406             }
00407             // If the user is not currently editing the parameter, we display
00408             // the value pointed to by the value field of the param structure.
00409             else
00410                 snprintf (tempStr, lineLength,
00411                         subStr, item->param->getVal());                       
00412 
00413             // Attach the parameter string to the growing line.
00414             strncat (line, tempStr, lineLength);
00415         }
00416         // If the string is not a printf-style conversion specifier for a float,
00417         // simply catenate the string with the growing line of text.
00418         else
00419         {
00420             strncat (line, subStr, lineLength);
00421         }
00422            
00423         frontTab = backTab + 1;
00424         i++;
00425     }
00426 
00427     // Append a space to the very end of the line.  The LCD driver looks to the
00428     // last character in the line to determine whether to highlight any
00429     // remaining whitespace after the text ends.  This approach causes problems
00430     // when the parameter is the last text on the line and we are in parameter
00431     // modification mode.  Without the extra space at the end of the line, the
00432     // LCD controller will highlight the rest of the line even though it is only
00433     // the parameter itself that should be highlighted.
00434     strncat (line, " ", lineLength);
00435 
00436     // If the parameter has not been selected for modification but the menu item
00437     // is currently selected, we highlight the entire line.  In the menu system,
00438     // the only allowable character are the standard ASCII codes (0-127).  We
00439     // use the (MSB) 7th bit of every character to indicate whether it should be
00440     // highlighted/inverted.
00441     if (!paramSel && itemSel)
00442     {
00443         // Set the MSB of each character to invert it when displayed.
00444         for (j = strlen(line) - 1; j>= 0; j--)
00445             line[j] |= 0x80;
00446     }
00447     
00448     delete[] tempStr;
00449     delete[] subStr;
00450 }
00451 
00452 
00453 // Returns true if the provided string is a printf-style conversion specifier
00454 // for a float (conversion character is f, e, E, g, or G).  Otherwise, returns
00455 // false.
00456 bool MenbedNavigator::checkConvSpec (const char *s)
00457 {
00458     char lastChar;
00459 
00460     // Conversion specifications must begin with a '%'.
00461     if (s[0] != '%')
00462         return false;
00463 
00464     // Identify the last last character in the conversion specification
00465     lastChar = s[strlen(s) - 1];
00466 
00467     // Check that the last character in the conversion specification is either a
00468     // 'f', 'e', 'E', 'g', or 'G'--the conversion specifiers for floats.  If it
00469     // is, the conversion specification is probably a valid conversion
00470     // specification.
00471     if ((lastChar == 'f') || (lastChar == 'e') || (lastChar == 'E') ||
00472             (lastChar == 'g') || (lastChar == 'G'))
00473         return true;
00474 
00475     // Otherwise, it is not.
00476     return false;
00477 }