void totpClient() { RTCunadjustedWizard(1); if(isRTCunadjusted()) { mMsgBoxPush(6); multiPrintXY(3, 2, "The OATH TOTP\nauthenticator\ncan't work with\nthe clock\nunadjusted.", TEXT_MODE_TRANSPARENT_BACKGROUND, TEXT_COLOR_BLACK); closeMsgBox(0, 7); return; } totp ts[MAX_DAY_EVENTS]; Menu menu; menu.type = MENUTYPE_FKEYS; MenuItem items[MAX_DAY_EVENTS]; menu.items = items; reload: menu.numitems = loadTOTPs(ts); for(int i = 0; i < menu.numitems; i++) { items[i].text = ts[i].name; } menu.title = (char*)"TOTP authenticator"; menu.scrollout = 1; menu.height = 7; menu.nodatamsg = (char*)"No tokens - press F2"; menu.returnOnRight = 1; while(1) { drawFkeyLabels(0, 0x0186, 0, 0, 0, 0x012A); // NEW, TIME if(menu.numitems) { drawFkeyLabels(0x0235, -1, 0x0188, 0x0038); // FACTOR, RENAME, DELETE } int res = doMenu(&menu); switch(res) { case MENU_RETURN_EXIT: return; case KEY_CTRL_F1: if(!menu.numitems) break; case MENU_RETURN_SELECTION: viewTOTPcode(&ts[menu.selection-1]); break; case KEY_CTRL_F2: if(menu.numitems >= MAX_DAY_EVENTS) { AUX_DisplayErrorMessage(0x2E); } else { if(addTOTPwizard()) goto reload; } break; case KEY_CTRL_F3: if(menu.numitems && renameTOTPscreen(menu.selection-1, ts[menu.selection-1].name)) goto reload; break; case KEY_CTRL_F4: case KEY_CTRL_DEL: if(menu.numitems && deleteTOTPprompt(menu.selection-1)) goto reload; break; case KEY_CTRL_F6: setTimezone(); break; } } }
int createWalletWizard(int isFirstUse) { SetBackGround(0x0A); drawScreenTitle("Create wallet", "Name:"); drawFkeyLabels(0, 0, 0, 0, 0, 0x04A3); if(isFirstUse) { multiPrintMini(0, 5*24, "To use the balance manager, start by\n" "creating a wallet."); } char wallet[MAX_WALLETNAME_SIZE+2] = ""; textInput input; input.charlimit=MAX_WALLETNAME_SIZE; input.acceptF6=1; input.forcetext=1; input.symbols = 0; input.buffer = (char*)wallet; while(1) { input.key=0; int res = doTextInput(&input); if (res==INPUT_RETURN_EXIT) return -1; // user aborted else if (res==INPUT_RETURN_CONFIRM) break; // continue to next step } SetBackGround(0x0A); drawScreenTitle("Create wallet", "Initial balance:"); drawFkeyLabels(-1, -1, -1, -1, -1, 0x04A4); char balance[20] = ""; Currency initialBalance; textInput input2; input2.charlimit=12; input2.acceptF6=1; input2.symbols = 0; // allow the decimal separator input2.buffer = (char*)balance; input2.type = INPUTTYPE_NUMERIC; while(1) { input2.key=0; int res = doTextInput(&input2); if (res==INPUT_RETURN_EXIT) return -1; // user aborted else if (res==INPUT_RETURN_CONFIRM) { if(!stringToCurrency(&initialBalance, balance)) break; else AUX_DisplayErrorMessage(0x43); } } createWallet(wallet, &initialBalance); if(isFirstUse) { char fname[MAX_FILENAME_SIZE]; walletNameToPath(fname, wallet); setCurrentWallet(fname); } return 0; }
void check_do_graph() { if(has_drawn_graph) { has_drawn_graph = 0; int key; int fkeymenu = 0; while(1) { DisplayStatusArea(); if(fkeymenu == 1) drawFkeyLabels(0x005F, 0x0060, 0x0061); // INITIAL, TRIG, STANDRD GetKey(&key); double xmin, xmax, ymin, ymax, xrange, yrange; get_xyminmax(&xmin, &xmax, &ymin, &ymax); xrange = xmax - xmin; yrange = ymax - ymin; if(fkeymenu == 0) { if(key == KEY_CTRL_LEFT || key == KEY_CTRL_RIGHT) { if(key==KEY_CTRL_LEFT) { xmin -= xrange * 0.15; xmax -= xrange * 0.15; } else { xmin += xrange * 0.15; xmax += xrange * 0.15; } // easier than having to set the symbols in the complicated eigenmath system: static char command[100]; sprintf(command, "xrange=(%g,%g)", xmin, xmax); execution_in_progress = 1; has_drawn_graph = 0; run(command); run(expr); execution_in_progress = 0; } else if(key == KEY_CTRL_DOWN || key == KEY_CTRL_UP) { if(key==KEY_CTRL_DOWN) { ymin -= yrange * 0.15; ymax -= yrange * 0.15; } else { ymin += yrange * 0.15; ymax += yrange * 0.15; } // easier than having to set the symbols in the complicated eigenmath system: static char command[100]; sprintf(command, "yrange=(%g,%g)", ymin, ymax); execution_in_progress = 1; has_drawn_graph = 0; run(command); run(expr); execution_in_progress = 0; } else if(key == KEY_CHAR_PLUS || key == KEY_CHAR_MINUS) { if(key==KEY_CHAR_PLUS) { // 0.75 is 3/4 xmin = xmin * 0.75; xmax = xmax * 0.75; ymin = ymin * 0.75; ymax = ymax * 0.75; } else { // 1.(3), or 1/(3/4), or 4/3 xmin = xmin * 4.0/3.0; xmax = xmax * 4.0/3.0; ymin = ymin * 4.0/3.0; ymax = ymax * 4.0/3.0; } // easier than having to set the symbols in the complicated eigenmath system: static char command[100]; sprintf(command, "yrange=(%g,%g)", ymin, ymax); execution_in_progress = 1; run(command); sprintf(command, "xrange=(%g,%g)", xmin, xmax); has_drawn_graph = 0; run(command); run(expr); execution_in_progress = 0; } else if(key == KEY_CTRL_F3) { fkeymenu = 1; key = 0; } else if(key == KEY_CTRL_EXIT || key==KEY_CTRL_F6) break; } if(fkeymenu == 1) { if(key == KEY_CTRL_F1) { execution_in_progress = 1; run("xrange=(-10,10)"); run("yrange=(-10,10)"); has_drawn_graph = 0; run(expr); execution_in_progress = 0; } else if(key == KEY_CTRL_F2) { execution_in_progress = 1; static char command[100]; sprintf(command, "xrange=(%g,%g)", -3.0*M_PI, 3.0*M_PI); run(command); run("yrange=(-1.6, 1.6)"); has_drawn_graph = 0; run(expr); execution_in_progress = 0; } else if(key == KEY_CTRL_F3) { execution_in_progress = 1; run("xrange=(-10,10)"); run("yrange=(-5,5)"); has_drawn_graph = 0; run(expr); execution_in_progress = 0; } else if(key == KEY_CTRL_EXIT) { fkeymenu = 0; execution_in_progress = 1; has_drawn_graph = 0; run(expr); execution_in_progress = 0; } } } } }
void textfileEditor(char* filename, char* basefolder) { int newfile = (filename == NULL); char sText[TEXT_BUFFER_SIZE] = ""; if(!newfile) { newfile = 0; int openerror = 0; int hFile = fileOpen(filename); // Get handle if(hFile >= 0) // Check if it opened { //opened unsigned int filesize = Bfile_GetFileSize_OS(hFile); if(!filesize || filesize > TEXT_BUFFER_SIZE) { openerror = 1; } else { Bfile_ReadFile_OS(hFile, sText, TEXT_BUFFER_SIZE, 0); } Bfile_CloseFile_OS(hFile); } else { openerror = 1; } if(openerror) { //Error opening file, abort AUX_DisplayErrorMessage(0x2B); // Data ERROR return; } } textEdit input; //input.forcetext=1; input.charlimit=TEXT_BUFFER_SIZE; input.buffer = (char*)sText; // calculate checksum so we can check for changes unsigned char origHash[20] = ""; sha1((unsigned char*)sText, strlen(sText), origHash); while(1) { input.key=0; int res = doTextEdit(&input); int exit = 0; switch(res) { case TEXTEDIT_RETURN_EXIT: { exit = 1; unsigned char newHash[20] = ""; sha1((unsigned char*)sText, strlen(sText), newHash); if(!memcmp(origHash, newHash, 20)) return; else { mMsgBoxPush(4); mPrintXY(3, 2, "Save this file?", TEXT_MODE_TRANSPARENT_BACKGROUND, TEXT_COLOR_BLACK); if(closeMsgBox(1, 4)) { // fall through } else { return; } } } case TEXTEDIT_RETURN_CONFIRM: { char newfilename[MAX_FILENAME_SIZE]; unsigned short newfilenameshort[0x10A]; if(newfile) { int backToEditor = 0; SetBackGround(13); drawScreenTitle("Text Editor", "Save file as:"); drawFkeyLabels(0x036F); // < textInput ninput; ninput.forcetext=1; ninput.charlimit=MAX_NAME_SIZE; char nfilename[MAX_NAME_SIZE]; nfilename[0] = 0; ninput.buffer = (char*)nfilename; while(1) { ninput.key = 0; int nres = doTextInput(&ninput); if (nres==INPUT_RETURN_EXIT || (nres==INPUT_RETURN_KEYCODE && ninput.key==KEY_CTRL_F1)) { // user aborted backToEditor = 1; break; } else if (nres==INPUT_RETURN_CONFIRM) { if(stringEndsInG3A(nfilename)) { mMsgBoxPush(4); multiPrintXY(3, 2, "g3a files can't\nbe created by\nan add-in.", TEXT_MODE_TRANSPARENT_BACKGROUND, TEXT_COLOR_BLACK); closeMsgBox(); } else { // create and save file strcpy(newfilename, basefolder); strcat(newfilename, nfilename); Bfile_StrToName_ncpy(newfilenameshort, newfilename, 0x10A); break; } } } if(backToEditor) continue; } else { // delete, then create and save file Bfile_StrToName_ncpy(newfilenameshort, filename, 0x10A); Bfile_DeleteEntry(newfilenameshort); } size_t size = strlen(sText); if(Bfile_CreateEntry_OS(newfilenameshort, CREATEMODE_FILE, &size) < 0) { //create the file // it appears file exists, overwrite? if(overwriteFilePrompt(newfilename)) { Bfile_DeleteEntry(newfilenameshort); Bfile_CreateEntry_OS(newfilenameshort, CREATEMODE_FILE, &size); } else continue; // abort file save so user can discard the file, or type another filename. } int h = Bfile_OpenFile_OS(newfilenameshort, READWRITE, 0); if(h >= 0) { // Still failing? //Write file contents Bfile_WriteFile_OS(h, sText, size); Bfile_CloseFile_OS(h); // clear unsaved changes "flag": sha1((unsigned char*)sText, strlen(sText), origHash); } if(exit) return; } break; } } }
int addTOTPwizard() { char friendlyname[25] = ""; char key[32] = ""; int curstep = 0; while(1) { SetBackGround(0x0A); drawScreenTitle("Add TOTP token"); // < (first label) and Next or Finish (last label) drawFkeyLabels((curstep>0 ? 0x036F : 0), 0, 0, 0, 0, (curstep==1 ? 0x04A4 : 0x04A3)); if(curstep == 0) { drawScreenTitle(NULL, "Friendly name:"); textInput input; input.charlimit=21; input.acceptF6=1; input.forcetext = 1; input.buffer = friendlyname; while(1) { input.key=0; int res = doTextInput(&input); if (res==INPUT_RETURN_EXIT) return 0; // user aborted else if (res==INPUT_RETURN_CONFIRM) { curstep++; break; } } } else if(curstep == 1) { drawScreenTitle(NULL, "Base32 key:"); multiPrintMini(0, 3*24+2, "This is often shown as a QR code.\n" "Try looking for the \"I can't scan a QR\n" "code\" option. A key usually looks\n" "like this: JBSWY3DPEHPK3PXP\n" "Some keys are longer."); textInput input; input.charlimit=32; input.acceptF6=1; input.symbols = 0; input.forcetext = 1; input.buffer = key; int inloop = 1; while(inloop) { input.key=0; int res = doTextInput(&input); if (res==INPUT_RETURN_EXIT) return 0; // user aborted else if (res==INPUT_RETURN_CONFIRM) { char* b = key; for(; *b; b++) { *b = toupper(*b); // commonly mistyped characters: if(*b == '0') *b = 'O'; if(*b == '1') *b = 'I'; } if(base32_validate(key)) { inloop = 0; // all fields complete, continue with token adding } else { AUX_DisplayErrorMessage(0x3E); } } else if (res==INPUT_RETURN_KEYCODE && input.key == KEY_CTRL_F1) { curstep--; break; } } if(!inloop) break; } } addTOTP(friendlyname, key); return 1; }
int balanceManagerChild(Menu* menu, char* currentWallet) { Currency balance; getWalletBalance(&balance, currentWallet); char balanceStr[15]; currencyToString(balanceStr, &balance); char subtitle[21]; strcpy(subtitle, (char*)"Balance: "); strcat(subtitle, balanceStr); Transaction txs[MAX_DAY_EVENTS]; char menulabels[MAX_DAY_EVENTS][44]; menu->numitems = getWalletTransactions(currentWallet, txs); MenuItem items[menu->numitems]; for(int i = 0; i < menu->numitems; i++) { char amount[15]; currencyToString(amount, &txs[i].amount); // build menu item so that the text is cut and the values aligned on the right column // independently of the description containing multibyte chars and their location char* s = txs[i].description; int len = 0, glen = 0; while(*s) { len++; glen++; if(MB_IsLead(*s)) glen--; if(glen >= 14) { // this way we only care about the section that is to be displayed break; } s++; } memset(menulabels[i], ' ', 43); // blank parts that would not be touched int offset = len-glen; memcpy(menulabels[i], txs[i].description, (glen > 14 ? 14+offset : len)); if(MB_IsLead(menulabels[i][14+offset])) menulabels[i][14+offset] = ' '; // eliminate half-MB char strncpy(menulabels[i]+15+offset, amount, 6); menulabels[i][21+offset] = 0; if(txs[i].credit) items[i].color = TEXT_COLOR_GREEN; else items[i].color = TEXT_COLOR_RED; items[i].text = menulabels[i]; } menu->items = items; while(1) { Bdisp_AllClr_VRAM(); drawScreenTitle("Balance Manager", subtitle); // VIEW, INSERT, EDIT, DELETE, empty, LOAD drawFkeyLabels(-1, 0x03B4, -1, -1, -1, 0x03B7); if(menu->numitems > 0) drawFkeyLabels(0x049F, -1, 0x0038); int res = doMenu(menu); switch(res) { case MENU_RETURN_EXIT: return 0; break; case KEY_CTRL_F1: case MENU_RETURN_SELECTION: if(menu->numitems) viewTransaction(&txs[menu->selection-1]); break; case KEY_CTRL_F2: if(addTransactionWizard(currentWallet)) { return 1; } break; case KEY_CTRL_F3: case KEY_CTRL_DEL: if(menu->numitems && deleteTransactionPrompt(txs, currentWallet, menu->numitems, menu->selection-1)) { return 1; } break; case KEY_CTRL_F6: if(changeWalletScreen(currentWallet)) { menu->selection = 0; menu->scroll = 0; return 1; } break; } } return 0; }
void passwordGenerator() { Menu menu; menu.type = MENUTYPE_FKEYS; menu.title = (char*)"Password Generator"; menu.height = 7; MenuItem items[6]; int length = 10; int seed = RTC_GetTicks() * (GetMainBatteryVoltage(1) % 100); char lstr[10]; items[1].text = (char*)"Include symbols"; items[1].type = MENUITEM_CHECKBOX; items[2].text = (char*)"Include numbers"; items[2].type = MENUITEM_CHECKBOX; items[2].value = MENUITEM_VALUE_CHECKED; items[3].text = (char*)"Include uppercase"; items[3].type = MENUITEM_CHECKBOX; items[3].value = MENUITEM_VALUE_CHECKED; items[4].text = (char*)"Include confusable"; items[4].type = MENUITEM_CHECKBOX; items[4].value = MENUITEM_VALUE_CHECKED; items[5].text = (char*)"Memorable vowel mix"; items[5].type = MENUITEM_CHECKBOX; menu.numitems = 6; menu.items = items; while(1) { drawFkeyLabels(0x03B3, 0, 0, 0, 0, 0x0184); // FILE, EXE (white) itoa(length, (unsigned char*)lstr); char t[20]; strcpy(t, "Length: "); strcat(t, lstr); items[0].text = t; switch(doMenu(&menu)) { case MENU_RETURN_EXIT: return; case MENU_RETURN_SELECTION: if(menu.selection > 1) items[menu.selection-1].value = !items[menu.selection-1].value; else { Selector sel; sel.min = 6; sel.value = length; sel.max = 30; sel.cycle = 1; sel.title = (char*)"Password Generator"; sel.subtitle = (char*)"Length"; if(doSelector(&sel) == SELECTOR_RETURN_SELECTION) { length = sel.value; } } break; case KEY_CTRL_F1: { Selector sel; sel.min = 1; sel.value = 10; sel.max = 1000; sel.cycle = 1; sel.title = (char*)"Generate to file"; sel.subtitle = (char*)"Number of passwords"; if(doSelector(&sel) != SELECTOR_RETURN_SELECTION) break; SetBackGround(10); drawScreenTitle("Generate to file", "Filename:"); char newname[MAX_NAME_SIZE]; newname[0] = 0; textInput input; input.forcetext=1; input.symbols = 0; input.charlimit=MAX_NAME_SIZE; input.buffer = (char*)newname; int inscreen = 1; while(inscreen) { input.key=0; int res = doTextInput(&input); if (res==INPUT_RETURN_EXIT) break; // user aborted else if (res==INPUT_RETURN_CONFIRM) { inscreen = 0; } } if(inscreen) break; char newfilename[MAX_FILENAME_SIZE]; strcpy(newfilename, SMEM_PREFIX); strcat(newfilename, newname); strcat(newfilename, ".txt"); unsigned short pFile[0x10A]; Bfile_StrToName_ncpy(pFile, newfilename, 0x10A); unsigned int size = 1; int ntry = 0; while(ntry < 2) { ntry++; int BCEres = Bfile_CreateEntry_OS(pFile, CREATEMODE_FILE, &size); if(BCEres >= 0) { int hFile = Bfile_OpenFile_OS(pFile, READWRITE, 0); // Get handle if(hFile >= 0) { char password[35]; char line[37]; for(int i = 0; i < sel.value; i++) { generateRandomString(password, length, items[1].value, items[2].value, items[3].value, items[4].value, items[5].value, &seed); sprintf(line, "%s\r\n", password); Bfile_WriteFile_OS(hFile, line, length+2); } Bfile_CloseFile_OS(hFile); } else AUX_DisplayErrorMessage(0x2B); break; } else if(ntry < 2) { // File creation probably failed due to the presence of a file with the same name if(overwriteFilePrompt(newfilename)) Bfile_DeleteEntry(pFile); else break; } else AUX_DisplayErrorMessage(0x2B); } break; } case KEY_CTRL_F6: int inscreen = 1; while(inscreen) { Bdisp_AllClr_VRAM(); drawScreenTitle("Password Generator", "Generated passwords:"); textArea text; text.type = TEXTAREATYPE_INSTANT_RETURN; text.scrollbar = 0; text.y = 48+3; text.lineHeight = 20; textElement e[5]; char passwords[5][35]; for(int i = 0; i < 5; i++) { generateRandomString(passwords[i], length, items[1].value, items[2].value, items[3].value, items[4].value, items[5].value, &seed); e[i].text = passwords[i]; if(i) e[i].newLine = 1; } text.elements = e; text.numelements = 5; doTextArea(&text); drawFkeyLabels(0x036F, 0, 0, 0, 0, 0x02B9); // <, REPEAT (white) while(1) { int key; mGetKey(&key); if(key == KEY_CTRL_F6) break; if(key == KEY_CTRL_F1 || key == KEY_CTRL_EXIT) { inscreen = 0; break; } } } break; } } }
int changeWalletScreen(char* currentWallet) { // returns 1 if user changes to another wallet char* currentWalletNice = filenameToName(currentWallet); Menu menu; menu.title = (char*)"Wallet List"; menu.scrollout=1; menu.type=MENUTYPE_FKEYS; menu.height = 7; MenuItem items[MAX_WALLETS]; int mustRefresh = 0; while(1) { char wallets[MAX_WALLETS][MAX_WALLETNAME_SIZE]; // build wallet list: unsigned short path[MAX_FILENAME_SIZE+1], found[MAX_FILENAME_SIZE+1]; char buffer[MAX_FILENAME_SIZE+1]; // make the buffer strcpy(buffer, BALANCEFOLDER"\\*"); file_type_t fileinfo; int findhandle; Bfile_StrToName_ncpy(path, buffer, MAX_FILENAME_SIZE+1); int ret = Bfile_FindFirst_NON_SMEM((const char*)path, &findhandle, (char*)found, &fileinfo); int i = 0; while(!ret) { Bfile_NameToStr_ncpy(buffer, found, MAX_FILENAME_SIZE+1); if(fileinfo.fsize == 0 && !(strcmp((char*)buffer, "..") == 0 || strcmp((char*)buffer, ".") == 0)) { // find folders strcpy(wallets[i], buffer); items[i].text = wallets[i]; i++; if(!strcmp(buffer, currentWalletNice)) menu.selection = i; if(i == MAX_WALLETS) break; } ret = Bfile_FindNext_NON_SMEM(findhandle, (char*)found, (char*)&fileinfo); } menu.items = items; menu.numitems = i; Bfile_FindClose(findhandle); drawFkeyLabels(0x000F, 0x0186, 0x0188, 0x0038, 0, 0); // SELECT, NEW, RENAME, DELETE int res = doMenu(&menu); switch(res) { case MENU_RETURN_EXIT: return mustRefresh; break; case KEY_CTRL_F1: case MENU_RETURN_SELECTION: if(strcmp(currentWalletNice, wallets[menu.selection-1])) { walletNameToPath(buffer, wallets[menu.selection-1]); setCurrentWallet(buffer); return 1; } return mustRefresh; break; case KEY_CTRL_F2: if(menu.numitems >= MAX_WALLETS) { AUX_DisplayErrorMessage( 0x2E ); } else { createWalletWizard(0); } break; case KEY_CTRL_F3: char newWallet[MAX_FILENAME_SIZE]; if(renameWalletScreen(wallets[menu.selection-1], newWallet)) { walletNameToPath(buffer, wallets[menu.selection-1]); if(!strcmp(currentWallet, buffer)) { // if the renamed wallet was the current one, we must set the current wallet to the // new name. setCurrentWallet(newWallet); mustRefresh = 1; } } break; case KEY_CTRL_F4: case KEY_CTRL_DEL: walletNameToPath(buffer, wallets[menu.selection-1]); if(deleteWalletPrompt(buffer)) { if(menu.numitems <= 1) { // this was the only wallet: delete pointer file too, so that user is prompted to create // a new wallet. unsigned short path[MAX_FILENAME_SIZE+1]; strcpy(buffer, BALANCEFOLDER"\\Wallet"); Bfile_StrToName_ncpy(path, buffer, MAX_FILENAME_SIZE); Bfile_DeleteEntry(path); return 1; } if(!strcmp(currentWallet, buffer)) { // if the deleted wallet was the current one, we must set the current wallet to the // first one on the list that is not the deleted one. // (by now we know there is more than one wallet in the list) for(int i = 0; i < menu.numitems; i++) { walletNameToPath(buffer, wallets[i]); if(strcmp(currentWallet, buffer)) break; } setCurrentWallet(buffer); mustRefresh = 1; } } break; } } }
int addTransactionWizard(char* wallet) { Transaction tx; tx.date.year = getCurrentYear(); tx.date.month = getCurrentMonth(); tx.date.day = getCurrentDay(); tx.time.hour = getCurrentHour(); tx.time.minute = getCurrentMinute(); tx.time.second = getCurrentSecond(); strcpy(tx.description, (char*)""); int curstep = 0; while(1) { SetBackGround(0x0A); drawScreenTitle("Add transaction"); // < (first label), SELECT of on date step, and Next or Finish (last label) drawFkeyLabels(curstep>0 ? 0x036F : -1, curstep == 2 ? 0x000F : 0, 0, 0, 0, curstep==4 ? 0x04A4 : 0x04A3); if(curstep == 0) { MenuItem menuitems[5]; menuitems[0].text = (char*)"Debit"; menuitems[1].text = (char*)"Credit"; Menu menu; menu.items=menuitems; menu.type=MENUTYPE_FKEYS; menu.numitems=2; menu.height=2; menu.startY=3; menu.pBaRtR=1; int inloop=1; while(inloop) { // this must be here, inside this loop: SetBackGround(0x0A); drawScreenTitle("Add transaction", "Select type:"); drawFkeyLabels(-1, -1, -1, -1, -1, 0x04A3); int res = doMenu(&menu); if(res == MENU_RETURN_EXIT) return 0; else if(res == KEY_CTRL_F6 || res == MENU_RETURN_SELECTION) { tx.credit = menu.selection == 2; curstep++; break; } } } else if(curstep == 1) { drawScreenTitle(NULL, "Amount:"); char samount[20] = ""; if(tx.amount.val) { currencyToString(samount, &tx.amount); } textInput input; input.charlimit=12; input.acceptF6=1; input.symbols = 0; // allow the decimal separator input.forcetext = 1; input.buffer = (char*)samount; input.type = INPUTTYPE_NUMERIC; while(1) { input.key=0; int res = doTextInput(&input); if (res==INPUT_RETURN_EXIT) return 0; // user aborted else if (res==INPUT_RETURN_CONFIRM) { if(!stringToCurrency(&tx.amount, samount)) { if(!tx.amount.val) { AUX_DisplayErrorMessage(0x4B); } else { curstep++; } break; } else AUX_DisplayErrorMessage(0x43); } else if (res==INPUT_RETURN_KEYCODE && input.key == KEY_CTRL_F1) { curstep--; break; } } } else if(curstep == 2) { drawScreenTitle(NULL, "Date:"); mPrintXY(7, 4, getInputDateFormatHint(), TEXT_MODE_TRANSPARENT_BACKGROUND, TEXT_COLOR_BLACK); textInput input; input.x=7; input.width=8; input.charlimit=8; input.acceptF6=1; input.type=INPUTTYPE_DATE; char datebuffer[15]; fillInputDate(&tx.date, datebuffer); input.buffer = (char*)datebuffer; while(1) { input.key=0; int res = doTextInput(&input); if (res==INPUT_RETURN_EXIT) return 0; // user aborted else if (res==INPUT_RETURN_CONFIRM) { int len = strlen(datebuffer); if(len == input.charlimit) { int yr,m,d; stringToDate(datebuffer, &yr, &m, &d); if(isDateValid(yr, m, d)) { tx.date.year = yr; tx.date.month = m; tx.date.day = d; curstep++; break; // continue to next step } else invalidFieldMsg(0); } else invalidFieldMsg(0); } else if (res==INPUT_RETURN_KEYCODE) { if(input.key==KEY_CTRL_F1) { curstep=curstep-1; break; } else if(input.key==KEY_CTRL_F2) { int ey=0, em=0, ed=0; if(!selectDateScreen(&ey, &em, &ed, (char*)"Select transaction date:", NULL, 1)) { tx.date.year = ey; tx.date.month = em; tx.date.day = ed; curstep++; break; // continue to next step } break; //redraw } } } } else if(curstep == 3) { drawScreenTitle(NULL, "Time:"); mPrintXY(8, 4, "HHMMSS", TEXT_MODE_TRANSPARENT_BACKGROUND, TEXT_COLOR_BLACK); textInput input; input.x=8; input.width=6; input.charlimit=6; input.acceptF6=1; input.type=INPUTTYPE_TIME; char tbuffer[15]; fillInputTime(&tx.time, tbuffer); input.buffer = (char*)tbuffer; while(1) { input.key=0; int res = doTextInput(&input); if (res==INPUT_RETURN_EXIT) return 0; // user aborted else if (res==INPUT_RETURN_CONFIRM) { if((int)strlen(tbuffer) == input.charlimit) { int h, m, s; stringToTime(tbuffer, &h, &m, &s); if(isTimeValid(h, m, s)) { tx.time.hour = h; tx.time.minute = m; tx.time.second = s; curstep++; break; // continue to next step } else invalidFieldMsg(1); } else invalidFieldMsg(1); } else if (res==INPUT_RETURN_KEYCODE && input.key==KEY_CTRL_F1) { curstep--; break; } } } else if(curstep == 4) { drawScreenTitle(NULL, "Description:"); textInput input; input.charlimit=128; input.acceptF6=1; input.buffer = (char*)tx.description; int inloop = 1; while(inloop) { input.key=0; int res = doTextInput(&input); if (res==INPUT_RETURN_EXIT) return 0; // user aborted else if (res==INPUT_RETURN_CONFIRM) inloop = 0; // all fields complete, continue with transaction adding else if (res==INPUT_RETURN_KEYCODE && input.key == KEY_CTRL_F1) { curstep--; break; } } if(!inloop) break; } } addTransaction(&tx, wallet); return 1; }
int fileBrowserSub(char* browserbasepath, char* filename, char* filter, char* filter2, char* title) { Menu menu; MenuItemIcon icontable[12]; buildIconTable(icontable); // first get file count so we know how much to alloc GetFiles(NULL, NULL, browserbasepath, &menu.numitems, filter, filter2); MenuItem* menuitems = NULL; File* files = NULL; if(menu.numitems > 0) { menuitems = (MenuItem*)alloca(menu.numitems*sizeof(MenuItem)); files = (File*)alloca(menu.numitems*sizeof(File)); // populate arrays GetFiles(files, menuitems, browserbasepath, &menu.numitems, filter, filter2); menu.items = menuitems; } char titleBuffer[120]; char titleBufferBuf[120]; int smemfree; unsigned short smemMedia[10]={'\\','\\','f','l','s','0',0}; Bfile_GetMediaFree_OS( smemMedia, &smemfree ); char friendlypath[MAX_FILENAME_SIZE]; strcpy(friendlypath, browserbasepath+6); friendlypath[strlen(friendlypath)-1] = '\0'; //remove ending slash like OS does // test to see if friendlypath is too big int jump4=0; while(1) { int temptextX=7*18+10; // px length of menu title + 10, like menuGUI goes. int temptextY=0; PrintMini(&temptextX, &temptextY, (char*)friendlypath, 0, 0xFFFFFFFF, 0, 0, COLOR_BLACK, COLOR_WHITE, 0, 0); // fake draw if(temptextX>LCD_WIDTH_PX-6) { char newfriendlypath[MAX_FILENAME_SIZE]; shortenDisplayPath(friendlypath, newfriendlypath, (jump4 ? 4 : 1)); if(strlen(friendlypath) > strlen(newfriendlypath) && strlen(newfriendlypath) > 3) { // check if len > 3 because shortenDisplayPath may return just "..." when the folder name is too big // shortenDisplayPath still managed to shorten, copy and continue jump4 = 1; //it has been shortened already, so next time jump the first four characters strcpy(friendlypath, newfriendlypath); } else { // shortenDisplayPath can't shorten any more even if it still // doesn't fit in the screen, so give up. break; } } else break; } menu.subtitle = friendlypath; menu.type = MENUTYPE_MULTISELECT; menu.scrollout=1; menu.nodatamsg = (char*)"No Data"; menu.title = title; menu.height=7; while(1) { Bdisp_AllClr_VRAM(); drawFkeyLabels((menu.numitems ? 0x03B1 : 0), -1, -1, -1, -1, 0x03DF); // OPEN, VERSION itoa(smemfree, (unsigned char*)titleBuffer); LocalizeMessage1( 340, titleBufferBuf ); //"bytes free" strncat((char*)titleBuffer, (char*)titleBufferBuf, 65); menu.statusText = (char*)titleBuffer; int res = doMenu(&menu, icontable); switch(res) { case MENU_RETURN_EXIT: if(!strcmp(browserbasepath,"\\\\fls0\\")) { //check that we aren't already in the root folder //we are, return 0 so we exit //return 0; // in this add-in, the file browser shouldn't return } else { int i=strlen(browserbasepath)-2; while (i>=0 && browserbasepath[i] != '\\') i--; if (browserbasepath[i] == '\\') { char tmp[MAX_FILENAME_SIZE] = ""; memcpy(tmp,browserbasepath,i+1); tmp[i+1] = '\0'; strcpy(browserbasepath, tmp); } return 1; //reload at new folder } break; case KEY_CTRL_F1: case MENU_RETURN_SELECTION: if(!menu.numitems) break; if(menuitems[menu.selection-1].isfolder) { strcpy(browserbasepath, files[menu.selection-1].filename); //switch to selected folder strcat(browserbasepath, "\\"); return 1; //reload at new folder } else { strcpy(filename,files[menu.selection-1].filename); return 2; } break; case KEY_CTRL_F6: showAbout(); break; } } return 1; }
int doTextInput(textInput* input) { if(input->type==INPUTTYPE_NORMAL) { drawFkeyLabels(-1, -1, -1, (input->symbols? 0x02A1 : -1), 0x0307); // CHAR, A<>a } int wasInClip=0; if (input->key) input->cursor = EditMBStringChar((unsigned char*)input->buffer, input->charlimit, input->cursor, input->key); int widthForSyscalls = input->width; if(input->width == 21) { widthForSyscalls = 20; clearLine(1, input->y); // remove aestethically unpleasing bit of background at the end of the field } while(1) { if(input->forcetext && strlen(input->buffer)==0) { input->buffer[0]='\xd8'; input->buffer[1]='\x0'; } DisplayMBString2(0, (unsigned char*)input->buffer, input->start, input->cursor, 0, input->x, input->y*24-24, widthForSyscalls+input->x, input->width==21? 0 : 1); drawLine(input->x*18-18, input->y*24-1, input->width == 21 ? LCD_WIDTH_PX-1 : input->width*18+input->x*18-18-1, input->y*24-1, COLOR_GRAY); drawLine(input->x*18-18, input->y*24+23, input->width == 21 ? LCD_WIDTH_PX-1 : input->width*18+input->x*18-18-1, input->y*24+23, COLOR_GRAY); if(input->width != 21) { //vertical lines, start and end drawLine(input->x*18-18, input->y*24-1, input->x*18-18, input->y*24+23, COLOR_GRAY); drawLine((input->x*18-18)+18*input->width, input->y*24-1, (input->x*18-18)+18*input->width, input->y*24+23, COLOR_GRAY); } if(input->type==INPUTTYPE_DATE) { //vertical lines: dd, mm and yyyy separators switch(getSetting(SETTING_DATEFORMAT)) { case 0: case 1: drawLine((input->x*18-18)+18*2, input->y*24-1, (input->x*18-18)+18*2, input->y*24+22, COLOR_GRAY); drawLine((input->x*18-18)+18*4+1, input->y*24-1, (input->x*18-18)+18*4+1, input->y*24+23, COLOR_GRAY); break; case 2: drawLine((input->x*18-18)+18*4, input->y*24-1, (input->x*18-18)+18*4, input->y*24+22, COLOR_GRAY); drawLine((input->x*18-18)+18*6+1, input->y*24-1, (input->x*18-18)+18*6+1, input->y*24+23, COLOR_GRAY); break; } } else if(input->type==INPUTTYPE_TIME) { //vertical lines: hh, mm and ss separators drawLine((input->x*18-18)+18*2, input->y*24-1, (input->x*18-18)+18*2, input->y*24+23, COLOR_GRAY); drawLine((input->x*18-18)+18*4, input->y*24-1, (input->x*18-18)+18*4, input->y*24+23, COLOR_GRAY); } int keyflag = GetSetupSetting( (unsigned int)0x14); if(input->type==INPUTTYPE_NORMAL) { if(keyflag == 0x02) { // in clip mode wasInClip=1; drawFkeyLabels(0x0034, 0x0069); // COPY (white), CUT (white) } else if(wasInClip) { // clear, because we were in clip mode before wasInClip=0; drawFkeyLabels(0,0); // empty first two } } mGetKey(&input->key); if (GetSetupSetting((unsigned int)0x14) == 0x01 || GetSetupSetting((unsigned int)0x14) == 0x04 || GetSetupSetting( (unsigned int)0x14) == 0x84) { keyflag = GetSetupSetting( (unsigned int)0x14); // make sure the flag we're using is the // updated one. we can't update always because that way alpha-not-lock will cancel when F5 is // pressed. } if(input->key == KEY_CTRL_EXE || (input->key == KEY_CTRL_F6 && input->acceptF6)) { // Next step if(!input->forcetext || (strlen((char*)input->buffer) > 0 && input->buffer[0]!='\xd8')) { // input can be empty, or it already has some text Cursor_SetFlashOff(); return INPUT_RETURN_CONFIRM; } else { mMsgBoxPush(4); multiPrintXY(3, 2, "Field can't be\nleft blank.", TEXT_MODE_TRANSPARENT_BACKGROUND, TEXT_COLOR_BLACK); closeMsgBox(); } } else if(input->key == KEY_CTRL_EXIT) { // Aborted Cursor_SetFlashOff(); return INPUT_RETURN_EXIT; } else if(input->key == KEY_CTRL_F1 || input->key == KEY_CTRL_F2) { Cursor_SetFlashOff(); return INPUT_RETURN_KEYCODE; } else if(input->key == KEY_CTRL_F4 && input->type == INPUTTYPE_NORMAL && input->symbols) { short character = selectCharacterAux(); if (character) input->cursor = EditMBStringChar((unsigned char*)input->buffer, input->charlimit, input->cursor, character); } else if(input->key == KEY_CTRL_F5 && input->type == INPUTTYPE_NORMAL) { // switch between lower and upper-case alpha switch(keyflag) { case 0x08: case 0x88: SetSetupSetting((unsigned int)0x14, keyflag-0x04); continue; //do not process the key, because otherwise we will leave alpha status case 0x04: case 0x84: SetSetupSetting((unsigned int)0x14, keyflag+0x04); continue; //do not process the key, because otherwise we will leave alpha status } } if(input->key && input->key < 30000) { if(input->type == INPUTTYPE_NORMAL || (input->key >= KEY_CHAR_0 && input->key <= KEY_CHAR_9) || (input->key == KEY_CHAR_DP && !input->symbols && input->type == INPUTTYPE_NUMERIC)) { // either a normal input, or only allow digits and eventually the decimal separator if ((GetSetupSetting((unsigned int)0x14) == 0x08 || GetSetupSetting((unsigned int)0x14) == 0x88) && input->key >= KEY_CHAR_A && input->key <= KEY_CHAR_Z) //if lowercase and key is char... input->key = input->key + 32; // to switch to lower-case characters input->cursor = EditMBStringChar((unsigned char*)input->buffer, input->charlimit, input->cursor, input->key); } } else EditMBStringCtrl2((unsigned char*)input->buffer, input->charlimit+1, &input->start, &input->cursor, &input->key, input->x, input->y*24-24, 1, widthForSyscalls+input->x-1 ); if(input->key == KEY_CTRL_PASTE) { // at this point it will have already pasted int pos = strlen(input->buffer)-1; if(input->forcetext && pos > 0 && input->buffer[pos]=='\xd8') { input->buffer[pos]='\x0'; } } } Cursor_SetFlashOff(); return INPUT_RETURN_CONFIRM; }