Esempio n. 1
0
void drawMenuFlames(signed short flames[COLS][(ROWS + MENU_FLAME_ROW_PADDING)][3], unsigned char mask[COLS][ROWS]) {
	short i, j, versionStringLength;
	color tempColor = {0};
	const color *maskColor = &black;
    char dchar;
    
    versionStringLength = strLenWithoutEscapes(BROGUE_VERSION_STRING);
	
	for (j=0; j<ROWS; j++) {
		for (i=0; i<COLS; i++) {
            if (j == ROWS - 1 && i >= COLS - versionStringLength) {
                dchar = BROGUE_VERSION_STRING[i - (COLS - versionStringLength)];
            } else {
                dchar = ' ';
            }
            
			if (mask[i][j] == 100) {
				plotCharWithColor(dchar, i, j, &darkGray, maskColor);
			} else {
				tempColor = black;
				tempColor.red	= flames[i][j][0] / MENU_FLAME_PRECISION_FACTOR;
				tempColor.green	= flames[i][j][1] / MENU_FLAME_PRECISION_FACTOR;
				tempColor.blue	= flames[i][j][2] / MENU_FLAME_PRECISION_FACTOR;
				if (mask[i][j] > 0) {
					applyColorAverage(&tempColor, maskColor, mask[i][j]);
				}
				plotCharWithColor(dchar, i, j, &darkGray, &tempColor);
			}
		}
	}
}
Esempio n. 2
0
boolean dialogChooseFile(char *path, const char *suffix, const char *prompt) {
	short i, j, count, x, y, width, height, suffixLength, pathLength, maxPathLength, currentPageStart;
	brogueButton buttons[FILES_ON_PAGE_MAX + 2];
	fileEntry *files;
	boolean retval = false, again;
	cellDisplayBuffer dbuf[COLS][ROWS], rbuf[COLS][ROWS];
	color *dialogColor = &interfaceBoxColor;
	char *membuf;
	
	suffixLength = strlen(suffix);
	files = listFiles(&count, &membuf);
	copyDisplayBuffer(rbuf, displayBuffer);
	maxPathLength = strLenWithoutEscapes(prompt);
	
	// First, we want to filter the list by stripping out any filenames that do not end with suffix.
	// i is the entry we're testing, and j is the entry that we move it to if it qualifies.
	for (i=0, j=0; i<count; i++) {
		pathLength = strlen(files[i].path);
		//printf("\nString 1: %s", &(files[i].path[(max(0, pathLength - suffixLength))]));
		if (stringsExactlyMatch(&(files[i].path[(max(0, pathLength - suffixLength))]), suffix)) {
			
			// This file counts!
			if (i > j) {
				files[j] = files[i];
				//printf("\nMatching file: %s\twith date: %s", files[j].path, files[j].date);
			}
			j++;
			
			// Keep track of the longest length.
			if (min(pathLength, MAX_FILENAME_DISPLAY_LENGTH) + 10 > maxPathLength) {
				maxPathLength = min(pathLength, MAX_FILENAME_DISPLAY_LENGTH) + 10;
			}
		}
	}
	count = j;
	
	currentPageStart = 0;
	
	do { // Repeat to permit scrolling.
		again = false;
		
		for (i=0; i<min(count - currentPageStart, FILES_ON_PAGE_MAX); i++) {
			initializeButton(&(buttons[i]));
			buttons[i].flags &= ~(B_WIDE_CLICK_AREA | B_GRADIENT);
			buttons[i].buttonColor = *dialogColor;
            if (KEYBOARD_LABELS) {
                sprintf(buttons[i].text, "%c) ", 'a' + i);
            } else {
                buttons[i].text[0] = '\0';
            }
			strncat(buttons[i].text, files[currentPageStart+i].path, MAX_FILENAME_DISPLAY_LENGTH);
			
			// Clip off the file suffix from the button text.
			buttons[i].text[strlen(buttons[i].text) - suffixLength] = '\0'; // Snip!
			buttons[i].hotkey[0] = 'a' + i;
			buttons[i].hotkey[1] = 'A' + i;
			
			// Clip the filename length if necessary.
			if (strlen(buttons[i].text) > MAX_FILENAME_DISPLAY_LENGTH) {
				strcpy(&(buttons[i].text[MAX_FILENAME_DISPLAY_LENGTH - 3]), "...");
			}
			
			//printf("\nFound file: %s, with date: %s", files[currentPageStart+i].path, files[currentPageStart+i].date);
		}
		
		x = (COLS - maxPathLength) / 2;
		width = maxPathLength;
		height = min(count - currentPageStart, FILES_ON_PAGE_MAX) + 2;
		y = max(4, (ROWS - height) / 2);
		
		for (i=0; i<min(count - currentPageStart, FILES_ON_PAGE_MAX); i++) {
			pathLength = strlen(buttons[i].text);
			for (j=pathLength; j<(width - 8); j++) {
				buttons[i].text[j] = ' ';
			}
			buttons[i].text[j] = '\0';
			strcpy(&(buttons[i].text[j]), files[currentPageStart+i].date);
			buttons[i].x = x;
			buttons[i].y = y + 1 + i;
		}
		
		if (count > FILES_ON_PAGE_MAX) {
			// Create up and down arrows.
			initializeButton(&(buttons[i]));
			strcpy(buttons[i].text, "     *     ");
			buttons[i].symbol[0] = UP_ARROW_CHAR;
			if (currentPageStart <= 0) {
				buttons[i].flags &= ~(B_ENABLED | B_DRAW);
			} else {
				buttons[i].hotkey[0] = UP_ARROW;
				buttons[i].hotkey[1] = NUMPAD_8;
				buttons[i].hotkey[2] = PAGE_UP_KEY;
			}
			buttons[i].x = x + (width - 11)/2;
			buttons[i].y = y;
			
			i++;
			initializeButton(&(buttons[i]));
			strcpy(buttons[i].text, "     *     ");
			buttons[i].symbol[0] = DOWN_ARROW_CHAR;
			if (currentPageStart + FILES_ON_PAGE_MAX >= count) {
				buttons[i].flags &= ~(B_ENABLED | B_DRAW);
			} else {
				buttons[i].hotkey[0] = DOWN_ARROW;
				buttons[i].hotkey[1] = NUMPAD_2;
				buttons[i].hotkey[2] = PAGE_DOWN_KEY;
			}
			buttons[i].x = x + (width - 11)/2;
			buttons[i].y = y + i;
		}
		
		if (count) {
			clearDisplayBuffer(dbuf);
			printString(prompt, x, y - 1, &itemMessageColor, dialogColor, dbuf);
			rectangularShading(x - 1, y - 1, width + 1, height + 1, dialogColor, INTERFACE_OPACITY, dbuf);
			overlayDisplayBuffer(dbuf, NULL);
			
            //			for (j=0; j<min(count - currentPageStart, FILES_ON_PAGE_MAX); j++) {
            //				printf("\nSanity check BEFORE: %s, with date: %s", files[currentPageStart+j].path, files[currentPageStart+j].date);
            //				printf("\n   (button name)Sanity check BEFORE: %s", buttons[j].text);
            //			}
			
			i = buttonInputLoop(buttons,
								min(count - currentPageStart, FILES_ON_PAGE_MAX) + (count > FILES_ON_PAGE_MAX ? 2 : 0),
								x,
								y,
								width,
								height,
								NULL);
			
            //			for (j=0; j<min(count - currentPageStart, FILES_ON_PAGE_MAX); j++) {
            //				printf("\nSanity check AFTER: %s, with date: %s", files[currentPageStart+j].path, files[currentPageStart+j].date);
            //				printf("\n   (button name)Sanity check AFTER: %s", buttons[j].text);
            //			}
			
			overlayDisplayBuffer(rbuf, NULL);
			
			if (i < min(count - currentPageStart, FILES_ON_PAGE_MAX)) {
				if (i >= 0) {
					retval = true;
					strcpy(path, files[currentPageStart+i].path);
				} else { // i is -1
					retval = false;
				}
			} else if (i == min(count - currentPageStart, FILES_ON_PAGE_MAX)) { // Up arrow
				again = true;
				currentPageStart -= FILES_ON_PAGE_MAX;
			} else if (i == min(count - currentPageStart, FILES_ON_PAGE_MAX) + 1) { // Down arrow
				again = true;
				currentPageStart += FILES_ON_PAGE_MAX;
			}
		}
		
	} while (again);
	
	free(files);
	free(membuf);
	
	if (count == 0) {
		dialogAlert("No applicable files found.");
		return false;
	} else {
		return retval;
	}
}
Esempio n. 3
0
void drawMenuFlames(
	BROGUE_DRAW_CONTEXT *context, 
	signed short flames[COLS][(ROWS + MENU_FLAME_ROW_PADDING)][3]) {

	short i, j, versionStringLength;
    char dchar;
    
    versionStringLength = strLenWithoutEscapes(BROGUE_VERSION_STRING);
	
	for (j=0; j<ROWS; j++) {
		for (i=0; i<COLS; i++) {
            if (j == ROWS - 1 && i >= COLS - versionStringLength) {
                dchar = BROGUE_VERSION_STRING[i - (COLS - versionStringLength)];
            } else {
                dchar = ' ';
            }
            
			BrogueDrawContext_setForeground(
				context, colorForDisplay(darkGray));

			if (i < COLS - 1)
			{
				color ul, ur, bl, br;
				memset(&ul, 0, sizeof(color));
				memset(&ur, 0, sizeof(color));
				memset(&bl, 0, sizeof(color));
				memset(&br, 0, sizeof(color));

				ul.red = flames[i][j][0] / MENU_FLAME_PRECISION_FACTOR;
				ul.green = flames[i][j][1] / MENU_FLAME_PRECISION_FACTOR;
				ul.blue = flames[i][j][2] / MENU_FLAME_PRECISION_FACTOR;

				ur.red = flames[i + 1][j][0] / MENU_FLAME_PRECISION_FACTOR;
				ur.green = flames[i + 1][j][1] / MENU_FLAME_PRECISION_FACTOR;
				ur.blue = flames[i + 1][j][2] / MENU_FLAME_PRECISION_FACTOR;

				bl.red = flames[i][j + 1][0] / MENU_FLAME_PRECISION_FACTOR;
				bl.green = flames[i][j + 1][1] / MENU_FLAME_PRECISION_FACTOR;
				bl.blue = flames[i][j + 1][2] / MENU_FLAME_PRECISION_FACTOR;

				br.red = flames[i + 1][j + 1][0] / MENU_FLAME_PRECISION_FACTOR;
				br.green = flames[i + 1][j + 1][1] / MENU_FLAME_PRECISION_FACTOR;
				br.blue = flames[i + 1][j + 1][2] / MENU_FLAME_PRECISION_FACTOR;

				BrogueDrawContext_blendBackground(
					context, colorForDisplay(ul), colorForDisplay(ur),
					colorForDisplay(bl), colorForDisplay(br));
			}
			else
			{
				color upper, lower;

				upper.red = flames[i][j][0] / MENU_FLAME_PRECISION_FACTOR;
				upper.green = flames[i][j][1] / MENU_FLAME_PRECISION_FACTOR;
				upper.blue = flames[i][j][2] / MENU_FLAME_PRECISION_FACTOR;

				lower.red = flames[i][j + 1][0] / MENU_FLAME_PRECISION_FACTOR;
				lower.green = flames[i][j + 1][1] / MENU_FLAME_PRECISION_FACTOR;
				lower.blue = flames[i][j + 1][2] / MENU_FLAME_PRECISION_FACTOR;

				BrogueDrawContext_blendBackground(
					context, colorForDisplay(upper), colorForDisplay(upper),
					colorForDisplay(lower), colorForDisplay(lower));
			}

			BrogueDrawContext_drawChar(context, i, j, dchar);
		}
	}
}
Esempio n. 4
0
boolean dialogChooseFile(char *path, const char *suffix, const char *prompt) {
	short i, j, count, x, y, width, height, suffixLength, pathLength, maxPathLength, currentPageStart;
	brogueButton buttons[FILES_ON_PAGE_MAX + 2];
	fileEntry *files;
	boolean retval = false, again;
	color *dialogColor = &interfaceBoxColor;
	char *membuf;
	
	suffixLength = strlen(suffix);
	files = listFiles(&count, &membuf);
//	copyDisplayBuffer(rbuf, displayBuffer);
	maxPathLength = strLenWithoutEscapes(prompt);
	
	// First, we want to filter the list by stripping out any filenames that do not end with suffix.
	// i is the entry we're testing, and j is the entry that we move it to if it qualifies.
	for (i=0, j=0; i<count; i++) {
		pathLength = strlen(files[i].path);
		//printf("\nString 1: %s", &(files[i].path[(max(0, pathLength - suffixLength))]));
		if (stringsExactlyMatch(&(files[i].path[(max(0, pathLength - suffixLength))]), suffix)) {
			
			// This file counts!
			if (i > j) {
				files[j] = files[i];
				//printf("\nMatching file: %s\twith date: %s", files[j].path, files[j].date);
			}
			j++;
			
			// Keep track of the longest length.
			if (min(pathLength, MAX_FILENAME_DISPLAY_LENGTH) + 10 > maxPathLength) {
				maxPathLength = min(pathLength, MAX_FILENAME_DISPLAY_LENGTH) + 10;
			}
		}
	}
	count = j;
	
	currentPageStart = 0;
	
	do { // Repeat to permit scrolling.
		again = false;
		
		for (i=0; i<min(count - currentPageStart, FILES_ON_PAGE_MAX); i++) {
			initializeButton(&(buttons[i]));
			buttons[i].flags &= ~(B_WIDE_CLICK_AREA | B_GRADIENT);
			buttons[i].buttonColor = *dialogColor;
			sprintf(buttons[i].text, "%c)\t", 'a' + i);
			strncat(buttons[i].text, files[currentPageStart+i].path, MAX_FILENAME_DISPLAY_LENGTH);
			
			// Clip off the file suffix from the button text.
			buttons[i].text[strlen(buttons[i].text) - suffixLength] = '\0'; // Snip!
			buttons[i].hotkey[0] = 'a' + i;
			buttons[i].hotkey[1] = 'A' + i;
			
			// Clip the filename length if necessary.
			if (strlen(buttons[i].text) > MAX_FILENAME_DISPLAY_LENGTH) {
				strcpy(&(buttons[i].text[MAX_FILENAME_DISPLAY_LENGTH - 3]), "...");
			}
			
			//printf("\nFound file: %s, with date: %s", files[currentPageStart+i].path, files[currentPageStart+i].date);
		}
		
		x = (COLS - maxPathLength) / 2;
		width = maxPathLength;
		height = min(count - currentPageStart, FILES_ON_PAGE_MAX) + 5;
		y = max(4, (ROWS - height) / 2);
		
		for (i=0; i<min(count - currentPageStart, FILES_ON_PAGE_MAX); i++) {
			strcat(buttons[i].text, "\t");
			strcat(buttons[i].text, files[currentPageStart+i].date);
			buttons[i].x = 1;
			buttons[i].y = 3 + i;
			buttons[i].width = width;
		}
		
		if (count > FILES_ON_PAGE_MAX) {

			// Create up and down arrows.
			initializeButton(&(buttons[i]));
			strcpy(buttons[i].text, "     *     ");
			buttons[i].symbol[0] = UP_ARROW_CHAR;
			if (currentPageStart <= 0) {
				buttons[i].flags &= ~(B_ENABLED | B_DRAW);
			} else {
				buttons[i].hotkey[0] = UP_ARROW;
				buttons[i].hotkey[1] = NUMPAD_8;
				buttons[i].hotkey[2] = PAGE_UP_KEY;
			}
			buttons[i].x = (width - 11)/2;
			buttons[i].y = 2;
			
			i++;
			initializeButton(&(buttons[i]));
			strcpy(buttons[i].text, "     *     ");
			buttons[i].symbol[0] = DOWN_ARROW_CHAR;
			if (currentPageStart + FILES_ON_PAGE_MAX >= count) {
				buttons[i].flags &= ~(B_ENABLED | B_DRAW);
			} else {
				buttons[i].hotkey[0] = DOWN_ARROW;
				buttons[i].hotkey[1] = NUMPAD_2;
				buttons[i].hotkey[2] = PAGE_DOWN_KEY;
			}
			buttons[i].x = (width - 11)/2;
			buttons[i].y = 2 + i;
		}
		
		if (count) {
			BROGUE_WINDOW *root, *window;
			BROGUE_DRAW_CONTEXT *context;
			BROGUE_EFFECT *effect;
			int tabStops[2] = { 3, width - 8 }; 

			root = ioGetRoot();
			window = BrogueWindow_open(
				root, (COLS - width) / 2, (ROWS - height) / 2, 
				width, height);
			context = BrogueDrawContext_open(window);
			effect = BrogueEffect_open(context, BUTTON_EFFECT_NAME);

			BrogueWindow_setColor(window, windowColor);
			BrogueDrawContext_enableProportionalFont(context, 1);
			BrogueDrawContext_setTabStops(context, 2, tabStops);

			BrogueDrawContext_drawAsciiString(context, 1, 1, prompt);

//			for (j=0; j<min(count - currentPageStart, FILES_ON_PAGE_MAX); j++) {
//				printf("\nSanity check BEFORE: %s, with date: %s", files[currentPageStart+j].path, files[currentPageStart+j].date);
//				printf("\n   (button name)Sanity check BEFORE: %s", buttons[j].text);
//			}
			
			i = buttonInputLoop(buttons,
								min(count - currentPageStart, FILES_ON_PAGE_MAX) + (count > FILES_ON_PAGE_MAX ? 2 : 0),
								context, 
								effect, 
								x,
								y,
								width,
								height,
								NULL); 

			BrogueWindow_close(window);
			
//			for (j=0; j<min(count - currentPageStart, FILES_ON_PAGE_MAX); j++) {
//				printf("\nSanity check AFTER: %s, with date: %s", files[currentPageStart+j].path, files[currentPageStart+j].date);
//				printf("\n   (button name)Sanity check AFTER: %s", buttons[j].text);
//			}

			if (i < min(count - currentPageStart, FILES_ON_PAGE_MAX)) {
				if (i >= 0) {
					retval = true;
					strcpy(path, files[currentPageStart+i].path);
				} else { // i is -1
					retval = false;
				}
			} else if (i == min(count - currentPageStart, FILES_ON_PAGE_MAX)) { // Up arrow
				again = true;
				currentPageStart -= FILES_ON_PAGE_MAX;
			} else if (i == min(count - currentPageStart, FILES_ON_PAGE_MAX) + 1) { // Down arrow
				again = true;
				currentPageStart += FILES_ON_PAGE_MAX;
			}
		}
		
	} while (again);
	
	free(files);
	free(membuf);
	
	if (count == 0) {
		dialogAlert("找不到合适的文件。");
		return false;
	} else {
		return retval;
	}
}
Esempio n. 5
0
// Draws the button to the screen, or to a display buffer if one is given.
// Button back color fades from -50% intensity at the edges to the back color in the middle.
// Text is white, but can use color escapes.
//		Hovering highlight augments fore and back colors with buttonHoverColor by 20%.
//		Pressed darkens the middle color (or turns it the hover color if the button is black).
void drawButton(brogueButton *button, enum buttonDrawStates highlight, cellDisplayBuffer dbuf[COLS][ROWS]) {
	short i, textLoc, width, midPercent, symbolNumber, opacity, oldRNG;
	color fColor, bColor, fColorBase, bColorBase, bColorEdge, bColorMid;
	uchar displayCharacter;
	
	if (!(button->flags & B_DRAW)) {
		return;
	}
    //assureCosmeticRNG;
	oldRNG = rogue.RNG;
    rogue.RNG = RNG_COSMETIC;
    
	symbolNumber = 0;
	
	width = strLenWithoutEscapes(button->text);
	bColorBase = button->buttonColor;
	fColorBase = ((button->flags & B_ENABLED) ? white : gray);
	
	if (highlight == BUTTON_HOVER && (button->flags & B_HOVER_ENABLED)) {
		//applyColorAugment(&fColorBase, &buttonHoverColor, 20);
		//applyColorAugment(&bColorBase, &buttonHoverColor, 20);
		applyColorAverage(&fColorBase, &buttonHoverColor, 25);
		applyColorAverage(&bColorBase, &buttonHoverColor, 25);
	}
	
	bColorEdge	= bColorBase;
	bColorMid	= bColorBase;
	applyColorAverage(&bColorEdge, &black, 50);
	
	if (highlight == BUTTON_PRESSED) {
		applyColorAverage(&bColorMid, &black, 75);
		if (COLOR_DIFF(bColorMid, bColorBase) < 50) {
			bColorMid	= bColorBase;
			applyColorAverage(&bColorMid, &buttonHoverColor, 50);
		}
	}
	bColor = bColorMid;
	
	opacity = button->opacity;
	if (highlight == BUTTON_HOVER || highlight == BUTTON_PRESSED) {
		opacity = 100 - ((100 - opacity) * opacity / 100); // Apply the opacity twice.
	}
	
	for (i = textLoc = 0; i < width && i + button->x < COLS; i++, textLoc++) {
		while (button->text[textLoc] == COLOR_ESCAPE) {
			textLoc = decodeMessageColor(button->text, textLoc, &fColorBase);
		}
		
		fColor = fColorBase;
		
		if (button->flags & B_GRADIENT) {
            midPercent = smoothHiliteGradient(i, width - 1);
			bColor = bColorEdge;
			applyColorAverage(&bColor, &bColorMid, midPercent);
		}
		
		if (highlight == BUTTON_PRESSED) {
			applyColorAverage(&fColor, &bColor, 30);
		}
		
		if (button->opacity < 100) {
			applyColorAverage(&fColor, &bColor, 100 - opacity);
		}
		
		bakeColor(&fColor);
		bakeColor(&bColor);
		separateColors(&fColor, &bColor);
		
		displayCharacter = button->text[textLoc];
		if (button->text[textLoc] == '*') {
			if (button->symbol[symbolNumber]) {
				displayCharacter = button->symbol[symbolNumber];
			}
			symbolNumber++;
		}
		
		if (coordinatesAreInWindow(button->x + i, button->y)) {
			if (dbuf) {
				plotCharToBuffer(displayCharacter, button->x + i, button->y, &fColor, &bColor, dbuf);
				dbuf[button->x + i][button->y].opacity = opacity;
			} else {
				plotCharWithColor(displayCharacter, button->x + i, button->y, &fColor, &bColor);
			}
		}
	}
    restoreRNG;
}
Esempio n. 6
0
// Processes one round of user input, and bakes the necessary graphical changes into state->dbuf.
// Does NOT display the buttons or revert the display afterward.
// Assumes that the display has already been updated (via overlayDisplayBuffer(state->dbuf, NULL))
// and that input has been solicited (via nextBrogueEvent(event, ___, ___, ___)).
// Also relies on the buttonState having been initialized with initializeButtonState() or otherwise.
// Returns the index of a button if one is chosen.
// Otherwise, returns -1. That can be if the user canceled (in which case *canceled is true),
// or, more commonly, if the user's input in this particular split-second round was not decisive.
short processButtonInput(buttonState *state, boolean *canceled, rogueEvent *event) {
	short i, k, x, y;
	boolean buttonUsed = false;
	
	// Mouse event:
	if (event->eventType == MOUSE_DOWN
		|| event->eventType == MOUSE_UP
		|| event->eventType == MOUSE_ENTERED_CELL) {
		
		x = event->param1;
		y = event->param2;
		
		// Revert the button with old focus, if any.
		if (state->buttonFocused >= 0) {
			drawButton(&(state->buttons[state->buttonFocused]), BUTTON_NORMAL, state->dbuf);
			state->buttonFocused = -1;
		}
		
		// Find the button with new focus, if any.
		for (i=0; i < state->buttonCount; i++) {
			if ((state->buttons[i].flags & B_DRAW)
				&& (state->buttons[i].flags & B_ENABLED)
				&& (state->buttons[i].y == y || ((state->buttons[i].flags & B_WIDE_CLICK_AREA) && abs(state->buttons[i].y - y) <= 1))
				&& x >= state->buttons[i].x
				&& x < state->buttons[i].x + strLenWithoutEscapes(state->buttons[i].text)) {
				
				state->buttonFocused = i;
				if (event->eventType == MOUSE_DOWN) {
					state->buttonDepressed = i; // Keeps track of which button is down at the moment. Cleared on mouseup.
				}
				break;
			}
		}
		if (i == state->buttonCount) { // No focus this round.
			state->buttonFocused = -1;
		}
		
		if (state->buttonDepressed >= 0) {
			if (state->buttonDepressed == state->buttonFocused) {
				drawButton(&(state->buttons[state->buttonDepressed]), BUTTON_PRESSED, state->dbuf);
			}
		} else if (state->buttonFocused >= 0) {
			// If no button is depressed, then update the appearance of the button with the new focus, if any.
			drawButton(&(state->buttons[state->buttonFocused]), BUTTON_HOVER, state->dbuf);
		}
		
		// Mouseup:
		if (event->eventType == MOUSE_UP) {
			if (state->buttonDepressed == state->buttonFocused && state->buttonFocused >= 0) {
				// If a button is depressed, and the mouseup happened on that button, it has been chosen and we're done.
				buttonUsed = true;
			} else {
				// Otherwise, no button is depressed. If one was previously depressed, redraw it.
				if (state->buttonDepressed >= 0) {
					drawButton(&(state->buttons[state->buttonDepressed]), BUTTON_NORMAL, state->dbuf);
				} else if (!(x >= state->winX && x < state->winX + state->winWidth
							 && y >= state->winY && y < state->winY + state->winHeight)) {
					// Clicking outside of a button means canceling.
					if (canceled) {
						*canceled = true;
					}
				}
				
				if (state->buttonFocused >= 0) {
					// Buttons don't hover-highlight when one is depressed, so we have to fix that when the mouse is up.
					drawButton(&(state->buttons[state->buttonFocused]), BUTTON_HOVER, state->dbuf);
				}
				state->buttonDepressed = -1;
			}
		}
	}
	
	// Keystroke:
	if (event->eventType == KEYSTROKE) {
		
		// Cycle through all of the hotkeys of all of the buttons.
		for (i=0; i < state->buttonCount; i++) {
			for (k = 0; k < 10 && state->buttons[i].hotkey[k]; k++) {
				if (event->param1 == state->buttons[i].hotkey[k]) {
					// This button was chosen.
					
					if (state->buttons[i].flags & B_DRAW) {
						// Restore the depressed and focused buttons.
						if (state->buttonDepressed >= 0) {
							drawButton(&(state->buttons[state->buttonDepressed]), BUTTON_NORMAL, state->dbuf);
						}
						if (state->buttonFocused >= 0) {
							drawButton(&(state->buttons[state->buttonFocused]), BUTTON_NORMAL, state->dbuf);
						}
						
						// If the button likes to flash when keypressed:
						if (state->buttons[i].flags & B_KEYPRESS_HIGHLIGHT) {
							// Depress the chosen button.
							drawButton(&(state->buttons[i]), BUTTON_PRESSED, state->dbuf);
							
							// Update the display.
							overlayDisplayBuffer(state->rbuf, NULL);
							overlayDisplayBuffer(state->dbuf, NULL);
							
							// Wait for a little; then we're done.
							pauseBrogue(50);
						}
					}
					
					state->buttonDepressed = i;
					buttonUsed = true;
					break;
				}
			}
		}
		
		if (!buttonUsed
			&& (event->param1 == ESCAPE_KEY || event->param1 == ACKNOWLEDGE_KEY)) {
			// If the player pressed escape, we're done.
			if (canceled) {
				*canceled = true;
			}
		}
	}
	
	if (buttonUsed) {
		state->buttonChosen = state->buttonDepressed;
		return state->buttonChosen;
	} else {
		return -1;
	}
}