예제 #1
0
/* 
 * 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;
}
예제 #2
0
/* 
 * 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;
}
예제 #3
0
/*
 * 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();
}