static enum themable_icons shortcut_menu_get_icon(int selected_item, void * data) { (void)data; struct shortcut *sc = get_shortcut(selected_item); if (!sc) return Icon_NOICON; if (sc->icon == Icon_NOICON) { switch (sc->type) { case SHORTCUT_FILE: return filetype_get_icon(filetype_get_attr(sc->u.path)); case SHORTCUT_BROWSER: return Icon_Folder; case SHORTCUT_SETTING: return Icon_Menu_setting; case SHORTCUT_DEBUGITEM: return Icon_Menu_functioncall; case SHORTCUT_PLAYLISTMENU: return Icon_Playlist; case SHORTCUT_SHUTDOWN: return Icon_System_menu; case SHORTCUT_TIME: return Icon_Menu_functioncall; default: break; } } return sc->icon; }
static int shortcut_menu_speak_item(int selected_item, void * data) { (void)data; struct shortcut *sc = get_shortcut(selected_item); if (sc && sc->talk_clip[0]) talk_file(NULL, NULL, sc->talk_clip, NULL, NULL, false); return 0; }
void shortcuts_add(enum shortcut_type type, const char* value) { struct shortcut* sc = get_shortcut(shortcut_count++); if (!sc) return; init_shortcut(sc); sc->type = type; if (type == SHORTCUT_SETTING) sc->u.setting = (void*)value; else strlcpy(sc->u.path, value, MAX_PATH); if (first_idx_to_writeback < 0) first_idx_to_writeback = shortcut_count - 1; register_storage_idle_func(shortcuts_ata_idle_callback); }
static const char * shortcut_menu_get_name(int selected_item, void * data, char * buffer, size_t buffer_len) { (void)data; (void)buffer; (void)buffer_len; struct shortcut *sc = get_shortcut(selected_item); if (!sc) return ""; if (sc->type == SHORTCUT_SETTING) return sc->name[0] ? sc->name : P2STR(ID2P(sc->u.setting->lang_id)); else if (sc->type == SHORTCUT_SEPARATOR || sc->type == SHORTCUT_TIME) return sc->name; else if (sc->type == SHORTCUT_SHUTDOWN && sc->name[0] == '\0') { /* No translation support as only soft_shutdown has LANG_SHUTDOWN defined */ return type_strings[SHORTCUT_SHUTDOWN]; } return sc->name[0] ? sc->name : sc->u.path; }
static void shortcuts_ata_idle_callback(void* data) { (void)data; int fd; char buf[MAX_PATH]; int current_idx = first_idx_to_writeback; if (first_idx_to_writeback < 0) return; fd = open(SHORTCUTS_FILENAME, O_APPEND|O_RDWR|O_CREAT, 0644); if (fd < 0) return; while (current_idx < shortcut_count) { struct shortcut* sc = get_shortcut(current_idx++); const char *type; int len; if (!sc) break; type = type_strings[sc->type]; len = snprintf(buf, MAX_PATH, "[shortcut]\ntype: %s\ndata: ", type); write(fd, buf, len); if (sc->type == SHORTCUT_SETTING) write(fd, sc->u.setting->cfg_name, strlen(sc->u.setting->cfg_name)); else write(fd, sc->u.path, strlen(sc->u.path)); write(fd, "\n\n", 2); } close(fd); if (first_idx_to_writeback == 0) { /* reload all shortcuts because we appended to the shortcuts file which * has not been read yet. */ reset_shortcuts(); shortcuts_init(); } first_idx_to_writeback = -1; }
/* Read in a character, interpret it as a shortcut or toggle if * necessary, and return it. * Set ran_func to TRUE if we ran a function associated with a * shortcut key, and set finished to TRUE if we're done after running * or trying to run a function associated with a shortcut key. * refresh_func is the function we will call to refresh the edit window. */ int do_statusbar_input(bool *ran_func, bool *finished, void (*refresh_func)(void)) { int input; /* The character we read in. */ static int *kbinput = NULL; /* The input buffer. */ static size_t kbinput_len = 0; /* The length of the input buffer. */ const sc *s; bool have_shortcut = FALSE; const subnfunc *f; *ran_func = FALSE; *finished = FALSE; /* Read in a character. */ input = get_kbinput(bottomwin); #ifndef NANO_TINY if (input == KEY_WINCH) return KEY_WINCH; #endif #ifndef DISABLE_MOUSE /* If we got a mouse click and it was on a shortcut, read in the * shortcut character. */ if (func_key && input == KEY_MOUSE) { if (do_statusbar_mouse() == 1) input = get_kbinput(bottomwin); else { meta_key = FALSE; func_key = FALSE; input = ERR; } } #endif /* Check for a shortcut in the current list. */ s = get_shortcut(&input); /* If we got a shortcut from the current list, or a "universal" * statusbar prompt shortcut, set have_shortcut to TRUE. */ have_shortcut = (s != NULL); /* If we got a non-high-bit control key, a meta key sequence, or a * function key, and it's not a shortcut or toggle, throw it out. */ if (!have_shortcut) { if (is_ascii_cntrl_char(input) || meta_key || func_key) { beep(); meta_key = FALSE; func_key = FALSE; input = ERR; } } /* If we got a character, and it isn't a shortcut or toggle, * it's a normal text character. Display the warning if we're * in view mode, or add the character to the input buffer if * we're not. */ if (input != ERR && !have_shortcut) { /* If we're using restricted mode, the filename isn't blank, * and we're at the "Write File" prompt, disable text input. */ if (!ISSET(RESTRICTED) || openfile->filename[0] == '\0' || currmenu != MWRITEFILE) { kbinput_len++; kbinput = (int *)nrealloc(kbinput, kbinput_len * sizeof(int)); kbinput[kbinput_len - 1] = input; } } /* If we got a shortcut, or if there aren't any other characters * waiting after the one we read in, we need to display all the * characters in the input buffer if it isn't empty. */ if (have_shortcut || get_key_buffer_len() == 0) { if (kbinput != NULL) { /* Display all the characters in the input buffer at * once, filtering out control characters. */ char *output = charalloc(kbinput_len + 1); size_t i; bool got_enter; /* Whether we got the Enter key. */ for (i = 0; i < kbinput_len; i++) output[i] = (char)kbinput[i]; output[i] = '\0'; do_statusbar_output(output, kbinput_len, &got_enter, FALSE); free(output); /* Empty the input buffer. */ kbinput_len = 0; free(kbinput); kbinput = NULL; } if (have_shortcut) { if (s->scfunc == do_tab || s->scfunc == do_enter_void) ; else if (s->scfunc == total_refresh) total_statusbar_refresh(refresh_func); else if (s->scfunc == do_cut_text_void) { /* If we're using restricted mode, the filename * isn't blank, and we're at the "Write File" * prompt, disable Cut. */ if (!ISSET(RESTRICTED) || openfile->filename[0] == '\0' || currmenu != MWRITEFILE) do_statusbar_cut_text(); } else if (s->scfunc == do_left) do_statusbar_left(); else if (s->scfunc == do_right) do_statusbar_right(); #ifndef NANO_TINY else if (s->scfunc == do_prev_word_void) do_statusbar_prev_word(FALSE); else if (s->scfunc == do_next_word_void) do_statusbar_next_word(FALSE); #endif else if (s->scfunc == do_home) do_statusbar_home(); else if (s->scfunc == do_end) do_statusbar_end(); else if (s->scfunc == do_verbatim_input) { /* If we're using restricted mode, the filename * isn't blank, and we're at the "Write File" * prompt, disable verbatim input. */ if (!ISSET(RESTRICTED) || currmenu != MWRITEFILE || openfile->filename[0] == '\0') { bool got_enter; /* Whether we got the Enter key. */ do_statusbar_verbatim_input(&got_enter); /* If we got the Enter key, remove it from the input * buffer, set input to the key value for Enter, and * set finished to TRUE to indicate that we're done. */ if (got_enter) { get_input(NULL, 1); input = sc_seq_or(do_enter_void, 0); *finished = TRUE; } } } else if (s->scfunc == do_delete) { /* If we're using restricted mode, the filename * isn't blank, and we're at the "Write File" * prompt, disable Delete. */ if (!ISSET(RESTRICTED) || openfile->filename[0] == '\0' || currmenu != MWRITEFILE) do_statusbar_delete(); } else if (s->scfunc == do_backspace) { /* If we're using restricted mode, the filename * isn't blank, and we're at the "Write File" * prompt, disable Backspace. */ if (!ISSET(RESTRICTED) || openfile->filename[0] == '\0' || currmenu != MWRITEFILE) do_statusbar_backspace(); } else { /* Handle any other shortcut in the current menu, setting * ran_func to TRUE if we try to run their associated * functions and setting finished to TRUE to indicate * that we're done after running or trying to run their * associated functions. */ f = sctofunc((sc *) s); if (s->scfunc != NULL) { *ran_func = TRUE; if (f && (!ISSET(VIEW_MODE) || f->viewok) && f->scfunc != do_gotolinecolumn_void) f->scfunc(); } *finished = TRUE; } } } return input; }
/* Get a string of input at the statusbar prompt. This should only be * called from do_prompt(). */ const sc *get_prompt_string(int *actual, bool allow_tabs, #ifndef DISABLE_TABCOMP bool allow_files, #endif const char *curranswer, bool *meta_key, bool *func_key, #ifndef NANO_TINY filestruct **history_list, #endif void (*refresh_func)(void), int menu #ifndef DISABLE_TABCOMP , bool *list #endif ) { int kbinput = ERR; bool have_shortcut, ran_func, finished; size_t curranswer_len; const sc *s; #ifndef DISABLE_TABCOMP bool tabbed = FALSE; /* Whether we've pressed Tab. */ #endif #ifndef NANO_TINY char *history = NULL; /* The current history string. */ char *magichistory = NULL; /* The temporary string typed at the bottom of the history, if * any. */ #ifndef DISABLE_TABCOMP int last_kbinput = ERR; /* The key we pressed before the current key. */ size_t complete_len = 0; /* The length of the original string that we're trying to * tab complete, if any. */ #endif #endif /* !NANO_TINY */ answer = mallocstrcpy(answer, curranswer); curranswer_len = strlen(answer); /* If reset_statusbar_x is TRUE, restore statusbar_x and * statusbar_pww to what they were before this prompt. Then, if * statusbar_x is uninitialized or past the end of curranswer, put * statusbar_x at the end of the string and update statusbar_pww * based on it. We do these things so that the cursor position * stays at the right place if a prompt-changing toggle is pressed, * or if this prompt was started from another prompt and we cancel * out of it. */ if (reset_statusbar_x) { statusbar_x = old_statusbar_x; statusbar_pww = old_pww; } if (statusbar_x == (size_t)-1 || statusbar_x > curranswer_len) { statusbar_x = curranswer_len; statusbar_pww = statusbar_xplustabs(); } currmenu = menu; #ifdef DEBUG fprintf(stderr, "get_prompt_string: answer = \"%s\", statusbar_x = %lu\n", answer, (unsigned long) statusbar_x); #endif update_statusbar_line(answer, statusbar_x); /* Refresh the edit window and the statusbar before getting * input. */ wnoutrefresh(edit); wnoutrefresh(bottomwin); /* If we're using restricted mode, we aren't allowed to change the * name of the current file once it has one, because that would * allow writing to files not specified on the command line. In * this case, disable all keys that would change the text if the * filename isn't blank and we're at the "Write File" prompt. */ while (1) { kbinput = do_statusbar_input(meta_key, func_key, &have_shortcut, &ran_func, &finished, TRUE, refresh_func); assert(statusbar_x <= strlen(answer)); s = get_shortcut(currmenu, &kbinput, meta_key, func_key); if (s) if (s->scfunc == do_cancel || s->scfunc == do_enter_void) break; #ifndef DISABLE_TABCOMP if (s && s->scfunc != do_tab) tabbed = FALSE; #endif #ifndef DISABLE_TABCOMP #ifndef NANO_TINY if (s && s->scfunc == do_tab) { if (history_list != NULL) { if (last_kbinput != sc_seq_or(do_tab, NANO_CONTROL_I)) complete_len = strlen(answer); if (complete_len > 0) { answer = mallocstrcpy(answer, get_history_completion(history_list, answer, complete_len)); statusbar_x = strlen(answer); } } else #endif /* !NANO_TINY */ if (allow_tabs) answer = input_tab(answer, allow_files, &statusbar_x, &tabbed, refresh_func, list); update_statusbar_line(answer, statusbar_x); } else #endif /* !DISABLE_TABCOMP */ #ifndef NANO_TINY if (s && s->scfunc == get_history_older_void) { if (history_list != NULL) { /* If we're scrolling up at the bottom of the * history list and answer isn't blank, save answer * in magichistory. */ if ((*history_list)->next == NULL && answer[0] != '\0') magichistory = mallocstrcpy(magichistory, answer); /* Get the older search from the history list and * save it in answer. If there is no older search, * don't do anything. */ if ((history = get_history_older(history_list)) != NULL) { answer = mallocstrcpy(answer, history); statusbar_x = strlen(answer); } update_statusbar_line(answer, statusbar_x); /* This key has a shortcut list entry when it's used * to move to an older search, which means that * finished has been set to TRUE. Set it back to * FALSE here, so that we aren't kicked out of the * statusbar prompt. */ finished = FALSE; } } else if (s && s->scfunc == get_history_newer_void) { if (history_list != NULL) { /* Get the newer search from the history list and * save it in answer. If there is no newer search, * don't do anything. */ if ((history = get_history_newer(history_list)) != NULL) { answer = mallocstrcpy(answer, history); statusbar_x = strlen(answer); } /* If, after scrolling down, we're at the bottom of * the history list, answer is blank, and * magichistory is set, save magichistory in * answer. */ if ((*history_list)->next == NULL && *answer == '\0' && magichistory != NULL) { answer = mallocstrcpy(answer, magichistory); statusbar_x = strlen(answer); } update_statusbar_line(answer, statusbar_x); /* This key has a shortcut list entry when it's used * to move to a newer search, which means that * finished has been set to TRUE. Set it back to * FALSE here, so that we aren't kicked out of the * statusbar prompt. */ finished = FALSE; } } else #endif /* !NANO_TINY */ if (s && s->scfunc == do_help_void) { update_statusbar_line(answer, statusbar_x); /* This key has a shortcut list entry when it's used to * go to the help browser or display a message * indicating that help is disabled, which means that * finished has been set to TRUE. Set it back to FALSE * here, so that we aren't kicked out of the statusbar * prompt. */ finished = FALSE; } /* If we have a shortcut with an associated function, break out * if we're finished after running or trying to run the * function. */ if (finished) break; #if !defined(NANO_TINY) && !defined(DISABLE_TABCOMP) last_kbinput = kbinput; #endif reset_statusbar_cursor(); wnoutrefresh(bottomwin); } #ifndef NANO_TINY /* Set the current position in the history list to the bottom and * free magichistory, if we need to. */ if (history_list != NULL) { history_reset(*history_list); if (magichistory != NULL) free(magichistory); } #endif /* We've finished putting in an answer or run a normal shortcut's * associated function, so reset statusbar_x and statusbar_pww. If * we've finished putting in an answer, reset the statusbar cursor * position too. */ if (s) { if (s->scfunc == do_cancel || s->scfunc == do_enter_void || ran_func) { statusbar_x = old_statusbar_x; statusbar_pww = old_pww; if (!ran_func) reset_statusbar_x = TRUE; /* Otherwise, we're still putting in an answer or a shortcut with * an associated function, so leave the statusbar cursor position * alone. */ } else reset_statusbar_x = FALSE; } *actual = kbinput; return s; }
/* Ask a simple Yes/No (and optionally All) question, specified in msg, * on the statusbar. Return 1 for Yes, 0 for No, 2 for All (if all is * TRUE when passed in), and -1 for Cancel. */ int do_yesno_prompt(bool all, const char *msg) { int ok = -2, width = 16; const char *yesstr; /* String of Yes characters accepted. */ const char *nostr; /* Same for No. */ const char *allstr; /* And All, surprise! */ const sc *s; int oldmenu = currmenu; assert(msg != NULL); /* yesstr, nostr, and allstr are strings of any length. Each string * consists of all single-byte characters accepted as valid * characters for that value. The first value will be the one * displayed in the shortcuts. */ /* TRANSLATORS: For the next three strings, if possible, specify * the single-byte shortcuts for both your language and English. * For example, in French: "OoYy" for "Oui". */ yesstr = _("Yy"); nostr = _("Nn"); allstr = _("Aa"); if (!ISSET(NO_HELP)) { char shortstr[3]; /* Temp string for Yes, No, All. */ if (COLS < 32) width = COLS / 2; /* Clear the shortcut list from the bottom of the screen. */ blank_bottombars(); sprintf(shortstr, " %c", yesstr[0]); wmove(bottomwin, 1, 0); onekey(shortstr, _("Yes"), width); if (all) { wmove(bottomwin, 1, width); shortstr[1] = allstr[0]; onekey(shortstr, _("All"), width); } wmove(bottomwin, 2, 0); shortstr[1] = nostr[0]; onekey(shortstr, _("No"), width); wmove(bottomwin, 2, 16); onekey("^C", _("Cancel"), width); } wattron(bottomwin, reverse_attr); blank_statusbar(); mvwaddnstr(bottomwin, 0, 0, msg, actual_x(msg, COLS - 1)); wattroff(bottomwin, reverse_attr); /* Refresh the edit window and the statusbar before getting * input. */ wnoutrefresh(edit); wnoutrefresh(bottomwin); do { int kbinput; bool meta_key, func_key; #ifndef DISABLE_MOUSE int mouse_x, mouse_y; #endif currmenu = MYESNO; kbinput = get_kbinput(bottomwin, &meta_key, &func_key); s = get_shortcut(currmenu, &kbinput, &meta_key, &func_key); if (s && s->scfunc == do_cancel) ok = -1; #ifndef DISABLE_MOUSE else if (kbinput == KEY_MOUSE) { /* We can click on the Yes/No/All shortcut list to * select an answer. */ if (get_mouseinput(&mouse_x, &mouse_y, FALSE) == 0 && wmouse_trafo(bottomwin, &mouse_y, &mouse_x, FALSE) && mouse_x < (width * 2) && mouse_y > 0) { int x = mouse_x / width; /* Calculate the x-coordinate relative to the * two columns of the Yes/No/All shortcuts in * bottomwin. */ int y = mouse_y - 1; /* Calculate the y-coordinate relative to the * beginning of the Yes/No/All shortcuts in * bottomwin, i.e. with the sizes of topwin, * edit, and the first line of bottomwin * subtracted out. */ assert(0 <= x && x <= 1 && 0 <= y && y <= 1); /* x == 0 means they clicked Yes or No. y == 0 * means Yes or All. */ ok = -2 * x * y + x - y + 1; if (ok == 2 && !all) ok = -2; } } #endif /* !DISABLE_MOUSE */ else if (s && s->scfunc == total_refresh) { total_redraw(); continue; } else { /* Look for the kbinput in the Yes, No and (optionally) * All strings. */ if (strchr(yesstr, kbinput) != NULL) ok = 1; else if (strchr(nostr, kbinput) != NULL) ok = 0; else if (all && strchr(allstr, kbinput) != NULL) ok = 2; } } while (ok == -2); currmenu = oldmenu; return ok; }
int do_shortcut_menu(void *ignored) { (void)ignored; struct simplelist_info list; struct shortcut *sc; int done = GO_TO_PREVIOUS; if (first_handle == 0) shortcuts_init(); simplelist_info_init(&list, P2STR(ID2P(LANG_SHORTCUTS)), shortcut_count, NULL); list.get_name = shortcut_menu_get_name; list.action_callback = shortcut_menu_get_action; if (global_settings.show_icons) list.get_icon = shortcut_menu_get_icon; list.title_icon = Icon_Bookmark; if (global_settings.talk_menu) list.get_talk = shortcut_menu_speak_item; push_current_activity(ACTIVITY_SHORTCUTSMENU); while (done == GO_TO_PREVIOUS) { if (simplelist_show_list(&list)) break; /* some error happened?! */ if (list.selection == -1) break; else { sc = get_shortcut(list.selection); if (!sc) continue; switch (sc->type) { case SHORTCUT_PLAYLISTMENU: if (!file_exists(sc->u.path)) { splash(HZ, ID2P(LANG_NO_FILES)); break; } else { onplay_show_playlist_menu(sc->u.path); } break; case SHORTCUT_FILE: if (!file_exists(sc->u.path)) { splash(HZ, ID2P(LANG_NO_FILES)); break; } /* else fall through */ case SHORTCUT_BROWSER: { struct browse_context browse; browse_context_init(&browse, global_settings.dirfilter, 0, NULL, NOICON, sc->u.path, NULL); if (sc->type == SHORTCUT_FILE) browse.flags |= BROWSE_RUNFILE; done = rockbox_browse(&browse); } break; case SHORTCUT_SETTING: do_setting_screen(sc->u.setting, sc->name[0] ? sc->name : P2STR(ID2P(sc->u.setting->lang_id)),NULL); break; case SHORTCUT_DEBUGITEM: run_debug_screen(sc->u.path); break; case SHORTCUT_SHUTDOWN: #if CONFIG_CHARGING if (charger_inserted()) charging_splash(); else #endif sys_poweroff(); break; case SHORTCUT_TIME: #if CONFIG_RTC if (sc->u.timedata.talktime) { talk_timedate(); talk_force_enqueue_next(); } else #endif { char timer_buf[10]; set_sleep_timer(sc->u.timedata.sleep_timeout * 60); splashf(HZ, "%s (%s)", str(LANG_SLEEP_TIMER), sleep_timer_formatter(timer_buf, sizeof(timer_buf), sc->u.timedata.sleep_timeout, NULL)); } break; case SHORTCUT_UNDEFINED: default: break; } } } pop_current_activity(); return done; }
static int readline_cb(int n, char *buf, void *parameters) { (void)n; (void)parameters; struct shortcut **param = (struct shortcut**)parameters; struct shortcut* sc = *param; char *name, *value; if (!strcasecmp(skip_whitespace(buf), "[shortcut]")) { if (sc && verify_shortcut(sc)) shortcut_count++; sc = get_shortcut(shortcut_count); if (!sc) return 1; init_shortcut(sc); *param = sc; } else if (sc && settings_parseline(buf, &name, &value)) { if (!strcmp(name, "type")) { int t = 0; for (t=0; t<SHORTCUT_TYPE_COUNT && sc->type == SHORTCUT_UNDEFINED; t++) if (!strcmp(value, type_strings[t])) sc->type = t; } else if (!strcmp(name, "name")) { strlcpy(sc->name, value, MAX_SHORTCUT_NAME); } else if (!strcmp(name, "data")) { switch (sc->type) { case SHORTCUT_UNDEFINED: case SHORTCUT_TYPE_COUNT: *param = NULL; break; case SHORTCUT_BROWSER: case SHORTCUT_FILE: case SHORTCUT_DEBUGITEM: case SHORTCUT_PLAYLISTMENU: strlcpy(sc->u.path, value, MAX_PATH); break; case SHORTCUT_SETTING: sc->u.setting = find_setting_by_cfgname(value, NULL); break; case SHORTCUT_TIME: #if CONFIG_RTC sc->u.timedata.talktime = false; if (!strcasecmp(value, "talk")) sc->u.timedata.talktime = true; else #endif if (!strncasecmp(value, "sleep ", strlen("sleep "))) sc->u.timedata.sleep_timeout = atoi(&value[strlen("sleep ")]); else sc->type = SHORTCUT_UNDEFINED; /* error */ break; case SHORTCUT_SEPARATOR: case SHORTCUT_SHUTDOWN: break; } } else if (!strcmp(name, "icon")) { if (!strcmp(value, "filetype") && sc->type != SHORTCUT_SETTING && sc->u.path[0]) { sc->icon = filetype_get_icon(filetype_get_attr(sc->u.path)); } else { sc->icon = atoi(value); } } else if (!strcmp(name, "talkclip")) { strlcpy(sc->talk_clip, value, MAX_PATH); } } return 0; }