Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 }
Generated on Thu Jul 14 2022 12:14:44 by
