Пример #1
0
// Displays a bunch of buttons and collects user input.
// Returns the index number of the chosen button, or -1 if the user cancels.
// A window region is described by winX, winY, winWidth and winHeight.
// Clicking outside of that region will constitute canceling.
short buttonInputLoop(brogueButton *buttons,
					  short buttonCount,
					  short winX,
					  short winY,
					  short winWidth,
					  short winHeight,
					  rogueEvent *returnEvent) {
	short x, y, button; // (x, y) keeps track of the mouse location
	boolean canceled;
	rogueEvent theEvent;
	buttonState state = {0};
	
	assureCosmeticRNG;
	
	canceled = false;
	
	x = y = -1;
	
	initializeButtonState(&state, buttons, buttonCount, winX, winY, winWidth, winHeight);
	
//	short i, j;
//	for (i=0; i<COLS; i++) {
//		for (j=0; j<COLS; j++) {
//			if (i >= winX		&& i < winX + winWidth
//				&& j >= winY	&& j < winY + winHeight) {
//				plotCharWithColor(' ', i, j, &white, &gray);
//			}
//		}
//	}
	
	do {
		// Update the display.
		overlayDisplayBuffer(state.dbuf, NULL);
		
		// Get input.
		nextBrogueEvent(&theEvent, true, false, false);
		
		// Process the input.
		button = processButtonInput(&state, &canceled, &theEvent);
		
		// Revert the display.
		overlayDisplayBuffer(state.rbuf, NULL);
		
	} while (button == -1 && !canceled);
	
	if (returnEvent) {
		*returnEvent = theEvent;
	}
	
	//overlayDisplayBuffer(dbuf, NULL); // hangs around
	
	restoreRNG;
	
	return button;
}
Пример #2
0
// Displays a bunch of buttons and collects user input.
// Returns the index number of the chosen button, or -1 if the user cancels.
// A window region is described by winX, winY, winWidth and winHeight.
// Clicking outside of that region will constitute canceling.
short buttonInputLoop(brogueButton *buttons,
					  short buttonCount,
					  short winX,
					  short winY,
					  short winWidth,
					  short winHeight,
					  rogueEvent *returnEvent) {
	short x, y, button; // (x, y) keeps track of the mouse location
	boolean canceled;
	rogueEvent theEvent;
	buttonState state = {0};
	
	assureCosmeticRNG;
	
	canceled = false;
	x = y = -1;
	initializeButtonState(&state, buttons, buttonCount, winX, winY, winWidth, winHeight);
	
	do {
        // Update the display.
        overlayDisplayBuffer(state.dbuf, NULL);
		
		// Get input.
		nextBrogueEvent(&theEvent, true, false, false);
		
		// Process the input.
		button = processButtonInput(&state, &canceled, &theEvent);
		
		// Revert the display.
        overlayDisplayBuffer(state.rbuf, NULL);
		
	} while (button == -1 && !canceled);
	
	if (returnEvent) {
		*returnEvent = theEvent;
	}
	
	//overlayDisplayBuffer(dbuf, NULL); // hangs around
	
	restoreRNG;
	
	return button;
}
Пример #3
0
void dialogAlert(char *message) {
    cellDisplayBuffer rbuf[COLS][ROWS];
    
	brogueButton OKButton;
	initializeButton(&OKButton);
	strcpy(OKButton.text, "     OK     ");
	OKButton.hotkey[0] = RETURN_KEY;
	OKButton.hotkey[1] = ENTER_KEY;
	OKButton.hotkey[2] = ACKNOWLEDGE_KEY;
	printTextBox(message, COLS/3, ROWS/3, COLS/3, &white, &interfaceBoxColor, rbuf, &OKButton, 1);
    overlayDisplayBuffer(rbuf, NULL);
}
Пример #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;
	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;
	}
}
Пример #5
0
void titleMenu() {
	signed short flames[COLS][(ROWS + MENU_FLAME_ROW_PADDING)][3]; // red, green and blue
	signed short colorSources[MENU_FLAME_COLOR_SOURCE_COUNT][4]; // red, green, blue, and rand, one for each color source (no more than MENU_FLAME_COLOR_SOURCE_COUNT).
	color *colors[COLS][(ROWS + MENU_FLAME_ROW_PADDING)];
	unsigned char mask[COLS][ROWS];
	boolean controlKeyWasDown = false;
	
	short i, b, x, y, button;
	buttonState state;
	brogueButton buttons[6];
	char whiteColorEscape[10] = "";
	char goldColorEscape[10] = "";
	char newGameText[100] = "", customNewGameText[100] = "";
	rogueEvent theEvent;
	enum NGCommands buttonCommands[6] = {NG_NEW_GAME, NG_OPEN_GAME, NG_VIEW_RECORDING, NG_HIGH_SCORES, NG_QUIT};
	
	cellDisplayBuffer shadowBuf[COLS][ROWS];
	
	// Initialize the RNG so the flames aren't always the same.
	
	seedRandomGenerator(0);
	
	// Empty nextGamePath and nextGameSeed so that the buttons don't try to load an old game path or seed.
	rogue.nextGamePath[0] = '\0';
	rogue.nextGameSeed = 0;
	
	// Initialize the title menu buttons.
	encodeMessageColor(whiteColorEscape, 0, &white);
    encodeMessageColor(goldColorEscape, 0, KEYBOARD_LABELS ? &itemMessageColor : &white);
	sprintf(newGameText, "      %sN%sew Game      ", goldColorEscape, whiteColorEscape);
	sprintf(customNewGameText, " %sN%sew Game (custom) ", goldColorEscape, whiteColorEscape);
	b = 0;
	button = -1;
	
	initializeButton(&(buttons[b]));
	strcpy(buttons[b].text, newGameText);
	buttons[b].hotkey[0] = 'n';
	buttons[b].hotkey[1] = 'N';
	b++;
	
	initializeButton(&(buttons[b]));
	sprintf(buttons[b].text, "     %sO%spen Game      ", goldColorEscape, whiteColorEscape);
	buttons[b].hotkey[0] = 'o';
	buttons[b].hotkey[1] = 'O';
	b++;
	
	initializeButton(&(buttons[b]));
	sprintf(buttons[b].text, "   %sV%siew Recording   ", goldColorEscape, whiteColorEscape);
	buttons[b].hotkey[0] = 'v';
	buttons[b].hotkey[1] = 'V';
	b++;
	
	initializeButton(&(buttons[b]));
	sprintf(buttons[b].text, "    %sH%sigh Scores     ", goldColorEscape, whiteColorEscape);
	buttons[b].hotkey[0] = 'h';
	buttons[b].hotkey[1] = 'H';
	b++;
	
    // Seth:
/*	initializeButton(&(buttons[b]));
	sprintf(buttons[b].text, "        %sQ%suit        ", goldColorEscape, whiteColorEscape);
	buttons[b].hotkey[0] = 'q';
	buttons[b].hotkey[1] = 'Q';
	b++;*/
	
	x = COLS - 1 - 20 - 2;
	y = ROWS - 1;
	for (i = b-1; i >= 0; i--) {
		y -= 2;
		buttons[i].x = x;
		buttons[i].y = y;
		buttons[i].buttonColor = titleButtonColor;
		buttons[i].flags |= B_WIDE_CLICK_AREA;
	}
	
	blackOutScreen();
	clearDisplayBuffer(shadowBuf);
	initializeButtonState(&state, buttons, b, x, y, 20, b*2-1);
	rectangularShading(x, y, 20, b*2-1, &black, INTERFACE_OPACITY, shadowBuf);
	drawButtonsInState(&state);
    
	initializeMenuFlames(true, colors, colorSources, flames, mask);
    rogue.creaturesWillFlashThisTurn = false; // total unconscionable hack
	
	do {
		if (!controlKeyWasDown && controlKeyIsDown()) {
			strcpy(state.buttons[0].text, customNewGameText);
			drawButtonsInState(&state);
			buttonCommands[0] = NG_NEW_GAME_WITH_SEED;
			controlKeyWasDown = true;
		} else if (controlKeyWasDown && !controlKeyIsDown()) {
			strcpy(state.buttons[0].text, newGameText);
			drawButtonsInState(&state);
			buttonCommands[0] = NG_NEW_GAME;
			controlKeyWasDown = false;
		}
		
		// Update the display.
		updateMenuFlames(colors, colorSources, flames);
		drawMenuFlames(flames, mask);
		overlayDisplayBuffer(shadowBuf, NULL);
		overlayDisplayBuffer(state.dbuf, NULL);
		
		// Pause briefly.
		if (pauseBrogue(MENU_FLAME_UPDATE_DELAY)) {
			// There was input during the pause! Get the input.
			nextBrogueEvent(&theEvent, true, false, true);
			
			// Process the input.
			button = processButtonInput(&state, NULL, &theEvent);
		}
		
		// Revert the display.
		overlayDisplayBuffer(state.rbuf, NULL);
		
	} while (button == -1 && rogue.nextGame == NG_NOTHING);
	drawMenuFlames(flames, mask);
	if (button != -1) {
		rogue.nextGame = buttonCommands[button];
	}
}
Пример #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;
	}
}