UI Menu more or less done perfectly.
This commit is contained in:
1
lib/AudioFile
Submodule
1
lib/AudioFile
Submodule
Submodule lib/AudioFile added at bcb61a47e6
@ -16,7 +16,7 @@ void drawStateOverworld() {
|
||||
map_t *map = GAME.currentMap;
|
||||
if(map == NULL) return;
|
||||
|
||||
// Try get player
|
||||
// Draw the map, based on player position
|
||||
entity_t *player = mapEntityGetByType(map, ENTITY_TYPE_PLAYER);
|
||||
uint16_t cameraPositionX, cameraPositionY;
|
||||
if(player == NULL) {
|
||||
@ -27,14 +27,14 @@ void drawStateOverworld() {
|
||||
cameraPositionY = player->y;
|
||||
}
|
||||
|
||||
drawMap(
|
||||
GAME.currentMap,
|
||||
cameraPositionX, cameraPositionY,
|
||||
0, 0,
|
||||
FRAME_WIDTH, FRAME_HEIGHT
|
||||
);
|
||||
// drawMap(
|
||||
// GAME.currentMap,
|
||||
// cameraPositionX, cameraPositionY,
|
||||
// 0, 0,
|
||||
// FRAME_WIDTH, FRAME_HEIGHT
|
||||
// );
|
||||
|
||||
// Draw UI
|
||||
drawUITextbox();
|
||||
// drawUITextbox();
|
||||
drawUITestMenu();
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
#include "display/draw/drawtext.h"
|
||||
#include "ui/textbox.h"
|
||||
#include "ui/testmenu.h"
|
||||
#include "util/math.h"
|
||||
|
||||
void drawUIBox(
|
||||
const uint16_t x,
|
||||
@ -60,66 +61,134 @@ void drawUIBox(
|
||||
}
|
||||
|
||||
void drawUIMenu(
|
||||
const menu_t *menu,
|
||||
menu_t *menu,
|
||||
const uint16_t x,
|
||||
const uint16_t y,
|
||||
const uint16_t width,
|
||||
const char_t* strings[],
|
||||
const int16_t stringCount,
|
||||
const uint16_t height,
|
||||
const uint8_t cursorColor,
|
||||
const uint8_t textColor
|
||||
) {
|
||||
assertTrue(menu, "Menu cannot be NULL.");
|
||||
assertTrue(strings, "Strings cannot be NULL.");
|
||||
assertTrue(stringCount > 0, "String count must be greater than 0.");
|
||||
assertTrue(menu->rows > 0, "Rows must be greater than 0.");
|
||||
assertTrue(menu->columns > 0, "Columns must be greater than 0.");
|
||||
assertTrue(width*2 > menu->columns, "Width must be greater than columns.");
|
||||
|
||||
uint16_t stringWidth = (width / menu->columns) + 1;// +1 for cursor and padding
|
||||
uint16_t colWidth;
|
||||
uint16_t startingCol;
|
||||
uint16_t startingRow;
|
||||
uint16_t rowCount;
|
||||
uint16_t colCount;
|
||||
char_t *str;
|
||||
size_t i;
|
||||
|
||||
// Draw the menu
|
||||
for(uint16_t row = 0; row < menu->rows; row++) {
|
||||
for(uint16_t col = 0; col < menu->columns; col++) {
|
||||
// Determine the width of each column. This must include space for the cursor
|
||||
// and the text.
|
||||
if(menu->columns == 1 || rowCount == 0) {
|
||||
colWidth = width;
|
||||
colCount = 1;
|
||||
} else {
|
||||
size_t longestString = 0;
|
||||
i = 0;
|
||||
while(true) {
|
||||
str = menu->strings[i++];
|
||||
if(str == NULL) break;
|
||||
|
||||
size_t len = strlen(str);
|
||||
if(len > longestString) longestString = len;
|
||||
|
||||
// If we overrun the size of the box, we can stop looking.
|
||||
if((len+1) > width) {
|
||||
longestString = width;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// How many columns can we fit?
|
||||
uint16_t possibleColumnsAtThisWidth = width / (longestString + 1);
|
||||
|
||||
if(possibleColumnsAtThisWidth < menu->columns) {
|
||||
// We need to take a subset of the columns
|
||||
colWidth = width / possibleColumnsAtThisWidth;
|
||||
colCount = possibleColumnsAtThisWidth;
|
||||
} else {
|
||||
// We can fit all columns in
|
||||
colWidth = width / menu->columns;
|
||||
colCount = menu->columns;
|
||||
}
|
||||
|
||||
assertTrue(longestString != 0, "Longest string has length 0?");
|
||||
}
|
||||
|
||||
// Determine count of rows to render
|
||||
if(rowCount == 1) {
|
||||
rowCount = 1;
|
||||
} else {
|
||||
rowCount = mathMin(rowCount, height);
|
||||
}
|
||||
|
||||
// Where are we rendering from?
|
||||
startingCol = menu->renderOffsetX;
|
||||
|
||||
if(menu->x >= startingCol + colCount) {
|
||||
startingCol = (menu->x + 1) - colCount;
|
||||
} else if(menu->x < startingCol) {
|
||||
startingCol = menu->x;
|
||||
}
|
||||
|
||||
startingRow = menu->renderOffsetY;
|
||||
if(menu->y >= startingRow + rowCount) {
|
||||
startingRow = (menu->y + 1) - rowCount;
|
||||
} else if(menu->y < startingRow) {
|
||||
startingRow = menu->y;
|
||||
}
|
||||
|
||||
// Update back to the menu
|
||||
menu->renderOffsetX = startingCol;
|
||||
menu->renderOffsetY = startingRow;
|
||||
|
||||
for(uint16_t col = startingCol; col < startingCol+colCount; col++) {
|
||||
for(uint16_t row = startingRow; row < startingRow+rowCount; row++) {
|
||||
uint16_t index = (row * menu->columns) + col;
|
||||
if(index >= stringCount) break;
|
||||
if(menu->strings[index] == NULL) continue;
|
||||
|
||||
drawText(
|
||||
strings[index],
|
||||
-1,
|
||||
x + (col * stringWidth) + 1,
|
||||
y + row,
|
||||
menu->strings[index],
|
||||
colWidth,
|
||||
x + (colWidth * (col - startingCol)) + 1,
|
||||
y + (row - startingRow),
|
||||
textColor
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the cursor
|
||||
size_t i = (x + (menu->x * stringWidth)) + ((y + menu->y) * FRAME_WIDTH);
|
||||
i = (
|
||||
x + ((menu->x - startingCol) * colWidth)
|
||||
) + (
|
||||
(y + (menu->y - startingRow)) * FRAME_WIDTH
|
||||
);
|
||||
FRAME_BUFFER[i] = '>';
|
||||
FRAME_COLOR[i] = cursorColor;
|
||||
}
|
||||
|
||||
void drawUIMenuBox(
|
||||
const menu_t *menu,
|
||||
menu_t *menu,
|
||||
const uint16_t x,
|
||||
const uint16_t y,
|
||||
const uint16_t width,
|
||||
const uint16_t height,
|
||||
const char_t* strings[],
|
||||
const int16_t stringCount,
|
||||
const uint8_t cursorColor,
|
||||
const uint8_t textColor,
|
||||
const uint8_t boxColor
|
||||
) {
|
||||
drawUIBox(x, y, width, height, boxColor, true);
|
||||
|
||||
// drawUIMenu(
|
||||
// menu,
|
||||
// x + 1, y + 1, width - 2,
|
||||
// strings, stringCount,
|
||||
// cursorColor, textColor
|
||||
// );
|
||||
drawUIMenu(
|
||||
menu,
|
||||
x + 1, y + 1,
|
||||
width - 2, height - 2,
|
||||
cursorColor, textColor
|
||||
);
|
||||
}
|
||||
|
||||
void drawUITextbox() {
|
||||
@ -159,44 +228,10 @@ void drawUITextbox() {
|
||||
}
|
||||
|
||||
void drawUITestMenu() {
|
||||
const char_t* strings[] = {
|
||||
"Option 1",
|
||||
"Option 2",
|
||||
"Option 3",
|
||||
"Option 4",
|
||||
"Option 5",
|
||||
"Option 6",
|
||||
"Option 7",
|
||||
"Option 8",
|
||||
"Option 9",
|
||||
"Option 10",
|
||||
"Option 11",
|
||||
"Option 12",
|
||||
"Option 13",
|
||||
"Option 14",
|
||||
"Option 15",
|
||||
"Option 16",
|
||||
"Option 17",
|
||||
"Option 18",
|
||||
"Option 19",
|
||||
"Option 20",
|
||||
"Option 21",
|
||||
"Option 22",
|
||||
"Option 23",
|
||||
"Option 24",
|
||||
"Option 25",
|
||||
"Option 26",
|
||||
"Option 27",
|
||||
"Option 28",
|
||||
"Option 29",
|
||||
"Option 30"
|
||||
};
|
||||
|
||||
drawUIMenuBox(
|
||||
&TEST_MENU.menu,
|
||||
0, 0,
|
||||
FRAME_WIDTH, 5,
|
||||
strings, sizeof(strings) / sizeof(char_t*),
|
||||
COLOR_CYAN, COLOR_WHITE, COLOR_MAGENTA
|
||||
COLOR_CYAN, COLOR_RED, COLOR_WHITE
|
||||
);
|
||||
}
|
@ -40,19 +40,16 @@ void drawUIBox(
|
||||
* @param x The x position to draw the menu.
|
||||
* @param y The y position to draw the menu.
|
||||
* @param width The width of the menu.
|
||||
* @param strings The strings to draw in the menu.
|
||||
* @param stringCount The number of strings in the menu.
|
||||
* @param height The height of the menu.
|
||||
* @param cursorColor The color of the cursor.
|
||||
* @param textColor The color of the text.
|
||||
*/
|
||||
void drawUIMenu(
|
||||
const menu_t *menu,
|
||||
menu_t *menu,
|
||||
const uint16_t x,
|
||||
const uint16_t y,
|
||||
const uint16_t width,
|
||||
|
||||
const char_t* strings[],
|
||||
const int16_t stringCount,
|
||||
const uint16_t height,
|
||||
const uint8_t cursorColor,
|
||||
const uint8_t textColor
|
||||
);
|
||||
@ -65,20 +62,16 @@ void drawUIMenu(
|
||||
* @param y The y position to draw the menu.
|
||||
* @param width The width of the menu.
|
||||
* @param height The height of the menu.
|
||||
* @param strings The strings to draw in the menu.
|
||||
* @param stringCount The number of strings in the menu.
|
||||
* @param cursorColor The color of the cursor.
|
||||
* @param textColor The color of the text.
|
||||
* @param boxColor The color of the box.
|
||||
*/
|
||||
void drawUIMenuBox(
|
||||
const menu_t *menu,
|
||||
menu_t *menu,
|
||||
const uint16_t x,
|
||||
const uint16_t y,
|
||||
const uint16_t width,
|
||||
const uint16_t height,
|
||||
const char_t* strings[],
|
||||
const int16_t stringCount,
|
||||
const uint8_t cursorColor,
|
||||
const uint8_t textColor,
|
||||
const uint8_t boxColor
|
||||
|
@ -10,7 +10,11 @@
|
||||
#include "input.h"
|
||||
#include "game/time.h"
|
||||
|
||||
void menuInit(menu_t *menu, const uint16_t rows, const uint16_t columns) {
|
||||
void menuInit(
|
||||
menu_t *menu,
|
||||
const uint16_t columns,
|
||||
const uint16_t rows
|
||||
) {
|
||||
assertNotNull(menu, "Menu cannot be NULL.");
|
||||
assertTrue(rows > 0, "Rows must be greater than 0.");
|
||||
assertTrue(columns > 0, "Columns must be greater than 0.");
|
||||
@ -109,4 +113,15 @@ void menuPositionSet(menu_t *menu, const uint16_t x, const uint16_t y) {
|
||||
assertNotNull(menu, "Menu cannot be NULL.");
|
||||
menu->x = x % menu->columns;
|
||||
menu->y = y % menu->rows;
|
||||
|
||||
// Is there a string here?
|
||||
uint16_t index = (menu->y * menu->columns) + menu->x;
|
||||
if(menu->strings[index] == NULL) {
|
||||
if(menu->y == 0) {
|
||||
// idk yet
|
||||
menu->x = 0;
|
||||
} else {
|
||||
menu->y--;
|
||||
}
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@
|
||||
|
||||
#define MENU_HELD_TIME_INITIAL 0.5f
|
||||
#define MENU_HELD_TIME_REPEAT 0.2f
|
||||
#define MENU_ITEM_COUNT_MAX 256
|
||||
|
||||
typedef enum {
|
||||
MENU_DIRECTION_UP = 0,
|
||||
@ -22,6 +23,10 @@ typedef struct {
|
||||
uint16_t x, y;
|
||||
uint16_t rows, columns;
|
||||
float_t repeatHeld;
|
||||
const char_t* strings[MENU_ITEM_COUNT_MAX];
|
||||
|
||||
// Visual things
|
||||
uint16_t renderOffsetX, renderOffsetY;
|
||||
} menu_t;
|
||||
|
||||
/**
|
||||
|
@ -10,7 +10,30 @@
|
||||
testmenu_t TEST_MENU;
|
||||
|
||||
void testMenuInit() {
|
||||
menuInit(&TEST_MENU.menu, 3, 4);
|
||||
const char_t* strings[] = {
|
||||
"Option 1",
|
||||
"Option 2",
|
||||
"Option 3",
|
||||
"Option 4",
|
||||
"Option 5",
|
||||
"Option 6",
|
||||
"Option 7",
|
||||
"Option 8",
|
||||
"Option 9",
|
||||
"Option 10",
|
||||
"Option 11",
|
||||
"Option 12",
|
||||
"Option 13",
|
||||
"Option 14",
|
||||
"Option 15",
|
||||
"Option 16",
|
||||
"Option 17",
|
||||
};
|
||||
|
||||
uint16_t columns = 3;
|
||||
uint16_t rows = 6;
|
||||
menuInit(&TEST_MENU.menu, columns, rows);
|
||||
memcpy(TEST_MENU.menu.strings, strings, sizeof(strings));
|
||||
}
|
||||
|
||||
void testMenuUpdate() {
|
||||
|
Reference in New Issue
Block a user