/* * ui: a character card maker, shows the immediate mode ui driving something you can see * * build: ./build.sh -d -m ui,font obj/ui * run: obj/ui * * type a name, set the stats, pick a mood and a color. drag the panel titles to move them, click one to collapse it */ #include #include #include "konprogram.h" #include "konui.h" #if !defined(KON_MODULE_UI) || !defined(KON_MODULE_FONT) #error "build with: ./build.sh -d -m ui,font obj/ui" #endif #define MOODS 5 #define STATS 3 /*** colors ***/ #define COL_BACKGROUND 0xFF1B1826u #define COL_PANEL 0xFF26223Au #define COL_TITLE 0xFF332E4Eu #define COL_WIDGET 0xFF3A3558u #define COL_HOVER 0xFF48426Au #define COL_BORDER 0xFF4A4468u #define COL_PINK 0xFFF2A7C3u #define COL_MINT 0xFF8FD3C8u #define COL_YELLOW 0xFFF3DDA0u #define COL_TEXT 0xFFE4DDF0u #define COL_DIM 0xFF9A93B3u typedef struct state { kon_ui_t *ui; kon_uiPanel_t editor, picker; kon_font_t *big; char name[20]; int stats[STATS]; int mood; int red, green, blue; int shadow; } state_t; static const char *moodNames[MOODS] = { "calm", "shy", "cheerful", "sleepy", "stern" }; static const char *statNames[STATS] = { "courage", "charm", "focus" }; static const uint32_t statColors[STATS] = { COL_PINK, COL_YELLOW, COL_MINT }; /*** drawing ***/ static uint32_t mix(uint32_t a, uint32_t b, int t, int max) { uint32_t out = 0xFF000000u; int shift; for (shift = 0; shift <= 16; shift += 8) { int ca = (int)((a >> shift) & 0xFF), cb = (int)((b >> shift) & 0xFF); out |= (uint32_t)(ca + (cb - ca) * t / max) << shift; } return out; } static void drawCard(const state_t *state, kon_framebuffer_t *fb, kon_font_t *small) { const int x = 330, y = 50, w = 270, h = 260; uint32_t base = 0xFF000000u | ((uint32_t)state->red << 16) | ((uint32_t)state->green << 8) | (uint32_t)state->blue; uint32_t dark = mix(base, COL_BACKGROUND, 3, 4); char line[48]; int i, row; if (state->shadow) kon_fillRectangle(fb, x + 6, y + 6, w, h, 0x60000000u); for (row = 0; row < h; row++) kon_fillRectangle(fb, x, y + row, w, 1, mix(base, dark, row, h - 1)); kon_drawRectangle(fb, x, y, w, h, COL_BORDER); kon_drawRectangle(fb, x + 6, y + 6, w - 12, h - 12, mix(base, COL_BACKGROUND, 1, 2)); kon_drawText(fb, state->big, x + 20, y + 52, state->name[0] ? state->name : "unnamed", COL_BACKGROUND); snprintf(line, sizeof line, "feeling %s", moodNames[state->mood]); kon_drawText(fb, small, x + 20, y + 76, line, COL_BACKGROUND); for (i = 0; i < STATS; i++) { int by = y + 120 + i * 40; kon_drawText(fb, small, x + 20, by, statNames[i], COL_BACKGROUND); kon_fillRectangle(fb, x + 20, by + 8, w - 40, 8, mix(base, COL_BACKGROUND, 1, 3)); kon_fillRectangle(fb, x + 20, by + 8, (w - 40) * state->stats[i] / 10, 8, statColors[i]); } } /*** program ***/ static int event(kon_program_t *program, const kon_event_t *ev, void *user) { state_t *state = user; (void)program; kon_uiFeedEvent(state->ui, ev); return kon_uiWantsMouse(state->ui) || kon_uiWantsKeyboard(state->ui); } static void draw(kon_program_t *program, kon_framebuffer_t *game, void *user) { kon_clearFramebuffer(game, COL_BACKGROUND); drawCard(user, game, program->font); } static void drawScreen(kon_program_t *program, kon_framebuffer_t *screen, void *user) { state_t *state = user; int i; (void)program; kon_uiBegin(state->ui, screen); if (kon_uiBeginPanel(state->ui, "Card", &state->editor)) { kon_uiTextInput(state->ui, "name", state->name, sizeof state->name); kon_uiSeparator(state->ui); for (i = 0; i < STATS; i++) kon_uiSliderInt(state->ui, statNames[i], &state->stats[i], 0, 10); kon_uiSeparator(state->ui); kon_uiSliderInt(state->ui, "red", &state->red, 0, 255); kon_uiSliderInt(state->ui, "green", &state->green, 0, 255); kon_uiSliderInt(state->ui, "blue", &state->blue, 0, 255); kon_uiCheckbox(state->ui, "shadow", &state->shadow); } kon_uiEndPanel(state->ui); if (kon_uiBeginPanel(state->ui, "Mood", &state->picker)) { for (i = 0; i < MOODS; i++) { if (kon_uiSelectable(state->ui, moodNames[i], i == state->mood)) state->mood = i; } } kon_uiEndPanel(state->ui); kon_uiEnd(state->ui); } static int init(kon_program_t *program, void *user) { state_t *state = user; kon_uiTheme_t *theme; state->ui = kon_uiCreate(program->font); state->big = kon_loadBuiltinFont(2); if (!state->ui || !state->big) return 0; theme = kon_uiTheme(state->ui); theme->panel = COL_PANEL; theme->title = COL_TITLE; theme->text = COL_TEXT; theme->textDim = COL_DIM; theme->widget = COL_WIDGET; theme->hover = COL_HOVER; theme->active = 0xFF6B4F80u; theme->accent = 0xFFA66A92u; theme->border = COL_BORDER; state->editor = (kon_uiPanel_t){ 20, 20, 230, 0, 0, 0 }; state->picker = (kon_uiPanel_t){ 20, 310, 230, 0, 0, 0 }; snprintf(state->name, sizeof state->name, "Hanako"); state->stats[0] = 4; state->stats[1] = 8; state->stats[2] = 6; state->red = 214; state->green = 170; state->blue = 200; state->shadow = 1; return 1; } static void shutdown(kon_program_t *program, void *user) { state_t *state = user; (void)program; kon_uiDestroy(state->ui); kon_freeFont(state->big); } int main(void) { state_t state = {0}; kon_programConfig_t config = {0}; config.title = "ui"; config.gameWidth = 640; config.gameHeight = 360; config.windowWidth = 960; config.windowHeight = 540; config.user = &state; config.init = init; config.event = event; config.draw = draw; config.drawScreen = drawScreen; config.shutdown = shutdown; return kon_programRun(&config); }