mirror of https://github.com/fairyglade/ly
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
649 lines
10 KiB
C
649 lines
10 KiB
C
#include "dragonfail.h"
|
|
#include "termbox.h"
|
|
#include "ctypes.h"
|
|
|
|
#include "inputs.h"
|
|
#include "utils.h"
|
|
#include "config.h"
|
|
#include "draw.h"
|
|
|
|
#include <ctype.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stropts.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
|
#include <sys/kbio.h>
|
|
#else // linux
|
|
#include <linux/kd.h>
|
|
#endif
|
|
|
|
#define DOOM_STEPS 13
|
|
|
|
void draw_init(struct term_buf* buf)
|
|
{
|
|
buf->width = tb_width();
|
|
buf->height = tb_height();
|
|
hostname(&buf->info_line);
|
|
buf->info_line = NULL;
|
|
|
|
u16 len_login = strlen(lang.login);
|
|
u16 len_password = strlen(lang.password);
|
|
|
|
if (len_login > len_password)
|
|
{
|
|
buf->labels_max_len = len_login;
|
|
}
|
|
else
|
|
{
|
|
buf->labels_max_len = len_password;
|
|
}
|
|
|
|
buf->box_height = 7 + (2 * config.margin_box_v);
|
|
buf->box_width =
|
|
(2 * config.margin_box_h)
|
|
+ (config.input_len + 1)
|
|
+ buf->labels_max_len;
|
|
|
|
#if defined(__linux__)
|
|
buf->box_chars.left_up = 0x250c;
|
|
buf->box_chars.left_down = 0x2514;
|
|
buf->box_chars.right_up = 0x2510;
|
|
buf->box_chars.right_down = 0x2518;
|
|
buf->box_chars.top = 0x2500;
|
|
buf->box_chars.bot = 0x2500;
|
|
buf->box_chars.left = 0x2502;
|
|
buf->box_chars.right = 0x2502;
|
|
#else
|
|
buf->box_chars.left_up = '+';
|
|
buf->box_chars.left_down = '+';
|
|
buf->box_chars.right_up = '+';
|
|
buf->box_chars.right_down= '+';
|
|
buf->box_chars.top = '-';
|
|
buf->box_chars.bot = '-';
|
|
buf->box_chars.left = '|';
|
|
buf->box_chars.right = '|';
|
|
#endif
|
|
}
|
|
|
|
void draw_free(struct term_buf* buf)
|
|
{
|
|
if (config.animate)
|
|
{
|
|
free(buf->tmp_buf);
|
|
}
|
|
}
|
|
|
|
void draw_box(struct term_buf* buf)
|
|
{
|
|
u16 box_x = (buf->width - buf->box_width) / 2;
|
|
u16 box_y = (buf->height - buf->box_height) / 2;
|
|
u16 box_x2 = (buf->width + buf->box_width) / 2;
|
|
u16 box_y2 = (buf->height + buf->box_height) / 2;
|
|
buf->box_x = box_x;
|
|
buf->box_y = box_y;
|
|
|
|
if (!config.hide_borders)
|
|
{
|
|
// corners
|
|
tb_change_cell(
|
|
box_x - 1,
|
|
box_y - 1,
|
|
buf->box_chars.left_up,
|
|
config.fg,
|
|
config.bg);
|
|
tb_change_cell(
|
|
box_x2,
|
|
box_y - 1,
|
|
buf->box_chars.right_up,
|
|
config.fg,
|
|
config.bg);
|
|
tb_change_cell(
|
|
box_x - 1,
|
|
box_y2,
|
|
buf->box_chars.left_down,
|
|
config.fg,
|
|
config.bg);
|
|
tb_change_cell(
|
|
box_x2,
|
|
box_y2,
|
|
buf->box_chars.right_down,
|
|
config.fg,
|
|
config.bg);
|
|
|
|
// top and bottom
|
|
struct tb_cell c1 = {buf->box_chars.top, config.fg, config.bg};
|
|
struct tb_cell c2 = {buf->box_chars.bot, config.fg, config.bg};
|
|
|
|
for (u8 i = 0; i < buf->box_width; ++i)
|
|
{
|
|
tb_put_cell(
|
|
box_x + i,
|
|
box_y - 1,
|
|
&c1);
|
|
tb_put_cell(
|
|
box_x + i,
|
|
box_y2,
|
|
&c2);
|
|
}
|
|
|
|
// left and right
|
|
c1.ch = buf->box_chars.left;
|
|
c2.ch = buf->box_chars.right;
|
|
|
|
for (u8 i = 0; i < buf->box_height; ++i)
|
|
{
|
|
tb_put_cell(
|
|
box_x - 1,
|
|
box_y + i,
|
|
&c1);
|
|
|
|
tb_put_cell(
|
|
box_x2,
|
|
box_y + i,
|
|
&c2);
|
|
}
|
|
}
|
|
|
|
if (config.blank_box)
|
|
{
|
|
struct tb_cell blank = {' ', config.fg, config.bg};
|
|
|
|
for (u8 i = 0; i < buf->box_height; ++i)
|
|
{
|
|
for (u8 k = 0; k < buf->box_width; ++k)
|
|
{
|
|
tb_put_cell(
|
|
box_x + k,
|
|
box_y + i,
|
|
&blank);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct tb_cell* strn_cell(char* s, u16 len) // throws
|
|
{
|
|
struct tb_cell* cells = malloc((sizeof (struct tb_cell)) * len);
|
|
char* s2 = s;
|
|
u32 c;
|
|
|
|
if (cells != NULL)
|
|
{
|
|
for (u16 i = 0; i < len; ++i)
|
|
{
|
|
if ((s2 - s) >= len)
|
|
{
|
|
break;
|
|
}
|
|
|
|
s2 += utf8_char_to_unicode(&c, s2);
|
|
|
|
cells[i].ch = c;
|
|
cells[i].bg = config.bg;
|
|
cells[i].fg = config.fg;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dgn_throw(DGN_ALLOC);
|
|
}
|
|
|
|
return cells;
|
|
}
|
|
|
|
struct tb_cell* str_cell(char* s) // throws
|
|
{
|
|
return strn_cell(s, strlen(s));
|
|
}
|
|
|
|
void draw_labels(struct term_buf* buf) // throws
|
|
{
|
|
// login text
|
|
struct tb_cell* login = str_cell(lang.login);
|
|
|
|
if (dgn_catch())
|
|
{
|
|
dgn_reset();
|
|
}
|
|
else
|
|
{
|
|
tb_blit(
|
|
buf->box_x + config.margin_box_h,
|
|
buf->box_y + config.margin_box_v + 4,
|
|
strlen(lang.login),
|
|
1,
|
|
login);
|
|
free(login);
|
|
}
|
|
|
|
// password text
|
|
struct tb_cell* password = str_cell(lang.password);
|
|
|
|
if (dgn_catch())
|
|
{
|
|
dgn_reset();
|
|
}
|
|
else
|
|
{
|
|
tb_blit(
|
|
buf->box_x + config.margin_box_h,
|
|
buf->box_y + config.margin_box_v + 6,
|
|
strlen(lang.password),
|
|
1,
|
|
password);
|
|
free(password);
|
|
}
|
|
|
|
if (buf->info_line != NULL)
|
|
{
|
|
u16 len = strlen(buf->info_line);
|
|
struct tb_cell* info_cell = str_cell(buf->info_line);
|
|
|
|
if (dgn_catch())
|
|
{
|
|
dgn_reset();
|
|
}
|
|
else
|
|
{
|
|
tb_blit(
|
|
buf->box_x + ((buf->box_width - len) / 2),
|
|
buf->box_y + config.margin_box_v,
|
|
len,
|
|
1,
|
|
info_cell);
|
|
free(info_cell);
|
|
}
|
|
}
|
|
}
|
|
|
|
void draw_f_commands()
|
|
{
|
|
struct tb_cell* f1 = str_cell(lang.f1);
|
|
|
|
if (dgn_catch())
|
|
{
|
|
dgn_reset();
|
|
}
|
|
else
|
|
{
|
|
tb_blit(0, 0, strlen(lang.f1), 1, f1);
|
|
free(f1);
|
|
}
|
|
|
|
struct tb_cell* f2 = str_cell(lang.f2);
|
|
|
|
if (dgn_catch())
|
|
{
|
|
dgn_reset();
|
|
}
|
|
else
|
|
{
|
|
tb_blit(strlen(lang.f1) + 1, 0, strlen(lang.f2), 1, f2);
|
|
free(f2);
|
|
}
|
|
}
|
|
|
|
void draw_lock_state(struct term_buf* buf)
|
|
{
|
|
// get values
|
|
int fd = open(config.console_dev, O_RDONLY);
|
|
|
|
if (fd < 0)
|
|
{
|
|
buf->info_line = lang.err_console_dev;
|
|
return;
|
|
}
|
|
|
|
bool numlock_on;
|
|
bool capslock_on;
|
|
|
|
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
|
int led;
|
|
ioctl(fd, KDGETLED, &led);
|
|
numlock_on = led & LED_NUM;
|
|
capslock_on = led & LED_CAP;
|
|
#else // linux
|
|
char led;
|
|
ioctl(fd, KDGKBLED, &led);
|
|
numlock_on = led & K_NUMLOCK;
|
|
capslock_on = led & K_CAPSLOCK;
|
|
#endif
|
|
|
|
close(fd);
|
|
|
|
// print text
|
|
u16 pos_x = buf->width - strlen(lang.numlock);
|
|
|
|
if (numlock_on)
|
|
{
|
|
struct tb_cell* numlock = str_cell(lang.numlock);
|
|
|
|
if (dgn_catch())
|
|
{
|
|
dgn_reset();
|
|
}
|
|
else
|
|
{
|
|
tb_blit(pos_x, 0, strlen(lang.numlock), 1, numlock);
|
|
free(numlock);
|
|
}
|
|
}
|
|
|
|
pos_x -= strlen(lang.capslock) + 1;
|
|
|
|
if (capslock_on)
|
|
{
|
|
struct tb_cell* capslock = str_cell(lang.capslock);
|
|
|
|
if (dgn_catch())
|
|
{
|
|
dgn_reset();
|
|
}
|
|
else
|
|
{
|
|
tb_blit(pos_x, 0, strlen(lang.capslock), 1, capslock);
|
|
free(capslock);
|
|
}
|
|
}
|
|
}
|
|
|
|
void draw_desktop(struct desktop* target)
|
|
{
|
|
u16 len = strlen(target->list[target->cur]);
|
|
|
|
if (len > (target->visible_len - 3))
|
|
{
|
|
len = target->visible_len - 3;
|
|
}
|
|
|
|
tb_change_cell(
|
|
target->x,
|
|
target->y,
|
|
'<',
|
|
config.fg,
|
|
config.bg);
|
|
|
|
tb_change_cell(
|
|
target->x + target->visible_len - 1,
|
|
target->y,
|
|
'>',
|
|
config.fg,
|
|
config.bg);
|
|
|
|
for (u16 i = 0; i < len; ++ i)
|
|
{
|
|
tb_change_cell(
|
|
target->x + i + 2,
|
|
target->y,
|
|
target->list[target->cur][i],
|
|
config.fg,
|
|
config.bg);
|
|
}
|
|
}
|
|
|
|
void draw_input(struct text* input)
|
|
{
|
|
u16 len = strlen(input->text);
|
|
u16 visible_len = input->visible_len;
|
|
|
|
if (len > visible_len)
|
|
{
|
|
len = visible_len;
|
|
}
|
|
|
|
struct tb_cell* cells = strn_cell(input->visible_start, len);
|
|
|
|
if (dgn_catch())
|
|
{
|
|
dgn_reset();
|
|
}
|
|
else
|
|
{
|
|
tb_blit(input->x, input->y, len, 1, cells);
|
|
free(cells);
|
|
|
|
struct tb_cell c1 = {' ', config.fg, config.bg};
|
|
|
|
for (u16 i = input->end - input->visible_start; i < visible_len; ++i)
|
|
{
|
|
tb_put_cell(
|
|
input->x + i,
|
|
input->y,
|
|
&c1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void draw_input_mask(struct text* input)
|
|
{
|
|
u16 len = strlen(input->text);
|
|
u16 visible_len = input->visible_len;
|
|
|
|
if (len > visible_len)
|
|
{
|
|
len = visible_len;
|
|
}
|
|
|
|
struct tb_cell c1 = {config.asterisk, config.fg, config.bg};
|
|
struct tb_cell c2 = {' ', config.fg, config.bg};
|
|
|
|
for (u16 i = 0; i < visible_len; ++i)
|
|
{
|
|
if (input->visible_start + i < input->end)
|
|
{
|
|
tb_put_cell(
|
|
input->x + i,
|
|
input->y,
|
|
&c1);
|
|
}
|
|
else
|
|
{
|
|
tb_put_cell(
|
|
input->x + i,
|
|
input->y,
|
|
&c2);
|
|
}
|
|
}
|
|
}
|
|
|
|
void position_input(
|
|
struct term_buf* buf,
|
|
struct desktop* desktop,
|
|
struct text* login,
|
|
struct text* password)
|
|
{
|
|
u16 x = buf->box_x + config.margin_box_h + buf->labels_max_len + 1;
|
|
i32 len = buf->box_x + buf->box_width - config.margin_box_h - x;
|
|
|
|
if (len < 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
desktop->x = x;
|
|
desktop->y = buf->box_y + config.margin_box_v + 2;
|
|
desktop->visible_len = len;
|
|
|
|
login->x = x;
|
|
login->y = buf->box_y + config.margin_box_v + 4;
|
|
login->visible_len = len;
|
|
|
|
password->x = x;
|
|
password->y = buf->box_y + config.margin_box_v + 6;
|
|
password->visible_len = len;
|
|
}
|
|
|
|
static void doom_init(struct term_buf* buf)
|
|
{
|
|
buf->init_width = buf->width;
|
|
buf->init_height = buf->height;
|
|
|
|
u16 tmp_len = buf->width * buf->height;
|
|
buf->tmp_buf = malloc(tmp_len);
|
|
tmp_len -= buf->width;
|
|
|
|
if (buf->tmp_buf == NULL)
|
|
{
|
|
dgn_throw(DGN_ALLOC);
|
|
}
|
|
|
|
memset(buf->tmp_buf, 0, tmp_len);
|
|
memset(buf->tmp_buf + tmp_len, DOOM_STEPS - 1, buf->width);
|
|
}
|
|
|
|
void animate_init(struct term_buf* buf)
|
|
{
|
|
if (config.animate)
|
|
{
|
|
switch(config.animation)
|
|
{
|
|
default:
|
|
{
|
|
doom_init(buf);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void doom(struct term_buf* term_buf)
|
|
{
|
|
static struct tb_cell fire[DOOM_STEPS] =
|
|
{
|
|
{' ', 9, 0}, // default
|
|
{0x2591, 2, 0}, // red
|
|
{0x2592, 2, 0}, // red
|
|
{0x2593, 2, 0}, // red
|
|
{0x2588, 2, 0}, // red
|
|
{0x2591, 4, 2}, // yellow
|
|
{0x2592, 4, 2}, // yellow
|
|
{0x2593, 4, 2}, // yellow
|
|
{0x2588, 4, 2}, // yellow
|
|
{0x2591, 8, 4}, // white
|
|
{0x2592, 8, 4}, // white
|
|
{0x2593, 8, 4}, // white
|
|
{0x2588, 8, 4}, // white
|
|
};
|
|
|
|
u16 src;
|
|
u16 random;
|
|
u16 dst;
|
|
|
|
u16 w = term_buf->init_width;
|
|
u8* tmp = term_buf->tmp_buf;
|
|
|
|
if ((term_buf->width != term_buf->init_width) || (term_buf->height != term_buf->init_height))
|
|
{
|
|
return;
|
|
}
|
|
|
|
struct tb_cell* buf = tb_cell_buffer();
|
|
|
|
for (u16 x = 0; x < w; ++x)
|
|
{
|
|
for (u16 y = 1; y < term_buf->init_height; ++y)
|
|
{
|
|
src = y * w + x;
|
|
random = ((rand() % 7) & 3);
|
|
dst = src - random + 1;
|
|
|
|
if (w > dst)
|
|
{
|
|
dst = 0;
|
|
}
|
|
else
|
|
{
|
|
dst -= w;
|
|
}
|
|
|
|
tmp[dst] = tmp[src] - (random & 1);
|
|
|
|
if (tmp[dst] > 12)
|
|
{
|
|
tmp[dst] = 0;
|
|
}
|
|
|
|
buf[dst] = fire[tmp[dst]];
|
|
buf[src] = fire[tmp[src]];
|
|
}
|
|
}
|
|
}
|
|
|
|
void animate(struct term_buf* buf)
|
|
{
|
|
buf->width = tb_width();
|
|
buf->height = tb_height();
|
|
|
|
if (config.animate)
|
|
{
|
|
switch(config.animation)
|
|
{
|
|
default:
|
|
{
|
|
doom(buf);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool cascade(struct term_buf* term_buf, u8* fails)
|
|
{
|
|
u16 width = term_buf->width;
|
|
u16 height = term_buf->height;
|
|
|
|
struct tb_cell* buf = tb_cell_buffer();
|
|
bool changes = false;
|
|
char c_under;
|
|
char c;
|
|
|
|
for (int i = height - 2; i >= 0; --i)
|
|
{
|
|
for (int k = 0; k < width; ++k)
|
|
{
|
|
c = buf[i * width + k].ch;
|
|
|
|
if (isspace(c))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
c_under = buf[(i + 1) * width + k].ch;
|
|
|
|
if (!isspace(c_under))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!changes)
|
|
{
|
|
changes = true;
|
|
}
|
|
|
|
if ((rand() % 10) > 7)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
buf[(i + 1) * width + k] = buf[i * width + k];
|
|
buf[i * width + k].ch = ' ';
|
|
}
|
|
}
|
|
|
|
// stop force-updating
|
|
if (!changes)
|
|
{
|
|
sleep(7);
|
|
*fails = 0;
|
|
|
|
return false;
|
|
}
|
|
|
|
// force-update
|
|
return true;
|
|
}
|