foxygit / ytmdl Log in
commits tags

/c/src/input_field.c · 2.52 KB

raw
#include "input_field.h"

#include <string.h>

void input_field_init(InputField *f) {
    f->buf[0] = '\0';
    f->len = 0;
    f->cursor = 0;
}

void input_field_clear(InputField *f) {
    input_field_init(f);
}

int input_field_handle_key(InputField *f, int ch) {
    if (ch >= 32 && ch < 127) {
        if (f->len + 1 < sizeof(f->buf)) {
            memmove(f->buf + f->cursor + 1, f->buf + f->cursor, f->len - f->cursor + 1);
            f->buf[f->cursor] = (char)ch;
            f->cursor++;
            f->len++;
        }
        return 1;
    }
    switch (ch) {
        case KEY_BACKSPACE:
        case 127:
        case 8:
            if (f->cursor > 0) {
                memmove(f->buf + f->cursor - 1, f->buf + f->cursor, f->len - f->cursor + 1);
                f->cursor--;
                f->len--;
            }
            return 1;
        case KEY_DC:
            if (f->cursor < f->len) {
                memmove(f->buf + f->cursor, f->buf + f->cursor + 1, f->len - f->cursor);
                f->len--;
            }
            return 1;
        case KEY_LEFT:
            if (f->cursor > 0) f->cursor--;
            return 1;
        case KEY_RIGHT:
            if (f->cursor < f->len) f->cursor++;
            return 1;
        case KEY_HOME:
        case 1: /* Ctrl+A */
            f->cursor = 0;
            return 1;
        case KEY_END:
        case 5: /* Ctrl+E */
            f->cursor = f->len;
            return 1;
        case 21: /* Ctrl+U: clear to start */
            memmove(f->buf, f->buf + f->cursor, f->len - f->cursor + 1);
            f->len -= f->cursor;
            f->cursor = 0;
            return 1;
        case 11: /* Ctrl+K: clear to end */
            f->buf[f->cursor] = '\0';
            f->len = f->cursor;
            return 1;
        default:
            return 0;
    }
}

void input_field_draw(WINDOW *win, int y, int x, int width, const InputField *f, int focused,
                       const char *placeholder) {
    if (width <= 0) return;
    wmove(win, y, x);
    for (int i = 0; i < width; i++) waddch(win, ' ');

    if (f->len == 0 && !focused) {
        wattron(win, A_DIM);
        mvwaddnstr(win, y, x, placeholder, width);
        wattroff(win, A_DIM);
        return;
    }

    size_t start = 0;
    if (f->cursor >= (size_t)width) start = f->cursor - width + 1;
    size_t visible_len = f->len - start;
    if (visible_len > (size_t)width) visible_len = width;

    mvwaddnstr(win, y, x, f->buf + start, (int)visible_len);

    if (focused) {
        wmove(win, y, x + (int)(f->cursor - start));
    }
}