notcurses
notcurses copied to clipboard
API feels gimped, need ncplanes without parents
Currently it seems, I can't have a ncplane
without a parent ncplane. There is one exception noted in the source: ncdirect
gets internal API ncplane_new_internal
to create a rootless plane. After all, such planes are convenient, but no dice for the stinking API coder :wink: .
The only way to maintain nccell
information outside of a ncplane are unwieldy private ncplane/nccell copies (you can't reuse the ncplane struct , because a) its internal api and b) you need a parent). You also can't reuse nccell
because it needs a plane for storage. So the API coder writes code like at the bottom of this issue (an extended rgb.c demo). The amount of copying going with a strdup
for each cell is just not nice. With a parentless ncplane, a ncplane_copy
function would just need to memcpy
all the cells and strdup
the egcpool or ?
With parentless planes, you can also do operations like temporarily hiding and showing a plane much easier:
// hide
oldparent = ncplane_parent( n);
ncplane_reparent( n, NULL);
// show
ncplane_reparent( n, oldparent)
should do the trick. Generally I would prefer to setup my ncplanes first completely "offscreen" so to speak and then assemble them myself in z order before rendering. That would be easy with rootless planes, impossible without.
I am not sure if all my troubles went away if ncplane could be rootless, but it feels like it.
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <notcurses/notcurses.h>
struct cellcopy
{
uint64_t channels;
char *string;
uint16_t stylemask;
};
struct cellcopyarray
{
struct cellcopy *cells;
unsigned int width;
unsigned int height;
};
void cellcopyarray_init_with_plane( struct cellcopyarray *array,
struct ncplane *plane)
{
unsigned int rows, cols;
struct cellcopy *copies;
struct cellcopy *copy;
struct nccell c;
if( ! array || ! plane)
return;
ncplane_dim_yx( plane, &rows, &cols);
// Allocate memory for the new array of nccell structures
copies = calloc( rows * cols, sizeof( struct cellcopy));
if( copies == NULL)
{
*array = (struct cellcopyarray) { NULL, -1 , -1};
return;
}
array->cells = copies;
array->width = cols;
array->height = rows;
// Iterate over each cell in the ncplane
for( unsigned int y = 0; y < rows; y++)
{
for( unsigned int x = 0; x < cols; x++)
{
c = (struct nccell) NCCELL_TRIVIAL_INITIALIZER; // somehow needed
if( ncplane_at_yx_cell( plane, y, x, &c) < 0)
{
free( array->cells); // Free the allocated memory in case of error
*array = (struct cellcopyarray) { NULL, -1 , -1};
return; // Failed to get cell at the specified coordinates
}
copy = copies++;
// Manually copy the cell contents
copy->string = nccell_strdup( plane, &c);
// Copy the cell channels
copy->channels = c.channels;
// Copy the cell style mask
copy->stylemask = c.stylemask;
nccell_release( plane, &c);
}
}
}
void cellcopyarray_done( struct cellcopyarray *array)
{
struct cellcopy *copies;
struct cellcopy *sentinel;
if( ! array)
return;
copies = array->cells;
sentinel = &copies[ array->height * array->width];
while( copies < sentinel)
{
free( copies->string);
++copies;
}
free( array->cells);
}
void cellcopyarray_write_to_plane( struct cellcopyarray *array, struct ncplane *plane)
{
struct nccell c;
struct cellcopy *copy;
struct cellcopy *copies;
unsigned int rows, cols;
unsigned int x, y;
if( ! array || ! plane)
return;
ncplane_dim_yx( plane, &rows, &cols);
if( array->width != cols)
abort();
if( array->height != rows)
abort();
copies = array->cells;
// Iterate over each cell in the array
for( y = 0; y < (unsigned int) array->height; y++)
for( x = 0; x < (unsigned int) array->width; x++)
{
// Get the cell from the array
// Write the cell to the ncplane
c = (struct nccell) NCCELL_TRIVIAL_INITIALIZER; // somehow needed
if( ncplane_at_yx_cell( plane, y, x, &c) < 0)
{
abort();
}
copy = copies++;
nccell_prime( plane, &c,
copy->string,
copy->stylemask,
copy->channels);
if( ncplane_putc_yx( plane, y, x, &c) < 0)
{
abort();
}
nccell_release( plane, &c);
}
}
int main(void){
if(!setlocale(LC_ALL, "")){
fprintf(stderr, "Couldn't set locale\n");
return EXIT_FAILURE;
}
struct notcurses_options opts = {
.flags = NCOPTION_INHIBIT_SETLOCALE
| NCOPTION_NO_ALTERNATE_SCREEN
| NCOPTION_SUPPRESS_BANNERS
| NCOPTION_DRAIN_INPUT,
};
struct notcurses* nc = notcurses_core_init(&opts, NULL);
if(nc == NULL){
return EXIT_FAILURE;
}
unsigned dimy, dimx;
struct ncplane* plane = notcurses_stdplane(nc);
ncplane_dim_yx(plane, &dimy, &dimx);
int r , g, b;
r = 0;
g = 0x80;
b = 0;
ncplane_set_bg_rgb8(plane, 0x40, 0x20, 0x40);
for(unsigned y = 0 ; y < dimy ; ++y){
for(unsigned x = 0 ; x < dimx ; ++x){
if(ncplane_set_fg_rgb8(plane, r, g, b)){
goto err;
}
if(ncplane_cursor_move_yx(plane, y, x)){
goto err;
}
if(ncplane_putchar(plane, 'x') <= 0){
goto err;
}
if(g % 2){
if(--b <= 0){
++g;
b = 0;
}
}else{
if(++b >= 256){
++g;
b = 255;
}
}
}
}
struct cellcopyarray array;
cellcopyarray_init_with_plane( &array, plane);
if( ! array.cells)
return EXIT_FAILURE;
ncplane_erase( plane);
cellcopyarray_write_to_plane( &array, plane);
cellcopyarray_done( &array);
if(notcurses_render(nc)){
notcurses_stop(nc);
return EXIT_FAILURE;
}
notcurses_stop(nc);
return EXIT_SUCCESS;
err:
notcurses_stop(nc);
return EXIT_FAILURE;
}