/** * Display the monster list statically. This will force the list to be * displayed to the provided dimensions. Contents will be adjusted accordingly. * * In order to support more efficient monster flicker animations, this function * uses a shared list object so that it's not constantly allocating and freeing * the list. * * \param height is the height of the list. * \param width is the width of the list. */ void monster_list_show_subwindow(int height, int width) { textblock *tb; monster_list_t *list; int i; if (height < 1 || width < 1) return; tb = textblock_new(); list = monster_list_shared_instance(); /* Force an update if detected monsters */ for (i = 1; i < cave_monster_max(cave); i++) { if (mflag_has(cave_monster(cave, i)->mflag, MFLAG_MARK)) { list->creation_turn = -1; break; } } monster_list_reset(list); monster_list_collect(list); monster_list_get_glyphs(list); monster_list_sort(list, monster_list_standard_compare); /* Draw the list to exactly fit the subwindow. */ monster_list_format_textblock(list, tb, height, width, NULL, NULL); textui_textblock_place(tb, SCREEN_REGION, NULL); textblock_free(tb); }
/** * This draws the Object Recall subwindow when displaying a particular object * (e.g. a helmet in the backpack, or a scroll on the ground) */ void display_object_recall(struct object *obj) { char header_buf[120]; textblock *tb = object_info(obj, OINFO_NONE); object_desc(header_buf, sizeof(header_buf), obj, ODESC_PREFIX | ODESC_FULL); clear_from(0); textui_textblock_place(tb, SCREEN_REGION, header_buf); textblock_free(tb); }
/** * Display monster recall statically. * * This is intended to be called in a subwindow, since it clears the entire * window before drawing, and has no interactivity. * * \param race is the monster race we are describing. * \param lore is the known information about the monster race. */ void lore_show_subwindow(const monster_race *race, const monster_lore *lore) { int y; textblock *tb; assert(race && lore); /* Erase the window, since textui_textblock_place() only clears what it * needs */ for (y = 0; y < Term->hgt; y++) Term_erase(0, y, 255); tb = textblock_new(); lore_description(tb, race, lore, FALSE); textui_textblock_place(tb, SCREEN_REGION, NULL); textblock_free(tb); }
/** * Display the object list statically. This will force the list to be displayed * to the provided dimensions. Contents will be adjusted accordingly. * * In order to be more efficient, this function uses a shared list object so * that it's not constantly allocating and freeing the list. * * \param height is the height of the list. * \param width is the width of the list. */ void object_list_show_subwindow(int height, int width) { textblock *tb; object_list_t *list; if (height < 1 || width < 1) return; tb = textblock_new(); list = object_list_shared_instance(); object_list_reset(list); object_list_collect(list); object_list_sort(list, object_list_standard_compare); /* Draw the list to exactly fit the subwindow. */ object_list_format_textblock(list, tb, height, width, NULL, NULL); textui_textblock_place(tb, SCREEN_REGION, NULL); textblock_free(tb); }
/* pick the context menu options appropiate for the item */ int context_menu_object(const object_type *o_ptr, const int slot) { menu_type *m; region r; int selected; char *labels; char header[120]; textblock *tb; region area = { 0, 0, 0, 0 }; bool allowed = TRUE; int mode = OPT(rogue_like_commands) ? KEYMAP_MODE_ROGUE : KEYMAP_MODE_ORIG; unsigned char cmdkey; m = menu_dynamic_new(); if (!m || !o_ptr) { return 0; } object_desc(header, sizeof(header), o_ptr, ODESC_PREFIX | ODESC_BASE); labels = string_make(lower_case); m->selections = labels; /* 'I' is used for inspect in both keymaps. */ menu_dynamic_add_label(m, "Inspect", 'I', MENU_VALUE_INSPECT, labels); if (obj_can_browse(o_ptr)) { if (obj_can_cast_from(o_ptr) && player_can_cast(p_ptr, FALSE)) { ADD_LABEL("Cast", CMD_CAST, MN_ROW_VALID); } if (obj_can_study(o_ptr) && player_can_study(p_ptr, FALSE)) { cmd_code study_cmd = player_has(PF_CHOOSE_SPELLS) ? CMD_STUDY_SPELL : CMD_STUDY_BOOK; /* Hack - Use the STUDY_BOOK command key so that we get the correct command key. */ cmdkey = cmd_lookup_key_unktrl(CMD_STUDY_BOOK, mode); menu_dynamic_add_label(m, "Study", cmdkey, study_cmd, labels); } if (player_can_read(p_ptr, FALSE)) { ADD_LABEL("Browse", CMD_BROWSE_SPELL, MN_ROW_VALID); } } else if (obj_is_useable(o_ptr)) { if (obj_is_wand(o_ptr)) { menu_row_validity_t valid = (obj_has_charges(o_ptr)) ? MN_ROW_VALID : MN_ROW_INVALID; ADD_LABEL("Aim", CMD_USE_WAND, valid); } else if (obj_is_rod(o_ptr)) { menu_row_validity_t valid = (obj_can_zap(o_ptr)) ? MN_ROW_VALID : MN_ROW_INVALID; ADD_LABEL("Zap", CMD_USE_ROD, valid); } else if (obj_is_staff(o_ptr)) { menu_row_validity_t valid = (obj_has_charges(o_ptr)) ? MN_ROW_VALID : MN_ROW_INVALID; ADD_LABEL("Use", CMD_USE_STAFF, valid); } else if (obj_is_scroll(o_ptr)) { menu_row_validity_t valid = (player_can_read(p_ptr, FALSE)) ? MN_ROW_VALID : MN_ROW_INVALID; ADD_LABEL("Read", CMD_READ_SCROLL, valid); } else if (obj_is_potion(o_ptr)) { ADD_LABEL("Quaff", CMD_QUAFF, MN_ROW_VALID); } else if (obj_is_food(o_ptr)) { ADD_LABEL("Eat", CMD_EAT, MN_ROW_VALID); } else if (obj_is_activatable(o_ptr)) { menu_row_validity_t valid = (slot >= INVEN_WIELD && obj_can_activate(o_ptr)) ? MN_ROW_VALID : MN_ROW_INVALID; ADD_LABEL("Activate", CMD_ACTIVATE, valid); } else if (obj_can_fire(o_ptr)) { ADD_LABEL("Fire", CMD_FIRE, MN_ROW_VALID); } else { ADD_LABEL("Use", CMD_USE_ANY, MN_ROW_VALID); } } if (obj_can_refill(o_ptr)) { ADD_LABEL("Refill", CMD_REFILL, MN_ROW_VALID); } if (slot >= INVEN_WIELD && obj_can_takeoff(o_ptr)) { ADD_LABEL("Take off", CMD_TAKEOFF, MN_ROW_VALID); } else if (slot < INVEN_WIELD && obj_can_wear(o_ptr)) { //if (obj_is_armor(o_ptr)) { // menu_dynamic_add(m, "Wear", 2); //} else { // menu_dynamic_add(m, "Wield", 2); //} ADD_LABEL("Equip", CMD_WIELD, MN_ROW_VALID); } if (slot >= 0) { if (!store_in_store || cave_shopnum(cave, p_ptr->py, p_ptr->px) == STORE_HOME) { ADD_LABEL("Drop", CMD_DROP, MN_ROW_VALID); if (o_ptr->number > 1) { /* 'D' is used for squelch in rogue keymap, so we'll just swap letters. */ cmdkey = (mode == KEYMAP_MODE_ORIG) ? 'D' : 'k'; menu_dynamic_add_label(m, "Drop All", cmdkey, MENU_VALUE_DROP_ALL, labels); } } } else { menu_row_validity_t valid = (inven_carry_okay(o_ptr)) ? MN_ROW_VALID : MN_ROW_INVALID; ADD_LABEL("Pick up", CMD_PICKUP, valid); } ADD_LABEL("Throw", CMD_THROW, MN_ROW_VALID); ADD_LABEL("Inscribe", CMD_INSCRIBE, MN_ROW_VALID); if (obj_has_inscrip(o_ptr)) { ADD_LABEL("Uninscribe", CMD_UNINSCRIBE, MN_ROW_VALID); } ADD_LABEL( (object_is_squelched(o_ptr) ? "Unignore" : "Ignore"), CMD_DESTROY, MN_ROW_VALID); /* work out display region */ r.width = (int)menu_dynamic_longest_entry(m) + 3 + 2; /* +3 for tag, 2 for pad */ r.col = Term->wid - r.width - 1; r.row = 1; r.page_rows = m->count; area.width = -(r.width + 2); /* Hack -- no flush needed */ msg_flag = FALSE; screen_save(); /* Display info */ tb = object_info(o_ptr, OINFO_NONE); object_desc(header, sizeof(header), o_ptr, ODESC_PREFIX | ODESC_FULL); textui_textblock_place(tb, area, format("%s", header)); textblock_free(tb); menu_layout(m, &r); region_erase_bordered(&r); prt(format("(Enter to select, ESC) Command for %s:", header), 0, 0); selected = menu_dynamic_select(m); menu_dynamic_free(m); string_free(labels); screen_load(); cmdkey = cmd_lookup_key(selected, mode); switch (selected) { case -1: /* User cancelled the menu. */ return 3; case MENU_VALUE_INSPECT: /* copied from textui_obj_examine */ /* Display info */ tb = object_info(o_ptr, OINFO_NONE); object_desc(header, sizeof(header), o_ptr, ODESC_PREFIX | ODESC_FULL); textui_textblock_show(tb, area, format("%s", header)); textblock_free(tb); return 2; case MENU_VALUE_DROP_ALL: /* Drop entire stack with confirmation. */ if (get_check(format("Drop %s? ", header))) { cmd_insert(store_in_store ? CMD_STASH : CMD_DROP); cmd_set_arg_item(cmd_get_top(), 0, slot); cmd_set_arg_number(cmd_get_top(), 1, o_ptr->number); } return 1; case CMD_STUDY_SPELL: /* Hack - Use the STUDY_BOOK command key so that get_item_allow() works properly. */ cmdkey = cmd_lookup_key(CMD_STUDY_BOOK, mode); /* Fall through. */ case CMD_BROWSE_SPELL: case CMD_STUDY_BOOK: case CMD_CAST: case CMD_DESTROY: case CMD_WIELD: case CMD_TAKEOFF: case CMD_INSCRIBE: case CMD_UNINSCRIBE: case CMD_PICKUP: case CMD_DROP: case CMD_REFILL: case CMD_THROW: case CMD_USE_WAND: case CMD_USE_ROD: case CMD_USE_STAFF: case CMD_READ_SCROLL: case CMD_QUAFF: case CMD_EAT: case CMD_ACTIVATE: case CMD_FIRE: case CMD_USE_ANY: /* Check for inscriptions that trigger confirmation. */ allowed = key_confirm_command(cmdkey) && get_item_allow(slot, cmdkey, selected, FALSE); break; default: /* Invalid command; prevent anything from happening. */ bell("Invalid context menu command."); allowed = FALSE; break; } if (!allowed) return 1; if (selected == CMD_DESTROY) { /* squelch or unsquelch the item */ textui_cmd_destroy_menu(slot); } else if (selected == CMD_BROWSE_SPELL) { /* browse a spellbook */ /* copied from textui_spell_browse */ textui_book_browse(o_ptr); return 2; } else if (selected == CMD_STUDY_SPELL) { /* study a spell book */ /* copied from textui_obj_study */ int spell = get_spell(o_ptr, "study", spell_okay_to_study); if (spell >= 0) { cmd_insert(CMD_STUDY_SPELL); cmd_set_arg_choice(cmd_get_top(), 0, spell); } } else if (selected == CMD_CAST) { if (obj_can_browse(o_ptr)) { /* copied from textui_obj_cast */ const char *verb = ((p_ptr->class->spell_book == TV_MAGIC_BOOK) ? "cast" : "recite"); int spell = get_spell(o_ptr, verb, spell_okay_to_cast); if (spell >= 0) { cmd_insert(CMD_CAST); cmd_set_arg_choice(cmd_get_top(), 0, spell); } } } else {
int edit_text(char *buffer, int buflen) { int len = strlen(buffer); bool done = FALSE; int cursor = 0; while (!done) { int x, y; struct keypress ke; region area = { 1, HIST_INSTRUCT_ROW + 1, 71, 5 }; textblock *tb = textblock_new(); size_t *line_starts = NULL, *line_lengths = NULL; size_t n_lines; /* Display on screen */ clear_from(HIST_INSTRUCT_ROW); textblock_append(tb, buffer); textblock_append(tb, "\n"); /* XXX This shouldn't be necessary */ textui_textblock_place(tb, area, NULL); n_lines = textblock_calculate_lines(tb, &line_starts, &line_lengths, area.width); /* Set cursor to current editing position */ get_screen_loc(cursor, &x, &y, n_lines, line_starts, line_lengths); Term_gotoxy(1 + x, 19 + y); ke = inkey(); switch (ke.code) { case ESCAPE: return -1; case KC_ENTER: done = TRUE; break; case ARROW_LEFT: if (cursor > 0) cursor--; break; case ARROW_RIGHT: if (cursor < len) cursor++; break; case ARROW_DOWN: { int add = line_lengths[y] + 1; if (cursor + add < len) cursor += add; break; } case ARROW_UP: if (y > 0) { int up = line_lengths[y - 1] + 1; if (cursor - up >= 0) cursor -= up; } break; case KC_END: cursor = MAX(0, len); break; case KC_HOME: cursor = 0; break; case KC_BACKSPACE: case KC_DELETE: { /* Refuse to backspace into oblivion */ if ((ke.code == KC_BACKSPACE && cursor == 0) || (ke.code == KC_DELETE && cursor >= len)) break; /* Move the string from k to nul along to the left by 1 */ if (ke.code == KC_BACKSPACE) memmove(&buffer[cursor - 1], &buffer[cursor], len - cursor); else memmove(&buffer[cursor], &buffer[cursor + 1], len - cursor - 1); /* Decrement */ if (ke.code == KC_BACKSPACE) cursor--; len--; /* Terminate */ buffer[len] = '\0'; break; } default: { bool atnull = (buffer[cursor] == 0); if (!isprint(ke.code)) break; if (atnull) { /* Make sure we have enough room for a new character */ if ((cursor + 1) >= buflen) break; } else { /* Make sure we have enough room to add a new character */ if ((cursor + 1) >= buflen) break; /* Move the rest of the buffer along to make room */ memmove(&buffer[cursor + 1], &buffer[cursor], len - cursor); } /* Insert the character */ buffer[cursor++] = (char)ke.code; len++; /* Terminate */ buffer[len] = '\0'; break; } } textblock_free(tb); } return 0; }