all repos — mgba @ 0511d0a69e4e86f111cdd5bf60ad46f7bdb0ff5f

mGBA Game Boy Advance Emulator

GUI: Add icons and scrolling enhancements
Jeffrey Pfau jeffrey@endrift.com
Sat, 09 Jan 2016 00:54:18 -0800
commit

0511d0a69e4e86f111cdd5bf60ad46f7bdb0ff5f

parent

90eca20ab26783409a8eecd5e6093c84b715a091

M src/gba/gui/gui-runner.csrc/gba/gui/gui-runner.c

@@ -203,7 +203,7 @@ runner->params.drawStart();

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, "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 @@ runner->params.drawStart();

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 @@ if (drawFps) {

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(); }
M src/platform/3ds/CMakeLists.txtsrc/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 @@ ${CMAKE_CURRENT_SOURCE_DIR}/ctr-gpu.c

${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

@@ -58,6 +60,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
M src/platform/3ds/gui-font.csrc/platform/3ds/gui-font.c

@@ -7,8 +7,9 @@ #include "util/gui/font.h"

#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 @@ #define GLYPH_HEIGHT 12

struct GUIFont { struct ctrTexture texture; + struct ctrTexture icons; }; struct GUIFont* GUIFontCreate(void) {

@@ -35,11 +37,23 @@ GSPGPU_FlushDataCache(font, font_size);

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 @@ u16 v = (glyph / 16u) * CELL_HEIGHT;

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; + } +}
M src/platform/3ds/main.csrc/platform/3ds/main.c

@@ -410,7 +410,7 @@ }

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;
M src/platform/psp2/CMakeLists.txtsrc/platform/psp2/CMakeLists.txt

@@ -19,13 +19,23 @@ 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}) 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
M src/platform/psp2/gui-font.csrc/platform/psp2/gui-font.c

@@ -13,9 +13,11 @@ #define CELL_WIDTH 32

#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 @@ if (!font) {

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 @@ CELL_WIDTH - (metric.padding.left + metric.padding.right) * 2,

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; + } +}
M src/platform/psp2/main.csrc/platform/psp2/main.c

@@ -72,7 +72,7 @@

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) {
M src/platform/wii/CMakeLists.txtsrc/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
M src/platform/wii/gui-font.csrc/platform/wii/gui-font.c

@@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this

* 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 <malloc.h>

@@ -16,6 +17,7 @@ #define CELL_WIDTH 32

struct GUIFont { TPLFile tdf; + TPLFile iconsTdf; }; struct GUIFont* GUIFontCreate(void) {

@@ -32,11 +34,21 @@ return 0;

} 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 @@ GX_Color1u32(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(); +}
M src/platform/wii/main.csrc/platform/wii/main.c

@@ -59,7 +59,7 @@

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 @@ }

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) {
M src/util/gui.hsrc/util/gui.h

@@ -59,7 +59,7 @@

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 @@ #define GUI_PARAMS_TRAIL {}, GUI_CURSOR_NOT_PRESENT, 0, 0, "", 0

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
M src/util/gui/file-select.csrc/util/gui/file-select.c

@@ -71,8 +71,8 @@ params->drawStart();

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 @@ params->drawStart();

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(); }
M src/util/gui/font-metrics.csrc/util/gui/font-metrics.c

@@ -135,3 +135,21 @@ { 7, 11, { 2, 4, 3, 5 }}, // 0x7D "}"

{ 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 }, +};
M src/util/gui/font-metrics.hsrc/util/gui/font-metrics.h

@@ -9,5 +9,6 @@

#include "util/gui/font.h" extern struct GUIFontGlyphMetric defaultFontMetrics[]; +extern struct GUIIconMetric defaultIconMetrics[]; #endif
M src/util/gui/font.csrc/util/gui/font.c

@@ -15,12 +15,12 @@ }

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 @@ x += GUIFontGlyphWidth(font, c);

} } -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);
M src/util/gui/font.hsrc/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 @@ int left;

} 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
M src/util/gui/menu.csrc/util/gui/menu.c

@@ -25,7 +25,7 @@ GUIInvalidateKeys(params);

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 @@ menu->index = GUIMenuItemListSize(&menu->items) - 1;

} } 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 @@ if (params->guiPrepare) {

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 @@ break;

} } + 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 @@ }

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 @@ } else {

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 @@ time_t t = time(0);

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); }