4 errors
Dependencies: KS0108_PCF8574 mbed
menbed/menbedNavigator.cpp
- Committer:
- GuiTwo
- Date:
- 2012-09-05
- Revision:
- 0:936f1c020120
File content as of revision 0:936f1c020120:
#include "mbed.h" #include "include/menbedNavigator.h" #include "include/menbedButtonEvent.h" #include "include/menbedMenuMessage.h" #include "include/menbedMenu.h" #include <cstdio> extern void toggleLed3(); MenbedNavigator::MenbedNavigator(MenbedMenu *rootMenu, MenbedDisplayer *displayer) : activeMenu(rootMenu), displayer(displayer) { selectedItemIndex = -1; topOfScreenItemIndex = 0; paramEditMode = false; numLines = displayer->getDisplay()->getLines(); lineLength = displayer->getDisplay()->getLineLength(); } void MenbedNavigator::updateDisplay() { MenbedMenuMessage menuMsg (numLines, lineLength); printMenu (menuMsg.text); menuMsg.showUpArrow = (topOfScreenItemIndex >= 1); menuMsg.showDownArrow = (topOfScreenItemIndex + numLines < (int)(activeMenu->menuItems.size())); displayer->update (&menuMsg); } void MenbedNavigator::handleButtonEvent (MenbedButtonEvent buttonEvent) { numButtons = buttonEvent.numButtons; switch (buttonEvent.name) { case MenbedButtonEvent::ButtonSelect: // Select if (!paramEditMode && (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_RELEASED_SHORT)) selectItem(); else if (paramEditMode && (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_RELEASED_SHORT)) saveParam(); else if ((numButtons < 4) && paramEditMode && (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_HELD_LONG)) restoreParam(); else if ((numButtons < 4) && !paramEditMode && (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_HELD_LONG)) gotoParent(); break; case MenbedButtonEvent::ButtonDown: if (paramEditMode && (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED)) decParam(); else if (!paramEditMode && (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED)) moveDown(); break; case MenbedButtonEvent::ButtonUp: if (numButtons > 2) { if (paramEditMode && (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED)) incParam(); else if (!paramEditMode && (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED)) moveUp(); } break; case MenbedButtonEvent::ButtonCancel: if (numButtons > 3) { if (paramEditMode && (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED)) restoreParam(); else if (!paramEditMode && (buttonEvent.action == MenbedButtonEvent::BUTTON_ACTION_PUSHED)) gotoParent(); } break; } updateDisplay(); //menuRefresh_refreshed(); } void MenbedNavigator::selectItem() { MenbedMenu **childMenuPtr; MenbedMenu *childMenu; if ((selectedItemIndex < 0) || (selectedItemIndex >= (int)(activeMenu->menuItems.size()))) return; // If it exists, execute the function associated with the menu item if (activeMenu->menuItems[selectedItemIndex]->selFcn != NULL) activeMenu->menuItems[selectedItemIndex]->selFcn(); // Show the child menu associated with the menu item. Initially, the first // item in the child menu is placed at the top of the screen, but is it // left unselected. childMenuPtr = activeMenu->menuItems[selectedItemIndex]->childMenu; if (childMenuPtr != NULL) { childMenu = *(activeMenu->menuItems[selectedItemIndex]->childMenu); if (!activeMenu->menuItems[selectedItemIndex]->childMenuIsAncestor) { childMenu->parentMenu = activeMenu; childMenu->parentSelectedItemIndex = selectedItemIndex; childMenu->parentTopOfScreenItemIndex = topOfScreenItemIndex; } else childMenu->parentMenu = NULL; activeMenu = childMenu; topOfScreenItemIndex = 0; selectedItemIndex = -1; } // Otherwise, if the current menu item has a parameter that can be modified, // we switch to the parameter editing mode. else if ((activeMenu->menuItems[selectedItemIndex]->param != NULL) && (activeMenu->menuItems[selectedItemIndex]->param->inc() != 0)) { // All incrementing and decrementing of the parameter actually happens // to a shadow variable in the param structure named tempValue. The // parameter value used by the other parts of the system is not updated // until the user is done editing the parameter. activeMenu->menuItems[selectedItemIndex]->param->initVal = activeMenu->menuItems[selectedItemIndex]->param->getVal(); activeMenu->menuItems[selectedItemIndex]->param->tempVal = activeMenu->menuItems[selectedItemIndex]->param->initVal; paramEditMode = true; } } void MenbedNavigator::gotoParent() { if (activeMenu->parentMenu == NULL) return; selectedItemIndex = activeMenu->parentSelectedItemIndex; topOfScreenItemIndex = activeMenu->parentTopOfScreenItemIndex; activeMenu = activeMenu->parentMenu; } void MenbedNavigator::moveUp() { // If we're already at the top of the menu, do nothing if (selectedItemIndex <= -1) return; // If the top item of the menu is already selected, we send a NOP message // which deselects the top line and displays the down arrow if the menu // contains more items than can fit on the screen. In effect, this allows // the user to deselect all menu items which adds a nice look to the system. else if (selectedItemIndex == 0) selectedItemIndex = -1; // If the currently selected menu item is the also the one at the top of the // screen, we need to scroll the screen down and add the item above the // currently selected one to the top of the screen. else if (selectedItemIndex == topOfScreenItemIndex) { selectedItemIndex--; topOfScreenItemIndex--; } // The selected item is not the top item on the screen. All we need to do // is select the item above the currently selected item. else selectedItemIndex--; } void MenbedNavigator::moveDown() { // If the last item of the menu is already selected, our behavior depends // on how many buttons are present. If there is no up button, we cycle // back to the top of the menu. Otherwise, if an up button is present, // we do nothing. if (selectedItemIndex >= ((int)(activeMenu->menuItems.size()) - 1)) { if (numButtons < 3) { selectedItemIndex = -1; topOfScreenItemIndex = 0; } else ; } // If the menu item displayed at the bottom of the screen is already // selected, we will need to scroll the screen up to make room for a new // line at the bottom of the screen. else if (selectedItemIndex == (topOfScreenItemIndex + numLines - 1)) { selectedItemIndex++; topOfScreenItemIndex++; } // Otherwise, if the currently selected menu item is now the one displayed // at the bottom of the screen, we simply change which of the visible items // is highlighted. else selectedItemIndex++; } void MenbedNavigator::incParam() { float inc; float tempVal; if (paramEditMode != true) return; inc = activeMenu->menuItems[selectedItemIndex]->param->inc(); // Initialize our own local copy of the parameter's temporary value. We do // this so that we can more easily check for violations of the allowed min // and max values. tempVal = activeMenu->menuItems[selectedItemIndex]->param->tempVal; tempVal += inc; // Check the bounds on the parameter. if (tempVal > activeMenu->menuItems[selectedItemIndex]->param->max()) tempVal = activeMenu->menuItems[selectedItemIndex]->param->max(); else if (tempVal < activeMenu->menuItems[selectedItemIndex]->param->min()) tempVal = activeMenu->menuItems[selectedItemIndex]->param->min(); // Assign the local temp. value back to the temporary value in the active // parameter structue. activeMenu->menuItems[selectedItemIndex]->param->tempVal = tempVal; // If the parameter is configured to produce live updates, call the // finalValFcn. if (activeMenu->menuItems[selectedItemIndex]->param->liveUpdate()) activeMenu->menuItems[selectedItemIndex]->param->setVal(tempVal); } void MenbedNavigator::decParam() { float inc; float tempVal; if (paramEditMode != true) return; inc = activeMenu->menuItems[selectedItemIndex]->param->inc(); // Initialize our own local copy of the parameter's temporary value. We do // this so that we can more easily check for violations of the allowed min // and max values. tempVal = activeMenu->menuItems[selectedItemIndex]->param->tempVal; tempVal -= inc; // Check the bounds on the parameter. if (tempVal > activeMenu->menuItems[selectedItemIndex]->param->max()) tempVal = activeMenu->menuItems[selectedItemIndex]->param->max(); // If we reach the minimum parameter value when we only have a down button // and not an up button connected to the system, we wrap the parameter // value back around to its maximum. Otherwise, if there is an up button // present, we peg the parameter at its minimum value. else if (tempVal < activeMenu->menuItems[selectedItemIndex]->param->min()) { if (numButtons >= 3) tempVal = activeMenu->menuItems[selectedItemIndex]->param->min(); else tempVal = activeMenu->menuItems[selectedItemIndex]->param->max(); } // Assign the local temp. value back to the temporary value in the active // parameter structue. activeMenu->menuItems[selectedItemIndex]->param->tempVal = tempVal; // If the parameter is configured to produce live updates, call the // finalValFcn. if (activeMenu->menuItems[selectedItemIndex]->param->liveUpdate()) activeMenu->menuItems[selectedItemIndex]->param->setVal(tempVal); } void MenbedNavigator::saveParam() { // Save the changes made the shadow variable tempValue to the real parameter // value that is used by the rest of the application. activeMenu->menuItems[selectedItemIndex]->param->setVal ( activeMenu->menuItems[selectedItemIndex]->param->tempVal ); paramEditMode = false; } void MenbedNavigator::restoreParam() { // Revert any changes made the parameter by calling the finalValFcn with // the initVal that was stored when we first began editing this parameter. activeMenu->menuItems[selectedItemIndex]->param->setVal( activeMenu->menuItems[selectedItemIndex]->param->initVal ); paramEditMode = false; } void MenbedNavigator::printMenu (char *menuStr) { uint8_t i; char *lineStr = new char[lineLength]; bool itemSel; menuStr[0] = '\0'; for (i=topOfScreenItemIndex; i<topOfScreenItemIndex + numLines; i++) { // Make sure we don't try to print more menu items than exist in the // active menu. if (i > ((int)activeMenu->menuItems.size() - 1)) { strcat (menuStr, "\n"); continue; } itemSel = (i == selectedItemIndex); printItem (activeMenu->menuItems[i], lineStr, itemSel, paramEditMode && itemSel); strncat (menuStr, lineStr, lineLength); strcat (menuStr, "\n"); } delete[] lineStr; } void MenbedNavigator::printItem (MenbedMenuItem *item, char *line, bool itemSel, bool paramSel) { uint8_t i = 0; int8_t j; char *tempStr = new char[lineLength]; char *frontTab, *backTab; char *subStr = new char[lineLength]; uint8_t copySize; // Clear the line of text line[0] = '\0'; // Iterate over the element in the array of text strings in the provided // menu item until an empty string is found indicating the end of the text // that should be printed for the current line. For safety, we assume there // are a maximum of three element in the array: 1) text before the // parameter, 2) the parameter, and 3) text after the parameter. frontTab = item->text; while ((strlen (frontTab) > 0) && (i < 3)) { backTab = strchr (frontTab, '\t'); if (backTab == NULL) { backTab = frontTab + strlen(frontTab); i = 3; // force our way out of the while loop } copySize = backTab - frontTab; if (copySize >= lineLength) copySize = lineLength - 1; strncpy (subStr, frontTab, copySize); subStr[copySize] = '\0'; // If the current string in the array is a printf-style conversion // specifier for a float, we replace it with the parameter value. if (checkConvSpec (subStr)) { // If the user is currently editing the parameter, print the value // of the shadow variable tempValue instead of the parameters actual // value. The tempValue is not copied over to the value field of // the structure until the user is done editing the parameter. To // show that the parameter is being edited, we highlight the value // by inverting the text. if (paramSel) { snprintf (tempStr, lineLength, subStr, item->param->tempVal); // We highlight the parameter by inverting the characters on the // screen. The menu system only allows the standard (0-127) // ASCII character, so we use the MSB/7th bit of each character // to indicate that it should be inverted when printed on the // screen. for (j=strlen(tempStr) - 1; j>=0; j--) tempStr[j] |= 0x80; } // If the user is not currently editing the parameter, we display // the value pointed to by the value field of the param structure. else snprintf (tempStr, lineLength, subStr, item->param->getVal()); // Attach the parameter string to the growing line. strncat (line, tempStr, lineLength); } // If the string is not a printf-style conversion specifier for a float, // simply catenate the string with the growing line of text. else { strncat (line, subStr, lineLength); } frontTab = backTab + 1; i++; } // Append a space to the very end of the line. The LCD driver looks to the // last character in the line to determine whether to highlight any // remaining whitespace after the text ends. This approach causes problems // when the parameter is the last text on the line and we are in parameter // modification mode. Without the extra space at the end of the line, the // LCD controller will highlight the rest of the line even though it is only // the parameter itself that should be highlighted. strncat (line, " ", lineLength); // If the parameter has not been selected for modification but the menu item // is currently selected, we highlight the entire line. In the menu system, // the only allowable character are the standard ASCII codes (0-127). We // use the (MSB) 7th bit of every character to indicate whether it should be // highlighted/inverted. if (!paramSel && itemSel) { // Set the MSB of each character to invert it when displayed. for (j = strlen(line) - 1; j>= 0; j--) line[j] |= 0x80; } delete[] tempStr; delete[] subStr; } // Returns true if the provided string is a printf-style conversion specifier // for a float (conversion character is f, e, E, g, or G). Otherwise, returns // false. bool MenbedNavigator::checkConvSpec (const char *s) { char lastChar; // Conversion specifications must begin with a '%'. if (s[0] != '%') return false; // Identify the last last character in the conversion specification lastChar = s[strlen(s) - 1]; // Check that the last character in the conversion specification is either a // 'f', 'e', 'E', 'g', or 'G'--the conversion specifiers for floats. If it // is, the conversion specification is probably a valid conversion // specification. if ((lastChar == 'f') || (lastChar == 'e') || (lastChar == 'E') || (lastChar == 'g') || (lastChar == 'G')) return true; // Otherwise, it is not. return false; }