Added basic message boxes

This commit is contained in:
Adubbz 2018-03-03 20:53:42 +11:00 committed by plutoo
parent bec1047ab9
commit e93a484e86
12 changed files with 303 additions and 30 deletions

View File

@ -9,7 +9,7 @@ endef
test : pc_main/main.cpp pc_main/pc_launch.c \
common/menu.c common/font.c common/language.c common/launch.c \
common/menu-entry.c common/menu-list.c common/text.c \
common/menu-entry.c common/menu-list.c common/message-box.c common/text.c \
common/nanojpeg.c common/ui.c common/math.c common/theme.c \
build_pc/tahoma24.o build_pc/tahoma12.o build_pc/interuimedium20.o build_pc/interuimedium30.o \
build_pc/interuiregular14.o build_pc/interuiregular18.o \

View File

@ -137,3 +137,4 @@ static inline color_t FetchPixelColor(uint32_t x, uint32_t y)
void DrawPixel(uint32_t x, uint32_t y, color_t clr);
void DrawText(const ffnt_header_t* font, uint32_t x, uint32_t y, color_t clr, const char* text);
void DrawTextTruncate(const ffnt_header_t* font, uint32_t x, uint32_t y, color_t clr, const char* text, uint32_t max_width, const char* end_text);
void GetTextDimensions(const ffnt_header_t* font, const char* text, uint32_t* width_out, uint32_t* height_out);

View File

@ -166,3 +166,35 @@ void DrawTextTruncate(const ffnt_header_t* font, uint32_t x, uint32_t y, color_t
{
DrawText_(font, x, y, clr, text, max_width, end_text);
}
void GetTextDimensions(const ffnt_header_t* font, const char* text, uint32_t* width_out, uint32_t* height_out)
{
uint32_t x = 0;
uint32_t width = 0, height = 0;
while (*text)
{
glyph_t glyph;
uint32_t codepoint = DecodeUTF8(&text);
if (codepoint == '\n')
{
x = 0;
height += font->height;
continue;
}
if (!FontLoadGlyph(&glyph, font, codepoint))
{
if (!FontLoadGlyph(&glyph, font, '?'))
continue;
}
x += glyph.advance;
if (x > width)
width = x;
}
*width_out = width;
*height_out = height;
}

View File

@ -335,11 +335,21 @@ void menuEntryParseIcon(menuEntry_s* me) {
njDone();
me->icon_gfx_small = downscaleIcon(me->icon_gfx);
me->icon_gfx_small = downscaleImg(me->icon_gfx, 256, 256, 140, 140, IMAGE_MODE_RGB24);
}
uint8_t *downscaleIcon(const uint8_t *image) {
uint8_t *out = (uint8_t*)malloc(140*140*3);
uint8_t *downscaleImg(const uint8_t *image, int srcWidth, int srcHeight, int destWidth, int destHeight, ImageMode mode) {
uint8_t *out;
switch (mode) {
case IMAGE_MODE_RGBA32:
out = (uint8_t*)malloc(destWidth*destHeight*4);
break;
default:
out = (uint8_t*)malloc(destWidth*destHeight*3);
break;
}
if (out == NULL) {
return NULL;
@ -348,13 +358,13 @@ uint8_t *downscaleIcon(const uint8_t *image) {
int tmpx, tmpy;
int pos;
float sourceX, sourceY;
int destWidth = 140, destHeight = 140;
float xScale = 256.0 / (float)destWidth;
float yScale = 256.0 / (float)destHeight;
float xScale = (float)srcWidth / (float)destWidth;
float yScale = (float)srcHeight / (float)destHeight;
int pixelX, pixelY;
uint8_t r1, r2, r3, r4;
uint8_t g1, g2, g3, g4;
uint8_t b1, b2, b3, b4;
uint8_t a1, a2, a3, a4;
float fx, fy, fx1, fy1;
int w1, w2, w3, w4;
@ -366,26 +376,57 @@ uint8_t *downscaleIcon(const uint8_t *image) {
pixelY = (int)sourceY;
// get colours from four surrounding pixels
pos = ((pixelY + 0) * 256 + pixelX + 0) * 3;
if (mode == IMAGE_MODE_RGBA32)
pos = ((pixelY + 0) * srcWidth + pixelX + 0) * 4;
else
pos = ((pixelY + 0) * srcWidth + pixelX + 0) * 3;
r1 = image[pos+0];
g1 = image[pos+1];
b1 = image[pos+2];
pos = ((pixelY + 0) * 256 + pixelX + 1) * 3;
if (mode == IMAGE_MODE_RGBA32)
a1 = image[pos+3];
if (mode == IMAGE_MODE_RGBA32)
pos = ((pixelY + 0) * srcWidth + pixelX + 1) * 4;
else
pos = ((pixelY + 0) * srcWidth + pixelX + 1) * 3;
r2 = image[pos+0];
g2 = image[pos+1];
b2 = image[pos+2];
pos = ((pixelY + 1) * 256 + pixelX + 0) * 3;
if (mode == IMAGE_MODE_RGBA32)
a2 = image[pos+3];
if (mode == IMAGE_MODE_RGBA32)
pos = ((pixelY + 1) * srcWidth + pixelX + 0) * 4;
else
pos = ((pixelY + 1) * srcWidth + pixelX + 0) * 3;
r3 = image[pos+0];
g3 = image[pos+1];
b3 = image[pos+2];
pos = ((pixelY + 1) * 256 + pixelX + 1) * 3;
if (mode == IMAGE_MODE_RGBA32)
a3 = image[pos+3];
if (mode == IMAGE_MODE_RGBA32)
pos = ((pixelY + 1) * srcWidth + pixelX + 1) * 4;
else
pos = ((pixelY + 1) * srcWidth + pixelX + 1) * 3;
r4 = image[pos+0];
g4 = image[pos+1];
b4 = image[pos+2];
if (mode == IMAGE_MODE_RGBA32)
a4 = image[pos+3];
// determine weights
fx = sourceX - pixelX;
fy = sourceY - pixelY;
@ -398,10 +439,17 @@ uint8_t *downscaleIcon(const uint8_t *image) {
w4 = (int)(fx*fy*256.0);
// set output pixels
if (mode == IMAGE_MODE_RGBA32)
pos = ((tmpy*destWidth) + tmpx) * 4;
else
pos = ((tmpy*destWidth) + tmpx) * 3;
out[pos+0] = (uint8_t)((r1 * w1 + r2 * w2 + r3 * w3 + r4 * w4) >> 8);
out[pos+1] = (uint8_t)((g1 * w1 + g2 * w2 + g3 * w3 + g4 * w4) >> 8);
out[pos+2] = (uint8_t)((b1 * w1 + b2 * w2 + b3 * w3 + b4 * w4) >> 8);
if (mode == IMAGE_MODE_RGBA32)
out[pos+3] = (uint8_t)((a1 * w1 + a2 * w2 + a3 * w3 + a4 * w4) >> 8);
}
}

View File

@ -104,7 +104,7 @@ int menuScan(const char* target) {
bool entrytype=0;
memset(tmp_path, 0, sizeof(tmp_path));
snprintf(tmp_path, sizeof(tmp_path)-1, "%s%s", s_menu[!s_curMenu].dirname, dp->d_name);
snprintf(tmp_path, sizeof(tmp_path)-1, "%s/%s", s_menu[!s_curMenu].dirname, dp->d_name);
#ifdef SWITCH
fsdev_dir_t* dirSt = (fsdev_dir_t*)dir->dirData->dirStruct;

View File

@ -14,11 +14,7 @@ void launchMenuEntryTask(menuEntry_s* arg)
launchMenuEntry(me);
}
typedef enum
{
IMAGE_MODE_RGB24,
IMAGE_MODE_RGBA32
} ImageMode;
//Draws an RGB888 or RGBA8888 image.
static void drawImage(int x, int y, int width, int height, const uint8_t *image, ImageMode mode) {
@ -47,7 +43,6 @@ static void drawImage(int x, int y, int width, int height, const uint8_t *image,
uint8_t *folder_icon_small;
uint8_t *invalid_icon_small;
double timer;
static void drawEntry(menuEntry_s* me, int off_x, int is_active) {
int x, y;
@ -73,7 +68,7 @@ static void drawEntry(menuEntry_s* me, int off_x, int is_active) {
int shadow_size = 4;
if (is_active) {
highlight_multiplier = fmax(0.0, fabs(fmod(timer, 1.0) - 0.5) / 0.5);
highlight_multiplier = fmax(0.0, fabs(fmod(menuTimer, 1.0) - 0.5) / 0.5);
border_color = MakeColor(themeCurrent.highlightColor.r + (255 - themeCurrent.highlightColor.r) * highlight_multiplier, themeCurrent.highlightColor.g + (255 - themeCurrent.highlightColor.g) * highlight_multiplier, themeCurrent.highlightColor.b + (255 - themeCurrent.highlightColor.b) * highlight_multiplier, 255);
border_start_x = start_x-6;
border_end_x = end_x+6;
@ -234,9 +229,10 @@ void menuStartup() {
menuScan(path);
folder_icon_small = downscaleIcon(folder_icon_bin);
invalid_icon_small = downscaleIcon(invalid_icon_bin);
folder_icon_small = downscaleImg(folder_icon_bin, 256, 256, 140, 140, IMAGE_MODE_RGB24);
invalid_icon_small = downscaleImg(invalid_icon_bin, 256, 256, 140, 140, IMAGE_MODE_RGB24);
computeFrontGradient(themeCurrent.frontWaveColor, 280);
//menuCreateMsgBox(780, 300, "This is a test");
}
color_t waveBlendAdd(color_t a, color_t b, float alpha) {
@ -316,7 +312,7 @@ void drawBackBtn(menu_s* menu, bool emptyDir) {
#endif
{
drawImage(x_image, 720 - 48, 32, 32, themeCurrent.buttonBImage, IMAGE_MODE_RGBA32);
DrawText(interuiregular18, x_text, 720 - 47, themeCurrent.textColor, textGetString(StrId_Actions_Back));
DrawText(interuimedium20, x_text, 720 - 47, themeCurrent.textColor, textGetString(StrId_Actions_Back));
}
}
@ -332,10 +328,10 @@ void menuLoop() {
}
}
drawWave(0, timer, themeCurrent.backWaveColor, 295, 0.0, 3.0);
drawWave(1, timer, themeCurrent.middleWaveColor, 290, 2.0, 3.5);
drawWave(2, timer, themeCurrent.frontWaveColor, 280, 4.0, -2.5);
timer += 0.05;
drawWave(0, menuTimer, themeCurrent.backWaveColor, 295, 0.0, 3.0);
drawWave(1, menuTimer, themeCurrent.middleWaveColor, 290, 2.0, 3.5);
drawWave(2, menuTimer, themeCurrent.frontWaveColor, 280, 4.0, -2.5);
menuTimer += 0.05;
drawImage(40, 20, 140, 60, themeCurrent.hbmenuLogoImage, IMAGE_MODE_RGBA32);
DrawText(interuiregular14, 180, 46, themeCurrent.textColor, VERSION);
@ -407,4 +403,6 @@ void menuLoop() {
drawBackBtn(menu, false);
}
menuDrawMsgBox();
}

View File

@ -50,12 +50,25 @@ struct menuEntry_s_tag
NacpStruct *nacp;
};
typedef enum
{
IMAGE_MODE_RGB24,
IMAGE_MODE_RGBA32
} ImageMode;
double menuTimer;
void menuCreateMsgBox(int width, int height, const char *text);
void menuCloseMsgBox();
bool menuIsMsgBoxOpen();
void menuDrawMsgBox(void);
void menuEntryInit(menuEntry_s* me, MenuEntryType type);
void menuEntryFree(menuEntry_s* me);
bool fileExists(const char* path);
bool menuEntryLoad(menuEntry_s* me, const char* name, bool shortcut);
void menuEntryParseIcon(menuEntry_s* me);
uint8_t *downscaleIcon(const uint8_t *image);
uint8_t *downscaleImg(const uint8_t *image, int srcWidth, int srcHeight, int destWidth, int destHeight, ImageMode mode);
void menuEntryParseNacp(menuEntry_s* me);
menu_s* menuGetCurrent(void);

171
common/message-box.c Normal file
View File

@ -0,0 +1,171 @@
#include "common.h"
typedef struct
{
uint32_t width;
uint32_t height;
color_t *bg;
const char *text;
} MessageBox;
MessageBox currMsgBox;
void drawMsgBoxBgToBuff(color_t *buff, int width, int height) {
int x, y;
int off;
int circle_center_x, circle_center_y;
int corner_size = 0;
float rad, alpha;
color_t base_color = MakeColor(255, 255, 255, 255);
color_t color;
for (y=0; y<height; y++) {
for (x=0; x<width; x++) {
if (corner_size > 0) {
if (x<corner_size && y<corner_size) { // top left corner
circle_center_x = corner_size-1;
circle_center_y = corner_size-1;
}
else if (x>width-corner_size && y<corner_size) { // top right corner
circle_center_x = width-corner_size;
circle_center_y = corner_size-1;
}
else if (x<corner_size && y>height-corner_size) { // bottom left corner
circle_center_x = corner_size-1;
circle_center_y = height-corner_size;
}
else if (x>width-corner_size && y>height-corner_size) { // bottom right corner
circle_center_x = width-corner_size;
circle_center_y = height-corner_size;
}
else {
circle_center_x = -1;
circle_center_y = -1;
}
if (circle_center_x == -1 && circle_center_y == -1) {
color = base_color;
}
else {
rad = sqrt(pow(circle_center_x - x, 2) + pow(circle_center_y - y, 2));
alpha = (float)corner_size - rad;
if (rad < corner_size) {
if (alpha < 1.0) {
color = MakeColor(base_color.r, base_color.g, base_color.b, base_color.a * alpha);
}
else
color = base_color;
}
else
color = MakeColor(0, 0, 0, 0);
}
}
else
color = base_color;
if (y == height - 80) {
color = themeCurrent.seperatorColor;
}
off = (y * width + x);
*((uint32_t *)&buff[off]) = color.r | (color.g<<8) | (color.b<<16) | (color.a<<24);
}
}
}
void menuDrawMsgBox() {
if (!menuIsMsgBoxOpen())
return;
int off;
int x, y;
int start_x = 1280 / 2 - currMsgBox.width / 2;
int start_y = 720 / 2 - currMsgBox.height / 2;
int end_x = start_x + currMsgBox.width;
uint32_t text_width, text_height;
color_t curr_color;
color_t border_color;
int sep_start_y = currMsgBox.height - 80;
int border_thickness = 6;
int shadow_start_y, shadow_y;
int shadow_inset;
int shadow_size = 4;
float highlight_multiplier = highlight_multiplier = fmax(0.0, fabs(fmod(menuTimer, 1.0) - 0.5) / 0.5);
color_t shadow_color;
uint8_t shadow_alpha_base = 80;
border_color = MakeColor(themeCurrent.highlightColor.r + (255 - themeCurrent.highlightColor.r) * highlight_multiplier, themeCurrent.highlightColor.g + (255 - themeCurrent.highlightColor.g) * highlight_multiplier, themeCurrent.highlightColor.b + (255 - themeCurrent.highlightColor.b) * highlight_multiplier, 255);
// Darken the background
for (y=0; y<720; y++) {
for (x=0; x<1280; x++) {
DrawPixel(x, y, MakeColor(0, 0, 0, 100));
}
}
// Draw the message box background
for (y=0; y<currMsgBox.height; y++) {
for (x=0; x<currMsgBox.width; x++) {
off = (y * currMsgBox.width + x);
curr_color = currMsgBox.bg[off];
if (((x<border_thickness || x>=currMsgBox.width-border_thickness) && y>sep_start_y) ||
(y>sep_start_y && y<=sep_start_y+border_thickness) || (y>=currMsgBox.height-border_thickness)) {
curr_color = border_color;
}
DrawPixel(start_x+x, start_y+y, curr_color);
}
}
GetTextDimensions(interuimedium20, currMsgBox.text, &text_width, &text_height);
if (text_width < currMsgBox.width && text_height < sep_start_y) {
DrawText(interuiregular18, start_x + (currMsgBox.width - text_width) / 2, start_y + (currMsgBox.height - text_height - 80) / 2, MakeColor(0, 0, 0, 255), currMsgBox.text);
}
DrawText(interuimedium20, start_x + 365, start_y + 245, MakeColor(0, 0, 0, 255), "OK");
shadow_start_y = start_y + currMsgBox.height;
for (shadow_y=shadow_start_y; shadow_y <shadow_start_y+shadow_size; shadow_y++) {
for (x=start_x; x<end_x; x++) {
shadow_color = MakeColor(0, 0, 0, shadow_alpha_base * (1.0 - (float)(shadow_y - shadow_start_y) / ((float)shadow_size)));
shadow_inset =(shadow_y-shadow_start_y);
if (x >= start_x + shadow_inset && x <= end_x - shadow_inset) {
DrawPixel(x, shadow_y, shadow_color);
}
}
}
}
void menuCreateMsgBox(int width, int height, const char *text) {
if (menuIsMsgBoxOpen())
return;
currMsgBox = (MessageBox) { width, height, NULL, text };
currMsgBox.bg = malloc(currMsgBox.width*currMsgBox.height*4);
if (currMsgBox.bg) {
drawMsgBoxBgToBuff(currMsgBox.bg, currMsgBox.width, currMsgBox.height);
}
}
bool menuIsMsgBoxOpen() {
return currMsgBox.width != 0 || currMsgBox.height != 0 || currMsgBox.bg || currMsgBox.text;
}
void menuCloseMsgBox() {
if (currMsgBox.bg) {
free(currMsgBox.bg);
currMsgBox.bg = NULL;
}
currMsgBox.width = currMsgBox.height = 0;
currMsgBox.text = NULL;
}

View File

@ -16,6 +16,7 @@ void themeStartup(ThemePreset preset) {
backWaveColor: MakeColor(154, 171, 255, 255),
backgroundColor: MakeColor(233, 236, 241, 255),
highlightColor: MakeColor(91, 237, 224, 255),
seperatorColor: MakeColor(219, 218, 219, 255),
enableWaveBlending: 0,
buttonAImage: button_a_light_bin,
buttonBImage: button_b_light_bin,
@ -31,6 +32,7 @@ void themeStartup(ThemePreset preset) {
backWaveColor: MakeColor(73, 103, 169, 255),
backgroundColor: MakeColor(45, 45, 50, 255),
highlightColor: MakeColor(91, 237, 224, 255),
seperatorColor: MakeColor(219, 218, 219, 255),
enableWaveBlending: 0,
buttonAImage: button_a_dark_bin,
buttonBImage: button_b_dark_bin,

View File

@ -10,6 +10,8 @@ typedef struct
color_t backWaveColor;
color_t backgroundColor;
color_t highlightColor;
color_t seperatorColor;
color_t activeColor;
bool enableWaveBlending;
const uint8_t *buttonAImage;
const uint8_t *buttonBImage;

View File

@ -80,7 +80,10 @@ bool menuUpdate(void) {
if (down & KEY_A)
{
if (menu->nEntries > 0)
if (menuIsMsgBoxOpen()) {
menuCloseMsgBox();
}
else if (menu->nEntries > 0)
{
int i;
menuEntry_s* me;

View File

@ -70,7 +70,10 @@ extern "C" bool menuUpdate(void) {
}
else if (!new_return_state && return_state)
{
if (menu->nEntries > 0)
if (menuIsMsgBoxOpen()) {
menuCloseMsgBox();
}
else if (menu->nEntries > 0)
{
int i;
menuEntry_s* me;