qrcode generalization #699 (#713)

Add convenience function ncplane_home(). Add an ncblitter_e param
to ncplane_qrcode(), and split int maxversion into value-result
int* ymax and int* xmax. Write the actual sizes of the resulting
visual into these parameters. Update the qrcode demo. Add the
qrcode PoC. Update demos to ncplane_home(), where possible.

ncplane_qrcode() now takes an ncblitter_e and two value-result int*s
in the place of a single value int. The final size of the displayed qrcode
is written to *ymax and *xmax. If the code can't fit within the specified
dimensions, an error is returned. Standard rules for pluggable blitters
apply regarding fallback etc. #699
This commit is contained in:
Nick Black 2020-06-13 22:24:50 -04:00 committed by GitHub
parent 22dc5014cc
commit 0084dbaa6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 192 additions and 112 deletions

View File

@ -15,6 +15,11 @@ rearrangements of Notcurses.
can be taken into account (the latter contains a `blitter_e` field). can be taken into account (the latter contains a `blitter_e` field).
* Added `ncuplot_sample()` and `ncdplot_sample()`, allowing retrieval of * Added `ncuplot_sample()` and `ncdplot_sample()`, allowing retrieval of
sample data from `ncuplot`s and `ncdplot`s, respectively. sample data from `ncuplot`s and `ncdplot`s, respectively.
* Added convenience function `ncplane_home()`, which sets the cursor
to the plane's origin (and returns `void`, since it cannot fail).
* `ncplane_qrcode()` now accepts an `ncblitter_e`, and two value-result
`int*`s `ymax` and `xmax`. The actual size of the drawn code is
returned in these parameters.
* 1.5.0 (2020-07-08) * 1.5.0 (2020-07-08)
* The various `bool`s of `struct notcurses_options` have been folded into * The various `bool`s of `struct notcurses_options` have been folded into

View File

@ -11,7 +11,7 @@ version 2, notcurses will honor Semantic Versioning.
* [Reels](#reels) ([ncreel Examples](#ncreel-examples)) * [Reels](#reels) ([ncreel Examples](#ncreel-examples))
* [Widgets](#widgets) ([Readers](#readers)) * [Widgets](#widgets) ([Readers](#readers))
* [Channels](#channels) * [Channels](#channels)
* [Visuals](#visuals) ([Multimedia](#multimedia)) * [Visuals](#visuals) ([QR codes](#qrcodes)) ([Multimedia](#multimedia)) ([Pixels](#pixels))
* [C++](#c++) * [C++](#c++)
A full API reference [is available](https://nick-black.com/notcurses/). Manual A full API reference [is available](https://nick-black.com/notcurses/). Manual
@ -2675,6 +2675,22 @@ int ncvisual_stream(struct notcurses* nc, struct ncvisual* ncv,
const struct ncvisual_options* vopts, void* curry); const struct ncvisual_options* vopts, void* curry);
``` ```
### QR codes
If build with libqrcodegen support, `ncplane_qrcode()` can be used to draw
a QR code for arbitrary data.
```c
// Draw a QR code at the current position on the plane. If there is insufficient
// room to draw the code here, or there is any other error, non-zero will be
// returned. Otherwise, the QR code "version" (size) is returned. The QR code
// is (version * 4 + 17) columns wide, and ⌈version * 4 + 17⌉ rows tall (the
// properly-scaled values are written back to '*ymax' and '*xmax').
int ncplane_qrcode(struct ncplane* n, ncblitter_e blitter, int* ymax,
int* xmax, const void* data, size_t len);
```
### Multimedia ### Multimedia
When compiled against a suitable engine (FFmpeg and OpenImageIO are both When compiled against a suitable engine (FFmpeg and OpenImageIO are both

View File

@ -1027,9 +1027,9 @@ namespace ncpp
return error_guard_cond<bool, bool> (ret, ret); return error_guard_cond<bool, bool> (ret, ret);
} }
int qrcode (int maxversion, const void *data, size_t len) const NOEXCEPT_MAYBE int qrcode (ncblitter_e blitter, int* ymax, int* xmax, const void *data, size_t len) const NOEXCEPT_MAYBE
{ {
int ret = ncplane_qrcode (plane, maxversion, data, len); int ret = ncplane_qrcode (plane, blitter, ymax, xmax, data, len);
return error_guard_cond<int> (ret, ret < 0); return error_guard_cond<int> (ret, ret < 0);
} }

View File

@ -1339,6 +1339,9 @@ ncplane_align(const struct ncplane* n, ncalign_e align, int c){
// plane's dimensions. // plane's dimensions.
API int ncplane_cursor_move_yx(struct ncplane* n, int y, int x); API int ncplane_cursor_move_yx(struct ncplane* n, int y, int x);
// Move the cursor to 0, 0. Can't fail.
API void ncplane_home(struct ncplane* n);
// Get the current position of the cursor within n. y and/or x may be NULL. // Get the current position of the cursor within n. y and/or x may be NULL.
API void ncplane_cursor_yx(const struct ncplane* n, int* RESTRICT y, int* RESTRICT x); API void ncplane_cursor_yx(const struct ncplane* n, int* RESTRICT y, int* RESTRICT x);
@ -1998,12 +2001,24 @@ ncplane_fg_alpha(const struct ncplane* nc){
return channels_fg_alpha(ncplane_channels(nc)); return channels_fg_alpha(ncplane_channels(nc));
} }
// Is the plane's foreground using the "default foreground color"?
static inline bool
ncplane_fg_default_p(const struct ncplane* nc){
return channels_fg_default_p(ncplane_channels(nc));
}
// Extract 2 bits of background alpha from 'struct ncplane', shifted to LSBs. // Extract 2 bits of background alpha from 'struct ncplane', shifted to LSBs.
static inline unsigned static inline unsigned
ncplane_bg_alpha(const struct ncplane* nc){ ncplane_bg_alpha(const struct ncplane* nc){
return channels_bg_alpha(ncplane_channels(nc)); return channels_bg_alpha(ncplane_channels(nc));
} }
// Is the plane's background using the "default background color"?
static inline bool
ncplane_bg_default_p(const struct ncplane* nc){
return channels_bg_default_p(ncplane_channels(nc));
}
// Extract 24 bits of foreground RGB from 'n', split into components. // Extract 24 bits of foreground RGB from 'n', split into components.
static inline unsigned static inline unsigned
ncplane_fg_rgb(const struct ncplane* n, unsigned* r, unsigned* g, unsigned* b){ ncplane_fg_rgb(const struct ncplane* n, unsigned* r, unsigned* g, unsigned* b){
@ -2947,11 +2962,10 @@ API int ncsubproc_destroy(struct ncsubproc* n);
// Draw a QR code at the current position on the plane. If there is insufficient // Draw a QR code at the current position on the plane. If there is insufficient
// room to draw the code here, or there is any other error, non-zero will be // room to draw the code here, or there is any other error, non-zero will be
// returned. Otherwise, the QR code "version" (size) is returned. The QR code // returned. Otherwise, the QR code "version" (size) is returned. The QR code
// is (version * 4 + 17) columns wide, and ⌈version * 4 + 17 / 2⌉ rows tall. If // is (version * 4 + 17) columns wide, and ⌈version * 4 + 17⌉ rows tall (the
// maxversion is not zero, it plays a hard limit on the QR code size. Though the // properly-scaled values are written back to '*ymax' and '*xmax').
// max version of current QR codes is 40, greater values are allowed, for API int ncplane_qrcode(struct ncplane* n, ncblitter_e blitter, int* ymax,
// future compatability (provide 0 for no artificial bound). int* xmax, const void* data, size_t len);
API int ncplane_qrcode(struct ncplane* n, int maxversion, const void* data, size_t len);
#define NCREADER_OPTION_HORSCROLL 0x0001ull #define NCREADER_OPTION_HORSCROLL 0x0001ull
#define NCREADER_OPTION_VERSCROLL 0x0002ull #define NCREADER_OPTION_VERSCROLL 0x0002ull

View File

@ -502,6 +502,7 @@ void ncreader_destroy(struct ncreader* n, char** contents);
int ncplane_puttext(struct ncplane* n, int y, ncalign_e align, const char* text, size_t* bytes); int ncplane_puttext(struct ncplane* n, int y, ncalign_e align, const char* text, size_t* bytes);
int ncplane_putnstr_yx(struct ncplane* n, int y, int x, size_t s, const char* gclusters); int ncplane_putnstr_yx(struct ncplane* n, int y, int x, size_t s, const char* gclusters);
int ncplane_putnstr_aligned(struct ncplane* n, int y, ncalign_e align, size_t s, const char* gclustarr); int ncplane_putnstr_aligned(struct ncplane* n, int y, ncalign_e align, size_t s, const char* gclustarr);
int ncplane_qrcode(struct ncplane* n, ncblitter_e blitter, int* ymax, int* xmax, const void* data, size_t len);
""") """)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -55,7 +55,7 @@ int allglyphs_demo(struct notcurses* nc){
int dimy, dimx; int dimy, dimx;
struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx); struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
ncplane_erase(n); ncplane_erase(n);
ncplane_cursor_move_yx(n, 0, 0); ncplane_home(n);
uint32_t tl = 0, tr = 0, bl = 0, br = 0; uint32_t tl = 0, tr = 0, bl = 0, br = 0;
channel_set_rgb(&tl, 0, 0, 0); channel_set_rgb(&tl, 0, 0, 0);
channel_set_rgb(&tr, 0, 0xff, 0); channel_set_rgb(&tr, 0, 0xff, 0);

View File

@ -7,30 +7,32 @@ static int y, x, dy, dx;
static int static int
dragonmayer(struct ncvisual* ncv, const char* str, int iters){ dragonmayer(struct ncvisual* ncv, const char* str, int iters){
int total = 0;
char c; char c;
int r; int r;
while( (c = *str++) ){ while( (c = *str++) ){
switch(c){ switch(c){
case 'X': case 'X':
if(iters > 1){ if(iters > 1){
if( (r = dragonmayer(ncv, "X+YF+", iters - 1)) ){ if((r = dragonmayer(ncv, "X+YF+", iters - 1)) < 0){
return r; return r;
} }
total += r;
} }
break; break;
case 'Y': case 'Y':
if(iters > 1){ if(iters > 1){
if( (r = dragonmayer(ncv, "-FX-Y", iters - 1)) ){ if((r = dragonmayer(ncv, "-FX-Y", iters - 1)) < 0){
return r; return r;
} }
total += r;
} }
break; break;
case '+': { int tmp = dy; dy = -dx; dx = tmp; break; } case '+': { int tmp = dy; dy = -dx; dx = tmp; break; }
case '-': { int tmp = -dy; dy = dx; dx = tmp; break; } case '-': { int tmp = -dy; dy = dx; dx = tmp; break; }
case 'F': // FIXME want a line case 'F': // FIXME want a line
// FIXME some of these will fail...hella lame, check against dims if(ncvisual_set_yx(ncv, y, x, pixel) == 0){
if(ncvisual_set_yx(ncv, y, x, pixel) < 0){ ++total;
done = true;
} }
x += dx; x += dx;
y += dy; y += dy;
@ -39,7 +41,7 @@ dragonmayer(struct ncvisual* ncv, const char* str, int iters){
return -1; return -1;
} }
} }
return 0; return total;
} }
int dragon_demo(struct notcurses* nc){ int dragon_demo(struct notcurses* nc){
@ -78,17 +80,20 @@ int dragon_demo(struct notcurses* nc){
free(rgba); free(rgba);
struct timespec scaled; struct timespec scaled;
timespec_div(&demodelay, 4, &scaled); timespec_div(&demodelay, 4, &scaled);
int lasttotal = 0;
int iters = 0; int iters = 0;
int r = 0;
do{ do{
++iters; ++iters;
lasttotal = r;
pixel = 0xffffffffull; pixel = 0xffffffffull;
ncpixel_set_rgb(&pixel, 0, 0x11 * iters, 0); ncpixel_set_rgb(&pixel, 0, 0xb * iters, 0);
dx = dxstart; dx = dxstart;
dy = dystart; dy = dystart;
x = dimx / 2; x = dimx / 2;
y = dimy / 2; y = dimy / 3;
int r = dragonmayer(ncv, LINDENSTART, iters); r = dragonmayer(ncv, LINDENSTART, iters);
if(r){ if(r < 0){
ncvisual_destroy(ncv); ncvisual_destroy(ncv);
return r; return r;
} }
@ -102,8 +107,7 @@ int dragon_demo(struct notcurses* nc){
} }
DEMO_RENDER(nc); DEMO_RENDER(nc);
demo_nanosleep(nc, &scaled); demo_nanosleep(nc, &scaled);
ncplane_erase(n); }while(lasttotal != r);
}while(!done);
ncvisual_destroy(ncv); ncvisual_destroy(ncv);
return 0; return 0;
} }

View File

@ -51,11 +51,11 @@ zoom_map(struct notcurses* nc, const char* map, int* ret){
// we start at the lower left corner of the outzoomed map // we start at the lower left corner of the outzoomed map
int truex, truey; // dimensions of true display int truex, truey; // dimensions of true display
notcurses_term_dim_yx(nc, &truey, &truex); notcurses_term_dim_yx(nc, &truey, &truex);
int delty = yscale; int delty = 2;
int deltx = xscale; int deltx = 2;
if(truey > truex){ if(truey > truex){
++delty; ++delty;
}else if(truex > truey * 2){ }else if(truex > truey){
++deltx; ++deltx;
} }
// to zoom in on the map, we're going to scale the full image to a plane // to zoom in on the map, we're going to scale the full image to a plane

View File

@ -32,9 +32,7 @@ int intro(struct notcurses* nc){
channel_set_rgb(&ccll, 0x88, 0, 0xcc); channel_set_rgb(&ccll, 0x88, 0, 0xcc);
channel_set_rgb(&cclr, 0, 0, 0); channel_set_rgb(&cclr, 0, 0, 0);
// we use full block rather+fg than space+bg to conflict less with the menu // we use full block rather+fg than space+bg to conflict less with the menu
if(ncplane_cursor_move_yx(ncp, 0, 0)){ ncplane_home(ncp);
return -1;
}
if(ncplane_highgradient_sized(ncp, ccul, ccur, ccll, cclr, rows, cols) <= 0){ if(ncplane_highgradient_sized(ncp, ccul, ccur, ccll, cclr, rows, cols) <= 0){
return -1; return -1;
} }

View File

@ -199,12 +199,12 @@ int normal_demo(struct notcurses* nc){
} }
if(notcurses_canutf8(nc)){ if(notcurses_canutf8(nc)){
ncplane_erase(nstd); ncplane_erase(nstd);
ncplane_cursor_move_yx(n, 0, 0); ncplane_home(n);
if(rotate_plane(nc, n)){ if(rotate_plane(nc, n)){
goto err; goto err;
} }
} }
ncplane_cursor_move_yx(n, 0, 0); ncplane_home(n);
uint64_t tl, tr, bl, br; uint64_t tl, tr, bl, br;
tl = tr = bl = br = 0; tl = tr = bl = br = 0;
channels_set_fg_rgb(&tl, 0, 0, 0); channels_set_fg_rgb(&tl, 0, 0, 0);

View File

@ -1,20 +1,5 @@
#include "demo.h" #include "demo.h"
#ifdef USE_QRCODEGEN
#include <sys/random.h> #include <sys/random.h>
// FIXME duplicated--ought these just be exported?
#define QR_BASE_SIZE 17
#define PER_QR_VERSION 4
static inline int
qrcode_rows(int version){
return (QR_BASE_SIZE + (version * PER_QR_VERSION)) / 2;
}
static inline int
qrcode_cols(int version){
return QR_BASE_SIZE + (version * PER_QR_VERSION);
}
#endif
int qrcode_demo(struct notcurses* nc){ int qrcode_demo(struct notcurses* nc){
if(!notcurses_canutf8(nc)){ if(!notcurses_canutf8(nc)){
@ -36,33 +21,19 @@ int qrcode_demo(struct notcurses* nc){
memcpy(data + done, &r, sizeof(r)); memcpy(data + done, &r, sizeof(r));
done += sizeof(r); done += sizeof(r);
} }
if(ncplane_cursor_move_yx(n, 0, 0)){ ncplane_home(n);
ncplane_destroy(n); int y = dimy, x = dimx;
return -1; ncplane_home(n);
} int qlen = ncplane_qrcode(n, NCBLIT_DEFAULT, &y, &x, data, len);
int qlen = ncplane_qrcode(n, 0, data, len); if(qlen > 0){ // FIXME can fail due to being too large for display; distinguish this case
// can fail due to being too large for the terminal (FIXME), or ASCII mode ncplane_move_yx(n, (dimy - y) / 2, (dimx - x) / 2);
if(qlen > 0){ ncplane_home(n);
ncplane_move_yx(n, dimy / 2 - qrcode_rows(qlen) / 2, ncplane_set_fg_rgb(n, random() % 255 + 1, random() % 255 + 1, random() % 255 + 1);
dimx / 2 - qrcode_cols(qlen) / 2);
if(ncplane_cursor_move_yx(n, 0, 0)){
ncplane_destroy(n);
return -1;
}
uint64_t tl = 0, bl = 0, br = 0, tr = 0;
channels_set_fg_rgb(&tl, random() % 255 + 1, random() % 255 + 1, random() % 255 + 1);
channels_set_fg_rgb(&tr, random() % 255 + 1, random() % 255 + 1, random() % 255 + 1);
channels_set_fg_rgb(&bl, random() % 255 + 1, random() % 255 + 1, random() % 255 + 1);
channels_set_fg_rgb(&br, random() % 255 + 1, random() % 255 + 1, random() % 255 + 1);
if(ncplane_stain(n, qrcode_rows(qlen), qrcode_cols(qlen), tl, tr, bl, br) <= 0){
ncplane_destroy(n);
return -1;
}
DEMO_RENDER(nc); DEMO_RENDER(nc);
} }
} }
ncplane_mergedown(n, stdn); // leave the last one on-screen
ncplane_destroy(n); ncplane_destroy(n);
#endif #endif
DEMO_RENDER(nc);
return 0; return 0;
} }

View File

@ -47,7 +47,7 @@ draw_block(struct ncplane* nn, uint32_t blockstart){
cell_set_fg_rgb(&vl, 255, 255, 255); cell_set_fg_rgb(&vl, 255, 255, 255);
cell_set_bg_rgb(&hl, 0, 0, 0); cell_set_bg_rgb(&hl, 0, 0, 0);
cell_set_bg_rgb(&vl, 0, 0, 0); cell_set_bg_rgb(&vl, 0, 0, 0);
ncplane_cursor_move_yx(nn, 0, 0); ncplane_home(nn);
unsigned control = NCBOXGRAD_TOP | NCBOXGRAD_BOTTOM | NCBOXGRAD_LEFT | NCBOXGRAD_RIGHT; unsigned control = NCBOXGRAD_TOP | NCBOXGRAD_BOTTOM | NCBOXGRAD_LEFT | NCBOXGRAD_RIGHT;
if(ncplane_box_sized(nn, &ul, &ur, &ll, &lr, &hl, &vl, dimy, dimx, control)){ if(ncplane_box_sized(nn, &ul, &ur, &ll, &lr, &hl, &vl, dimy, dimx, control)){
return -1; return -1;

View File

@ -534,7 +534,7 @@ int ncplane_rotate_ccw(ncplane* n){
static inline int static inline int
qrcode_rows(int version){ qrcode_rows(int version){
return (QR_BASE_SIZE + (version * PER_QR_VERSION)) / 2; return QR_BASE_SIZE + (version * PER_QR_VERSION);
} }
static inline int static inline int
@ -542,9 +542,10 @@ qrcode_cols(int version){
return QR_BASE_SIZE + (version * PER_QR_VERSION); return QR_BASE_SIZE + (version * PER_QR_VERSION);
} }
int ncplane_qrcode(ncplane* n, int maxversion, const void* data, size_t len){ int ncplane_qrcode(ncplane* n, ncblitter_e blitter, int* ymax,
int* xmax, const void* data, size_t len){
const int MAX_QR_VERSION = 40; // QR library only supports up to 40 const int MAX_QR_VERSION = 40; // QR library only supports up to 40
if(maxversion < 0){ if(*ymax <= 0 || *xmax <= 0){
return -1; return -1;
} }
if(len == 0){ if(len == 0){
@ -552,25 +553,24 @@ int ncplane_qrcode(ncplane* n, int maxversion, const void* data, size_t len){
} }
const int starty = n->y; const int starty = n->y;
const int startx = n->x; const int startx = n->x;
const int availx = n->lenx - startx; if(*xmax > n->lenx - startx){
const int availy = n->leny - starty;
if(availy < qrcode_rows(1)){
return -1; return -1;
} }
if(availx < qrcode_cols(1)){ if(*ymax > n->leny - starty){
return -1; return -1;
} }
const int availsquare = availy * 2 < availx ? availy * 2 : availx; if(*ymax < qrcode_rows(1)){
const int roomforver = (availsquare - QR_BASE_SIZE) / 4; return -1;
if(maxversion == 0){
maxversion = roomforver;
}else if(maxversion > roomforver){
maxversion = roomforver;
} }
if(maxversion > MAX_QR_VERSION){ if(*xmax < qrcode_cols(1)){
maxversion = MAX_QR_VERSION; return -1;
} }
const size_t bsize = qrcodegen_BUFFER_LEN_FOR_VERSION(maxversion); const int availsquare = *ymax * 2 < *xmax ? *ymax * 2 : *xmax;
int roomforver = (availsquare - QR_BASE_SIZE) / PER_QR_VERSION;
if(roomforver > MAX_QR_VERSION){
roomforver = MAX_QR_VERSION;
}
const size_t bsize = qrcodegen_BUFFER_LEN_FOR_VERSION(roomforver);
if(bsize < len){ if(bsize < len){
return -1; return -1;
} }
@ -581,40 +581,59 @@ int ncplane_qrcode(ncplane* n, int maxversion, const void* data, size_t len){
free(dst); free(dst);
return -1; return -1;
} }
unsigned r, g, b;
// FIXME default might not be all-white
if(ncplane_fg_default_p(n)){
r = g = b = 0xff;
}else{
ncplane_fg_rgb(n, &r, &g, &b);
}
memcpy(src, data, len); memcpy(src, data, len);
int ret = -1; int ret = -1;
if(qrcodegen_encodeBinary(src, len, dst, qrcodegen_Ecc_HIGH, 1, maxversion, qrcodegen_Mask_AUTO, true)){ int yscale, xscale;
ret = qrcodegen_getSize(dst); if(qrcodegen_encodeBinary(src, len, dst, qrcodegen_Ecc_HIGH, 1, roomforver, qrcodegen_Mask_AUTO, true)){
for(int y = starty ; y < starty + (ret + 1) / 2 ; ++y){ const int square = qrcodegen_getSize(dst);
for(int x = startx ; x < startx + ret ; ++x){ uint32_t* rgba = malloc(square * square * sizeof(uint32_t));
const bool top = qrcodegen_getModule(dst, x, y); if(rgba){
const bool bot = qrcodegen_getModule(dst, x, y + 1); for(int y = starty ; y < starty + square ; ++y){
const char* egc; for(int x = startx ; x < startx + square ; ++x){
if(top && bot){ const bool pixel = qrcodegen_getModule(dst, x, y);
egc = ""; ncpixel_set_a(&rgba[y * square + x], 0xff);
}else if(top){ ncpixel_set_rgb(&rgba[y * square + x], r * pixel, g * pixel, b * pixel);
egc = "";
}else if(bot){
egc = "";
}else{
egc = " ";
} }
int sbytes; }
if(ncplane_putegc_yx(n, y, x, egc, &sbytes) <= 0){ struct ncvisual* ncv = ncvisual_from_rgba(rgba, square, square * sizeof(uint32_t), square);
ret = -1; free(rgba);
break; if(ncv){
ret = square;
struct ncvisual_options vopts = {
.n = n,
.blitter = blitter,
};
if(ncvisual_render(n->nc, ncv, &vopts) == n){
ret = square;
} }
ncvisual_geom(n->nc, ncv, &vopts, NULL, NULL, &yscale, &xscale);
} }
} }
} }
free(src); free(src);
free(dst); free(dst);
return ret < 0 ? ret : (ret - QR_BASE_SIZE) / PER_QR_VERSION; if(ret > 0){
ret = (ret - QR_BASE_SIZE) / PER_QR_VERSION;
*ymax = qrcode_rows(ret) / yscale;
*xmax = qrcode_cols(ret) / xscale;
return ret;
}
return -1;
} }
#else #else
int ncplane_qrcode(ncplane* n, int maxversion, const void* data, size_t len){ int ncplane_qrcode(ncplane* n, ncblitter_e blitter, int* ymax, int* xmax,
const void* data, size_t len){
(void)n; (void)n;
(void)maxversion; (void)blitter;
(void)ymax;
(void)xmax;
(void)data; (void)data;
(void)len; (void)len;
return -1; return -1;

View File

@ -340,6 +340,11 @@ ncplane* ncplane_aligned(ncplane* n, int rows, int cols, int yoff,
return ncplane_create(n->nc, n, rows, cols, yoff, ncplane_align(n, align, cols), opaque); return ncplane_create(n->nc, n, rows, cols, yoff, ncplane_align(n, align, cols), opaque);
} }
void ncplane_home(ncplane* n){
n->x = 0;
n->y = 0;
}
inline int ncplane_cursor_move_yx(ncplane* n, int y, int x){ inline int ncplane_cursor_move_yx(ncplane* n, int y, int x){
if(x >= n->lenx){ if(x >= n->lenx){
return -1; return -1;

View File

@ -241,9 +241,7 @@ class ncppplot {
} }
} }
} }
if(ncplane_cursor_move_yx(ncp, 0, 0)){ ncplane_home(ncp);
return -1;
}
return 0; return 0;
} }

View File

@ -142,7 +142,7 @@ int runreels(NotCurses& nc, ncreel_options& nopts){
case 'q': case 'q':
return 0; return 0;
case 'a':{ case 'a':{
TabletCtx* tctx = new TabletCtx(); auto tctx = new TabletCtx();
nr->add(nullptr, nullptr, tabletfxn, tctx); nr->add(nullptr, nullptr, tabletfxn, tctx);
break; break;
} }

47
src/poc/qrcode.c Normal file
View File

@ -0,0 +1,47 @@
#include <unistd.h>
#include <locale.h>
#include <notcurses/notcurses.h>
static int
render_qrcode(struct ncplane* n, int dimy, int dimx, const char* text){
int y = dimy, x = dimx;
ncplane_home(n);
int ver = ncplane_qrcode(n, NCBLIT_DEFAULT, &y, &x, text, strlen(text));
if(ver < 0){
return -1;
}
if(ncplane_putstr_yx(n, y + 1, 0, text) < 0){
return -1;
}
if(notcurses_render(ncplane_notcurses(n))){
return -1;
}
sleep(2);
return 0;
}
int main(int argc, const char** argv){
if(setlocale(LC_ALL, "") == NULL){
return EXIT_FAILURE;
}
struct notcurses_options opts = {
.flags = NCOPTION_INHIBIT_SETLOCALE | NCOPTION_NO_ALTERNATE_SCREEN,
};
struct notcurses* nc = notcurses_init(&opts, NULL);
int dimy, dimx;
struct ncplane* std = notcurses_stddim_yx(nc, &dimy, &dimx);
while(*++argv){
if(render_qrcode(std, dimy, dimx, *argv)){
notcurses_stop(nc);
return EXIT_FAILURE;
}
}
if(argc < 2){
if(render_qrcode(std, dimy, dimx, "https://nick-black.com")){
notcurses_stop(nc);
return EXIT_FAILURE;
}
}
notcurses_stop(nc);
return EXIT_SUCCESS;
}

View File

@ -12,7 +12,7 @@ rotate_grad(struct notcurses* nc){
}; };
int dimy, dimx; int dimy, dimx;
struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx); struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
ncplane_cursor_move_yx(n, 0, 0); ncplane_home(n);
uint32_t tl = 0, tr = 0, bl = 0, br = 0; uint32_t tl = 0, tr = 0, bl = 0, br = 0;
channel_set_rgb(&tl, 0xff, 0, 0); channel_set_rgb(&tl, 0xff, 0, 0);
channel_set_rgb(&tr, 0, 0, 0xff); channel_set_rgb(&tr, 0, 0, 0xff);

View File

@ -440,7 +440,9 @@ TEST_CASE("Fills") {
#ifdef USE_QRCODEGEN #ifdef USE_QRCODEGEN
SUBCASE("QRCodes") { SUBCASE("QRCodes") {
const char* qr = "a very simple qr code"; const char* qr = "a very simple qr code";
CHECK(0 < ncplane_qrcode(n_, 0, qr, strlen(qr))); int dimy, dimx;
ncplane_dim_yx(n_, &dimy, &dimx);
CHECK(0 < ncplane_qrcode(n_, NCBLIT_DEFAULT, &dimy, &dimx, qr, strlen(qr)));
CHECK(0 == notcurses_render(nc_)); CHECK(0 == notcurses_render(nc_));
} }
#endif #endif