ncneofetch: create info plane #550

This commit is contained in:
nick black 2020-06-17 19:39:37 -04:00
parent 31bd01b56d
commit 7ca5a7e82c
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
5 changed files with 159 additions and 60 deletions

View File

@ -2,7 +2,10 @@ This document attempts to list user-visible changes and any major internal
rearrangements of Notcurses.
* 1.5.2 (not yet released)
* The `ncneofetch` program has been added, of no great consequence.
* A `NULL` value can now be passed as `sbytes` to `ncplane_puttext()`.
* `ncdirect_render_image()` has been added, allowing images to be
rendered in direct mode.
* 1.5.1 (2020-07-15)
* The semantics of rendering have changed slightly. In 1.5.0 and prior

View File

@ -320,6 +320,11 @@ int ncdirect_cursor_up(struct ncdirect* nc, int num);
int ncdirect_cursor_left(struct ncdirect* nc, int num);
int ncdirect_cursor_right(struct ncdirect* nc, int num);
int ncdirect_cursor_down(struct ncdirect* nc, int num);
// Display an image using the specified blitter and scaling. The image may
// be arbitrarily many rows -- the output will scroll -- but will only occupy
// the column of the cursor, and those to the right.
nc_err_e ncdirect_render_image(const char* filename, ncblitter_e blitter, ncscale_e scale);
```
## Alignment

View File

@ -41,6 +41,31 @@ struct ncmultiselector; // widget supporting selecting 0..n from n options
struct ncreader; // widget supporting free string input ala readline
struct ncfadectx; // context for a palette fade operation
// each has the empty cell in addition to the product of its dimensions. i.e.
// NCBLIT_1x1 has two states: empty and full block. NCBLIT_1x1x4 has five
// states: empty, the three shaded blocks, and the full block.
typedef enum {
NCBLIT_DEFAULT, // let the ncvisual pick
NCBLIT_1x1, // full block █
NCBLIT_2x1, // full/(upper|left) blocks ▄█
NCBLIT_1x1x4, // shaded full blocks ▓▒░█
NCBLIT_2x2, // quadrants ▗▐ ▖▄▟▌▙█
NCBLIT_4x1, // four vert/horz levels █▆▄▂ / ▎▌▊█
NCBLIT_BRAILLE, // 4 rows, 2 cols (braille) ⡀⡄⡆⡇⢀⣀⣄⣆⣇⢠⣠⣤⣦⣧⢰⣰⣴⣶⣷⢸⣸⣼⣾⣿
NCBLIT_8x1, // eight vert/horz levels █▇▆▅▄▃▂▁ / ▏▎▍▌▋▊▉█
NCBLIT_SIXEL, // 6 rows, 1 col (RGB), spotty support among terminals
} ncblitter_e;
// How to scale an ncvisual during rendering. NCSCALE_NONE will apply no
// scaling. NCSCALE_SCALE scales a visual to the plane's size, maintaining
// aspect ratio. NCSCALE_STRETCH stretches and scales the image in an
// attempt to fill the entirety of the plane.
typedef enum {
NCSCALE_NONE,
NCSCALE_SCALE,
NCSCALE_STRETCH,
} ncscale_e;
// Initialize a direct-mode notcurses context on the connected terminal at 'fp'.
// 'fp' must be a tty. You'll usually want stdout. Direct mode supportes a
// limited subset of notcurses routines which directly affect 'fp', and neither
@ -102,6 +127,12 @@ API int ncdirect_cursor_yx(struct ncdirect* n, int* y, int* x);
API int ncdirect_cursor_push(struct ncdirect* n);
API int ncdirect_cursor_pop(struct ncdirect* n);
// Display an image using the specified blitter and scaling. The image may
// // be arbitrarily many rows -- the output will scroll -- but will only occupy
// // the column of the cursor, and those to the right.
API nc_err_e ncdirect_render_image(const char* filename, ncblitter_e blitter,
ncscale_e scale);
// Clear the screen.
API int ncdirect_clear(struct ncdirect* nc);
@ -898,16 +929,6 @@ typedef struct notcurses_options {
// there can be four numbers separated by commas.
API int notcurses_lex_margins(const char* op, notcurses_options* opts);
// How to scale a visual in ncvisual_decode(). NCSCALE_NONE will apply no
// scaling. NCSCALE_SCALE scales a visual to the plane's size, maintaining
// aspect ratio. NCSCALE_STRETCH stretches and scales the image in an attempt
// to fill the entirety of the plane.
typedef enum {
NCSCALE_NONE,
NCSCALE_SCALE,
NCSCALE_STRETCH,
} ncscale_e;
// Lex a visual scaling mode (one of "none", "stretch", or "scale").
API int notcurses_lex_scalemode(const char* op, ncscale_e* scalemode);
@ -2170,6 +2191,30 @@ ncplane_rounded_box(struct ncplane* n, uint32_t attr, uint64_t channels,
return ret;
}
static inline int
ncplane_perimeter_rounded(struct ncplane* n, uint32_t attrword,
uint64_t channels, unsigned ctlword){
if(ncplane_cursor_move_yx(n, 0, 0)){
return -1;
}
int dimy, dimx;
ncplane_dim_yx(n, &dimy, &dimx);
cell ul = CELL_TRIVIAL_INITIALIZER;
cell ur = CELL_TRIVIAL_INITIALIZER;
cell ll = CELL_TRIVIAL_INITIALIZER;
cell lr = CELL_TRIVIAL_INITIALIZER;
cell vl = CELL_TRIVIAL_INITIALIZER;
cell hl = CELL_TRIVIAL_INITIALIZER;
if(cells_rounded_box(n, attrword, channels, &ul, &ur, &ll, &lr, &hl, &vl)){
return -1;
}
int r = ncplane_box_sized(n, &ul, &ur, &ll, &lr, &hl, &vl, dimy, dimx, ctlword);
cell_release(n, &ul); cell_release(n, &ur);
cell_release(n, &ll); cell_release(n, &lr);
cell_release(n, &hl); cell_release(n, &vl);
return r;
}
static inline int
ncplane_rounded_box_sized(struct ncplane* n, uint32_t attr, uint64_t channels,
int ylen, int xlen, unsigned ctlword){
@ -2199,6 +2244,30 @@ ncplane_double_box(struct ncplane* n, uint32_t attr, uint64_t channels,
return ret;
}
static inline int
ncplane_perimeter_double(struct ncplane* n, uint32_t attrword,
uint64_t channels, unsigned ctlword){
if(ncplane_cursor_move_yx(n, 0, 0)){
return -1;
}
int dimy, dimx;
ncplane_dim_yx(n, &dimy, &dimx);
cell ul = CELL_TRIVIAL_INITIALIZER;
cell ur = CELL_TRIVIAL_INITIALIZER;
cell ll = CELL_TRIVIAL_INITIALIZER;
cell lr = CELL_TRIVIAL_INITIALIZER;
cell vl = CELL_TRIVIAL_INITIALIZER;
cell hl = CELL_TRIVIAL_INITIALIZER;
if(cells_double_box(n, attrword, channels, &ul, &ur, &ll, &lr, &hl, &vl)){
return -1;
}
int r = ncplane_box_sized(n, &ul, &ur, &ll, &lr, &hl, &vl, dimy, dimx, ctlword);
cell_release(n, &ul); cell_release(n, &ur);
cell_release(n, &ll); cell_release(n, &lr);
cell_release(n, &hl); cell_release(n, &vl);
return r;
}
static inline int
ncplane_double_box_sized(struct ncplane* n, uint32_t attr, uint64_t channels,
int ylen, int xlen, unsigned ctlword){
@ -2225,21 +2294,6 @@ API struct ncvisual* ncvisual_from_rgba(const void* rgba, int rows,
API struct ncvisual* ncvisual_from_bgra(const void* rgba, int rows,
int rowstride, int cols);
// each has the empty cell in addition to the product of its dimensions. i.e.
// NCBLIT_1x1 has two states: empty and full block. NCBLIT_1x1x4 has five
// states: empty, the three shaded blocks, and the full block.
typedef enum {
NCBLIT_DEFAULT, // let the ncvisual pick
NCBLIT_1x1, // full block █
NCBLIT_2x1, // full/(upper|left) blocks ▄█
NCBLIT_1x1x4, // shaded full blocks ▓▒░█
NCBLIT_2x2, // quadrants ▗▐ ▖▄▟▌▙█
NCBLIT_4x1, // four vert/horz levels █▆▄▂ / ▎▌▊█
NCBLIT_BRAILLE, // 4 rows, 2 cols (braille) ⡀⡄⡆⡇⢀⣀⣄⣆⣇⢠⣠⣤⣦⣧⢰⣰⣴⣶⣷⢸⣸⣼⣾⣿
NCBLIT_8x1, // eight vert/horz levels █▇▆▅▄▃▂▁ / ▏▎▍▌▋▊▉█
NCBLIT_SIXEL, // 6 rows, 1 col (RGB), spotty support among terminals
} ncblitter_e;
// Promote an ncplane 'n' to an ncvisual. The plane may contain only spaces,
// half blocks, and full blocks. The latter will be checked, and any other
// glyph will result in a NULL being returned. This function exists so that

View File

@ -67,34 +67,13 @@ done:
return dinfo;
}
static int
linux_ncneofetch(struct notcurses* nc){
static const distro_info*
linux_ncneofetch(void){
const distro_info* dinfo = getdistro();
if(dinfo == NULL){
return -1;
return NULL;
}
nc_err_e err;
struct ncvisual* ncv = ncvisual_from_file(dinfo->logofile, &err);
if(ncv == NULL){
fprintf(stderr, "Error opening logo file at %s\n", dinfo->logofile);
return -1;
}
struct ncvisual_options vopts = {
.scaling = NCSCALE_SCALE,
.blitter = NCBLIT_2x2,
};
struct ncplane* n = ncvisual_render(nc, ncv, &vopts);
if(n == NULL){
ncvisual_destroy(ncv);
return -1;
}
if(notcurses_render(nc)){
ncvisual_destroy(ncv);
return -1;
}
ncplane_destroy(n);
ncvisual_destroy(ncv);
return 0;
return dinfo;
}
typedef enum {
@ -119,19 +98,77 @@ get_kernel(void){
return NCNEO_UNKNOWN;
}
static struct ncplane*
display(struct notcurses* nc, const distro_info* dinfo){
if(dinfo->logofile){
nc_err_e err;
struct ncvisual* ncv = ncvisual_from_file(dinfo->logofile, &err);
if(ncv == NULL){
fprintf(stderr, "Error opening logo file at %s\n", dinfo->logofile);
return NULL;
}
struct ncvisual_options vopts = {
.scaling = NCSCALE_SCALE,
.blitter = NCBLIT_2x2,
.n = notcurses_stdplane(nc),
};
if(ncvisual_render(nc, ncv, &vopts) == NULL){
ncvisual_destroy(ncv);
return NULL;
}
ncvisual_destroy(ncv);
}
return 0;
}
static const distro_info*
freebsd_ncneofetch(void){
static const distro_info fbsd = {
.name = "FreeBSD",
.logofile = NULL, // FIXME
};
return &fbsd;
}
static int
infoplane(struct notcurses* nc){
struct ncplane* infop = ncplane_new(nc, 8, 60, 0, 0, NULL);
if(infop == NULL){
return -1;
}
if(ncplane_perimeter_rounded(infop, 0, 0, 0)){
return -1;
}
return 0;
}
static int
ncneofetch(struct notcurses* nc){
const distro_info* dinfo = NULL;
ncneo_kernel_e kern = get_kernel();
switch(kern){
case NCNEO_LINUX:
return linux_ncneofetch(nc);
dinfo = linux_ncneofetch();
break;
case NCNEO_FREEBSD:
// FIXME
dinfo = freebsd_ncneofetch();
break;
case NCNEO_UNKNOWN:
return -1;
break;
}
return -1;
if(dinfo == NULL){
return -1;
}
if(display(nc, dinfo)){
return -1; // FIXME soldier on, perhaps?
}
if(infoplane(nc)){
return -1;
}
if(notcurses_render(nc)){
return -1;
}
return 0;
}
int main(void){

View File

@ -12,7 +12,7 @@ auto pulser(struct notcurses* nc, struct ncplane* ncp __attribute__ ((unused)),
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
auto delta = timespec_to_ns(&now) - timespec_to_ns(pulsestart);
if(delta > 500000000){
if(delta > 250000000){
return 1;
}
return 0;
@ -62,14 +62,14 @@ TEST_CASE("Fade") {
CHECK(0 == notcurses_render(nc_));
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 500000000;
ts.tv_nsec = 250000000;
CHECK(0 == ncplane_fadeout(n_, &ts, nullptr, nullptr));
}
SUBCASE("FadeIn") {
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 500000000;
ts.tv_nsec = 250000000;
CHECK(0 == ncplane_fadein(n_, &ts, nullptr, nullptr));
}
@ -77,21 +77,21 @@ TEST_CASE("Fade") {
CHECK(0 == notcurses_render(nc_));
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 500000000;
ts.tv_nsec = 250000000;
CHECK(0 < ncplane_fadeout(n_, &ts, fadeaborter, nullptr));
}
SUBCASE("FadeInAbort") {
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 500000000;
ts.tv_nsec = 250000000;
CHECK(0 < ncplane_fadein(n_, &ts, fadeaborter, nullptr));
}
SUBCASE("Pulse") {
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 150000000;
ts.tv_nsec = 75000000;
ncplane_erase(n_);
ncplane_set_fg(n_, 0xffd700);
CHECK(0 < ncplane_printf_aligned(n_, dimy - 1, NCALIGN_CENTER, "pulllllllse"));