From 0084dbaa6d95d7eab967101d65592bb3c7d2da65 Mon Sep 17 00:00:00 2001 From: Nick Black Date: Sat, 13 Jun 2020 22:24:50 -0400 Subject: [PATCH] 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 --- NEWS.md | 5 ++ USAGE.md | 18 ++++- include/ncpp/Plane.hh | 4 +- include/notcurses/notcurses.h | 24 +++++-- python/src/notcurses/build_notcurses.py | 1 + src/demo/all.c | 2 +- src/demo/dragon.c | 28 ++++---- src/demo/eagle.c | 6 +- src/demo/intro.c | 4 +- src/demo/normal.c | 4 +- src/demo/qrcode.c | 47 +++--------- src/demo/unicodeblocks.c | 2 +- src/lib/fill.c | 95 +++++++++++++++---------- src/lib/notcurses.c | 5 ++ src/lib/plot.h | 4 +- src/ncreel/main.cpp | 2 +- src/poc/qrcode.c | 47 ++++++++++++ src/poc/rotator.c | 2 +- tests/fills.cpp | 4 +- 19 files changed, 192 insertions(+), 112 deletions(-) create mode 100644 src/poc/qrcode.c diff --git a/NEWS.md b/NEWS.md index 71134dfd1..a1290cf0b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -15,6 +15,11 @@ rearrangements of Notcurses. can be taken into account (the latter contains a `blitter_e` field). * Added `ncuplot_sample()` and `ncdplot_sample()`, allowing retrieval of 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) * The various `bool`s of `struct notcurses_options` have been folded into diff --git a/USAGE.md b/USAGE.md index a5fae62dc..2534f3f5e 100644 --- a/USAGE.md +++ b/USAGE.md @@ -11,7 +11,7 @@ version 2, notcurses will honor Semantic Versioning. * [Reels](#reels) ([ncreel Examples](#ncreel-examples)) * [Widgets](#widgets) ([Readers](#readers)) * [Channels](#channels) -* [Visuals](#visuals) ([Multimedia](#multimedia)) +* [Visuals](#visuals) ([QR codes](#qrcodes)) ([Multimedia](#multimedia)) ([Pixels](#pixels)) * [C++](#c++) 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); ``` +### 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 When compiled against a suitable engine (FFmpeg and OpenImageIO are both diff --git a/include/ncpp/Plane.hh b/include/ncpp/Plane.hh index ad0e30425..564caccbc 100644 --- a/include/ncpp/Plane.hh +++ b/include/ncpp/Plane.hh @@ -1027,9 +1027,9 @@ namespace ncpp return error_guard_cond (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 (ret, ret < 0); } diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index f9d92b6c6..acf4435b0 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -1339,6 +1339,9 @@ ncplane_align(const struct ncplane* n, ncalign_e align, int c){ // plane's dimensions. 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. 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)); } +// 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. static inline unsigned ncplane_bg_alpha(const struct ncplane* 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. static inline unsigned 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 // 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 / 2⌉ rows tall. If -// maxversion is not zero, it plays a hard limit on the QR code size. Though the -// max version of current QR codes is 40, greater values are allowed, for -// future compatability (provide 0 for no artificial bound). -API int ncplane_qrcode(struct ncplane* n, int maxversion, const void* data, size_t len); +// is (version * 4 + 17) columns wide, and ⌈version * 4 + 17⌉ rows tall (the +// properly-scaled values are written back to '*ymax' and '*xmax'). +API int ncplane_qrcode(struct ncplane* n, ncblitter_e blitter, int* ymax, + int* xmax, const void* data, size_t len); #define NCREADER_OPTION_HORSCROLL 0x0001ull #define NCREADER_OPTION_VERSCROLL 0x0002ull diff --git a/python/src/notcurses/build_notcurses.py b/python/src/notcurses/build_notcurses.py index 5a6842036..1d6937702 100644 --- a/python/src/notcurses/build_notcurses.py +++ b/python/src/notcurses/build_notcurses.py @@ -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_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_qrcode(struct ncplane* n, ncblitter_e blitter, int* ymax, int* xmax, const void* data, size_t len); """) if __name__ == "__main__": diff --git a/src/demo/all.c b/src/demo/all.c index d94d2a4df..15589508c 100644 --- a/src/demo/all.c +++ b/src/demo/all.c @@ -55,7 +55,7 @@ int allglyphs_demo(struct notcurses* nc){ int dimy, dimx; struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx); ncplane_erase(n); - ncplane_cursor_move_yx(n, 0, 0); + ncplane_home(n); uint32_t tl = 0, tr = 0, bl = 0, br = 0; channel_set_rgb(&tl, 0, 0, 0); channel_set_rgb(&tr, 0, 0xff, 0); diff --git a/src/demo/dragon.c b/src/demo/dragon.c index 5a23e698f..2ef8bb7f3 100644 --- a/src/demo/dragon.c +++ b/src/demo/dragon.c @@ -7,30 +7,32 @@ static int y, x, dy, dx; static int dragonmayer(struct ncvisual* ncv, const char* str, int iters){ + int total = 0; char c; int r; while( (c = *str++) ){ switch(c){ case 'X': if(iters > 1){ - if( (r = dragonmayer(ncv, "X+YF+", iters - 1)) ){ + if((r = dragonmayer(ncv, "X+YF+", iters - 1)) < 0){ return r; } + total += r; } break; case 'Y': if(iters > 1){ - if( (r = dragonmayer(ncv, "-FX-Y", iters - 1)) ){ + if((r = dragonmayer(ncv, "-FX-Y", iters - 1)) < 0){ return r; } + total += r; } 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 - // FIXME some of these will fail...hella lame, check against dims - if(ncvisual_set_yx(ncv, y, x, pixel) < 0){ - done = true; + if(ncvisual_set_yx(ncv, y, x, pixel) == 0){ + ++total; } x += dx; y += dy; @@ -39,7 +41,7 @@ dragonmayer(struct ncvisual* ncv, const char* str, int iters){ return -1; } } - return 0; + return total; } int dragon_demo(struct notcurses* nc){ @@ -78,17 +80,20 @@ int dragon_demo(struct notcurses* nc){ free(rgba); struct timespec scaled; timespec_div(&demodelay, 4, &scaled); + int lasttotal = 0; int iters = 0; + int r = 0; do{ ++iters; + lasttotal = r; pixel = 0xffffffffull; - ncpixel_set_rgb(&pixel, 0, 0x11 * iters, 0); + ncpixel_set_rgb(&pixel, 0, 0xb * iters, 0); dx = dxstart; dy = dystart; x = dimx / 2; - y = dimy / 2; - int r = dragonmayer(ncv, LINDENSTART, iters); - if(r){ + y = dimy / 3; + r = dragonmayer(ncv, LINDENSTART, iters); + if(r < 0){ ncvisual_destroy(ncv); return r; } @@ -102,8 +107,7 @@ int dragon_demo(struct notcurses* nc){ } DEMO_RENDER(nc); demo_nanosleep(nc, &scaled); - ncplane_erase(n); - }while(!done); + }while(lasttotal != r); ncvisual_destroy(ncv); return 0; } diff --git a/src/demo/eagle.c b/src/demo/eagle.c index e03cd3311..bc937611f 100644 --- a/src/demo/eagle.c +++ b/src/demo/eagle.c @@ -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 int truex, truey; // dimensions of true display notcurses_term_dim_yx(nc, &truey, &truex); - int delty = yscale; - int deltx = xscale; + int delty = 2; + int deltx = 2; if(truey > truex){ ++delty; - }else if(truex > truey * 2){ + }else if(truex > truey){ ++deltx; } // to zoom in on the map, we're going to scale the full image to a plane diff --git a/src/demo/intro.c b/src/demo/intro.c index 1b37e3279..b54a9bfb6 100644 --- a/src/demo/intro.c +++ b/src/demo/intro.c @@ -32,9 +32,7 @@ int intro(struct notcurses* nc){ channel_set_rgb(&ccll, 0x88, 0, 0xcc); channel_set_rgb(&cclr, 0, 0, 0); // we use full block rather+fg than space+bg to conflict less with the menu - if(ncplane_cursor_move_yx(ncp, 0, 0)){ - return -1; - } + ncplane_home(ncp); if(ncplane_highgradient_sized(ncp, ccul, ccur, ccll, cclr, rows, cols) <= 0){ return -1; } diff --git a/src/demo/normal.c b/src/demo/normal.c index 0e0f423b5..44d5ead88 100644 --- a/src/demo/normal.c +++ b/src/demo/normal.c @@ -199,12 +199,12 @@ int normal_demo(struct notcurses* nc){ } if(notcurses_canutf8(nc)){ ncplane_erase(nstd); - ncplane_cursor_move_yx(n, 0, 0); + ncplane_home(n); if(rotate_plane(nc, n)){ goto err; } } - ncplane_cursor_move_yx(n, 0, 0); + ncplane_home(n); uint64_t tl, tr, bl, br; tl = tr = bl = br = 0; channels_set_fg_rgb(&tl, 0, 0, 0); diff --git a/src/demo/qrcode.c b/src/demo/qrcode.c index 7bda73675..026c7e8bf 100644 --- a/src/demo/qrcode.c +++ b/src/demo/qrcode.c @@ -1,20 +1,5 @@ #include "demo.h" - -#ifdef USE_QRCODEGEN #include -// 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){ if(!notcurses_canutf8(nc)){ @@ -36,33 +21,19 @@ int qrcode_demo(struct notcurses* nc){ memcpy(data + done, &r, sizeof(r)); done += sizeof(r); } - if(ncplane_cursor_move_yx(n, 0, 0)){ - ncplane_destroy(n); - return -1; - } - int qlen = ncplane_qrcode(n, 0, data, len); - // can fail due to being too large for the terminal (FIXME), or ASCII mode - if(qlen > 0){ - ncplane_move_yx(n, dimy / 2 - qrcode_rows(qlen) / 2, - 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; - } + ncplane_home(n); + int y = dimy, x = dimx; + ncplane_home(n); + int qlen = ncplane_qrcode(n, NCBLIT_DEFAULT, &y, &x, data, len); + if(qlen > 0){ // FIXME can fail due to being too large for display; distinguish this case + ncplane_move_yx(n, (dimy - y) / 2, (dimx - x) / 2); + ncplane_home(n); + ncplane_set_fg_rgb(n, random() % 255 + 1, random() % 255 + 1, random() % 255 + 1); DEMO_RENDER(nc); } } + ncplane_mergedown(n, stdn); // leave the last one on-screen ncplane_destroy(n); #endif - DEMO_RENDER(nc); return 0; } diff --git a/src/demo/unicodeblocks.c b/src/demo/unicodeblocks.c index 811d7b6c3..1f5cc4fa1 100644 --- a/src/demo/unicodeblocks.c +++ b/src/demo/unicodeblocks.c @@ -47,7 +47,7 @@ draw_block(struct ncplane* nn, uint32_t blockstart){ cell_set_fg_rgb(&vl, 255, 255, 255); cell_set_bg_rgb(&hl, 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; if(ncplane_box_sized(nn, &ul, &ur, &ll, &lr, &hl, &vl, dimy, dimx, control)){ return -1; diff --git a/src/lib/fill.c b/src/lib/fill.c index 3f3b846f6..924b3fbee 100644 --- a/src/lib/fill.c +++ b/src/lib/fill.c @@ -534,7 +534,7 @@ int ncplane_rotate_ccw(ncplane* n){ static inline int qrcode_rows(int version){ - return (QR_BASE_SIZE + (version * PER_QR_VERSION)) / 2; + return QR_BASE_SIZE + (version * PER_QR_VERSION); } static inline int @@ -542,9 +542,10 @@ qrcode_cols(int 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 - if(maxversion < 0){ + if(*ymax <= 0 || *xmax <= 0){ return -1; } 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 startx = n->x; - const int availx = n->lenx - startx; - const int availy = n->leny - starty; - if(availy < qrcode_rows(1)){ + if(*xmax > n->lenx - startx){ return -1; } - if(availx < qrcode_cols(1)){ + if(*ymax > n->leny - starty){ return -1; } - const int availsquare = availy * 2 < availx ? availy * 2 : availx; - const int roomforver = (availsquare - QR_BASE_SIZE) / 4; - if(maxversion == 0){ - maxversion = roomforver; - }else if(maxversion > roomforver){ - maxversion = roomforver; + if(*ymax < qrcode_rows(1)){ + return -1; } - if(maxversion > MAX_QR_VERSION){ - maxversion = MAX_QR_VERSION; + if(*xmax < qrcode_cols(1)){ + 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){ return -1; } @@ -581,40 +581,59 @@ int ncplane_qrcode(ncplane* n, int maxversion, const void* data, size_t len){ free(dst); 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); int ret = -1; - if(qrcodegen_encodeBinary(src, len, dst, qrcodegen_Ecc_HIGH, 1, maxversion, qrcodegen_Mask_AUTO, true)){ - ret = qrcodegen_getSize(dst); - for(int y = starty ; y < starty + (ret + 1) / 2 ; ++y){ - for(int x = startx ; x < startx + ret ; ++x){ - const bool top = qrcodegen_getModule(dst, x, y); - const bool bot = qrcodegen_getModule(dst, x, y + 1); - const char* egc; - if(top && bot){ - egc = "█"; - }else if(top){ - egc = "▀"; - }else if(bot){ - egc = "▄"; - }else{ - egc = " "; + int yscale, xscale; + if(qrcodegen_encodeBinary(src, len, dst, qrcodegen_Ecc_HIGH, 1, roomforver, qrcodegen_Mask_AUTO, true)){ + const int square = qrcodegen_getSize(dst); + uint32_t* rgba = malloc(square * square * sizeof(uint32_t)); + if(rgba){ + for(int y = starty ; y < starty + square ; ++y){ + for(int x = startx ; x < startx + square ; ++x){ + const bool pixel = qrcodegen_getModule(dst, x, y); + ncpixel_set_a(&rgba[y * square + x], 0xff); + ncpixel_set_rgb(&rgba[y * square + x], r * pixel, g * pixel, b * pixel); } - int sbytes; - if(ncplane_putegc_yx(n, y, x, egc, &sbytes) <= 0){ - ret = -1; - break; + } + struct ncvisual* ncv = ncvisual_from_rgba(rgba, square, square * sizeof(uint32_t), square); + free(rgba); + 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(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 -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)maxversion; + (void)blitter; + (void)ymax; + (void)xmax; (void)data; (void)len; return -1; diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index 70c3e9366..c20870505 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -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); } +void ncplane_home(ncplane* n){ + n->x = 0; + n->y = 0; +} + inline int ncplane_cursor_move_yx(ncplane* n, int y, int x){ if(x >= n->lenx){ return -1; diff --git a/src/lib/plot.h b/src/lib/plot.h index 977b427a6..76dfc6b18 100644 --- a/src/lib/plot.h +++ b/src/lib/plot.h @@ -241,9 +241,7 @@ class ncppplot { } } } - if(ncplane_cursor_move_yx(ncp, 0, 0)){ - return -1; - } + ncplane_home(ncp); return 0; } diff --git a/src/ncreel/main.cpp b/src/ncreel/main.cpp index 6f8c7ccee..38e38ead8 100644 --- a/src/ncreel/main.cpp +++ b/src/ncreel/main.cpp @@ -142,7 +142,7 @@ int runreels(NotCurses& nc, ncreel_options& nopts){ case 'q': return 0; case 'a':{ - TabletCtx* tctx = new TabletCtx(); + auto tctx = new TabletCtx(); nr->add(nullptr, nullptr, tabletfxn, tctx); break; } diff --git a/src/poc/qrcode.c b/src/poc/qrcode.c new file mode 100644 index 000000000..2e4b2ba6d --- /dev/null +++ b/src/poc/qrcode.c @@ -0,0 +1,47 @@ +#include +#include +#include + +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; +} diff --git a/src/poc/rotator.c b/src/poc/rotator.c index 85dce2dcf..04a703fb2 100644 --- a/src/poc/rotator.c +++ b/src/poc/rotator.c @@ -12,7 +12,7 @@ rotate_grad(struct notcurses* nc){ }; int 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; channel_set_rgb(&tl, 0xff, 0, 0); channel_set_rgb(&tr, 0, 0, 0xff); diff --git a/tests/fills.cpp b/tests/fills.cpp index 5c8f0b17f..8010c7e6d 100644 --- a/tests/fills.cpp +++ b/tests/fills.cpp @@ -440,7 +440,9 @@ TEST_CASE("Fills") { #ifdef USE_QRCODEGEN SUBCASE("QRCodes") { 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_)); } #endif