/* Handle a mouse click on the statusbar prompt or the shortcut list. */ int do_statusbar_mouse(void) { int mouse_x, mouse_y; int retval = get_mouseinput(&mouse_x, &mouse_y, TRUE); /* We can click on the statusbar window text to move the cursor. */ if (retval == 0 && wmouse_trafo(bottomwin, &mouse_y, &mouse_x, FALSE)) { size_t start_col; assert(prompt != NULL); start_col = strlenpt(prompt) + 2; /* Move to where the click occurred. */ if (mouse_x >= start_col && mouse_y == 0) { size_t pww_save = statusbar_pww; statusbar_x = actual_x(answer, get_statusbar_page_start(start_col, start_col + statusbar_xplustabs()) + mouse_x - start_col); statusbar_pww = statusbar_xplustabs(); if (need_statusbar_update(pww_save)) update_statusbar_line(answer, statusbar_x); } } return retval; }
/* Our main file browser function. path is the tilde-expanded path we * start browsing from. */ char *do_browser(char *path, DIR *dir) { char *retval = NULL; int kbinput; bool old_const_update = ISSET(CONST_UPDATE); char *prev_dir = NULL; /* The directory we were in before backing up to "..". */ char *ans = NULL; /* The last answer the user typed at the statusbar prompt. */ size_t old_selected; /* The selected file we had before the current selected file. */ functionptrtype func; /* The function of the key the user typed in. */ curs_set(0); blank_statusbar(); bottombars(MBROWSER); wnoutrefresh(bottomwin); UNSET(CONST_UPDATE); ans = mallocstrcpy(NULL, ""); change_browser_directory: /* We go here after we select a new directory. */ /* Start with no key pressed. */ kbinput = ERR; path = mallocstrassn(path, get_full_path(path)); /* Save the current path in order to be used later. */ path_save = path; assert(path != NULL && path[strlen(path) - 1] == '/'); /* Get the file list, and set longest and width in the process. */ browser_init(path, dir); assert(filelist != NULL); /* Sort the file list. */ qsort(filelist, filelist_len, sizeof(char *), diralphasort); /* If prev_dir isn't NULL, select the directory saved in it, and * then blow it away. */ if (prev_dir != NULL) { browser_select_dirname(prev_dir); free(prev_dir); prev_dir = NULL; /* Otherwise, select the first file or directory in the list. */ } else selected = 0; old_selected = (size_t)-1; titlebar(path); while (TRUE) { struct stat st; int i; size_t fileline = selected / width; /* The line number the selected file is on. */ char *new_path; /* The path we switch to at the "Go to Directory" * prompt. */ /* Display the file list if we don't have a key, or if the * selected file has changed, and set width in the process. */ if (kbinput == ERR || old_selected != selected) browser_refresh(); old_selected = selected; kbinput = get_kbinput(edit); #ifndef NANO_TINY if (kbinput == KEY_WINCH) { kbinput = ERR; curs_set(0); continue; } #endif #ifndef DISABLE_MOUSE if (kbinput == KEY_MOUSE) { int mouse_x, mouse_y; /* We can click on the edit window to select a * filename. */ if (get_mouseinput(&mouse_x, &mouse_y, TRUE) == 0 && wmouse_trafo(edit, &mouse_y, &mouse_x, FALSE)) { /* longest is the width of each column. There * are two spaces between each column. */ selected = (fileline / editwinrows) * (editwinrows * width) + (mouse_y * width) + (mouse_x / (longest + 2)); /* If they clicked beyond the end of a row, * select the last filename in that row. */ if (mouse_x > width * (longest + 2)) selected--; /* If we're off the screen, select the last filename. */ if (selected > filelist_len - 1) selected = filelist_len - 1; /* If we selected the same filename as last time, * put back the Enter key so that it's read in. */ if (old_selected == selected) unget_kbinput(sc_seq_or(do_enter_void, 0), FALSE, FALSE); } } #endif /* !DISABLE_MOUSE */ func = parse_browser_input(&kbinput); if (func == total_refresh) { total_redraw(); } else if (func == do_help_void) { #ifndef DISABLE_HELP do_help_void(); /* Perhaps the window dimensions have changed. */ browser_refresh(); curs_set(0); #else nano_disabled_msg(); #endif } else if (func == do_search) { /* Search for a filename. */ curs_set(1); do_filesearch(); curs_set(0); } else if (func == do_research) { /* Search for another filename. */ do_fileresearch(); } else if (func == do_page_up) { if (selected >= (editwinrows + fileline % editwinrows) * width) selected -= (editwinrows + fileline % editwinrows) * width; else selected = 0; } else if (func == do_page_down) { selected += (editwinrows - fileline % editwinrows) * width; if (selected > filelist_len - 1) selected = filelist_len - 1; } else if (func == do_first_file) { selected = 0; } else if (func == do_last_file) { selected = filelist_len - 1; } else if (func == goto_dir_void) { /* Go to a specific directory. */ curs_set(1); i = do_prompt(TRUE, #ifndef DISABLE_TABCOMP FALSE, #endif MGOTODIR, ans, #ifndef DISABLE_HISTORIES NULL, #endif /* TRANSLATORS: This is a prompt. */ browser_refresh, _("Go To Directory")); curs_set(0); bottombars(MBROWSER); /* If the directory begins with a newline (i.e. an * encoded null), treat it as though it's blank. */ if (i < 0 || *answer == '\n') { /* We canceled. Indicate that on the statusbar, and * blank out ans, since we're done with it. */ statusbar(_("Cancelled")); ans = mallocstrcpy(ans, ""); continue; } else if (i != 0) { /* Put back the "Go to Directory" key and save * answer in ans, so that the file list is displayed * again, the prompt is displayed again, and what we * typed before at the prompt is displayed again. */ unget_kbinput(sc_seq_or(do_gotolinecolumn_void, 0), FALSE, FALSE); ans = mallocstrcpy(ans, answer); continue; } /* We have a directory. Blank out ans, since we're done * with it. */ ans = mallocstrcpy(ans, ""); /* Convert newlines to nulls, just before we go to the * directory. */ sunder(answer); align(&answer); new_path = real_dir_from_tilde(answer); if (new_path[0] != '/') { new_path = charealloc(new_path, strlen(path) + strlen(answer) + 1); sprintf(new_path, "%s%s", path, answer); } #ifndef DISABLE_OPERATINGDIR if (check_operating_dir(new_path, FALSE)) { statusbar(_("Can't go outside of %s in restricted mode"), operating_dir); free(new_path); continue; } #endif dir = opendir(new_path); if (dir == NULL) { /* We can't open this directory for some reason. * Complain. */ statusbar(_("Error reading %s: %s"), answer, strerror(errno)); beep(); free(new_path); continue; } /* Start over again with the new path value. */ free(path); path = new_path; goto change_browser_directory; } else if (func == do_up_void) { if (selected >= width) selected -= width; } else if (func == do_down_void) { if (selected + width <= filelist_len - 1) selected += width; } else if (func == do_left) { if (selected > 0) selected--; } else if (func == do_right) { if (selected < filelist_len - 1) selected++; } else if (func == do_enter_void) { /* We can't move up from "/". */ if (strcmp(filelist[selected], "/..") == 0) { statusbar(_("Can't move up a directory")); beep(); continue; } #ifndef DISABLE_OPERATINGDIR /* Note: The selected file can be outside the operating * directory if it's ".." or if it's a symlink to a * directory outside the operating directory. */ if (check_operating_dir(filelist[selected], FALSE)) { statusbar(_("Can't go outside of %s in restricted mode"), operating_dir); beep(); continue; } #endif if (stat(filelist[selected], &st) == -1) { /* We can't open this file for some reason. * Complain. */ statusbar(_("Error reading %s: %s"), filelist[selected], strerror(errno)); beep(); continue; } if (!S_ISDIR(st.st_mode)) { /* We've successfully opened a file, we're done, so * get out. */ retval = mallocstrcpy(NULL, filelist[selected]); break; } else if (strcmp(tail(filelist[selected]), "..") == 0) /* We've successfully opened the parent directory, * save the current directory in prev_dir, so that * we can easily return to it by hitting Enter. */ prev_dir = mallocstrcpy(NULL, striponedir(filelist[selected])); dir = opendir(filelist[selected]); if (dir == NULL) { /* We can't open this directory for some reason. * Complain. */ statusbar(_("Error reading %s: %s"), filelist[selected], strerror(errno)); beep(); continue; } path = mallocstrcpy(path, filelist[selected]); /* Start over again with the new path value. */ goto change_browser_directory; } else if (func == do_exit) { /* Exit from the file browser. */ break; } } titlebar(NULL); edit_refresh(); curs_set(1); if (old_const_update) SET(CONST_UPDATE); free(path); free(ans); free_chararray(filelist, filelist_len); filelist = NULL; filelist_len = 0; return retval; }
/* 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! */ 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"); do { int kbinput; functionptrtype func; #ifndef DISABLE_MOUSE int mouse_x, mouse_y; #endif if (!ISSET(NO_HELP)) { char shortstr[3]; /* Temporary string for (translated) " Y", " N" and " A". */ if (COLS < 32) width = COLS / 2; /* Clear the shortcut list from the bottom of the screen. */ blank_bottombars(); /* Now show the ones for "Yes", "No", "Cancel" and maybe "All". */ sprintf(shortstr, " %c", yesstr[0]); wmove(bottomwin, 1, 0); onekey(shortstr, _("Yes"), width); if (all) { shortstr[1] = allstr[0]; wmove(bottomwin, 1, width); onekey(shortstr, _("All"), width); } shortstr[1] = nostr[0]; wmove(bottomwin, 2, 0); onekey(shortstr, _("No"), width); wmove(bottomwin, 2, width); onekey("^C", _("Cancel"), width); } if (interface_color_pair[TITLE_BAR].bright) wattron(bottomwin, A_BOLD); wattron(bottomwin, interface_color_pair[TITLE_BAR].pairnum); blank_statusbar(); mvwaddnstr(bottomwin, 0, 0, msg, actual_x(msg, COLS - 1)); wattroff(bottomwin, A_BOLD); wattroff(bottomwin, interface_color_pair[TITLE_BAR].pairnum); /* Refresh edit window and statusbar before getting input. */ wnoutrefresh(edit); wnoutrefresh(bottomwin); currmenu = MYESNO; kbinput = get_kbinput(bottomwin); #ifndef NANO_TINY if (kbinput == KEY_WINCH) continue; #endif func = func_from_key(&kbinput); if (func == 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 (func == 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; }
/* Our main help-viewer function. */ void do_help(void) { int kbinput = ERR; bool old_no_help = ISSET(NO_HELP); size_t line = 0; /* The line number in help_text of the first displayed help * line. This variable is zero-based. */ size_t last_line = 0; /* The line number in help_text of the last help line. This * variable is zero-based. */ int oldmenu = currmenu; /* The menu we were called from. */ const char *ptr; /* The current line of the help text. */ size_t old_line = (size_t)-1; /* The line we were on before the current line. */ functionptrtype func; /* The function of the key the user typed in. */ /* Don't show a cursor in the help screen. */ curs_set(0); blank_edit(); blank_statusbar(); /* Set help_text as the string to display. */ help_init(); assert(help_text != NULL); if (ISSET(NO_HELP)) { /* Make sure that the help screen's shortcut list will actually * be displayed. */ UNSET(NO_HELP); window_init(); } bottombars(MHELP); wnoutrefresh(bottomwin); while (TRUE) { size_t i; ptr = help_text; /* Find the line number of the last line of the help text. */ for (last_line = 0; *ptr != '\0'; last_line++) { ptr += help_line_len(ptr); if (*ptr == '\n') ptr++; } if (last_line > 0) last_line--; /* Redisplay if the text was scrolled or an invalid key was pressed. */ if (line != old_line || kbinput == ERR) { blank_edit(); ptr = help_text; /* Advance in the text to the first line to be displayed. */ for (i = 0; i < line; i++) { ptr += help_line_len(ptr); if (*ptr == '\n') ptr++; } /* Now display as many lines as the window will hold. */ for (i = 0; i < editwinrows && *ptr != '\0'; i++) { size_t j = help_line_len(ptr); mvwaddnstr(edit, i, 0, ptr, j); ptr += j; if (*ptr == '\n') ptr++; } } wnoutrefresh(edit); old_line = line; lastmessage = HUSH; kbinput = get_kbinput(edit); #ifndef NANO_TINY if (kbinput == KEY_WINCH) { kbinput = ERR; continue; /* Redraw the screen. */ } #endif #ifndef DISABLE_MOUSE if (kbinput == KEY_MOUSE) { int mouse_x, mouse_y; get_mouseinput(&mouse_x, &mouse_y, TRUE); continue; /* Redraw the screen. */ } #endif func = parse_help_input(&kbinput); if (func == total_refresh) { total_redraw(); } else if (func == do_up_void) { if (line > 0) line--; } else if (func == do_down_void) { if (line + (editwinrows - 1) < last_line) line++; } else if (func == do_page_up) { if (line > editwinrows - 2) line -= editwinrows - 2; else line = 0; } else if (func == do_page_down) { if (line + (editwinrows - 1) < last_line) line += editwinrows - 2; } else if (func == do_first_line) { line = 0; } else if (func == do_last_line) { if (line + (editwinrows - 1) < last_line) line = last_line - (editwinrows - 1); } else if (func == do_exit) { /* Exit from the help viewer. */ break; } else unbound_key(kbinput); } if (old_no_help) { blank_bottombars(); wnoutrefresh(bottomwin); currmenu = oldmenu; SET(NO_HELP); window_init(); } else bottombars(oldmenu); #ifndef DISABLE_BROWSER if (oldmenu == MBROWSER || oldmenu == MWHEREISFILE || oldmenu == MGOTODIR) browser_refresh(); else #endif edit_refresh(); /* We're exiting from the help screen. */ free(help_text); }