foxygit / TransTUI Log in
commits tags

/src/ui/ui_splash.c · 4.68 KB

raw
#include "ui.h"

#include <curses.h>
#include <string.h>
#include <time.h>

#define GLYPH_H 5
#define GLYPH_W 5
#define LETTER_GAP 1

typedef const char *Glyph[GLYPH_H];

/* Blocky 5x5 "16-bit" pixel font, just enough letters to spell TRANSTUI. */
static const Glyph GLYPH_T = {"\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88", "  \xe2\x96\x88  ", "  \xe2\x96\x88  ",
                               "  \xe2\x96\x88  ", "  \xe2\x96\x88  "};
static const Glyph GLYPH_R = {"\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88 ", "\xe2\x96\x88   \xe2\x96\x88",
                               "\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88 ", "\xe2\x96\x88  \xe2\x96\x88 ", "\xe2\x96\x88   \xe2\x96\x88"};
static const Glyph GLYPH_A = {" \xe2\x96\x88\xe2\x96\x88\xe2\x96\x88 ", "\xe2\x96\x88   \xe2\x96\x88",
                               "\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88", "\xe2\x96\x88   \xe2\x96\x88", "\xe2\x96\x88   \xe2\x96\x88"};
static const Glyph GLYPH_N = {"\xe2\x96\x88   \xe2\x96\x88", "\xe2\x96\x88\xe2\x96\x88  \xe2\x96\x88", "\xe2\x96\x88 \xe2\x96\x88 \xe2\x96\x88",
                               "\xe2\x96\x88  \xe2\x96\x88\xe2\x96\x88", "\xe2\x96\x88   \xe2\x96\x88"};
static const Glyph GLYPH_S = {" \xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88", "\xe2\x96\x88    ", " \xe2\x96\x88\xe2\x96\x88\xe2\x96\x88 ",
                               "    \xe2\x96\x88", "\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88 "};
static const Glyph GLYPH_U = {"\xe2\x96\x88   \xe2\x96\x88", "\xe2\x96\x88   \xe2\x96\x88", "\xe2\x96\x88   \xe2\x96\x88",
                               "\xe2\x96\x88   \xe2\x96\x88", " \xe2\x96\x88\xe2\x96\x88\xe2\x96\x88 "};
static const Glyph GLYPH_I = {"\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88", "  \xe2\x96\x88  ", "  \xe2\x96\x88  ",
                               "  \xe2\x96\x88  ", "\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88"};

/* T R A N S T U I */
static const Glyph *const WORD[] = {&GLYPH_T, &GLYPH_R, &GLYPH_A, &GLYPH_N,
                                     &GLYPH_S, &GLYPH_T, &GLYPH_U, &GLYPH_I};
#define WORD_LEN (int)(sizeof(WORD) / sizeof(WORD[0]))

#define SPLASH_MS 3000

/* Returns the key that dismissed the splash, or ERR if it timed out on its
 * own - the caller feeds a real key straight into the normal key handler
 * instead of silently swallowing it, so e.g. pressing 'g' to skip the
 * splash also opens settings immediately rather than just landing on the
 * plain list view. */
int ui_splash_show(void)
{
    int rows, cols;
    getmaxyx(stdscr, rows, cols);

    int banner_w = WORD_LEN * GLYPH_W + (WORD_LEN - 1) * LETTER_GAP;
    const char *subtitle = "Transmission TUI Client";
    const char *hint = "Press any key to continue\xe2\x80\xa6";

    int content_w = banner_w;
    if ((int)strlen(subtitle) > content_w)
        content_w = (int)strlen(subtitle);
    int box_w = content_w + 8;
    if (box_w > cols - 2)
        box_w = cols - 2;
    int box_h = GLYPH_H + 6;
    if (box_h > rows - 2)
        box_h = rows - 2;
    if (box_w < 10 || box_h < 8)
        return ERR; /* terminal too small to bother */

    int box_y = (rows - box_h) / 2;
    int box_x = (cols - box_w) / 2;

    erase();
    WINDOW *win = derwin(stdscr, box_h, box_w, box_y, box_x);
    ui_box(win, box_h, box_w);
    ui_box_title(win, box_w, "TransTUI");

    int have_color = has_colors();
    int banner_y = 2;
    int banner_x = (box_w - banner_w) / 2;
    if (banner_x < 1)
        banner_x = 1;

    int white = have_color ? (COLOR_PAIR(CP_SPLASH_WHITE) | A_BOLD) : A_BOLD;

    wattron(win, white);
    for (int li = 0; li < WORD_LEN; li++)
        for (int r = 0; r < GLYPH_H; r++)
            mvwaddstr(win, banner_y + r, banner_x + li * (GLYPH_W + LETTER_GAP), (*WORD[li])[r]);
    wattroff(win, white);

    int sub_y = banner_y + GLYPH_H + 1;
    wattron(win, white);
    mvwprintw(win, sub_y, (box_w - (int)strlen(subtitle)) / 2, "%s", subtitle);
    wattroff(win, white);

    int hint_w = (int)strlen(hint) - 2; /* the ellipsis is one 3-byte UTF-8 char, not 3 cells */
    wattron(win, have_color ? COLOR_PAIR(CP_SPLASH_WHITE) : 0);
    mvwprintw(win, box_h - 2, (box_w - hint_w) / 2, "%s", hint);
    wattroff(win, have_color ? COLOR_PAIR(CP_SPLASH_WHITE) : 0);

    wnoutrefresh(win);
    doupdate();
    delwin(win);

    struct timespec t0;
    clock_gettime(CLOCK_MONOTONIC, &t0);
    timeout(50);
    int ch = ERR;
    for (;;) {
        ch = getch();
        if (ch != ERR)
            break;
        struct timespec now;
        clock_gettime(CLOCK_MONOTONIC, &now);
        long elapsed = (now.tv_sec - t0.tv_sec) * 1000 + (now.tv_nsec - t0.tv_nsec) / 1000000;
        if (elapsed >= SPLASH_MS)
            break;
    }
    return ch;
}