mirror of
https://github.com/dankamongmen/notcurses.git
synced 2024-11-02 09:40:15 +00:00
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:
parent
22dc5014cc
commit
0084dbaa6d
5
NEWS.md
5
NEWS.md
@ -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
|
||||||
|
18
USAGE.md
18
USAGE.md
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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__":
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -241,9 +241,7 @@ class ncppplot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(ncplane_cursor_move_yx(ncp, 0, 0)){
|
ncplane_home(ncp);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
47
src/poc/qrcode.c
Normal 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;
|
||||||
|
}
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user