/* * Run a menu. * * If popup is true, the screen is saved before the menu is drawn, and * restored afterwards. Each time a popup menu is redrawn, it resets the * screen before redrawing. */ ui_event menu_select(menu_type *menu, int notify, bool popup) { ui_event in = EVENT_EMPTY; ui_event out = EVENT_EMPTY; bool no_act = (menu->flags & MN_NO_ACTION) ? TRUE : FALSE; assert(menu->active.width != 0 && menu->active.page_rows != 0); notify |= (EVT_SELECT | EVT_ESCAPE); if (popup) { screen_save(); button_backup_all(TRUE); } /* Stop on first unhandled event */ //while (!(in.type & notify)) //while (!(in & notify)) while (!(in == EVT_SELECT) && !(in == EVT_ESCAPE)) { out = EVENT_EMPTY; menu_refresh(menu, popup); //in = inkey_ex(); in = inkey_m(); /* Handle mouse & keyboard commands */ //if (in.type == EVT_MOUSE) { if (in & 0x80) { //if (!no_act && menu_handle_action(menu, &in)) { // continue; //} //menu_handle_mouse(menu, &in, &out); if (in == EVT_RESIZE) { menu_calc_size(menu); if (menu->row_funcs->resize) menu->row_funcs->resize(menu); } else { if (!no_act && menu_handle_action(menu, &in)) { continue; } menu_handle_mouse(menu, &in, &out); } //} else if (in.type == EVT_KBRD) { } else { if (!no_act && menu->cmd_keys && //strchr(menu->cmd_keys, (char)in.key.code) && strchr(menu->cmd_keys, (char)in) && menu_handle_action(menu, &in)) continue; menu_handle_keypress(menu, &in, &out); }// else if (in.type == EVT_RESIZE) { // menu_calc_size(menu); // if (menu->row_funcs->resize) // menu->row_funcs->resize(menu); //} /* XXX should redraw menu here if cursor has moved */ /* if we requested it, send move events out */ if ((out == EVT_SELECT) && (menu->flags & MN_HANDLE_MOVE) && !no_act && menu_handle_action(menu, &out)) continue; /* If we've selected an item, then send that event out */ //if (out.type == EVT_SELECT && !no_act && menu_handle_action(menu, &out)) if ((out == EVT_SELECT) && !no_act && menu_handle_action(menu, &out)) continue; /* needed because EVT_* types are composed of multiple flags where in * angband they are one flag of an int, so the (notify & out) and * (!(in & notify)) is only true for particular EVT_* values */ /* Notify about the outgoing type */ //if (notify & out.type) { //if (notify & out) { if ((out == EVT_SELECT) || (out == EVT_ESCAPE)) { if (popup) { button_restore(); screen_load(); } return out; } } if (popup) { button_restore(); screen_load(); } return in; }
/* * Run multiple menus at the same time. * * If popup is true, the screen is saved before the menu is drawn, and * restored afterwards. Each time a popup menu is redrawn, it resets the * screen before redrawing. */ ui_event menu_select_multi(int *active, menu_type **menus, int num, int notify, bool popup) { ui_event in = EVENT_EMPTY; ui_event out = EVENT_EMPTY; bool no_act = FALSE; int i; assert(menus != NULL); assert(active != NULL); assert(num > 1); assert(*active < num); for (i = 0; i < num; i++) { assert(menus[i]->active.width != 0 && menus[i]->active.page_rows != 0); } notify |= (EVT_SELECT | EVT_ESCAPE); if (popup) { screen_save(); button_backup_all(TRUE); } /* Stop on first unhandled event */ //while (!(in.type & notify)) //while (!(in & notify)) while (!(in == EVT_SELECT) && !(in == EVT_ESCAPE)) { out = EVENT_EMPTY; if (popup) { button_restore(); screen_load(); screen_save(); button_backup_all(TRUE); } no_act = (menus[*active]->flags & MN_NO_ACTION) ? TRUE : FALSE; /* refresh all of the menus except the active one */ for (i = 0; i < num; i++) { if (i != *active) { menu_refresh(menus[i], FALSE); } } /* refresh the active menu */ menu_refresh(menus[*active], FALSE); //in = inkey_ex(); in = inkey_m(); /* Handle mouse & keyboard commands */ //if (in.type == EVT_MOUSE) { if (in & 0x80) { //if (!no_act && menu_handle_action(menu, &in)) { // continue; //} //menu_handle_mouse(menu, &in, &out); if (in == EVT_RESIZE) { /* resize all of the menus */ for (i = 0; i < num; i++) { menu_calc_size(menus[i]); if (menus[i]->row_funcs->resize) menus[i]->row_funcs->resize(menus[i]); } } else { int mx,my; char p; /* check which menu the click was in */ Term_peekmousepress(&p, &mx, &my); if (!rect_region_inside(&(menus[*active]->active), my, mx) ) { for (i = 0; i < num; i++) { if (rect_region_inside(&(menus[i]->active), my, mx)) { no_act = (menus[i]->flags & MN_NO_ACTION) ? TRUE : FALSE; *active = i; } } } /* handle the click in the active one */ if (!no_act && menu_handle_action(menus[*active], &in)) { continue; } menu_handle_mouse(menus[*active], &in, &out); } //} else if (in.type == EVT_KBRD) { } else { /* see if we need to move between menus */ /* handle the key press */ if (!no_act && menus[*active]->cmd_keys && //strchr(menu->cmd_keys, (char)in.key.code) && strchr(menus[*active]->cmd_keys, (char)in) && menu_handle_action(menus[*active], &in)) { continue; } menu_handle_keypress(menus[*active], &in, &out); }// else if (in.type == EVT_RESIZE) { // menu_calc_size(menu); // if (menu->row_funcs->resize) // menu->row_funcs->resize(menu); //} /* XXX should redraw menu here if cursor has moved */ /* if we requested it, send move events out */ if ((out == EVT_SELECT) && (menus[*active]->flags & MN_HANDLE_MOVE) && !no_act && menu_handle_action(menus[*active], &out)) continue; /* If we've selected an item, then send that event out */ //if (out.type == EVT_SELECT && !no_act && menu_handle_action(menu, &out)) if ((out == EVT_SELECT) && !no_act && menu_handle_action(menus[*active], &out)) continue; /* needed because EVT_* types are composed of multiple flags where in * angband they are one flag of an int, so the (notify & out) and * (!(in & notify)) is only true for particular EVT_* values */ /* Notify about the outgoing type */ //if (notify & out.type) { //if (notify & out) { if ((out == EVT_SELECT) || (out == EVT_ESCAPE)) { if (popup) { button_restore(); screen_load(); } return out; } } if (popup) { button_restore(); screen_load(); } return in; }
/* * Interactive group by. * Recognises inscriptions, graphical symbols, lore */ static void display_knowledge(const char *title, int *obj_list, int o_count, group_funcs g_funcs, member_funcs o_funcs, const char *otherfields) { /* maximum number of groups to display */ int max_group = g_funcs.maxnum < o_count ? g_funcs.maxnum : o_count; /* This could (should?) be (void **) */ int *g_list, *g_offset; const char **g_names; int g_name_len = 8; /* group name length, minumum is 8 */ int grp_cnt = 0; /* total number groups */ int g_cur = 0, grp_old = -1; /* group list positions */ int o_cur = 0; /* object list positions */ int g_o_count = 0; /* object count for group */ int oid = -1; /* object identifiers */ region title_area = { 0, 0, 0, 4 }; region group_region = { 0, 6, MISSING, -2 }; region object_region = { MISSING, 6, 0, -2 }; /* display state variables */ bool tiles = (current_graphics_mode != NULL); bool tile_picker = FALSE; bool glyph_picker = FALSE; byte attr_top = 0; byte char_left = 0; int delay = 0; menu_type group_menu; menu_type object_menu; menu_iter object_iter = { NULL, NULL, display_group_member, NULL, NULL }; /* Panel state */ /* These are swapped in parallel whenever the actively browsing " */ /* changes */ int *active_cursor = &g_cur, *inactive_cursor = &o_cur; menu_type *active_menu = &group_menu, *inactive_menu = &object_menu; int panel = 0; void *swapspace; bool do_swap = FALSE; bool flag = FALSE; bool redraw = TRUE; int browser_rows; int wid, hgt; int i; int prev_g = -1; int omode = OPT(rogue_like_commands); ui_event ke; /* Get size */ Term_get_size(&wid, &hgt); browser_rows = hgt - 8; /* Disable the roguelike commands for the duration */ OPT(rogue_like_commands) = FALSE; /* Determine if using tiles or not */ if (tiles) tiles = (current_graphics_mode->grafID != 0); if (g_funcs.gcomp) sort(obj_list, o_count, sizeof(*obj_list), g_funcs.gcomp); /* Sort everything into group order */ g_list = C_ZNEW(max_group + 1, int); g_offset = C_ZNEW(max_group + 1, int); for (i = 0; i < o_count; i++) { if (prev_g != g_funcs.group(obj_list[i])) { prev_g = g_funcs.group(obj_list[i]); g_offset[grp_cnt] = i; g_list[grp_cnt++] = prev_g; } } g_offset[grp_cnt] = o_count; g_list[grp_cnt] = -1; /* The compact set of group names, in display order */ g_names = C_ZNEW(grp_cnt, const char *); for (i = 0; i < grp_cnt; i++) { int len; g_names[i] = g_funcs.name(g_list[i]); len = strlen(g_names[i]); if (len > g_name_len) g_name_len = len; } /* Reasonable max group name len */ if (g_name_len >= 20) g_name_len = 20; object_region.col = g_name_len + 3; group_region.width = g_name_len; /* Leave room for the group summary information */ if (g_funcs.summary) object_region.page_rows = -3; /* Set up the two menus */ menu_init(&group_menu, MN_SKIN_SCROLL, menu_find_iter(MN_ITER_STRINGS)); menu_setpriv(&group_menu, grp_cnt, g_names); menu_layout(&group_menu, &group_region); menu_init(&object_menu, MN_SKIN_SCROLL, &object_iter); menu_setpriv(&object_menu, 0, &o_funcs); menu_layout(&object_menu, &object_region); o_funcs.is_visual = FALSE; /* Save screen */ screen_save(); clear_from(0); /* This is the event loop for a multi-region panel */ /* Panels are -- text panels, two menus, and visual browser */ /* with "pop-up menu" for lore */ while ((!flag) && (grp_cnt)) { bool recall = FALSE; if (redraw) { /* Print the title bits */ region_erase(&title_area); prt(format("Knowledge - %s", title), 2, 0); prt("Group", 4, 0); prt("Name", 4, g_name_len + 3); if (otherfields) prt(otherfields, 4, 46); /* Print dividers: horizontal and vertical */ for (i = 0; i < 79; i++) Term_putch(i, 5, TERM_WHITE, '='); for (i = 0; i < browser_rows; i++) Term_putch(g_name_len + 1, 6 + i, TERM_WHITE, '|'); /* Reset redraw flag */ redraw = FALSE; } if (g_cur != grp_old) { grp_old = g_cur; o_cur = 0; g_o_count = g_offset[g_cur + 1] - g_offset[g_cur]; menu_set_filter(&object_menu, obj_list + g_offset[g_cur], g_o_count); group_menu.cursor = g_cur; object_menu.cursor = 0; } /* HACK ... */ if (!(tile_picker || glyph_picker)) { /* ... The object menu may be browsing the entire group... */ o_funcs.is_visual = FALSE; menu_set_filter(&object_menu, obj_list + g_offset[g_cur], g_o_count); object_menu.cursor = o_cur; } else { /* ... or just a single element in the group. */ o_funcs.is_visual = TRUE; menu_set_filter(&object_menu, obj_list + o_cur + g_offset[g_cur], 1); object_menu.cursor = 0; } oid = obj_list[g_offset[g_cur] + o_cur]; /* Print prompt */ { const char *pedit = (!o_funcs.xattr) ? "" : (!(attr_idx | char_idx) ? ", 'c' to copy" : ", 'c', 'p' to paste"); const char *xtra = o_funcs.xtra_prompt ? o_funcs.xtra_prompt(oid) : ""; const char *pvs = ""; if (tile_picker) pvs = ", ENTER to accept"; else if (glyph_picker) pvs = ", 'i' to insert, ENTER to accept"; else if (o_funcs.xattr) pvs = ", 'v' for visuals"; prt(format("<dir>%s%s%s, ESC", pvs, pedit, xtra), hgt - 1, 0); } if (do_swap) { do_swap = FALSE; swap(active_menu, inactive_menu); swap(active_cursor, inactive_cursor); panel = 1 - panel; } if (g_funcs.summary && !tile_picker && !glyph_picker) { g_funcs.summary(g_cur, obj_list, g_o_count, g_offset[g_cur], object_menu.active.row + object_menu.active.page_rows, object_region.col); } menu_refresh(inactive_menu, FALSE); menu_refresh(active_menu, FALSE); handle_stuff(p_ptr); if (tile_picker) { bigcurs = TRUE; display_tiles(g_name_len + 3, 7, browser_rows - 1, wid - (g_name_len + 3), attr_top, char_left); place_tile_cursor(g_name_len + 3, 7, *o_funcs.xattr(oid), (byte) * o_funcs.xchar(oid), attr_top, char_left); } if (glyph_picker) { display_glyphs(g_name_len + 3, 7, browser_rows - 1, wid - (g_name_len + 3), *o_funcs.xattr(oid), *o_funcs.xchar(oid)); } if (delay) { /* Force screen update */ Term_fresh(); /* Delay */ Term_xtra(TERM_XTRA_DELAY, delay); delay = 0; } ke = inkey_ex(); if (!tile_picker && !glyph_picker) { ui_event ke0 = EVENT_EMPTY; if (ke.type == EVT_MOUSE) menu_handle_mouse(active_menu, &ke, &ke0); else if (ke.type == EVT_KBRD) menu_handle_keypress(active_menu, &ke, &ke0); if (ke0.type != EVT_NONE) ke = ke0; } /* XXX Do visual mode command if needed */ if (o_funcs.xattr && o_funcs.xchar) { if (tiles) { if (tile_picker_command(ke, &tile_picker, browser_rows - 1, wid - (g_name_len + 3), &attr_top, &char_left, o_funcs.xattr(oid), (byte *) o_funcs.xchar(oid), g_name_len + 3, 7, &delay)) continue; } else { if (glyph_command(ke, &glyph_picker, browser_rows - 1, wid - (g_name_len + 3), o_funcs.xattr(oid), o_funcs.xchar(oid), g_name_len + 3, 7)) continue; } } switch (ke.type) { case EVT_KBRD: { if (ke.key.code == 'r' || ke.key.code == 'R') recall = TRUE; else if (o_funcs.xtra_act) o_funcs.xtra_act(ke.key, oid); break; } case EVT_MOUSE: { /* Change active panels */ if (region_inside(&inactive_menu->boundary, &ke)) { swap(active_menu, inactive_menu); swap(active_cursor, inactive_cursor); panel = 1 - panel; } continue; } case EVT_ESCAPE: { if (panel == 1) do_swap = TRUE; else flag = TRUE; break; } case EVT_SELECT: { if (panel == 0) do_swap = TRUE; else if (panel == 1 && oid >= 0 && o_cur == active_menu->cursor) recall = TRUE; break; } case EVT_MOVE: { *active_cursor = active_menu->cursor; break; } default: { break; } } /* Recall on screen */ if (recall) { if (oid >= 0) o_funcs.lore(oid); redraw = TRUE; } } /* Restore roguelike option */ OPT(rogue_like_commands) = omode; /* Prompt */ if (!grp_cnt) prt(format("No %s known.", title), 15, 0); FREE(g_names); FREE(g_offset); FREE(g_list); screen_load(); }