From 0511d0a69e4e86f111cdd5bf60ad46f7bdb0ff5f Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 9 Jan 2016 00:54:18 -0800 Subject: [PATCH] GUI: Add icons and scrolling enhancements --- res/icons.png | Bin 0 -> 19426 bytes res/icons2x.png | Bin 0 -> 20032 bytes src/gba/gui/gui-runner.c | 6 +- src/platform/3ds/CMakeLists.txt | 6 ++ src/platform/3ds/gui-font.c | 55 ++++++++++++++++++- src/platform/3ds/main.c | 2 +- src/platform/psp2/CMakeLists.txt | 14 ++++- src/platform/psp2/gui-font.c | 50 +++++++++++++++++ src/platform/psp2/main.c | 2 +- src/platform/wii/CMakeLists.txt | 9 ++- src/platform/wii/gui-font.c | 91 +++++++++++++++++++++++++++++++ src/platform/wii/main.c | 4 +- src/util/gui.h | 4 +- src/util/gui/file-select.c | 8 +-- src/util/gui/font-metrics.c | 18 ++++++ src/util/gui/font-metrics.h | 1 + src/util/gui/font.c | 10 ++-- src/util/gui/font.h | 56 +++++++++++++++++-- src/util/gui/menu.c | 77 ++++++++++++++++++-------- 19 files changed, 360 insertions(+), 53 deletions(-) create mode 100644 res/icons.png create mode 100644 res/icons2x.png diff --git a/res/icons.png b/res/icons.png new file mode 100644 index 0000000000000000000000000000000000000000..719445152ad03ec44c7e5f8a3624a3ce2cf441be GIT binary patch literal 19426 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 O2WxYCvnY! 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.guiPrepare) { runner->params.guiPrepare(); } - GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Loading..."); + GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_ALIGN_HCENTER, 0xFFFFFFFF, "Loading..."); if (runner->params.guiFinish) { runner->params.guiFinish(); } @@ -216,7 +216,7 @@ void GBAGUIRun(struct GBAGUIRunner* runner, const char* path) { if (runner->params.guiPrepare) { runner->params.guiPrepare(); } - GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Load failed!"); + GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_ALIGN_HCENTER, 0xFFFFFFFF, "Load failed!"); if (runner->params.guiFinish) { runner->params.guiFinish(); } @@ -270,7 +270,7 @@ void GBAGUIRun(struct GBAGUIRunner* runner, const char* path) { if (runner->params.guiPrepare) { runner->params.guiPrepare(); } - GUIFontPrintf(runner->params.font, 0, GUIFontHeight(runner->params.font), GUI_TEXT_LEFT, 0x7FFFFFFF, "%.2f fps", runner->fps); + GUIFontPrintf(runner->params.font, 0, GUIFontHeight(runner->params.font), GUI_ALIGN_LEFT, 0x7FFFFFFF, "%.2f fps", runner->fps); if (runner->params.guiFinish) { runner->params.guiFinish(); } diff --git a/src/platform/3ds/CMakeLists.txt b/src/platform/3ds/CMakeLists.txt index d728f529d..dbc4480e9 100644 --- a/src/platform/3ds/CMakeLists.txt +++ b/src/platform/3ds/CMakeLists.txt @@ -28,6 +28,7 @@ set(CORE_VFS_SRC ${CORE_VFS_SRC} PARENT_SCOPE) set(OS_DEFINES ${OS_DEFINES} PARENT_SCOPE) list(APPEND GUI_SRC + ${CMAKE_CURRENT_BINARY_DIR}/icons.c ${CMAKE_CURRENT_BINARY_DIR}/font.c ${CMAKE_CURRENT_BINARY_DIR}/uishader.c ${CMAKE_CURRENT_BINARY_DIR}/uishader.h @@ -38,6 +39,7 @@ list(APPEND GUI_SRC ${CMAKE_CURRENT_SOURCE_DIR}/ctr-gpu.h) set_source_files_properties( + ${CMAKE_CURRENT_BINARY_DIR}/icons.c ${CMAKE_CURRENT_BINARY_DIR}/font.c ${CMAKE_CURRENT_BINARY_DIR}/uishader.c ${CMAKE_CURRENT_BINARY_DIR}/uishader.h @@ -59,6 +61,10 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/font.c COMMAND ${RAW2C} ${CMAKE_SOURCE_DIR}/src/platform/3ds/font.raw DEPENDS ${CMAKE_SOURCE_DIR}/src/platform/3ds/font.raw) +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icons.c + COMMAND ${RAW2C} ${CMAKE_SOURCE_DIR}/src/platform/3ds/icons.raw + DEPENDS ${CMAKE_SOURCE_DIR}/src/platform/3ds/icons.raw) + add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin.h MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/uishader.vsh diff --git a/src/platform/3ds/gui-font.c b/src/platform/3ds/gui-font.c index 8afb69e03..1b3e483ec 100644 --- a/src/platform/3ds/gui-font.c +++ b/src/platform/3ds/gui-font.c @@ -7,8 +7,9 @@ #include "util/gui/font-metrics.h" #include "util/png-io.h" #include "util/vfs.h" +#include "platform/3ds/ctr-gpu.h" +#include "icons.h" #include "font.h" -#include "ctr-gpu.h" #define CELL_HEIGHT 16 #define CELL_WIDTH 16 @@ -16,6 +17,7 @@ struct GUIFont { struct ctrTexture texture; + struct ctrTexture icons; }; struct GUIFont* GUIFontCreate(void) { @@ -35,11 +37,23 @@ struct GUIFont* GUIFontCreate(void) { GX_RequestDma((u32*) font, tex->data, font_size); gspWaitForDMA(); + tex = &guiFont->icons; + ctrTexture_Init(tex); + tex->data = vramAlloc(256 * 64 * 2); + tex->format = GPU_RGBA5551; + tex->width = 256; + tex->height = 64; + + GSPGPU_FlushDataCache(icons, icons_size); + GX_RequestDma((u32*) icons, tex->data, icons_size); + gspWaitForDMA(); + return guiFont; } void GUIFontDestroy(struct GUIFont* font) { vramFree(font->texture.data); + vramFree(font->icons.data); free(font); } @@ -71,3 +85,42 @@ void GUIFontDrawGlyph(const struct GUIFont* font, int glyph_x, int glyph_y, uint ctrAddRect(color, x, y, u, v, CELL_WIDTH, CELL_HEIGHT); } + +void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment align, enum GUIOrientation orient, uint32_t color, enum GUIIcon icon) { + ctrActivateTexture(&font->icons); + + if (icon >= GUI_ICON_MAX) { + return; + } + + struct GUIIconMetric metric = defaultIconMetrics[icon]; + switch (align & GUI_ALIGN_HCENTER) { + case GUI_ALIGN_HCENTER: + x -= metric.width / 2; + break; + case GUI_ALIGN_RIGHT: + x -= metric.width; + break; + } + switch (align & GUI_ALIGN_VCENTER) { + case GUI_ALIGN_VCENTER: + y -= metric.height / 2; + break; + case GUI_ALIGN_BOTTOM: + y -= metric.height; + break; + } + switch (orient) { + case GUI_ORIENT_HMIRROR: + ctrAddRectScaled(color, x + metric.width, y, -metric.width, metric.height, metric.x, metric.y, metric.width, metric.height); + break; + case GUI_ORIENT_VMIRROR: + ctrAddRectScaled(color, x, y + metric.height, metric.width, -metric.height, metric.x, metric.y, metric.width, metric.height); + break; + case GUI_ORIENT_0: + default: + // TODO: Rotation + ctrAddRect(color, x, y, metric.x, metric.y, metric.width, metric.height); + break; + } +} diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index 4b4c8448b..1aed46f87 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -410,7 +410,7 @@ static uint32_t _pollInput(void) { return keys; } -static enum GUICursorState _pollCursor(int* x, int* y) { +static enum GUICursorState _pollCursor(unsigned* x, unsigned* y) { hidScanInput(); if (!(hidKeysHeld() & KEY_TOUCH)) { return GUI_CURSOR_NOT_PRESENT; diff --git a/src/platform/psp2/CMakeLists.txt b/src/platform/psp2/CMakeLists.txt index cc1dfc01e..b374b61a3 100644 --- a/src/platform/psp2/CMakeLists.txt +++ b/src/platform/psp2/CMakeLists.txt @@ -19,8 +19,14 @@ set(OBJCOPY_CMD ${OBJCOPY} -I binary -O elf32-littlearm -B arm) list(APPEND GUI_SRC ${CMAKE_CURRENT_SOURCE_DIR}/gui-font.c) -set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/font.o ${CMAKE_CURRENT_BINARY_DIR}/backdrop.o PROPERTIES GENERATED ON) -add_executable(${BINARY_NAME}.elf ${PLATFORM_SRC} ${GUI_SRC} ${CMAKE_CURRENT_BINARY_DIR}/font.o ${CMAKE_CURRENT_BINARY_DIR}/backdrop.o main.c) +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/icons.o + ${CMAKE_CURRENT_BINARY_DIR}/font.o + ${CMAKE_CURRENT_BINARY_DIR}/backdrop.o + PROPERTIES GENERATED ON) +add_executable(${BINARY_NAME}.elf ${PLATFORM_SRC} ${GUI_SRC} main.c + ${CMAKE_CURRENT_BINARY_DIR}/icons.o + ${CMAKE_CURRENT_BINARY_DIR}/font.o + ${CMAKE_CURRENT_BINARY_DIR}/backdrop.o) set_target_properties(${BINARY_NAME}.elf PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${OS_LIB}) @@ -28,6 +34,10 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/font.o COMMAND ${OBJCOPY_CMD} font2x.png ${CMAKE_CURRENT_BINARY_DIR}/font.o WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/res) +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icons.o + COMMAND ${OBJCOPY_CMD} icons2x.png ${CMAKE_CURRENT_BINARY_DIR}/icons.o + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/res) + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/backdrop.o COMMAND ${OBJCOPY_CMD} backdrop.png ${CMAKE_CURRENT_BINARY_DIR}/backdrop.o WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/src/platform/psp2/gui-font.c b/src/platform/psp2/gui-font.c index d3c5ccb87..5d23e67d2 100644 --- a/src/platform/psp2/gui-font.c +++ b/src/platform/psp2/gui-font.c @@ -13,9 +13,11 @@ #define GLYPH_HEIGHT 24 extern const uint8_t _binary_font2x_png_start[]; +extern const uint8_t _binary_icons2x_png_start[]; struct GUIFont { vita2d_texture* tex; + vita2d_texture* icons; }; struct GUIFont* GUIFontCreate(void) { @@ -24,11 +26,13 @@ struct GUIFont* GUIFontCreate(void) { return 0; } font->tex = vita2d_load_PNG_buffer(_binary_font2x_png_start); + font->icons = vita2d_load_PNG_buffer(_binary_icons2x_png_start); return font; } void GUIFontDestroy(struct GUIFont* font) { vita2d_free_texture(font->tex); + vita2d_free_texture(font->icons); free(font); } @@ -57,3 +61,49 @@ void GUIFontDrawGlyph(const struct GUIFont* font, int x, int y, uint32_t color, CELL_HEIGHT - (metric.padding.top + metric.padding.bottom) * 2, 1, 1, color); } + +void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment align, enum GUIOrientation orient, uint32_t color, enum GUIIcon icon) { + if (icon >= GUI_ICON_MAX) { + return; + } + struct GUIIconMetric metric = defaultIconMetrics[icon]; + switch (align & GUI_ALIGN_HCENTER) { + case GUI_ALIGN_HCENTER: + x -= metric.width; + break; + case GUI_ALIGN_RIGHT: + x -= metric.width * 2; + break; + } + switch (align & GUI_ALIGN_VCENTER) { + case GUI_ALIGN_VCENTER: + y -= metric.height; + break; + case GUI_ALIGN_BOTTOM: + y -= metric.height * 2; + break; + } + + switch (orient) { + case GUI_ORIENT_HMIRROR: + vita2d_draw_texture_tint_part_scale(font->icons, x, y, + metric.x * 2, metric.y * 2, + metric.width * 2, metric.height * 2, + -1, 1, color); + return; + case GUI_ORIENT_VMIRROR: + vita2d_draw_texture_tint_part_scale(font->icons, x, y, + metric.x * 2, metric.y * 2, + metric.width * 2, metric.height * 2, + 1, -1, color); + return; + case GUI_ORIENT_0: + default: + // TOOD: Rotate + vita2d_draw_texture_tint_part(font->icons, x, y, + metric.x * 2, metric.y * 2, + metric.width * 2, metric.height * 2, + color); + break; + } +} diff --git a/src/platform/psp2/main.c b/src/platform/psp2/main.c index 9282cbcdb..3c8fd30a3 100644 --- a/src/platform/psp2/main.c +++ b/src/platform/psp2/main.c @@ -72,7 +72,7 @@ static uint32_t _pollInput(void) { return input; } -static enum GUICursorState _pollCursor(int* x, int* y) { +static enum GUICursorState _pollCursor(unsigned* x, unsigned* y) { SceTouchData touch; sceTouchPeek(0, &touch, 1); if (touch.reportNum < 1) { diff --git a/src/platform/wii/CMakeLists.txt b/src/platform/wii/CMakeLists.txt index 7e50df6d7..b72ac2d5c 100644 --- a/src/platform/wii/CMakeLists.txt +++ b/src/platform/wii/CMakeLists.txt @@ -15,7 +15,7 @@ source_group("Wii-specific code" FILES ${OS_SRC}) set(CORE_VFS_SRC ${CORE_VFS_SRC} PARENT_SCOPE) set(OS_DEFINES ${OS_DEFINES} PARENT_SCOPE) -list(APPEND GUI_SRC ${CMAKE_CURRENT_BINARY_DIR}/font.c ${CMAKE_CURRENT_SOURCE_DIR}/gui-font.c) +list(APPEND GUI_SRC ${CMAKE_CURRENT_BINARY_DIR}/font.c ${CMAKE_CURRENT_BINARY_DIR}/icons.c ${CMAKE_CURRENT_SOURCE_DIR}/gui-font.c) set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/font.c PROPERTIES GENERATED ON) add_executable(${BINARY_NAME}.elf ${GUI_SRC} main.c) @@ -24,7 +24,12 @@ target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${OS_LIB}) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/font.c COMMAND ${RAW2C} ${CMAKE_SOURCE_DIR}/src/platform/wii/font.tpl - MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/src/platform/wii/font.tpl + MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/src/platform/wii/font.tpl + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icons.c + COMMAND ${RAW2C} ${CMAKE_SOURCE_DIR}/src/platform/wii/icons.tpl + MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/src/platform/wii/icons.tpl WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) add_custom_target(${BINARY_NAME}.dol ALL diff --git a/src/platform/wii/gui-font.c b/src/platform/wii/gui-font.c index 1efe09e4e..731490e6a 100644 --- a/src/platform/wii/gui-font.c +++ b/src/platform/wii/gui-font.c @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "util/gui/font.h" #include "util/gui/font-metrics.h" +#include "icons.h" #include "font.h" #include @@ -16,6 +17,7 @@ struct GUIFont { TPLFile tdf; + TPLFile iconsTdf; }; struct GUIFont* GUIFontCreate(void) { @@ -32,11 +34,21 @@ struct GUIFont* GUIFontCreate(void) { } memcpy(fontTpl, font, font_size); TPL_OpenTPLFromMemory(&guiFont->tdf, fontTpl, font_size); + + void* iconsTpl = memalign(32, icons_size); + if (!iconsTpl) { + TPL_CloseTPLFile(&guiFont->tdf); + free(guiFont); + return 0; + } + memcpy(iconsTpl, icons, icons_size); + TPL_OpenTPLFromMemory(&guiFont->iconsTdf, iconsTpl, icons_size); return guiFont; } void GUIFontDestroy(struct GUIFont* font) { TPL_CloseTPLFile(&font->tdf); + TPL_CloseTPLFile(&font->iconsTdf); free(font); } @@ -89,3 +101,82 @@ void GUIFontDrawGlyph(const struct GUIFont* font, int x, int y, uint32_t color, GX_TexCoord2f32(tx / 512.f, (ty + CELL_HEIGHT - (metric.padding.top + metric.padding.bottom) * 2) / 256.f); GX_End(); } + +void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment align, enum GUIOrientation orient, uint32_t color, enum GUIIcon icon) { + if (icon >= GUI_ICON_MAX) { + return; + } + + color = (color >> 24) | (color << 8); + GXTexObj tex; + + struct GUIFont* ncfont = font; + TPL_GetTexture(&ncfont->iconsTdf, 0, &tex); + GX_LoadTexObj(&tex, GX_TEXMAP0); + + GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_NOOP); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + + struct GUIIconMetric metric = defaultIconMetrics[icon]; + switch (align & GUI_ALIGN_HCENTER) { + case GUI_ALIGN_HCENTER: + x -= metric.width; + break; + case GUI_ALIGN_RIGHT: + x -= metric.width * 2; + break; + } + switch (align & GUI_ALIGN_VCENTER) { + case GUI_ALIGN_VCENTER: + y -= metric.height; + break; + case GUI_ALIGN_BOTTOM: + y -= metric.height * 2; + break; + } + + float u[4]; + float v[4]; + + switch (orient) { + case GUI_ORIENT_0: + default: + // TODO: Rotations + u[0] = u[3] = metric.x / 256.f; + u[1] = u[2] = (metric.x + metric.width) / 256.f; + v[0] = v[1] = (metric.y + metric.height) / 64.f; + v[2] = v[3] = metric.y / 64.f; + break; + case GUI_ORIENT_HMIRROR: + u[0] = u[3] = (metric.x + metric.width) / 256.f; + u[1] = u[2] = metric.x / 256.f; + v[0] = v[1] = (metric.y + metric.height) / 64.f; + v[2] = v[3] = metric.y / 64.f; + break; + case GUI_ORIENT_VMIRROR: + u[0] = u[3] = metric.x / 256.f; + u[1] = u[2] = (metric.x + metric.width) / 256.f; + v[0] = v[1] = metric.y / 64.f; + v[2] = v[3] = (metric.y + metric.height) / 64.f; + break; + } + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position2s16(x, y + metric.height * 2); + GX_Color1u32(color); + GX_TexCoord2f32(u[0], v[0]); + + GX_Position2s16(x + metric.width * 2, y + metric.height * 2); + GX_Color1u32(color); + GX_TexCoord2f32(u[1], v[1]); + + GX_Position2s16(x + metric.width * 2, y); + GX_Color1u32(color); + GX_TexCoord2f32(u[2], v[2]); + + GX_Position2s16(x, y); + GX_Color1u32(color); + GX_TexCoord2f32(u[3], v[3]); + GX_End(); +} diff --git a/src/platform/wii/main.c b/src/platform/wii/main.c index bc5c2f7df..302a3c342 100644 --- a/src/platform/wii/main.c +++ b/src/platform/wii/main.c @@ -59,7 +59,7 @@ static int32_t _readGyroZ(struct GBARotationSource* source); static void _drawStart(void); static void _drawEnd(void); static uint32_t _pollInput(void); -static enum GUICursorState _pollCursor(int* x, int* y); +static enum GUICursorState _pollCursor(unsigned* x, unsigned* y); static void _guiPrepare(void); static void _guiFinish(void); @@ -467,7 +467,7 @@ static uint32_t _pollInput(void) { return keys; } -static enum GUICursorState _pollCursor(int* x, int* y) { +static enum GUICursorState _pollCursor(unsigned* x, unsigned* y) { ir_t ir; WPAD_IR(0, &ir); if (!ir.smooth_valid) { diff --git a/src/util/gui.h b/src/util/gui.h index 9d98cf4a8..e06205a82 100644 --- a/src/util/gui.h +++ b/src/util/gui.h @@ -59,7 +59,7 @@ struct GUIParams { void (*drawStart)(void); void (*drawEnd)(void); uint32_t (*pollInput)(void); - enum GUICursorState (*pollCursor)(int* x, int* y); + enum GUICursorState (*pollCursor)(unsigned* x, unsigned* y); int (*batteryState)(void); void (*guiPrepare)(void); void (*guiFinish)(void); @@ -78,7 +78,7 @@ struct GUIParams { void GUIInit(struct GUIParams* params); void GUIPollInput(struct GUIParams* params, uint32_t* newInput, uint32_t* heldInput); -enum GUICursorState GUIPollCursor(struct GUIParams* params, int* x, int* y); +enum GUICursorState GUIPollCursor(struct GUIParams* params, unsigned* x, unsigned* y); void GUIInvalidateKeys(struct GUIParams* params); #endif diff --git a/src/util/gui/file-select.c b/src/util/gui/file-select.c index 258307487..f13b5c86e 100644 --- a/src/util/gui/file-select.c +++ b/src/util/gui/file-select.c @@ -71,8 +71,8 @@ static bool _refreshDirectory(struct GUIParams* params, const char* currentPath, if (params->guiPrepare) { params->guiPrepare(); } - GUIFontPrintf(params->font, 0, GUIFontHeight(params->font), GUI_TEXT_LEFT, 0xFFFFFFFF, "(scanning for items: %zu)", i); - GUIFontPrintf(params->font, 0, GUIFontHeight(params->font) * 2, GUI_TEXT_LEFT, 0xFFFFFFFF, "%s", currentPath); + GUIFontPrintf(params->font, 0, GUIFontHeight(params->font), GUI_ALIGN_LEFT, 0xFFFFFFFF, "(scanning for items: %zu)", i); + GUIFontPrintf(params->font, 0, GUIFontHeight(params->font) * 2, GUI_ALIGN_LEFT, 0xFFFFFFFF, "%s", currentPath); if (params->guiFinish) { params->guiFinish(); } @@ -109,8 +109,8 @@ static bool _refreshDirectory(struct GUIParams* params, const char* currentPath, if (params->guiPrepare) { params->guiPrepare(); } - GUIFontPrintf(params->font, 0, GUIFontHeight(params->font), GUI_TEXT_LEFT, 0xFFFFFFFF, "(scanning item %zu of %zu)", i, items); - GUIFontPrintf(params->font, 0, GUIFontHeight(params->font) * 2, GUI_TEXT_LEFT, 0xFFFFFFFF, "%s", currentPath); + GUIFontPrintf(params->font, 0, GUIFontHeight(params->font), GUI_ALIGN_LEFT, 0xFFFFFFFF, "(scanning item %zu of %zu)", i, items); + GUIFontPrintf(params->font, 0, GUIFontHeight(params->font) * 2, GUI_ALIGN_LEFT, 0xFFFFFFFF, "%s", currentPath); if (params->guiFinish) { params->guiFinish(); } diff --git a/src/util/gui/font-metrics.c b/src/util/gui/font-metrics.c index 332339109..3430e3b4b 100644 --- a/src/util/gui/font-metrics.c +++ b/src/util/gui/font-metrics.c @@ -135,3 +135,21 @@ struct GUIFontGlyphMetric defaultFontMetrics[128] = { { 10, 5, { 5, 3, 6, 3 }}, // 0x7E "}" { 0, 0, { 0, 0, 0, 0 }}, // 0x7F }; + +struct GUIIconMetric defaultIconMetrics[] = { + [GUI_ICON_BATTERY_FULL] = { 0, 0, 32, 16 }, + [GUI_ICON_BATTERY_HIGH] = { 32, 0, 32, 16 }, + [GUI_ICON_BATTERY_HALF] = { 64, 0, 32, 16 }, + [GUI_ICON_BATTERY_LOW] = { 96, 0, 32, 16 }, + [GUI_ICON_BATTERY_EMPTY] = { 128, 0, 32, 16 }, + [GUI_ICON_SCROLLBAR_BUTTON] = { 6, 16, 4, 5 }, + [GUI_ICON_SCROLLBAR_TRACK] = { 23, 16, 2, 16 }, + [GUI_ICON_SCROLLBAR_THUMB] = { 38, 16, 4, 16 }, + [GUI_ICON_CURSOR] = { 48, 16, 16, 16 }, + [GUI_ICON_POINTER] = { 68, 20, 8, 8 }, + [GUI_ICON_BUTTON_CIRCLE] = { 2, 34, 12, 11 }, + [GUI_ICON_BUTTON_CROSS] = { 18, 34, 12, 11 }, + [GUI_ICON_BUTTON_TRIANGLE] = { 34, 34, 12, 11 }, + [GUI_ICON_BUTTON_SQUARE] = { 50, 34, 12, 11 }, + [GUI_ICON_BUTTON_HOME] = { 66, 34, 16, 16 }, +}; diff --git a/src/util/gui/font-metrics.h b/src/util/gui/font-metrics.h index 6ea1542a5..8cb3ffeb4 100644 --- a/src/util/gui/font-metrics.h +++ b/src/util/gui/font-metrics.h @@ -9,5 +9,6 @@ #include "util/gui/font.h" extern struct GUIFontGlyphMetric defaultFontMetrics[]; +extern struct GUIIconMetric defaultIconMetrics[]; #endif diff --git a/src/util/gui/font.c b/src/util/gui/font.c index dd055fc8c..a24ca9466 100644 --- a/src/util/gui/font.c +++ b/src/util/gui/font.c @@ -15,12 +15,12 @@ unsigned GUIFontSpanWidth(const struct GUIFont* font, const char* text) { return width; } -void GUIFontPrint(const struct GUIFont* font, int x, int y, enum GUITextAlignment align, uint32_t color, const char* text) { - switch (align) { - case GUI_TEXT_CENTER: +void GUIFontPrint(const struct GUIFont* font, int x, int y, enum GUIAlignment align, uint32_t color, const char* text) { + switch (align & GUI_ALIGN_HCENTER) { + case GUI_ALIGN_HCENTER: x -= GUIFontSpanWidth(font, text) / 2; break; - case GUI_TEXT_RIGHT: + case GUI_ALIGN_RIGHT: x -= GUIFontSpanWidth(font, text); break; default: @@ -34,7 +34,7 @@ void GUIFontPrint(const struct GUIFont* font, int x, int y, enum GUITextAlignmen } } -void GUIFontPrintf(const struct GUIFont* font, int x, int y, enum GUITextAlignment align, uint32_t color, const char* text, ...) { +void GUIFontPrintf(const struct GUIFont* font, int x, int y, enum GUIAlignment align, uint32_t color, const char* text, ...) { char buffer[256]; va_list args; va_start(args, text); diff --git a/src/util/gui/font.h b/src/util/gui/font.h index 626cfed38..f422d61ee 100644 --- a/src/util/gui/font.h +++ b/src/util/gui/font.h @@ -12,10 +12,46 @@ struct GUIFont; struct GUIFont* GUIFontCreate(void); void GUIFontDestroy(struct GUIFont*); -enum GUITextAlignment { - GUI_TEXT_LEFT = 0, - GUI_TEXT_CENTER, - GUI_TEXT_RIGHT +enum GUIAlignment { + GUI_ALIGN_LEFT = 1, + GUI_ALIGN_HCENTER = 3, + GUI_ALIGN_RIGHT = 2, + + GUI_ALIGN_TOP = 4, + GUI_ALIGN_VCENTER = 12, + GUI_ALIGN_BOTTOM = 8, +}; + +enum GUIOrientation { + GUI_ORIENT_0, + GUI_ORIENT_90_CCW, + GUI_ORIENT_180, + GUI_ORIENT_270_CCW, + + GUI_ORIENT_VMIRROR, + GUI_ORIENT_HMIRROR, + + GUI_ORIENT_90_CW = GUI_ORIENT_270_CCW, + GUI_ORIENT_270_CW = GUI_ORIENT_90_CCW +}; + +enum GUIIcon { + GUI_ICON_BATTERY_FULL, + GUI_ICON_BATTERY_HIGH, + GUI_ICON_BATTERY_HALF, + GUI_ICON_BATTERY_LOW, + GUI_ICON_BATTERY_EMPTY, + GUI_ICON_SCROLLBAR_THUMB, + GUI_ICON_SCROLLBAR_TRACK, + GUI_ICON_SCROLLBAR_BUTTON, + GUI_ICON_CURSOR, + GUI_ICON_POINTER, + GUI_ICON_BUTTON_CIRCLE, + GUI_ICON_BUTTON_CROSS, + GUI_ICON_BUTTON_TRIANGLE, + GUI_ICON_BUTTON_SQUARE, + GUI_ICON_BUTTON_HOME, + GUI_ICON_MAX, }; struct GUIFontGlyphMetric { @@ -29,13 +65,21 @@ struct GUIFontGlyphMetric { } padding; }; +struct GUIIconMetric { + int x; + int y; + int width; + int height; +}; + unsigned GUIFontHeight(const struct GUIFont*); unsigned GUIFontGlyphWidth(const struct GUIFont*, uint32_t glyph); unsigned GUIFontSpanWidth(const struct GUIFont*, const char* text); ATTRIBUTE_FORMAT(printf, 6, 7) -void GUIFontPrintf(const struct GUIFont*, int x, int y, enum GUITextAlignment, uint32_t color, const char* text, ...); -void GUIFontPrint(const struct GUIFont*, int x, int y, enum GUITextAlignment, uint32_t color, const char* text); +void GUIFontPrintf(const struct GUIFont*, int x, int y, enum GUIAlignment, uint32_t color, const char* text, ...); +void GUIFontPrint(const struct GUIFont*, int x, int y, enum GUIAlignment, uint32_t color, const char* text); void GUIFontDrawGlyph(const struct GUIFont*, int x, int y, uint32_t color, uint32_t glyph); +void GUIFontDrawIcon(const struct GUIFont*, int x, int y, enum GUIAlignment, enum GUIOrientation, uint32_t color, enum GUIIcon); #endif diff --git a/src/util/gui/menu.c b/src/util/gui/menu.c index 48cb947ab..b65d76052 100644 --- a/src/util/gui/menu.c +++ b/src/util/gui/menu.c @@ -25,7 +25,7 @@ enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* men while (true) { uint32_t newInput = 0; GUIPollInput(params, &newInput, 0); - int cx, cy; + unsigned cx, cy; enum GUICursorState cursor = GUIPollCursor(params, &cx, &cy); if (newInput & (1 << GUI_INPUT_UP) && menu->index > 0) { @@ -71,14 +71,26 @@ enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* men } } if (cursor != GUI_CURSOR_NOT_PRESENT) { - int index = (cy / lineHeight) - 2; - if (index >= 0 && index + start < GUIMenuItemListSize(&menu->items)) { - if (menu->index != index + start || !cursorOverItem) { - cursorOverItem = 1; + if (cx < params->width - 16) { + int index = (cy / lineHeight) - 2; + if (index >= 0 && index + start < GUIMenuItemListSize(&menu->items)) { + if (menu->index != index + start || !cursorOverItem) { + cursorOverItem = 1; + } + menu->index = index + start; + } else { + cursorOverItem = 0; + } + } else if (cursor == GUI_CURSOR_DOWN || cursor == GUI_CURSOR_DRAGGING) { + if (cy <= 2 * lineHeight && cy > lineHeight && menu->index > 0) { + --menu->index; + } else if (cy <= params->height && cy > params->height - lineHeight && menu->index < GUIMenuItemListSize(&menu->items) - 1) { + ++menu->index; + } else if (cy <= params->height - lineHeight && cy > 2 * lineHeight) { + size_t location = cy - 2 * lineHeight; + location *= GUIMenuItemListSize(&menu->items); + menu->index = location / (params->height - 3 * lineHeight); } - menu->index = index + start; - } else { - cursorOverItem = 0; } } @@ -117,23 +129,23 @@ enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* men params->guiPrepare(); } unsigned y = lineHeight; - GUIFontPrint(params->font, 0, y, GUI_TEXT_LEFT, 0xFFFFFFFF, menu->title); + GUIFontPrint(params->font, 0, y, GUI_ALIGN_LEFT, 0xFFFFFFFF, menu->title); if (menu->subtitle) { - GUIFontPrint(params->font, 0, y * 2, GUI_TEXT_LEFT, 0xFFFFFFFF, menu->subtitle); + GUIFontPrint(params->font, 0, y * 2, GUI_ALIGN_LEFT, 0xFFFFFFFF, menu->subtitle); } y += 2 * lineHeight; + size_t itemsPerScreen = (params->height - y) / lineHeight; size_t i; for (i = start; i < GUIMenuItemListSize(&menu->items); ++i) { int color = 0xE0A0A0A0; - char bullet = ' '; if (i == menu->index) { color = 0xFFFFFFFF; - bullet = '>'; + GUIFontDrawIcon(params->font, 2, y, GUI_ALIGN_BOTTOM | GUI_ALIGN_LEFT, GUI_ORIENT_0, 0xFFFFFFFF, GUI_ICON_POINTER); } struct GUIMenuItem* item = GUIMenuItemListGetPointer(&menu->items, i); - GUIFontPrintf(params->font, 0, y, GUI_TEXT_LEFT, color, "%c %s", bullet, item->title); + GUIFontPrintf(params->font, 0, y, GUI_ALIGN_LEFT, color, " %s", item->title); if (item->validStates && item->validStates[item->state]) { - GUIFontPrintf(params->font, params->width, y, GUI_TEXT_RIGHT, color, "%s ", item->validStates[item->state]); + GUIFontPrintf(params->font, params->width, y, GUI_ALIGN_RIGHT, color, "%s ", item->validStates[item->state]); } y += lineHeight; if (y + lineHeight > params->height) { @@ -141,9 +153,26 @@ enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* men } } + if (itemsPerScreen < GUIMenuItemListSize(&menu->items)) { + y = 2 * lineHeight; + GUIFontDrawIcon(params->font, params->width - 8, y, GUI_ALIGN_HCENTER | GUI_ALIGN_BOTTOM, GUI_ORIENT_VMIRROR, 0xFFFFFFFF, GUI_ICON_SCROLLBAR_BUTTON); + for (; y < params->height - 16; y += 16) { + GUIFontDrawIcon(params->font, params->width - 8, y, GUI_ALIGN_HCENTER | GUI_ALIGN_TOP, GUI_ORIENT_0, 0xFFFFFFFF, GUI_ICON_SCROLLBAR_TRACK); + } + GUIFontDrawIcon(params->font, params->width - 8, y, GUI_ALIGN_HCENTER | GUI_ALIGN_TOP, GUI_ORIENT_0, 0xFFFFFFFF, GUI_ICON_SCROLLBAR_BUTTON); + + size_t top = 2 * lineHeight; + y = menu->index * (y - top - 16) / GUIMenuItemListSize(&menu->items); + GUIFontDrawIcon(params->font, params->width - 8, top + y, GUI_ALIGN_HCENTER | GUI_ALIGN_TOP, GUI_ORIENT_0, 0xFFFFFFFF, GUI_ICON_SCROLLBAR_THUMB); + } + GUIDrawBattery(params); GUIDrawClock(params); + if (cursor != GUI_CURSOR_NOT_PRESENT) { + GUIFontDrawIcon(params->font, cx, cy, GUI_ALIGN_HCENTER | GUI_ALIGN_TOP, GUI_ORIENT_0, 0xFFFFFFFF, GUI_ICON_CURSOR); + } + if (params->guiFinish) { params->guiFinish(); } @@ -152,7 +181,7 @@ enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* men return GUI_MENU_EXIT_CANCEL; } -enum GUICursorState GUIPollCursor(struct GUIParams* params, int* x, int* y) { +enum GUICursorState GUIPollCursor(struct GUIParams* params, unsigned* x, unsigned* y) { if (!params->pollCursor) { return GUI_CURSOR_NOT_PRESENT; } @@ -207,29 +236,29 @@ void GUIDrawBattery(struct GUIParams* params) { color |= 0x3030FF; } - const char* batteryText; + enum GUIIcon batteryIcon; switch (state & ~BATTERY_CHARGING) { case BATTERY_EMPTY: - batteryText = "[ ]"; + batteryIcon = GUI_ICON_BATTERY_EMPTY; break; case BATTERY_LOW: - batteryText = "[I ]"; + batteryIcon = GUI_ICON_BATTERY_LOW; break; case BATTERY_HALF: - batteryText = "[II ]"; + batteryIcon = GUI_ICON_BATTERY_HALF; break; case BATTERY_HIGH: - batteryText = "[III ]"; + batteryIcon = GUI_ICON_BATTERY_HIGH; break; case BATTERY_FULL: - batteryText = "[IIII]"; + batteryIcon = GUI_ICON_BATTERY_FULL; break; default: - batteryText = "[????]"; + batteryIcon = GUI_ICON_BATTERY_EMPTY; break; } - GUIFontPrint(params->font, params->width, GUIFontHeight(params->font), GUI_TEXT_RIGHT, color, batteryText); + GUIFontDrawIcon(params->font, params->width, 0, GUI_ALIGN_RIGHT, GUI_ORIENT_0, color, batteryIcon); } void GUIDrawClock(struct GUIParams* params) { @@ -238,5 +267,5 @@ void GUIDrawClock(struct GUIParams* params) { struct tm tm; localtime_r(&t, &tm); strftime(buffer, sizeof(buffer), "%H:%M:%S", &tm); - GUIFontPrint(params->font, params->width / 2, GUIFontHeight(params->font), GUI_TEXT_CENTER, 0xFFFFFFFF, buffer); + GUIFontPrint(params->font, params->width / 2, GUIFontHeight(params->font), GUI_ALIGN_HCENTER, 0xFFFFFFFF, buffer); }