this locks like shit
Fork of MenuLCD_copy by
Embed:
(wiki syntax)
Show/hide line numbers
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 Tue Jul 12 2022 22:15:04 by
1.7.2
