static void file_selector_display_item(struct file_list *fl, int num, int first_item_num, int x, int y, int width, int height, int num_cols) { y += (num - first_item_num) % height; x += ((num - first_item_num) / height) * width; if (num >= fl->num_used_items) { tui_hline(x, y, ' ', width); } else { int len = strlen(fl->items[num].name); /* XXX: Assumes `width' is > 5! */ if (len > width - 2) { char *name = alloca(width - 2 + 1); if (fl->items[num].type == FT_DIR) { memcpy(name, fl->items[num].name, width - 3); name[width - 4] = name[width - 5] = '.'; name[width - 3] = '/'; } else { memcpy(name, fl->items[num].name, width - 2); name[width - 3] = name[width - 4] = '.'; } name[width - 2] = '\0'; tui_display(x, y, width, " %s ", name); } else { if (fl->items[num].type == FT_DIR) { tui_display(x, y, width, " %s/ ", fl->items[num].name); } else { tui_display(x, y, width, " %s ", fl->items[num].name); } } } }
void tui_message(const char *format,...) { int x, y, width, height; char *str; int str_length; va_list ap; tui_area_t backing_store = NULL; va_start(ap, format); str = lib_mvsprintf(format, ap); str_length = strlen(str); if (str_length > tui_num_cols() - 10) { str_length = tui_num_cols() - 10; str[str_length] = 0; } x = CENTER_X(str_length + 6); y = CENTER_Y(5); width = str_length + 6; height = 5; tui_display_window(x, y, width, height, MESSAGE_BORDER, MESSAGE_BACK, NULL, &backing_store); tui_set_attr(MESSAGE_FORE, MESSAGE_BACK, 0); tui_display(CENTER_X(str_length), y + 2, 0, str); getkey(); tui_area_put(backing_store, x, y); tui_area_free(backing_store); lib_free(str); }
int tui_input_string(const char *title, const char *prompt, char *buf, int buflen) { int field_width, x, y, width, height, retval; tui_area_t backing_store = NULL; if (buflen + 1 < tui_num_cols() - 12) field_width = buflen + 1; else field_width = tui_num_cols() - 12; width = field_width + 4; height = 4; x = CENTER_X(width); y = CENTER_Y(height); tui_display_window(x, y, width, height, REQUESTER_BORDER, REQUESTER_BACK, title, &backing_store); tui_set_attr(REQUESTER_FORE, REQUESTER_BACK, 0); tui_display(x + 2, y + 1, field_width, prompt); retval = _tui_input_string(x + 2, y + 2, buf, buflen, field_width, FIELD_FORE, FIELD_BACK); tui_area_put(backing_store, x, y); tui_area_free(backing_store); return retval; }
void tui_display_window(int x, int y, int width, int height, int foreground_color, int background_color, const char *title, tui_area_t *backing_store) { int i; if (backing_store != NULL) { /* 2 more chars on right, 1 more on bottom because of the "shadow". */ tui_area_get(backing_store, x, y, width + 2, height + 1); } tui_make_shadow(x + 2, y + 1, width, height); tui_set_attr(foreground_color, background_color, 0); tui_put_char(x, y, 0xc9); tui_hline(x + 1, y, 0xcd, width - 2); tui_put_char(x + width - 1, y, 0xbb); tui_put_char(x, y + height - 1, 0xc8); tui_hline(x + 1, y + height - 1, 0xcd, width - 2); tui_put_char(x + width - 1, y + height - 1, 0xbc); for (i = 0; i < height - 2; i++) { tui_put_char(x, y + i + 1, 0xba); tui_hline(x + 1, y + i + 1, ' ', width - 2); tui_put_char(x + width - 1, y + i + 1, 0xba); } if (!util_check_null_string(title)) { int title_x, title_length; title_length = strlen(title); title_x = x + (width - title_length - 4) / 2; tui_display(title_x, y, 0, "\x10 %s \x11", title); } }
void tui_clear_screen(void) { int i; _setcursortype(_NOCURSOR); tui_set_attr(FIRST_LINE_FORE, FIRST_LINE_BACK, 0); #ifndef UNSTABLE tui_display(0, 0, tui_num_cols(), "VICE version %s", VERSION); #else tui_display(0, 0, tui_num_cols(), "VICE version %s (unstable)", VERSION); #endif tui_set_attr(BACKPATTERN_FORE, BACKPATTERN_BACK, 0); for (i = 1; i < tui_num_lines() - 1; i++) tui_hline(0, i, BACKCHAR, tui_num_cols()); }
static TUI_MENU_CALLBACK(keyset_callback) { int direction, number; int value; char *rname; number = (int)param >> 8; direction = (int)param & 0xff; rname = lib_msprintf("KeySet%d%s", number, joystick_direction_to_string(direction)); if (been_activated) { kbd_code_t key; int width = 60, height = 5; int x = CENTER_X(width), y = CENTER_Y(height); tui_area_t backing_store = NULL; char *msg; msg = lib_msprintf("Press key for %s%s (Esc for none)...", direction == KEYSET_FIRE ? "" : "direction ", joystick_direction_to_string(direction)); tui_display_window(x, y, width, height, MESSAGE_BORDER, MESSAGE_BACK, NULL, &backing_store); tui_set_attr(MESSAGE_FORE, MESSAGE_BACK, 0); tui_display(CENTER_X(strlen(msg)), y + 2, 0, msg); lib_free(msg); /* Do not allow Alt as we need it for hotkeys. */ do { key = grab_key(); } while (key == K_LEFTALT || key == K_RIGHTALT); tui_area_put(backing_store, x, y); tui_area_free(backing_store); if (key == K_ESC) { key = K_NONE; } resources_set_int(rname, (int)key); } resources_get_int(rname, &value); lib_free(rname); return kbd_code_to_string((kbd_code_t)value); }
int tui_ask_confirmation(const char *format, ...) { int x, y, width, height; char *str; int str_length; va_list ap; tui_area_t backing_store = NULL; int c; va_start(ap, format); str = lib_mvsprintf(format, ap); str_length = strlen(str); if (str_length > tui_num_cols() - 10) { str_length = tui_num_cols() - 10; str[str_length] = 0; } x = CENTER_X(str_length + 6); y = CENTER_Y(5); width = str_length + 6; height = 5; tui_display_window(x, y, width, height, MESSAGE_BORDER, MESSAGE_BACK, NULL, &backing_store); tui_set_attr(MESSAGE_FORE, MESSAGE_BACK, 0); tui_display(CENTER_X(str_length), y + 2, 0, str); do { c = getkey(); } while (toupper(c) != 'Y' && toupper(c) != 'N'); tui_area_put(backing_store, x, y); tui_area_free(backing_store); lib_free(str); return toupper(c) == 'Y'; }
static int _tui_input_string(int x, int y, char *buf, int max_length, int displayed_length, int foreground_color, int background_color) { int cursor_pos = 0; int scroll_offset = 0; int string_length = strlen(buf); int need_redisplay = 1; tui_set_attr(foreground_color, background_color, 0); _setcursortype(_SOLIDCURSOR); while (1) { int key; if (need_redisplay) { tui_display(x, y, displayed_length, "%s", buf + scroll_offset); need_redisplay = 0; } tui_gotoxy(x + cursor_pos - scroll_offset, y); key = getkey(); switch (key) { case K_Left: if (cursor_pos > 0) { cursor_pos--; if (cursor_pos < scroll_offset) { scroll_offset = cursor_pos; need_redisplay = 1; } } break; case K_Right: if (cursor_pos < string_length) { cursor_pos++; if (cursor_pos >= (scroll_offset + displayed_length)) { scroll_offset = cursor_pos - displayed_length + 1; need_redisplay = 1; } } break; case K_Home: cursor_pos = 0; scroll_offset = 0; need_redisplay = 1; break; case K_End: cursor_pos = string_length; scroll_offset = cursor_pos - displayed_length + 1; if (scroll_offset < 0) scroll_offset = 0; need_redisplay = 1; break; case K_BackSpace: if (cursor_pos > 0 && cursor_pos <= string_length) { memmove(buf + cursor_pos - 1, buf + cursor_pos, string_length - cursor_pos + 1); string_length--; cursor_pos--; if (cursor_pos < scroll_offset) scroll_offset = cursor_pos; need_redisplay = 1; } break; case K_Delete: if (cursor_pos < string_length) { memmove(buf + cursor_pos, buf + cursor_pos + 1, string_length - cursor_pos); string_length--; need_redisplay = 1; } break; case K_Return: _setcursortype(_NOCURSOR); return 0; case K_Escape: _setcursortype(_NOCURSOR); return -1; default: if (key <= 0xff && isprint((char) key) && string_length < max_length) { memmove(buf + cursor_pos + 1, buf + cursor_pos, string_length - cursor_pos + 1); buf[cursor_pos] = (char) key; cursor_pos++; string_length++; if (cursor_pos - scroll_offset >= displayed_length) scroll_offset = cursor_pos - displayed_length + 1; need_redisplay = 1; } break; } } }
/* FIXME: documentation. */ char *tui_file_selector(const char *title, const char *directory, const char *pattern, const char *default_item, read_contents_func_type contents_func, char **browse_file_return, unsigned int *browse_file_number_return) { static char *return_path = NULL; struct file_list *fl; int curr_item, first_item, need_update; int x, y, width, height, num_cols, num_lines, field_width; int num_files; char str[0x100]; int str_len = 0; tui_area_t backing_store = NULL; if (contents_func != NULL) { *browse_file_return = NULL; } if (browse_file_number_return != NULL) { *browse_file_number_return = 0; } if (directory != NULL) { return_path = lib_stralloc(directory); } else { return_path = ioutil_current_dir(); } slashize_path(&return_path); fl = file_list_read(return_path, pattern); if (fl == NULL) { return NULL; } first_item = curr_item = 0; num_cols = 4; field_width = 18; num_lines = 17; height = num_lines + 2; width = field_width * num_cols + 4; num_files = num_cols * num_lines; if (default_item != NULL && *default_item) { int i; for (i = 0; i < fl->num_items; i++) { if (!strcasecmp(default_item, fl->items[i].name)) { curr_item = i; while (curr_item - first_item >= num_files) { first_item += num_lines; } break; } } } x = CENTER_X(width); y = CENTER_Y(height); need_update = 1; tui_area_get(&backing_store, x, y, width + 2, height + 1); tui_display_window(x, y, width, height, MENU_BORDER, MENU_BACK, title, NULL); while (1) { int key; tui_set_attr(MENU_FORE, MENU_BACK, 0); if (need_update) { file_selector_display_path(return_path, x + 1, y + height - 1, width - 2); file_selector_update(fl, first_item, x + 2, y + 1, field_width, num_lines, num_cols); tui_set_attr(FIRST_LINE_FORE, FIRST_LINE_BACK, 0); tui_display(0, tui_num_lines() - 1, tui_num_cols(), "\030\031\033\032: Move <Enter>: Select %s<Alt>-<letter>: Change drive", contents_func != NULL ? "<Space>: Preview " : ""); need_update = 0; } tui_set_attr(MENU_FORE, MENU_HIGHLIGHT, 0); file_selector_display_item(fl, curr_item, first_item, x + 2, y + 1, field_width, num_lines, num_cols); key = getkey(); tui_set_attr(MENU_FORE, MENU_BACK, 0); file_selector_display_item(fl, curr_item, first_item, x + 2, y + 1, field_width, num_lines, num_cols); switch (key) { case K_Escape: tui_area_put(backing_store, x, y); tui_area_free(backing_store); return NULL; case K_Left: str_len = 0; if (curr_item - num_lines >= 0) { curr_item -= num_lines; if (curr_item < first_item) { if (first_item >= num_lines) { first_item -= num_lines; need_update = 1; } else { curr_item += num_lines; } } } break; case K_Up: str_len = 0; if (curr_item > 0) { curr_item--; if (curr_item < first_item) { first_item = curr_item; need_update = 1; } } break; case K_Right: str_len = 0; if (curr_item + num_lines < fl->num_used_items) { curr_item += num_lines; if (curr_item - first_item >= num_files) { first_item += num_lines; need_update = 1; } } break; case K_Down: str_len = 0; if (curr_item < fl->num_used_items - 1) { curr_item++; if (curr_item == first_item + num_files) { first_item++; need_update = 1; } } break; case K_PageDown: str_len = 0; if (curr_item + num_files < fl->num_used_items) { curr_item += num_files; first_item += num_files; } need_update = 1; break; case K_PageUp: str_len = 0; if (curr_item - num_files >= 0) { curr_item -= num_files; first_item -= num_files; if (first_item < 0) { first_item = 0; } need_update = 1; } break; case K_Home: str_len = 0; curr_item = 0; if (first_item != 0) { first_item = 0; need_update = 1; } break; case K_End: str_len = 0; curr_item = fl->num_used_items - 1; first_item = curr_item - num_files + 1; if (first_item < 0) { first_item = 0; } need_update = 1; break; case K_Return: str_len = 0; if (fl->items[curr_item].type == FT_DIR) { struct file_list *new_fl; char *new_path; new_path = change_path(fl, return_path, curr_item); new_fl = file_list_read(new_path, pattern); if (new_fl != NULL) { file_list_free(fl); fl = new_fl; first_item = curr_item = 0; lib_free(return_path); return_path = new_path; need_update = 1; ioutil_chdir(return_path); } else { lib_free(new_path); } } else { char *p = util_concat(return_path, fl->items[curr_item].name, NULL); lib_free(return_path); return_path = p; tui_area_put(backing_store, x, y); tui_area_free(backing_store); return return_path; } break; case K_BackSpace: if (str_len > 1) { int n; str_len--; n = file_list_find(fl, str, str_len); if (n >= 0) { curr_item = n; if (curr_item < first_item) { first_item = curr_item; need_update = 1; } else if (first_item + num_files <= curr_item) { first_item = curr_item - num_files + 1; need_update = 1; } } } else { str_len = 0; curr_item = 0; if (first_item != 0) { first_item = 0; need_update = 1; } } break; case ' ': if (contents_func != NULL && fl->items[curr_item].type != FT_DIR && browse_file_return != NULL) { tui_display(0, tui_num_lines() - 1, tui_num_cols(), ""); *browse_file_return = tui_image_browser(fl->items[curr_item].name, contents_func, browse_file_number_return); if (*browse_file_return != NULL) { char *p = util_concat(return_path, fl->items[curr_item].name, NULL); lib_free(return_path); return_path = p; tui_area_put(backing_store, x, y); tui_area_free(backing_store); return return_path; } need_update = 1; break; } else { tui_beep(); } default: { int drive_num; drive_num = alt_key_to_drive_num(key); if (drive_num > 0) { /* `A-a' ... `A-z' change the current drive. */ int num_available_drives; int current_drive; _dos_getdrive(¤t_drive); _dos_setdrive(current_drive, &num_available_drives); if (drive_num <= num_available_drives) { char *new_path; /* FIXME: This is a hack... Maybe there is a cleaner way to do it, but for now I just don't know. */ _dos_setdrive(drive_num, &num_available_drives); new_path = ioutil_current_dir(); if (new_path != NULL) { slashize_path(&new_path); _dos_setdrive(current_drive, &num_available_drives); if (new_path != NULL) { struct file_list *new_fl; new_fl = file_list_read(new_path, pattern); if (new_fl != NULL) { file_list_free(fl); fl = new_fl; first_item = curr_item = 0; lib_free(return_path); return_path = new_path; need_update = 1; ioutil_chdir(return_path); } else { lib_free(new_path); } } } else { _dos_setdrive(current_drive, &num_available_drives); tui_beep(); } } else { tui_beep(); } } else if (isprint(key) && str_len < 0x100) { int n; str[str_len] = key; n = file_list_find(fl, str, str_len + 1); if (n < 0) { tui_beep(); } else { str_len++; curr_item = n; if (curr_item < first_item) { first_item = curr_item; need_update = 1; } else if (first_item + num_files <= curr_item) { first_item = curr_item - num_files + 1; need_update = 1; } } } } break; } } }