Merge branch 'master' of github.com:dankamongmen/notcurses

pull/456/head
nick black 5 years ago
commit e276a36264

@ -2,22 +2,35 @@ This document attempts to list user-visible changes and any major internal
rearrangements of Notcurses. rearrangements of Notcurses.
* 1.2.6 (not yet released) * 1.2.6 (not yet released)
* `ncplane_putsimple_yx()` and `ncplane_putstr_yx()` has been exported as a
static inline function.
* `ncplane_set_scrolling()` has been added, allowing control over whether a
plane scrolls. All planes, including the standard plane, do not scroll by
default. If scrolling is enabled, text output via the `*put*` family of
functions continues onto the next line when encountering the end of a row.
This does not apply to e.g. boxes or lines.
* `ncplane_putstr_yx()` now always returns the inverse of the number of
columns advanced on an error (it used to return the positive short count so
long as the error was due to plane geometry, not bad input).
* `ncplot_add_sample()` and `ncplot_set_sample()` have been changed to accept
a `uint64_t` rather than `int64_t`, since negative samples do not
currently make sense. Plots were made more accurate in general.
* 1.2.5 * 1.2.5
* Add ncplot, with support for sliding-windowed horizontal histograms. * Add ncplot, with support for sliding-windowed horizontal histograms.
* gradient, polyfill, ncplane_format() and ncplane_stain() all now return the * gradient, polyfill, `ncplane_format()` and `ncplane_stain()` all now return
number of cells written on success. Failure still sees -1 returned. the number of cells written on success. Failure still sees -1 returned.
* `ncvisual_render()` now returns the number of cells emitted on success, as * `ncvisual_render()` now returns the number of cells emitted on success, as
opposed to 0. Failure still sees -1 returned. opposed to 0. Failure still sees -1 returned.
* `ncvisual_render()` now interprets length parameters of -1 to mean "to the * `ncvisual_render()` now interprets length parameters of -1 to mean "to the
end along this axis", and no longer interprets 0 to mean this. 0 now means end along this axis", and no longer interprets 0 to mean this. 0 now means
"a length of 0", resulting in a zero-area rendering. "a length of 0", resulting in a zero-area rendering.
* `notcurses_at_yx()` no longer accepts a `cell*` as its last parameter. * `notcurses_at_yx()` no longer accepts a `cell*` as its last parameter.
Instead, it accepts a `uint32_t*` and a `uint64_t*`, and writes the Instead, it accepts a `uint32_t*` and a `uint64_t*`, and writes the
attribute and channels to these parameters. This was done because the attribute and channels to these parameters. This was done because the
`gcluster` field of the `cell*` was always set to 0, which was surprising `gcluster` field of the `cell*` was always set to 0, which was surprising
and a source of blunders. The EGC is returned via the `char*` return and a source of blunders. The EGC is returned via the `char*` return
value. https://github.com/dankamongmen/notcurses/issues/410 value. https://github.com/dankamongmen/notcurses/issues/410
* 1.2.4 2020-03-24 * 1.2.4 2020-03-24
* Add ncmultiselector * Add ncmultiselector

@ -18,7 +18,8 @@ option(USE_FFMPEG "Disable FFmpeg image/video support (recommended)" ON)
option(USE_NETWORK "Allow cargo to use the network" OFF) option(USE_NETWORK "Allow cargo to use the network" OFF)
option(USE_PANDOC "Build man pages and HTML reference with pandoc" ON) option(USE_PANDOC "Build man pages and HTML reference with pandoc" ON)
option(USE_PYTHON "Build Python wrappers" ON) option(USE_PYTHON "Build Python wrappers" ON)
option(USE_RUST "Build Rust wrappers/colloquy (experimental)" OFF) option(USE_RUST "Build Rust wrappers (experimental)" OFF)
option(USE_TESTS "Build doctest unit tests" ON)
############## END (additional) USER-SELECTABLE OPTIONS ################## ############## END (additional) USER-SELECTABLE OPTIONS ##################
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
@ -31,7 +32,9 @@ pkg_check_modules(AVUTIL REQUIRED libavutil>=56.0)
pkg_check_modules(SWSCALE REQUIRED libswscale>=5.0) pkg_check_modules(SWSCALE REQUIRED libswscale>=5.0)
endif() endif()
find_library(LIBRT rt) find_library(LIBRT rt)
if(${USE_TESTS})
find_package(doctest 2.3.5 REQUIRED) find_package(doctest 2.3.5 REQUIRED)
endif()
# libnotcurses # libnotcurses
file(GLOB NCSRCS CONFIGURE_DEPENDS src/lib/*.c) file(GLOB NCSRCS CONFIGURE_DEPENDS src/lib/*.c)
@ -68,11 +71,13 @@ target_include_directories(notcurses-static
) )
target_link_libraries(notcurses target_link_libraries(notcurses
PRIVATE PRIVATE
Threads::Threads
"${TERMINFO_LIBRARIES}" "${TERMINFO_LIBRARIES}"
"${LIBRT}" "${LIBRT}"
) )
target_link_libraries(notcurses-static target_link_libraries(notcurses-static
PRIVATE PRIVATE
Threads::Threads
"${TERMINFO_STATIC_LIBRARIES}" "${TERMINFO_STATIC_LIBRARIES}"
"${LIBRT}" "${LIBRT}"
) )
@ -106,7 +111,6 @@ target_link_libraries(notcurses
"${AVFORMAT_LIBRARIES}" "${AVFORMAT_LIBRARIES}"
"${AVUTIL_LIBRARIES}" "${AVUTIL_LIBRARIES}"
"${SWSCALE_LIBRARIES}" "${SWSCALE_LIBRARIES}"
Threads::Threads
) )
target_link_libraries(notcurses-static target_link_libraries(notcurses-static
PRIVATE PRIVATE
@ -114,7 +118,6 @@ target_link_libraries(notcurses-static
"${AVFORMAT_STATIC_LIBRARIES}" "${AVFORMAT_STATIC_LIBRARIES}"
"${AVUTIL_STATIC_LIBRARIES}" "${AVUTIL_STATIC_LIBRARIES}"
"${SWSCALE_STATIC_LIBRARIES}" "${SWSCALE_STATIC_LIBRARIES}"
Threads::Threads
) )
target_link_directories(notcurses target_link_directories(notcurses
PUBLIC PUBLIC
@ -330,6 +333,7 @@ foreach(f ${POCSRCS})
add_executable(${fe} ${f}) add_executable(${fe} ${f})
target_include_directories(${fe} target_include_directories(${fe}
PRIVATE include "${TERMINFO_INCLUDE_DIRS}" PRIVATE include "${TERMINFO_INCLUDE_DIRS}"
"${PROJECT_BINARY_DIR}/include"
) )
target_link_libraries(${fe} target_link_libraries(${fe}
PRIVATE notcurses++ "${TERMINFO_LIBRARIES}" PRIVATE notcurses++ "${TERMINFO_LIBRARIES}"
@ -528,6 +532,7 @@ target_compile_definitions(notcurses-view
endif() endif()
# Testing # Testing
if(${USE_TESTS})
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
include(CTest) include(CTest)
endif() endif()
@ -557,6 +562,7 @@ add_test(
NAME notcurses-tester NAME notcurses-tester
COMMAND notcurses-tester -p ${CMAKE_CURRENT_SOURCE_DIR}/data COMMAND notcurses-tester -p ${CMAKE_CURRENT_SOURCE_DIR}/data
) )
endif()
# pkg-config support # pkg-config support
configure_file(tools/notcurses.pc.in configure_file(tools/notcurses.pc.in
@ -624,13 +630,11 @@ if(${USE_PYTHON})
endif() endif()
endif() endif()
# Rust bindings + colloquy # Rust bindings
if(${USE_RUST}) if(${USE_RUST})
file(GLOB LIBNCRSSRC CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/rust/libnotcurses-sys/src/*.rs ${CMAKE_CURRENT_SOURCE_DIR}/rust/libnotcurses-sys/src/*.rs) file(GLOB LIBNCRSSRC CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/rust/libnotcurses-sys/src/*.rs ${CMAKE_CURRENT_SOURCE_DIR}/rust/libnotcurses-sys/src/*.rs)
file(GLOB COLLOQUYSRC CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/colloquy/src/*.rs ${CMAKE_CURRENT_SOURCE_DIR}/src/colloquy/src/*.yml)
set(LIBNOTCURSESSYS ${CMAKE_CURRENT_BINARY_DIR}/rust/debug/liblibnotcurses_sys.rlib) set(LIBNOTCURSESSYS ${CMAKE_CURRENT_BINARY_DIR}/rust/debug/liblibnotcurses_sys.rlib)
set(CRATENOTCURSES ${CMAKE_CURRENT_BINARY_DIR}/rust/debug/libnotcurses.rlib) set(CRATENOTCURSES ${CMAKE_CURRENT_BINARY_DIR}/rust/debug/libnotcurses.rlib)
set(COLLOQUY ${CMAKE_CURRENT_BINARY_DIR}/rust/debug/colloquy)
find_program(CARGO cargo REQUIRED) find_program(CARGO cargo REQUIRED)
# might need --locked here # might need --locked here
set(CARGO_ARGS --verbose --release) set(CARGO_ARGS --verbose --release)
@ -643,7 +647,7 @@ if(${USE_RUST})
COMMAND COMMAND
PKG_CONFIG_PATH=${CMAKE_CURRENT_BINARY_DIR} CARGO_HOME=${CMAKE_CURRENT_BINARY_DIR}/rust CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR}/rust ${CARGO} build ${CARGO_ARGS} PKG_CONFIG_PATH=${CMAKE_CURRENT_BINARY_DIR} CARGO_HOME=${CMAKE_CURRENT_BINARY_DIR}/rust CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR}/rust ${CARGO} build ${CARGO_ARGS}
DEPENDS DEPENDS
${COLLOQUYSRC} ${LIBNCRSSRC}
COMMENT "Building rust crate libnotcurses-sys" COMMENT "Building rust crate libnotcurses-sys"
WORKING_DIRECTORY WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}/rust/libnotcurses-sys ${CMAKE_CURRENT_SOURCE_DIR}/rust/libnotcurses-sys
@ -667,24 +671,6 @@ if(${USE_RUST})
DEPENDS DEPENDS
${CRATENOTCURSES} ${CRATENOTCURSES}
) )
add_custom_command(
OUTPUT
${COLLOQUY}
COMMAND
CARGO_HOME=${CMAKE_CURRENT_BINARY_DIR}/rust CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR}/rust ${CARGO} build ${CARGO_ARGS}
DEPENDS
${COLLOQUYSRC} ${CRATENOTCURSES}
COMMENT "Building colloquy"
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}/src/colloquy
)
add_custom_target(colloquy ALL
DEPENDS
${COLLOQUY}
)
set_target_properties(colloquy
PROPERTIES LOCATION ${CMAKE_CURRENT_BINARY_DIR}
)
endif() endif()
# Installation # Installation
@ -699,11 +685,13 @@ install(FILES
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
) )
if(${USE_FFMPEG})
file(GLOB TESTDATA CONFIGURE_DEPENDS data/*) file(GLOB TESTDATA CONFIGURE_DEPENDS data/*)
install(FILES install(FILES
${TESTDATA} ${TESTDATA}
DESTINATION ${CMAKE_INSTALL_DATADIR}/notcurses DESTINATION ${CMAKE_INSTALL_DATADIR}/notcurses
) )
endif()
install(DIRECTORY install(DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}/include/" "${CMAKE_CURRENT_SOURCE_DIR}/include/"
@ -725,7 +713,9 @@ install(TARGETS notcurses-demo DESTINATION bin)
install(TARGETS notcurses-input DESTINATION bin) install(TARGETS notcurses-input DESTINATION bin)
install(TARGETS notcurses-keyplot DESTINATION bin) install(TARGETS notcurses-keyplot DESTINATION bin)
install(TARGETS notcurses-ncreel DESTINATION bin) install(TARGETS notcurses-ncreel DESTINATION bin)
if(${USE_TESTS})
install(TARGETS notcurses-tester DESTINATION bin) install(TARGETS notcurses-tester DESTINATION bin)
endif()
install(TARGETS notcurses-tetris DESTINATION bin) install(TARGETS notcurses-tetris DESTINATION bin)
if(${USE_FFMPEG}) if(${USE_FFMPEG})
install(TARGETS notcurses-view DESTINATION bin) install(TARGETS notcurses-view DESTINATION bin)

@ -145,12 +145,12 @@ output of `pkg-config --cflags notcurses`. If using CMake, a support file is
provided, and can be accessed as `notcurses`. provided, and can be accessed as `notcurses`.
Before calling into notcurses—and usually as one of the first calls of the Before calling into notcurses—and usually as one of the first calls of the
program—be sure to call `setlocale(3)` with an appropriate UTF-8 `LC_ALL` program—be sure to call `setlocale(3)` with an appropriate UTF-8 locale. It is
locale. It is usually appropriate to use `setlocale(LC_ALL, "")`, relying on usually appropriate to use `setlocale(LC_ALL, "")`, relying on the user to
the user to properly set the `LANG` environment variable. notcurses will properly set the `LANG` environment variable. notcurses will refuse to start if
refuse to start if `nl_langinfo(3)` doesn't indicate `ANSI_X3.4-1968` or `nl_langinfo(3)` doesn't indicate `ANSI_X3.4-1968` or `UTF-8`. In addition, it
`UTF-8`. In addition, it is wise to mask most signals early in the program, is wise to mask most signals early in the program, before any threads are
before any threads are spawned (this is particularly critical for `SIGWINCH`). spawned (this is particularly critical for `SIGWINCH`).
notcurses requires an available `terminfo(5)` definition appropriate for the notcurses requires an available `terminfo(5)` definition appropriate for the
terminal. It is usually appropriate to pass `NULL` in the `termtype` field of a terminal. It is usually appropriate to pass `NULL` in the `termtype` field of a
@ -660,6 +660,30 @@ int ncplane_mergedown(struct ncplane* restrict src, struct ncplane* restrict dst
void ncplane_erase(struct ncplane* n); void ncplane_erase(struct ncplane* n);
``` ```
All planes, including the standard plane, are created with scrolling disabled.
Attempting to print past the end of a line will stop at the plane boundary,
and indicate an error. On a plane 10 columns wide and two rows high, printing
"0123456789" at the origin should succeed, but printing "01234567890" will by
default fail at the eleventh character. In either case, the cursor will be left
at location 0x10; it must be moved before further printing can take place. If
scrolling is enabled, the first row will be filled with 01234546789, the second
row will have 0 written to its first column, and the cursor will end up at 1x1.
Note that it is still an error to manually attempt to move the cursor off-plane,
or to specify off-plane output. Boxes do not scroll; attempting to draw a 2x11
box on our 2x10 plane will result in an error and no output. When scrolling is
enabled, and output takes place while the cursor is past the end of the last
row, the first row is discarded, all other rows are moved up, the last row is
cleared, and output begins at the beginning of the last row. This does not take
place until output is generated (i.e. it is possible to fill a plane when
scrolling is enabled).
```c
// All planes are created with scrolling disabled. Scrolling can be dynamically
// controlled with ncplane_set_scrolling(). Returns true if scrolling was
// previously enabled, or false if it was disabled.
bool ncplane_set_scrolling(struct ncplane* n, bool scrollp);
```
Planes can be freely resized, though they must retain a positive size in Planes can be freely resized, though they must retain a positive size in
both dimensions. The powerful `ncplane_resize()` allows resizing an `ncplane`, both dimensions. The powerful `ncplane_resize()` allows resizing an `ncplane`,
retaining all or a portion of the plane's existing content, and translating retaining all or a portion of the plane's existing content, and translating
@ -839,7 +863,14 @@ ncplane_putc(struct ncplane* n, const cell* c){
// Replace the cell at the specified coordinates with the provided 7-bit char // Replace the cell at the specified coordinates with the provided 7-bit char
// 'c'. Advance the cursor by 1. On success, returns 1. On failure, returns -1. // 'c'. Advance the cursor by 1. On success, returns 1. On failure, returns -1.
// This works whether the underlying char is signed or unsigned. // This works whether the underlying char is signed or unsigned.
int ncplane_putsimple_yx(struct ncplane* n, int y, int x, char c); static inline int
ncplane_putsimple_yx(struct ncplane* n, int y, int x, char c){
cell ce = CELL_INITIALIZER(c, ncplane_attr(n), ncplane_channels(n));
if(!cell_simple_p(&ce)){
return -1;
}
return ncplane_putc_yx(n, y, x, &ce);
}
// Call ncplane_putsimple_yx() at the current cursor location. // Call ncplane_putsimple_yx() at the current cursor location.
static inline int static inline int
@ -924,7 +955,8 @@ int ncplane_putwegc_stainable(struct ncplane* n, const wchar_t* gclust, int* sby
// (though not beyond the end of the plane); this number is returned on success. // (though not beyond the end of the plane); this number is returned on success.
// On error, a non-positive number is returned, indicating the number of cells // On error, a non-positive number is returned, indicating the number of cells
// which were written before the error. // which were written before the error.
int ncplane_putstr_yx(struct ncplane* n, int y, int x, const char* gclustarr); static inline int
ncplane_putstr_yx(struct ncplane* n, int y, int x, const char* gclusters);
static inline int static inline int
ncplane_putstr(struct ncplane* n, const char* gclustarr){ ncplane_putstr(struct ncplane* n, const char* gclustarr){

@ -73,9 +73,7 @@ libnotcurses.so.1 libnotcurses1 #MINVER#
ncplane_putegc_stainable@Base 1.2.1 ncplane_putegc_stainable@Base 1.2.1
ncplane_putegc_yx@Base 1.2.1 ncplane_putegc_yx@Base 1.2.1
ncplane_putsimple_stainable@Base 1.2.1 ncplane_putsimple_stainable@Base 1.2.1
ncplane_putsimple_yx@Base 1.2.1
ncplane_putstr_aligned@Base 1.2.1 ncplane_putstr_aligned@Base 1.2.1
ncplane_putstr_yx@Base 1.2.1
ncplane_putwegc_stainable@Base 1.2.1 ncplane_putwegc_stainable@Base 1.2.1
ncplane_reparent@Base 1.2.5 ncplane_reparent@Base 1.2.5
ncplane_resize@Base 1.2.1 ncplane_resize@Base 1.2.1
@ -95,6 +93,7 @@ libnotcurses.so.1 libnotcurses1 #MINVER#
ncplane_set_fg_palindex@Base 1.2.1 ncplane_set_fg_palindex@Base 1.2.1
ncplane_set_fg_rgb@Base 1.2.1 ncplane_set_fg_rgb@Base 1.2.1
ncplane_set_fg_rgb_clipped@Base 1.2.1 ncplane_set_fg_rgb_clipped@Base 1.2.1
ncplane_set_scrolling@Base 1.2.6
ncplane_set_userptr@Base 1.2.1 ncplane_set_userptr@Base 1.2.1
ncplane_stain@Base 1.2.5 ncplane_stain@Base 1.2.5
ncplane_styles@Base 1.2.1 ncplane_styles@Base 1.2.1

@ -17,6 +17,7 @@
<h1><a href="https://nick-black.com/dankwiki/index.php/Notcurses">notcurses</a> man pages (v1.2.5)</h1> <h1><a href="https://nick-black.com/dankwiki/index.php/Notcurses">notcurses</a> man pages (v1.2.5)</h1>
<a href="notcurses.3.html">notcurses(3)</a>—a blingful TUI library<br/> <a href="notcurses.3.html">notcurses(3)</a>—a blingful TUI library<br/>
<h2>Binaries (section 1)</h2> <h2>Binaries (section 1)</h2>
<a href="colloquy.1.html">colloquy</a>—attractive terminal dialogs<br/>
<a href="notcurses-demo.1.html">notcurses-demo</a>—shows off some notcurses features<br/> <a href="notcurses-demo.1.html">notcurses-demo</a>—shows off some notcurses features<br/>
<a href="notcurses-input.1.html">notcurses-input</a>—reads and decodes input events<br/> <a href="notcurses-input.1.html">notcurses-input</a>—reads and decodes input events<br/>
<a href="notcurses-keyplot.1.html">notcurses-input</a>—plots input events over time<br/> <a href="notcurses-keyplot.1.html">notcurses-input</a>—plots input events over time<br/>

@ -0,0 +1,44 @@
% colloquy(1)
% nick black <nickblack@linux.com>
% v1.2.5
# NAME
colloquy - Command line dialogs and widgets
# SYNOPSIS
**colloquy** [**-h|--help**]
# DESCRIPTION
**colloquy** uses notcurses to construct attractive widgets from the command
line and shell scripts. It can be used with any terminal environment, and
supports both keyboards and mice. Available widget types include:
* Message boxes requiring a button press to continue
* Selection of a single item from a list
* Selection of zero or more items from a list
Data to be displayed is provided on the command line, and the user's input
is reported on standard output. If the user aborts, the program returns
non-zero.
**colloquy** is inspired by (and compatible with a subset of) **dialog(1)**,
a similar tool built atop NCURSES.
# OPTIONS
**-h**|**--help**: Display a usage message
# NOTES
Optimal display requires a terminal advertising the **rgb** terminfo(5)
capability, or that the environment variable **COLORTERM** is defined to
**24bit** (and that the terminal honors this variable), along with a
fixed-width font with good coverage of the Unicode Block Drawing Characters.
# SEE ALSO
**dialog(1)**,
**notcurses(3)**

@ -77,6 +77,8 @@ ncplane_box_sized(struct ncplane* n, const cell* ul, const cell* ur,
upper-left corner at the cursor's current position, and its lower-right corner upper-left corner at the cursor's current position, and its lower-right corner
at **ystop**, **xstop**. at **ystop**, **xstop**.
Box- and line-drawing is unaffected by a plane's scrolling status.
# RETURN VALUES # RETURN VALUES
**ncplane_format** returns -1 if either **ystop** or **xstop** is less than the **ncplane_format** returns -1 if either **ystop** or **xstop** is less than the

@ -132,6 +132,8 @@ notcurses_ncplane - operations on notcurses planes
**void ncplane_erase(struct ncplane* n);** **void ncplane_erase(struct ncplane* n);**
**bool ncplane_set_scrolling(struct ncplane* n, bool scrollp);**
## DESCRIPTION ## DESCRIPTION
Ncplanes are the fundamental drawing object of notcurses. All output functions Ncplanes are the fundamental drawing object of notcurses. All output functions
@ -182,6 +184,26 @@ expressed relative to the standard plane, and returns coordinates relative to
of the rendering region. Only those cells where **src** intersects with **dst** of the rendering region. Only those cells where **src** intersects with **dst**
might see changes. It is an error to merge a plane onto itself. might see changes. It is an error to merge a plane onto itself.
## Scrolling
All planes, including the standard plane, are created with scrolling disabled.
Control scrolling on a per-plane basis with **ncplane_set_scrolling**.
Attempting to print past the end of a line will stop at the plane boundary, and
indicate an error. On a plane 10 columns wide and two rows high, printing
"0123456789" at the origin should succeed, but printing "01234567890" will by
default fail at the eleventh character. In either case, the cursor will be left
at location 0x10; it must be moved before further printing can take place. If
scrolling is enabled, the first row will be filled with 01234546789, the second
row will have 0 written to its first column, and the cursor will end up at 1x1.
Note that it is still an error to manually attempt to move the cursor
off-plane, or to specify off-plane output. Boxes do not scroll; attempting to
draw a 2x11 box on our 2x10 plane will result in an error and no output. When
scrolling is enabled, and output takes place while the cursor is past the end
of the last row, the first row is discarded, all other rows are moved up, the
last row is cleared, and output begins at the beginning of the last row. This
does not take place until output is generated (i.e. it is possible to fill a
plane when scrolling is enabled).
# RETURN VALUES # RETURN VALUES
**ncplane_new**, **ncplane_bound**, **ncplane_aligned**, and **ncplane_dup** **ncplane_new**, **ncplane_bound**, **ncplane_aligned**, and **ncplane_dup**
@ -193,6 +215,9 @@ cannot fail.
**ncplane_below** returns the plane below the specified ncplane. If the provided **ncplane_below** returns the plane below the specified ncplane. If the provided
plane is the bottommost plane, NULL is returned. It cannot fail. plane is the bottommost plane, NULL is returned. It cannot fail.
**ncplane_set_scrolling** returns **true** if scrolling was previously enabled,
and **false** otherwise.
Functions returning **int** return 0 on success, and non-zero on error. Functions returning **int** return 0 on success, and non-zero on error.
All other functions cannot fail (and return **void**). All other functions cannot fail (and return **void**).

@ -18,7 +18,8 @@ ncplane_putc(struct ncplane* n, const cell* c);**
**static inline int **static inline int
ncplane_putsimple(struct ncplane* n, char c);** ncplane_putsimple(struct ncplane* n, char c);**
**int ncplane_putsimple_yx(struct ncplane* n, int y, int x, char c);** **static inline int
ncplane_putsimple_yx(struct ncplane* n, int y, int x, char c);**
**int ncplane_putsimple_stainable(struct ncplane* n, char c);** **int ncplane_putsimple_stainable(struct ncplane* n, char c);**
@ -42,7 +43,8 @@ ncplane_putwegc_yx(struct ncplane* n, int y, int x, const wchar_t* gclust, int*
**int ncplane_putwegc_stainable(struct ncplane* n, const wchar_t* gclust, int* sbytes);** **int ncplane_putwegc_stainable(struct ncplane* n, const wchar_t* gclust, int* sbytes);**
**int ncplane_putstr_yx(struct ncplane* n, int y, int x, const char* gclustarr);** **static inline int
ncplane_putstr_yx(struct ncplane* n, int y, int x, const char* gclustarr);**
**static inline int **static inline int
ncplane_putstr(struct ncplane* n, const char* gclustarr);** ncplane_putstr(struct ncplane* n, const char* gclustarr);**

@ -30,7 +30,7 @@ typedef struct ncplot_options {
uint64_t rangex; uint64_t rangex;
// dependent min and max. set both equal to 0 to // dependent min and max. set both equal to 0 to
// use domain autodiscovery. // use domain autodiscovery.
int64_t miny, maxy; uint64_t miny, maxy;
bool labelaxisd; // label dependent axis bool labelaxisd; // label dependent axis
bool exponentialy; // is dependent exponential? bool exponentialy; // is dependent exponential?
bool vertical_indep; // vertical independent variable bool vertical_indep; // vertical independent variable
@ -41,8 +41,8 @@ typedef struct ncplot_options {
**struct ncplane* ncplot_plane(struct ncplot* n);** **struct ncplane* ncplot_plane(struct ncplot* n);**
**int ncplot_add_sample(struct ncplot* n, uint64_t x, int64_t y);** **int ncplot_add_sample(struct ncplot* n, uint64_t x, uint64_t y);**
**int ncplot_set_sample(struct ncplot* n, uint64_t x, int64_t y);** **int ncplot_set_sample(struct ncplot* n, uint64_t x, uint64_t y);**
**void ncplot_destroy(struct ncplot* n);** **void ncplot_destroy(struct ncplot* n);**

@ -118,13 +118,13 @@ namespace ncpp
return ncplane_pulse (plane, ts, fader, curry) != -1; return ncplane_pulse (plane, ts, fader, curry) != -1;
} }
bool mergedown (Plane* dst = nullptr) { bool mergedown (Plane* dst = nullptr) {
return ncplane_mergedown(*this, dst ? dst->plane : nullptr); return ncplane_mergedown(*this, dst ? dst->plane : nullptr);
} }
bool mergedown (Plane& dst) { bool mergedown (Plane& dst) {
return mergedown(&dst); return mergedown(&dst);
} }
bool gradient (const char* egc, uint32_t attrword, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr, int ystop, int xstop) const noexcept bool gradient (const char* egc, uint32_t attrword, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr, int ystop, int xstop) const noexcept
{ {
@ -539,8 +539,8 @@ namespace ncpp
} }
bool box (const Cell &ul, const Cell &ur, const Cell &ll, const Cell &lr, bool box (const Cell &ul, const Cell &ur, const Cell &ll, const Cell &lr,
const Cell &hline, const Cell &vline, int ystop, int xstop, const Cell &hline, const Cell &vline, int ystop, int xstop,
unsigned ctlword) const noexcept unsigned ctlword) const noexcept
{ {
return ncplane_box (plane, ul, ur, ll, lr, hline, vline, ystop, xstop, ctlword) != -1; return ncplane_box (plane, ul, ur, ll, lr, hline, vline, ystop, xstop, ctlword) != -1;
} }
@ -692,6 +692,11 @@ namespace ncpp
ncplane_set_bg_default (plane); ncplane_set_bg_default (plane);
} }
bool set_scrolling (bool scrollp) noexcept
{
return ncplane_set_scrolling (plane, scrollp);
}
void styles_set (CellStyle styles) const noexcept void styles_set (CellStyle styles) const noexcept
{ {
ncplane_styles_set (plane, static_cast<unsigned>(styles)); ncplane_styles_set (plane, static_cast<unsigned>(styles));
@ -882,7 +887,7 @@ namespace ncpp
void translate (const Plane *dst, int *y = nullptr, int *x = nullptr) const void translate (const Plane *dst, int *y = nullptr, int *x = nullptr) const
{ {
ncplane_translate(*this, dst ? dst->plane: nullptr, y, x); ncplane_translate(*this, dst ? dst->plane: nullptr, y, x);
} }
void translate (const Plane &dst, int *y = nullptr, int *x = nullptr) noexcept void translate (const Plane &dst, int *y = nullptr, int *x = nullptr) noexcept
@ -895,7 +900,7 @@ namespace ncpp
if (src == nullptr) if (src == nullptr)
throw invalid_argument ("'src' must be a valid pointer"); throw invalid_argument ("'src' must be a valid pointer");
ncplane_translate(*src, dst ? dst->plane : nullptr, y, x); ncplane_translate(*src, dst ? dst->plane : nullptr, y, x);
} }
static void translate (const Plane &src, const Plane &dst, int *y = nullptr, int *x = nullptr) noexcept static void translate (const Plane &src, const Plane &dst, int *y = nullptr, int *x = nullptr) noexcept
@ -951,7 +956,7 @@ namespace ncpp
protected: protected:
explicit Plane (ncplane *_plane, bool _is_stdplane) explicit Plane (ncplane *_plane, bool _is_stdplane)
: plane (_plane), : plane (_plane),
is_stdplane (_is_stdplane) is_stdplane (_is_stdplane)
{ {
if (_plane == nullptr) if (_plane == nullptr)
throw invalid_argument ("_plane must be a valid pointer"); throw invalid_argument ("_plane must be a valid pointer");

@ -0,0 +1,67 @@
#ifndef __NCPP_PLOT_HH
#define __NCPP_PLOT_HH
#include <notcurses/notcurses.h>
#include "Root.hh"
#include "NCAlign.hh"
namespace ncpp
{
class Plane;
class NCPP_API_EXPORT Plot : public Root
{
public:
static plot_options default_options;
public:
explicit Plot (Plane *plane, const plot_options *opts = nullptr)
: Plot (reinterpret_cast<ncplane*>(plane), opts)
{}
explicit Plot (Plane const* plane, const plot_options *opts = nullptr)
: Plot (const_cast<Plane*>(plane), opts)
{}
explicit Plot (Plane &plane, const plot_options *opts = nullptr)
: Plot (reinterpret_cast<ncplane*>(&plane), opts)
{}
explicit Plot (Plane const& plane, const plot_options *opts = nullptr)
: Plot (const_cast<Plane*>(&plane), opts)
{}
explicit Plot (ncplane *plane, const plot_options *opts = nullptr)
{
if (plane == nullptr)
throw invalid_argument ("'plane' must be a valid pointer");
plot = ncplot_create (plane, opts == nullptr ? &default_options : opts);
if (plot == nullptr)
throw init_error ("notcurses failed to create a new plot");
}
~Plot ()
{
if (!is_notcurses_stopped ())
ncplot_destroy (plot);
}
int add_sample(uint64_t x, uint64_t y)
{
return ncplot_add_sample (plot, x, y) >= 0;
}
int set_sample(uint64_t x, uint64_t y)
{
return ncplot_set_sample (plot, x, y) >= 0;
}
Plane* get_plane () const noexcept;
private:
ncplot *plot;
};
}
#endif

File diff suppressed because it is too large Load Diff

@ -123,7 +123,6 @@ int ncplane_move_yx(struct ncplane* n, int y, int x);
void ncplane_yx(struct ncplane* n, int* y, int* x); void ncplane_yx(struct ncplane* n, int* y, int* x);
void ncplane_dim_yx(const struct ncplane* n, int* rows, int* cols); void ncplane_dim_yx(const struct ncplane* n, int* rows, int* cols);
int ncplane_putc_yx(struct ncplane* n, int y, int x, const cell* c); int ncplane_putc_yx(struct ncplane* n, int y, int x, const cell* c);
int ncplane_putsimple_yx(struct ncplane* n, int y, int x, char c);
int ncplane_move_top(struct ncplane* n); int ncplane_move_top(struct ncplane* n);
int ncplane_move_bottom(struct ncplane* n); int ncplane_move_bottom(struct ncplane* n);
int ncplane_move_below(struct ncplane* n, struct ncplane* below); int ncplane_move_below(struct ncplane* n, struct ncplane* below);
@ -193,7 +192,6 @@ int ncplane_pulse(struct ncplane* n, const struct timespec* ts, fadecb fader, vo
int ncplane_putwc_yx(struct ncplane* n, int y, int x, wchar_t w); int ncplane_putwc_yx(struct ncplane* n, int y, int x, wchar_t w);
int ncplane_putwc(struct ncplane* n, wchar_t w); int ncplane_putwc(struct ncplane* n, wchar_t w);
int ncplane_putegc_yx(struct ncplane* n, int y, int x, const char* gclust, int* sbytes); int ncplane_putegc_yx(struct ncplane* n, int y, int x, const char* gclust, int* sbytes);
int ncplane_putstr_yx(struct ncplane* n, int y, int x, const char* gclustarr);
int ncplane_putstr_aligned(struct ncplane* n, int y, ncalign_e align, const char* s); int ncplane_putstr_aligned(struct ncplane* n, int y, ncalign_e align, const char* s);
void cell_init(cell* c); void cell_init(cell* c);
int cell_load(struct ncplane* n, cell* c, const char* gcluster); int cell_load(struct ncplane* n, cell* c, const char* gcluster);
@ -422,16 +420,17 @@ typedef struct ncplot_options {
uint64_t minchannel; uint64_t minchannel;
ncgridgeom_e gridtype; ncgridgeom_e gridtype;
uint64_t rangex; uint64_t rangex;
int64_t miny, maxy; uint64_t miny, maxy;
bool labelaxisd; bool labelaxisd;
bool exponentialy; bool exponentialy;
bool vertical_indep; bool vertical_indep;
} ncplot_options; } ncplot_options;
struct ncplot* ncplot_create(struct ncplane* n, const ncplot_options* opts); struct ncplot* ncplot_create(struct ncplane* n, const ncplot_options* opts);
struct ncplane* ncplot_plane(struct ncplot* n); struct ncplane* ncplot_plane(struct ncplot* n);
int ncplot_add_sample(struct ncplot* n, uint64_t x, int64_t y); int ncplot_add_sample(struct ncplot* n, uint64_t x, uint64_t y);
int ncplot_set_sample(struct ncplot* n, uint64_t x, int64_t y); int ncplot_set_sample(struct ncplot* n, uint64_t x, uint64_t y);
void ncplot_destroy(struct ncplot* n); void ncplot_destroy(struct ncplot* n);
bool ncplane_set_scrolling(struct ncplane* n, bool scrollp);
""") """)
if __name__ == "__main__": if __name__ == "__main__":

@ -2,9 +2,25 @@ extern crate libnotcurses_sys as ffi;
pub fn getc_blocking(_n: *mut ffi::notcurses, _ni: &mut ffi::ncinput) -> u32 { pub fn getc_blocking(_n: *mut ffi::notcurses, _ni: &mut ffi::ncinput) -> u32 {
unsafe { unsafe {
let mut sigmask: ffi::sigset_t = std::mem::zeroed(); let mut sigmask: ffi::sigset_t = std::mem::zeroed();
ffi::sigemptyset(&mut sigmask); ffi::sigemptyset(&mut sigmask);
return ffi::notcurses_getc(_n, std::ptr::null(), &mut sigmask, _ni); return ffi::notcurses_getc(_n, std::ptr::null(), &mut sigmask, _ni);
}
}
pub fn ncplane_putstr(_n: *mut ffi::ncplane, _str: &str) -> i32 {
unsafe {
return ffi::ncplane_putstr_yx(_n, -1, -1, std::ffi::CString::new(_str).expect("Bad string").as_ptr());
}
}
pub fn render(_n: *mut ffi::notcurses) -> std::result::Result<(), std::io::Error> {
unsafe {
let r = ffi::notcurses_render(_n);
if r != 0 {
return Err(std::io::Error::new(std::io::ErrorKind::Other, "error rendering"));
}
Ok(())
} }
} }

@ -1,410 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"hermit-abi 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bindgen"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cexpr 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"clang-sys 0.28.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"which 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cc"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cexpr"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clang-sys"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clap"
version = "2.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "colloquy"
version = "0.1.0"
dependencies = [
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libnotcurses-sys 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"notcurses 1.2.4",
]
[[package]]
name = "env_logger"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "hermit-abi"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "humantime"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazycell"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc-stdhandle"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libloading"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libnotcurses-sys"
version = "1.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bindgen 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "log"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "nom"
version = "4.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "notcurses"
version = "1.2.4"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc-stdhandle 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libnotcurses-sys 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pkg-config"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro2"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "quote"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.6.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "shlex"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "termcolor"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-width"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "which"
version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "yaml-rust"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
"checksum bindgen 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f1c85344eb535a31b62f0af37be84441ba9e7f0f4111eb0530f43d15e513fe57"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
"checksum cexpr 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fce5b5fb86b0c57c20c834c1b412fd09c77c8a59b9473f86272709e78874cd1d"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum clang-sys 0.28.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81de550971c976f176130da4b2978d3b524eaa0fd9ac31f3ceb5ae1231fb4853"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
"checksum hermit-abi 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e2c55f143919fbc0bc77e427fe2d74cf23786d7c1875666f2fde3ac3c659bb67"
"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
"checksum libc-stdhandle 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6dac2473dc28934c5e0b82250dab231c9d3b94160d91fe9ff483323b05797551"
"checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753"
"checksum libnotcurses-sys 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "69cd13c04e971783d60cc48e307d2dfd47f6cad8a1519d0c2439316db7eb31f8"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
"checksum regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3"
"checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
"checksum rustc-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"checksum which 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992"

@ -1,19 +0,0 @@
[package]
name = "colloquy"
version = "0.1.0"
authors = ["nick black <dankamongmen@gmail.com>"]
edition = "2018"
repository = "https://github.com/dankamongmen/notcurses"
license = "Apache-2.0"
description = "Notcurses-based utility for command-line TUI widgets"
homepage = "https://nick-black.com/dankwiki/index.php/Notcurses"
[dependencies]
libc = ">= 0.2.66"
notcurses = ">= 1.2.5"
libnotcurses-sys = ">= 1.2.5"
[dependencies.clap]
version = ">= 2.33.0"
default-features = false
features = ["yaml", "color", "suggestions"]

@ -1,31 +0,0 @@
name: colloquy
version: "0.1.0"
about: Attractive Notcurses UI widgets from the shell
author: Nick Black <dankamongmen@gmail.com>
args:
- verbose:
long: verbose
short: v
help: Verbose mode
# - file:
# long: file
# short: f
# help: Read configuration options from this file
# takes_value: true
- title:
long: title
short: t
help: Set the title text
- msgbox:
long: msgbox
help: Display arbitrary text with a single button to accept it
requires: text
- text:
help: The contents of the widget
index: 1
- height:
help: The height of the widget, 0 for screen height
index: 2
- width:
help: The width of the widget, 0 for screen width
index: 3

@ -1,45 +0,0 @@
extern crate notcurses;
extern crate libnotcurses_sys as ffi;
extern {
fn libc_stdout() -> *mut ffi::_IO_FILE;
}
fn main() {
use clap::{load_yaml, App};
let yaml = load_yaml!("cli.yml");
let matches = App::from_yaml(yaml).get_matches();
unsafe{
let _ = libc::setlocale(libc::LC_ALL, std::ffi::CString::new("").unwrap().as_ptr());
let opts: ffi::notcurses_options = ffi::notcurses_options {
inhibit_alternate_screen: true,
loglevel: 0,
termtype: std::ptr::null(),
retain_cursor: false,
suppress_banner: false,
no_winch_sighandler: false,
no_quit_sighandlers: false,
renderfp: std::ptr::null_mut(),
margin_t: 4,
margin_r: 4,
margin_b: 4,
margin_l: 4,
};
let nc = ffi::notcurses_init(&opts, libc_stdout());
let stdplane = ffi::notcurses_stdplane(nc);
let mut dimy = 0;
let mut dimx = 0;
ffi::ncplane_dim_yx(stdplane, &mut dimy, &mut dimx);
if matches.is_present("msgbox") {
ffi::ncplane_new(nc, dimy, dimx, 0, 0, std::ptr::null_mut());
}else{
eprintln!("Needed a widget type");
ffi::notcurses_stop(nc);
std::process::exit(1);
}
let mut ni: ffi::ncinput = std::mem::zeroed();
notcurses::getc_blocking(nc, &mut ni);
ffi::notcurses_stop(nc);
}
}

@ -72,7 +72,14 @@ struct timespec demodelay = {
#ifndef DFSG_BUILD #ifndef DFSG_BUILD
#ifdef USE_FFMPEG #ifdef USE_FFMPEG
#define NONFREE(name, fxn) { name, fxn, } #define NONFREE(name, fxn) { name, fxn, }
#else
#endif
#else
#define DFSG(name, fxn) { NULL, NULL, }
#endif #endif
#ifndef DFSG
#define DFSG(name, fxn) { name, fxn, }
#endif #endif
#ifndef NONFREE #ifndef NONFREE
#define NONFREE(name, fxn) { NULL, NULL, } #define NONFREE(name, fxn) { NULL, NULL, }
@ -99,7 +106,7 @@ static struct {
{ "grid", grid_demo, }, { "grid", grid_demo, },
{ "highcon", highcontrast_demo, }, { "highcon", highcontrast_demo, },
{ "intro", intro, }, { "intro", intro, },
NONFREE("jungle", jungle_demo), DFSG("jungle", jungle_demo),
{ NULL, NULL, }, { NULL, NULL, },
NONFREE("luigi", luigi_demo), NONFREE("luigi", luigi_demo),
{ NULL, NULL, }, { NULL, NULL, },

@ -454,6 +454,7 @@ int witherworm_demo(struct notcurses* nc){
size_t i; size_t i;
const size_t screens = sizeof(steps) / sizeof(*steps); const size_t screens = sizeof(steps) / sizeof(*steps);
struct ncplane* n = notcurses_stdplane(nc); struct ncplane* n = notcurses_stdplane(nc);
ncplane_set_scrolling(n, true);
ncplane_erase(n); ncplane_erase(n);
for(i = 0 ; i < screens ; ++i){ for(i = 0 ; i < screens ; ++i){
wchar_t key = NCKEY_INVALID; wchar_t key = NCKEY_INVALID;
@ -481,12 +482,15 @@ int witherworm_demo(struct notcurses* nc){
s = strs + random() % ((sizeof(strs) / sizeof(*strs)) - 1); s = strs + random() % ((sizeof(strs) / sizeof(*strs)) - 1);
size_t idx = 0; size_t idx = 0;
ncplane_cursor_yx(n, &y, &x); ncplane_cursor_yx(n, &y, &x);
// fprintf(stderr, "%02d %s\n", y, *s);
while((*s)[idx]){ // each multibyte char of string while((*s)[idx]){ // each multibyte char of string
if(ncplane_set_fg_rgb(n, channel_r(rgb), channel_g(rgb), channel_b(rgb))){ if(ncplane_set_fg_rgb(n, channel_r(rgb), channel_g(rgb), channel_b(rgb))){
return -1; return -1;
} }
if(y >= maxy || x >= maxx){ if(x >= maxx){
x = 0;
++y;
}
if(y >= maxy){
break; break;
} }
wchar_t wcs; wchar_t wcs;
@ -503,7 +507,7 @@ int witherworm_demo(struct notcurses* nc){
int ulen = 0; int ulen = 0;
int r; int r;
if(wcwidth(wcs) <= maxx - x){ if(wcwidth(wcs) <= maxx - x){
if((r = ncplane_putegc(n, &(*s)[idx], &ulen)) < 0){ if((r = ncplane_putegc(n, &(*s)[idx], &ulen)) <= 0){
if(ulen < 0){ if(ulen < 0){
return -1; return -1;
} }
@ -520,7 +524,7 @@ int witherworm_demo(struct notcurses* nc){
++egcs_out; ++egcs_out;
} }
rgb += step; rgb += step;
}while(y < maxy && x < maxx); }while(y < maxy);
struct ncplane* math = mathplane(nc); struct ncplane* math = mathplane(nc);
if(math == NULL){ if(math == NULL){
return -1; return -1;
@ -565,7 +569,7 @@ int witherworm_demo(struct notcurses* nc){
} }
}while(key < 0); }while(key < 0);
pthread_cancel(tid); pthread_cancel(tid);
void* result; void* result = NULL;
pthread_join(tid, &result); pthread_join(tid, &result);
ncplane_destroy(mess); ncplane_destroy(mess);
ncplane_destroy(math); ncplane_destroy(math);
@ -580,5 +584,6 @@ int witherworm_demo(struct notcurses* nc){
return 1; return 1;
} }
} }
ncplane_set_scrolling(n, false);
return 0; return 0;
} }

@ -41,13 +41,14 @@ perframecb(struct notcurses* nc, struct ncvisual* ncv __attribute__ ((unused)),
return -1; return -1;
} }
*(struct ncplane**)vnewplane = n; *(struct ncplane**)vnewplane = n;
uint64_t channels = 0;
channels_set_fg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
channels_set_bg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
ncplane_set_base(n, channels, 0, " ");
ncplane_set_bg_alpha(n, CELL_ALPHA_BLEND);
ncplane_set_scrolling(n, true);
} }
ncplane_dim_yx(n, &dimy, &dimx); ncplane_dim_yx(n, &dimy, &dimx);
uint64_t channels = 0;
channels_set_fg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
channels_set_bg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
ncplane_set_base(n, channels, 0, " ");
ncplane_set_bg_alpha(n, CELL_ALPHA_BLEND);
// fg/bg rgbs are set within loop // fg/bg rgbs are set within loop
int x = dimx - (frameno * 2); int x = dimx - (frameno * 2);
int r = startr; int r = startr;
@ -79,7 +80,7 @@ perframecb(struct notcurses* nc, struct ncvisual* ncv __attribute__ ((unused)),
if(ncplane_set_bg_rgb(n, (l + 1) * 0x2, 0x20, (l + 1) * 0x2)){ if(ncplane_set_bg_rgb(n, (l + 1) * 0x2, 0x20, (l + 1) * 0x2)){
return -1; return -1;
} }
if(ncplane_printf_yx(n, l, x, "%*.*s", len, len, leg[l] + stroff) != (int)len){ if(ncplane_printf_yx(n, l, x, "%*.*s", len, len, leg[l] + stroff) != len){
return -1; return -1;
} }
} }

@ -68,14 +68,15 @@ int main(void){
planes.emplace_back(6, plotlen, 31, 1, nullptr); planes.emplace_back(6, plotlen, 31, 1, nullptr);
struct ncplot_options popts{}; struct ncplot_options popts{};
for(auto i = 0u ; i < plots.size() ; ++i){ for(auto i = 0u ; i < plots.size() ; ++i){
if(i == plots.size() - 1){ popts.labelaxisd = (i % 2 == 0);
popts.labelaxisd = true;
}
popts.minchannel = popts.maxchannel = 0; popts.minchannel = popts.maxchannel = 0;
channels_set_fg_rgb(&popts.maxchannel, random() % 256, random() % 256, random() % 256); channels_set_fg_rgb(&popts.maxchannel, random() % 256, random() % 256, random() % 256);
channels_set_fg_rgb(&popts.minchannel, random() % 256, random() % 256, random() % 256); channels_set_fg_rgb(&popts.minchannel, random() % 256, random() % 256, random() % 256);
popts.gridtype = static_cast<ncgridgeom_e>(i); popts.gridtype = static_cast<ncgridgeom_e>(i);
plots[i] = ncplot_create(planes[i], &popts); plots[i] = ncplot_create(planes[i], &popts);
if(!plots[i]){
return EXIT_FAILURE;
}
} }
char32_t r; char32_t r;
ncinput ni; ncinput ni;

@ -72,6 +72,7 @@ typedef struct ncplane {
void* userptr; // slot for the user to stick some opaque pointer void* userptr; // slot for the user to stick some opaque pointer
cell basecell; // cell written anywhere that fb[i].gcluster == 0 cell basecell; // cell written anywhere that fb[i].gcluster == 0
struct notcurses* nc; // notcurses object of which we are a part struct notcurses* nc; // notcurses object of which we are a part
bool scrolling; // is scrolling enabled? always disabled by default
} ncplane; } ncplane;
typedef struct ncvisual { typedef struct ncvisual {
@ -160,7 +161,7 @@ typedef struct ncplot {
// domain minimum and maximum. if detectdomain is true, these are // domain minimum and maximum. if detectdomain is true, these are
// progressively enlarged/shrunk to fit the sample set. if not, samples // progressively enlarged/shrunk to fit the sample set. if not, samples
// outside these bounds are counted, but the displayed range covers only this. // outside these bounds are counted, but the displayed range covers only this.
int64_t miny, maxy; uint64_t miny, maxy;
// circular buffer, with the oldest element at slotstart, and slotcount // circular buffer, with the oldest element at slotstart, and slotcount
// elements. slotcount is max(columns, rangex). // elements. slotcount is max(columns, rangex).
int64_t* slots; int64_t* slots;

@ -6,6 +6,95 @@ ncplane* ncvisual_plane(ncvisual* ncv){
return ncv->ncp; return ncv->ncp;
} }
// alpha comes to us 0--255, but we have only 3 alpha values to map them to.
// settled on experimentally.
static inline bool
ffmpeg_trans_p(bool bgr, unsigned char alpha){
if(!bgr && alpha < 192){
return true;
}
return false;
}
// RGBA/BGRx blitter. For incoming BGRx (no transparency), bgr == true.
static inline int
tria_blit(ncplane* nc, int placey, int placex, int linesize, const void* data,
int begy, int begx, int leny, int lenx, bool bgr){
const int bpp = 32;
const int rpos = bgr ? 2 : 0;
const int bpos = bgr ? 0 : 2;
int dimy, dimx, x, y;
int visy = begy;
int total = 0; // number of cells written
ncplane_dim_yx(nc, &dimy, &dimx);
// FIXME not going to necessarily be safe on all architectures hrmmm
const unsigned char* dat = data;
for(y = placey ; visy < (begy + leny) && y < dimy ; ++y, visy += 2){
if(ncplane_cursor_move_yx(nc, y, placex)){
return -1;
}
int visx = begx;
for(x = placex ; visx < (begx + lenx) && x < dimx ; ++x, ++visx){
const unsigned char* rgbbase_up = dat + (linesize * visy) + (visx * bpp / CHAR_BIT);
const unsigned char* rgbbase_down = dat + (linesize * (visy + 1)) + (visx * bpp / CHAR_BIT);
//fprintf(stderr, "[%04d/%04d] bpp: %d lsize: %d %02x %02x %02x %02x\n", y, x, bpp, linesize, rgbbase_up[0], rgbbase_up[1], rgbbase_up[2], rgbbase_up[3]);
cell* c = ncplane_cell_ref_yx(nc, y, x);
// use the default for the background, as that's the only way it's
// effective in that case anyway
c->channels = 0;
c->attrword = 0;
if(ffmpeg_trans_p(bgr, rgbbase_up[3]) || ffmpeg_trans_p(bgr, rgbbase_down[3])){
cell_set_bg_alpha(c, CELL_ALPHA_TRANSPARENT);
if(ffmpeg_trans_p(bgr, rgbbase_up[3]) && ffmpeg_trans_p(bgr, rgbbase_down[3])){
cell_set_fg_alpha(c, CELL_ALPHA_TRANSPARENT);
}else if(ffmpeg_trans_p(bgr, rgbbase_up[3])){ // down has the color
if(cell_load(nc, c, "\u2584") <= 0){ // lower half block
return -1;
}
cell_set_fg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]);
}else{ // up has the color
if(cell_load(nc, c, "\u2580") <= 0){ // upper half block
return -1;
}
cell_set_fg_rgb(c, rgbbase_up[rpos], rgbbase_up[1], rgbbase_up[bpos]);
}
}else{
if(memcmp(rgbbase_up, rgbbase_down, 3) == 0){
cell_set_fg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]);
cell_set_bg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]);
if(cell_load(nc, c, " ") <= 0){ // only need the background
return -1;
}
}else{
cell_set_fg_rgb(c, rgbbase_up[rpos], rgbbase_up[1], rgbbase_up[bpos]);
cell_set_bg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]);
if(cell_load(nc, c, "\u2580") <= 0){ // upper half block
return -1;
}
}
}
++total;
}
}
return total;
}
// Blit a flat array 'data' of BGRx 32-bit values to the ncplane 'nc', offset
// from the upper left by 'placey' and 'placex'. Each row ought occupy
// 'linesize' bytes (this might be greater than lenx * 4 due to padding). A
// subregion of the input can be specified with 'begy'x'begx' and 'leny'x'lenx'.
int ncblit_bgrx(ncplane* nc, int placey, int placex, int linesize,
const void* data, int begy, int begx, int leny, int lenx){
return tria_blit(nc, placey, placex, linesize, data,
begy, begx, leny, lenx, true);
}
int ncblit_rgba(ncplane* nc, int placey, int placex, int linesize,
const void* data, int begy, int begx, int leny, int lenx){
return tria_blit(nc, placey, placex, linesize, data,
begy, begx, leny, lenx, false);
}
void ncvisual_destroy(ncvisual* ncv){ void ncvisual_destroy(ncvisual* ncv){
if(ncv){ if(ncv){
#ifdef USE_FFMPEG #ifdef USE_FFMPEG
@ -354,95 +443,6 @@ ncvisual* ncvisual_open_plane(notcurses* nc, const char* filename,
return ncv; return ncv;
} }
// alpha comes to us 0--255, but we have only 3 alpha values to map them to.
// settled on experimentally.
static inline bool
ffmpeg_trans_p(bool bgr, unsigned char alpha){
if(!bgr && alpha < 192){
return true;
}
return false;
}
// RGBA/BGRx blitter. For incoming BGRx (no transparency), bgr == true.
static inline int
tria_blit(ncplane* nc, int placey, int placex, int linesize, const void* data,
int begy, int begx, int leny, int lenx, bool bgr){
const int bpp = 32;
const int rpos = bgr ? 2 : 0;
const int bpos = bgr ? 0 : 2;
int dimy, dimx, x, y;
int visy = begy;
int total = 0; // number of cells written
ncplane_dim_yx(nc, &dimy, &dimx);
// FIXME not going to necessarily be safe on all architectures hrmmm
const unsigned char* dat = data;
for(y = placey ; visy < (begy + leny) && y < dimy ; ++y, visy += 2){
if(ncplane_cursor_move_yx(nc, y, placex)){
return -1;
}
int visx = begx;
for(x = placex ; visx < (begx + lenx) && x < dimx ; ++x, ++visx){
const unsigned char* rgbbase_up = dat + (linesize * visy) + (visx * bpp / CHAR_BIT);
const unsigned char* rgbbase_down = dat + (linesize * (visy + 1)) + (visx * bpp / CHAR_BIT);
//fprintf(stderr, "[%04d/%04d] bpp: %d lsize: %d %02x %02x %02x %02x\n", y, x, bpp, linesize, rgbbase_up[0], rgbbase_up[1], rgbbase_up[2], rgbbase_up[3]);
cell* c = ncplane_cell_ref_yx(nc, y, x);
// use the default for the background, as that's the only way it's
// effective in that case anyway
c->channels = 0;
c->attrword = 0;
if(ffmpeg_trans_p(bgr, rgbbase_up[3]) || ffmpeg_trans_p(bgr, rgbbase_down[3])){
cell_set_bg_alpha(c, CELL_ALPHA_TRANSPARENT);
if(ffmpeg_trans_p(bgr, rgbbase_up[3]) && ffmpeg_trans_p(bgr, rgbbase_down[3])){
cell_set_fg_alpha(c, CELL_ALPHA_TRANSPARENT);
}else if(ffmpeg_trans_p(bgr, rgbbase_up[3])){ // down has the color
if(cell_load(nc, c, "\u2584") <= 0){ // lower half block
return -1;
}
cell_set_fg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]);
}else{ // up has the color
if(cell_load(nc, c, "\u2580") <= 0){ // upper half block
return -1;
}
cell_set_fg_rgb(c, rgbbase_up[rpos], rgbbase_up[1], rgbbase_up[bpos]);
}
}else{
if(memcmp(rgbbase_up, rgbbase_down, 3) == 0){
cell_set_fg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]);
cell_set_bg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]);
if(cell_load(nc, c, " ") <= 0){ // only need the background
return -1;
}
}else{
cell_set_fg_rgb(c, rgbbase_up[rpos], rgbbase_up[1], rgbbase_up[bpos]);
cell_set_bg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]);
if(cell_load(nc, c, "\u2580") <= 0){ // upper half block
return -1;
}
}
}
++total;
}
}
return total;
}
// Blit a flat array 'data' of BGRx 32-bit values to the ncplane 'nc', offset
// from the upper left by 'placey' and 'placex'. Each row ought occupy
// 'linesize' bytes (this might be greater than lenx * 4 due to padding). A
// subregion of the input can be specified with 'begy'x'begx' and 'leny'x'lenx'.
int ncblit_bgrx(ncplane* nc, int placey, int placex, int linesize,
const void* data, int begy, int begx, int leny, int lenx){
return tria_blit(nc, placey, placex, linesize, data,
begy, begx, leny, lenx, true);
}
int ncblit_rgba(ncplane* nc, int placey, int placex, int linesize,
const void* data, int begy, int begx, int leny, int lenx){
return tria_blit(nc, placey, placex, linesize, data,
begy, begx, leny, lenx, false);
}
int ncvisual_render(const ncvisual* ncv, int begy, int begx, int leny, int lenx){ int ncvisual_render(const ncvisual* ncv, int begy, int begx, int leny, int lenx){
//fprintf(stderr, "render %dx%d+%dx%d\n", begy, begx, leny, lenx); //fprintf(stderr, "render %dx%d+%dx%d\n", begy, begx, leny, lenx);
if(begy < 0 || begx < 0 || lenx < -1 || leny < -1){ if(begy < 0 || begx < 0 || lenx < -1 || leny < -1){
@ -610,6 +610,7 @@ char* ncvisual_subtitle(const ncvisual* ncv){
int ncvisual_init(int loglevel){ int ncvisual_init(int loglevel){
(void)loglevel; (void)loglevel;
return 0; return 0; // allow success here
} }
#endif #endif

@ -282,6 +282,7 @@ ncplane_create(notcurses* nc, ncplane* n, int rows, int cols,
return NULL; return NULL;
} }
memset(p->fb, 0, fbsize); memset(p->fb, 0, fbsize);
p->scrolling = false;
p->userptr = NULL; p->userptr = NULL;
p->leny = rows; p->leny = rows;
p->lenx = cols; p->lenx = cols;
@ -340,8 +341,7 @@ ncplane* ncplane_aligned(ncplane* n, int rows, int cols, int yoff,
return ncplane_create(n->nc, NULL, rows, cols, yoff, ncplane_align(n, align, cols), opaque); return ncplane_create(n->nc, NULL, rows, cols, yoff, ncplane_align(n, align, cols), opaque);
} }
static inline int inline int ncplane_cursor_move_yx(ncplane* n, int y, int x){
ncplane_cursor_move_yx_locked(ncplane* n, int y, int x){
if(x >= n->lenx){ if(x >= n->lenx){
return -1; return -1;
}else if(x < 0){ }else if(x < 0){
@ -380,7 +380,7 @@ ncplane* ncplane_dup(ncplane* n, void* opaque){
if(egcpool_dup(&newn->pool, &n->pool)){ if(egcpool_dup(&newn->pool, &n->pool)){
ncplane_destroy(newn); ncplane_destroy(newn);
}else{ }else{
ncplane_cursor_move_yx_locked(newn, y, x); // FIXME what about error? ncplane_cursor_move_yx(newn, y, x);
n->attrword = attr; n->attrword = attr;
n->channels = chan; n->channels = chan;
ncplane_move_above_unsafe(newn, n); ncplane_move_above_unsafe(newn, n);
@ -1248,17 +1248,6 @@ const char* cell_extended_gcluster(const struct ncplane* n, const cell* c){
return extended_gcluster(n, c); return extended_gcluster(n, c);
} }
static void
advance_cursor(ncplane* n, int cols){
if(cursor_invalid_p(n)){
return; // stuck!
}
if((n->x += cols) >= n->lenx){
++n->y;
n->x = 0;
}
}
// 'n' ends up above 'above' // 'n' ends up above 'above'
int ncplane_move_above_unsafe(ncplane* restrict n, ncplane* restrict above){ int ncplane_move_above_unsafe(ncplane* restrict n, ncplane* restrict above){
if(n->z == above){ if(n->z == above){
@ -1319,10 +1308,6 @@ int ncplane_move_bottom(ncplane* n){
return 0; return 0;
} }
int ncplane_cursor_move_yx(ncplane* n, int y, int x){
return ncplane_cursor_move_yx_locked(n, y, x);
}
void ncplane_cursor_yx(const ncplane* n, int* y, int* x){ void ncplane_cursor_yx(const ncplane* n, int* y, int* x){
if(y){ if(y){
*y = n->y; *y = n->y;
@ -1332,11 +1317,6 @@ void ncplane_cursor_yx(const ncplane* n, int* y, int* x){
} }
} }
static inline bool
ncplane_cursor_stuck(const ncplane* n){
return (n->x >= n->lenx && n->y >= n->leny);
}
static inline void static inline void
cell_obliterate(ncplane* n, cell* c){ cell_obliterate(ncplane* n, cell* c){
cell_release(n, c); cell_release(n, c);
@ -1344,11 +1324,18 @@ cell_obliterate(ncplane* n, cell* c){
} }
int ncplane_putc_yx(ncplane* n, int y, int x, const cell* c){ int ncplane_putc_yx(ncplane* n, int y, int x, const cell* c){
if(ncplane_cursor_move_yx_locked(n, y, x)){ // if scrolling is enabled, check *before ncplane_cursor_move_yx()* whether
return -1; // we're past the end of the line, and move to the next line if so.
}
bool wide = cell_double_wide_p(c); bool wide = cell_double_wide_p(c);
if(wide && (n->x + 1 == n->lenx)){ if(x == -1 && y == -1 && n->x + wide >= n->lenx){
if(!n->scrolling){
return -1;
}
n->x = 0;
++n->y;
// FIXME if new n->y >= n->leny, scroll everything up a line and reset n->y
}
if(ncplane_cursor_move_yx(n, y, x)){
return -1; return -1;
} }
// A wide character obliterates anything to its immediate right (and marks // A wide character obliterates anything to its immediate right (and marks
@ -1388,18 +1375,10 @@ int ncplane_putc_yx(ncplane* n, int y, int x, const cell* c){
cell_release(n, candidate); cell_release(n, candidate);
} }
} }
advance_cursor(n, cols); n->x += cols;
return cols; return cols;
} }
int ncplane_putsimple_yx(struct ncplane* n, int y, int x, char c){
cell ce = CELL_INITIALIZER(c, ncplane_attr(n), ncplane_channels(n));
if(!cell_simple_p(&ce)){
return -1;
}
return ncplane_putc_yx(n, y, x, &ce);
}
int ncplane_putegc_yx(struct ncplane* n, int y, int x, const char* gclust, int* sbytes){ int ncplane_putegc_yx(struct ncplane* n, int y, int x, const char* gclust, int* sbytes){
cell c = CELL_TRIVIAL_INITIALIZER; cell c = CELL_TRIVIAL_INITIALIZER;
int primed = cell_prime(n, &c, gclust, n->attrword, n->channels); int primed = cell_prime(n, &c, gclust, n->attrword, n->channels);
@ -1488,34 +1467,6 @@ int cell_load(ncplane* n, cell* c, const char* gcluster){
return bytes; return bytes;
} }
int ncplane_putstr_yx(ncplane* n, int y, int x, const char* gclusters){
int ret = 0;
// FIXME speed up this blissfully naive solution
while(*gclusters){
// FIXME can we not dispense with this cell, and print directly in?
cell c;
memset(&c, 0, sizeof(c));
int wcs = cell_load(n, &c, gclusters);
int cols = ncplane_putegc_yx(n, y, x, gclusters, &wcs);
if(cols < 0){
if(wcs < 0){
return -ret;
}
break;
}
if(wcs == 0){
break;
}
ncplane_cursor_yx(n, &y, &x);
gclusters += wcs;
ret += wcs;
if(ncplane_cursor_stuck(n)){
break;
}
}
return ret;
}
unsigned notcurses_supported_styles(const notcurses* nc){ unsigned notcurses_supported_styles(const notcurses* nc){
unsigned styles = 0; unsigned styles = 0;
styles |= nc->standout ? NCSTYLE_STANDOUT : 0; styles |= nc->standout ? NCSTYLE_STANDOUT : 0;
@ -1688,7 +1639,7 @@ int ncplane_vline_interp(ncplane* n, const cell* c, int len,
bgdef = true; bgdef = true;
} }
for(ret = 0 ; ret < len ; ++ret){ for(ret = 0 ; ret < len ; ++ret){
if(ncplane_cursor_move_yx_locked(n, ypos + ret, xpos)){ if(ncplane_cursor_move_yx(n, ypos + ret, xpos)){
return -1; return -1;
} }
r1 += deltr; r1 += deltr;
@ -1744,7 +1695,7 @@ int ncplane_box(ncplane* n, const cell* ul, const cell* ur,
} }
if(!(ctlword & NCBOXMASK_TOP)){ // draw top border, if called for if(!(ctlword & NCBOXMASK_TOP)){ // draw top border, if called for
if(xstop - xoff >= 2){ if(xstop - xoff >= 2){
if(ncplane_cursor_move_yx_locked(n, yoff, xoff + 1)){ if(ncplane_cursor_move_yx(n, yoff, xoff + 1)){
return -1; return -1;
} }
if(!(ctlword & NCBOXGRAD_TOP)){ // cell styling, hl if(!(ctlword & NCBOXGRAD_TOP)){ // cell styling, hl
@ -1760,7 +1711,7 @@ int ncplane_box(ncplane* n, const cell* ul, const cell* ur,
} }
edges = !(ctlword & NCBOXMASK_TOP) + !(ctlword & NCBOXMASK_RIGHT); edges = !(ctlword & NCBOXMASK_TOP) + !(ctlword & NCBOXMASK_RIGHT);
if(edges >= box_corner_needs(ctlword)){ if(edges >= box_corner_needs(ctlword)){
if(ncplane_cursor_move_yx_locked(n, yoff, xstop)){ if(ncplane_cursor_move_yx(n, yoff, xstop)){
return -1; return -1;
} }
if(ncplane_putc(n, ur) < 0){ if(ncplane_putc(n, ur) < 0){
@ -1771,7 +1722,7 @@ int ncplane_box(ncplane* n, const cell* ul, const cell* ur,
// middle rows (vertical lines) // middle rows (vertical lines)
if(yoff < ystop){ if(yoff < ystop){
if(!(ctlword & NCBOXMASK_LEFT)){ if(!(ctlword & NCBOXMASK_LEFT)){
if(ncplane_cursor_move_yx_locked(n, yoff, xoff)){ if(ncplane_cursor_move_yx(n, yoff, xoff)){
return -1; return -1;
} }
if((ctlword & NCBOXGRAD_LEFT)){ // grad styling, ul->ll if((ctlword & NCBOXGRAD_LEFT)){ // grad styling, ul->ll
@ -1785,7 +1736,7 @@ int ncplane_box(ncplane* n, const cell* ul, const cell* ur,
} }
} }
if(!(ctlword & NCBOXMASK_RIGHT)){ if(!(ctlword & NCBOXMASK_RIGHT)){
if(ncplane_cursor_move_yx_locked(n, yoff, xstop)){ if(ncplane_cursor_move_yx(n, yoff, xstop)){
return -1; return -1;
} }
if((ctlword & NCBOXGRAD_RIGHT)){ // grad styling, ur->lr if((ctlword & NCBOXGRAD_RIGHT)){ // grad styling, ur->lr
@ -1803,7 +1754,7 @@ int ncplane_box(ncplane* n, const cell* ul, const cell* ur,
yoff = ystop; yoff = ystop;
edges = !(ctlword & NCBOXMASK_BOTTOM) + !(ctlword & NCBOXMASK_LEFT); edges = !(ctlword & NCBOXMASK_BOTTOM) + !(ctlword & NCBOXMASK_LEFT);
if(edges >= box_corner_needs(ctlword)){ if(edges >= box_corner_needs(ctlword)){
if(ncplane_cursor_move_yx_locked(n, yoff, xoff)){ if(ncplane_cursor_move_yx(n, yoff, xoff)){
return -1; return -1;
} }
if(ncplane_putc(n, ll) < 0){ if(ncplane_putc(n, ll) < 0){
@ -1812,7 +1763,7 @@ int ncplane_box(ncplane* n, const cell* ul, const cell* ur,
} }
if(!(ctlword & NCBOXMASK_BOTTOM)){ if(!(ctlword & NCBOXMASK_BOTTOM)){
if(xstop - xoff >= 2){ if(xstop - xoff >= 2){
if(ncplane_cursor_move_yx_locked(n, yoff, xoff + 1)){ if(ncplane_cursor_move_yx(n, yoff, xoff + 1)){
return -1; return -1;
} }
if(!(ctlword & NCBOXGRAD_BOTTOM)){ // cell styling, hl if(!(ctlword & NCBOXGRAD_BOTTOM)){ // cell styling, hl
@ -1828,7 +1779,7 @@ int ncplane_box(ncplane* n, const cell* ul, const cell* ur,
} }
edges = !(ctlword & NCBOXMASK_BOTTOM) + !(ctlword & NCBOXMASK_RIGHT); edges = !(ctlword & NCBOXMASK_BOTTOM) + !(ctlword & NCBOXMASK_RIGHT);
if(edges >= box_corner_needs(ctlword)){ if(edges >= box_corner_needs(ctlword)){
if(ncplane_cursor_move_yx_locked(n, yoff, xstop)){ if(ncplane_cursor_move_yx(n, yoff, xstop)){
return -1; return -1;
} }
if(ncplane_putc(n, lr) < 0){ if(ncplane_putc(n, lr) < 0){
@ -2015,3 +1966,9 @@ ncplane* ncplane_reparent(ncplane* n, ncplane* newparent){
} }
return n; return n;
} }
bool ncplane_set_scrolling(ncplane* n, bool scrollp){
bool old = n->scrolling;
n->scrolling = scrollp;
return old;
}

@ -4,13 +4,77 @@ static const struct {
ncgridgeom_e geom; ncgridgeom_e geom;
const wchar_t* egcs; const wchar_t* egcs;
} geomdata[] = { } geomdata[] = {
{ .geom = NCPLOT_1x1, .egcs = L"", }, { .geom = NCPLOT_1x1, .egcs = L" ", },
{ .geom = NCPLOT_2x1, .egcs = L"▄█", }, { .geom = NCPLOT_2x1, .egcs = L" ▄█", },
{ .geom = NCPLOT_1x1x4, .egcs = L"▒░▓█", }, { .geom = NCPLOT_1x1x4, .egcs = L" ▒░▓█", },
{ .geom = NCPLOT_4x1, .egcs = L"▂▄▆█", }, { .geom = NCPLOT_4x1, .egcs = L" ▂▄▆█", },
{ .geom = NCPLOT_8x1, .egcs = L"▁▂▃▄▅▆▇█", }, { .geom = NCPLOT_8x1, .egcs = L" ▁▂▃▄▅▆▇█", },
}; };
static int
redraw_plot(ncplot* n){
ncplane_erase(ncplot_plane(n));
int dimy, dimx;
ncplane_dim_yx(ncplot_plane(n), &dimy, &dimx);
// each transition is worth this much change in value
const size_t states = wcslen(geomdata[n->gridtype].egcs);
// FIXME can we not rid ourselves of this meddlesome double?
double interval = n->maxy < n->miny ? 0 : (n->maxy - n->miny) / ((double)dimy * states);
int idx = n->slotstart;
const int startx = n->labelaxisd ? PREFIXSTRLEN : 0;
if(n->labelaxisd){
// show the *top* of each interval range
for(int y = 0 ; y < dimy ; ++y){
char buf[PREFIXSTRLEN + 1];
ncmetric(interval * states * (y + 1) * 100, 100, buf, 0, 1000, '\0');
ncplane_putstr_yx(ncplot_plane(n), dimy - y - 1, PREFIXSTRLEN - strlen(buf), buf);
}
}
if(interval){
for(uint64_t x = startx ; x < n->slotcount + startx ; ++x){
if(x >= (unsigned)dimx){
break;
}
uint64_t gval = n->slots[idx]; // clip the value at the limits of the graph
if(gval < n->miny){
gval = n->miny;
}
if(gval > n->maxy){
gval = n->maxy;
}
// starting from the least-significant row, progress in the more significant
// direction, drawing egcs from the grid specification, aborting early if
// we can't draw anything in a given cell.
double intervalbase = n->miny;
for(int y = 0 ; y < dimy ; ++y){
// if we've got at least one interval's worth on the number of positions
// times the number of intervals per position plus the starting offset,
// we're going to print *something*
if(intervalbase >= gval){
break;
}
size_t egcidx = (gval - intervalbase) / interval;
if(egcidx >= states){
egcidx = states - 1;
}
if(ncplane_putwc_yx(ncplot_plane(n), dimy - y - 1, x, geomdata[n->gridtype].egcs[egcidx]) <= 0){
return -1;
}
intervalbase += (states * interval);
}
idx = (idx + 1) % n->slotcount;
}
}
if(ncplane_cursor_move_yx(ncplot_plane(n), 0, 0)){
return -1;
}
if(ncplane_stain(ncplot_plane(n), dimy - 1, dimx - 1, n->maxchannel,
n->maxchannel, n->minchannel, n->minchannel) <= 0){
return -1;
}
return 0;
}
ncplot* ncplot_create(ncplane* n, const ncplot_options* opts){ ncplot* ncplot_create(ncplane* n, const ncplot_options* opts){
// if miny == maxy, they both must be equal to 0 // if miny == maxy, they both must be equal to 0
if(opts->miny == opts->maxy && opts->miny){ if(opts->miny == opts->maxy && opts->miny){
@ -56,10 +120,14 @@ ncplot* ncplot_create(ncplane* n, const ncplot_options* opts){
ret->vertical_indep = opts->vertical_indep; ret->vertical_indep = opts->vertical_indep;
ret->gridtype = opts->gridtype; ret->gridtype = opts->gridtype;
ret->exponentialy = opts->exponentialy; ret->exponentialy = opts->exponentialy;
ret->detectdomain = opts->miny == opts->maxy; if( (ret->detectdomain = (opts->miny == opts->maxy)) ){
ret->maxy = 0;
ret->miny = ~(uint64_t)0ull;
}
ret->windowbase = 0; ret->windowbase = 0;
ret->slotstart = 0; ret->slotstart = 0;
ret->slotx = 0; ret->slotx = 0;
redraw_plot(ret);
return ret; return ret;
} }
free(ret); free(ret);
@ -76,7 +144,7 @@ ncplane* ncplot_plane(ncplot* n){
// return -1 if the value is outside of that range. // return -1 if the value is outside of that range.
static inline int static inline int
update_domain(ncplot* n, uint64_t x){ update_domain(ncplot* n, uint64_t x){
const int64_t val = n->slots[x % n->slotcount]; const uint64_t val = n->slots[x % n->slotcount];
if(n->detectdomain){ if(n->detectdomain){
if(val > n->maxy){ if(val > n->maxy){
n->maxy = val; n->maxy = val;
@ -127,8 +195,8 @@ window_slide(ncplot* n, uint64_t x){
// x must be within n's window // x must be within n's window
static inline void static inline void
update_sample(ncplot* n, uint64_t x, int64_t y, bool reset){ update_sample(ncplot* n, uint64_t x, uint64_t y, bool reset){
uint64_t idx = x/*(n->slotstart + delta)*/ % n->slotcount; uint64_t idx = x % n->slotcount;
if(reset){ if(reset){
n->slots[idx] = y; n->slots[idx] = y;
}else{ }else{
@ -136,74 +204,11 @@ update_sample(ncplot* n, uint64_t x, int64_t y, bool reset){
} }
} }
static int
redraw_plot(ncplot* n){
ncplane_erase(ncplot_plane(n)); // FIXME shouldn't need this
int dimy, dimx;
ncplane_dim_yx(ncplot_plane(n), &dimy, &dimx);
// each transition is worth this much change in value
const size_t states = wcslen(geomdata[n->gridtype].egcs);
double interval = (n->maxy - n->miny + 1) / ((double)dimy * states); // FIXME
int idx = n->slotstart;
const int startx = n->labelaxisd ? PREFIXSTRLEN : 0;
if(n->labelaxisd){
for(int y = 0 ; y < dimy ; ++y){
char buf[PREFIXSTRLEN + 1];
ncmetric(interval * states * y, 1, buf, 0, 1000, '\0');
ncplane_putstr_yx(ncplot_plane(n), dimy - y - 1, PREFIXSTRLEN - strlen(buf), buf);
}
}
for(uint64_t x = startx ; x < n->slotcount + startx ; ++x){
if(x >= (unsigned)dimx){
break;
}
int64_t gval = n->slots[idx]; // clip the value at the limits of the graph
if(gval < n->miny){
gval = n->miny;
}
if(gval > n->maxy){
gval = n->maxy;
}
// starting from the least-significant row, progress in the more significant
// direction, drawing egcs from the grid specification, aborting early if
// we can't draw anything in a given cell.
for(int y = 0 ; y < dimy ; ++y){
// if we've got at least one interval's worth on the number of positions
// times the number of intervals per position plus the starting offset,
// we're going to print *something*
if(n->miny + (interval * states) * y + interval > gval){
break;
}
size_t egcidx = (gval - n->miny) - (y * interval * states) - 1;
if(egcidx >= states){
egcidx = states - 1;
}
if(ncplane_putwc_yx(ncplot_plane(n), dimy - y - 1, x, geomdata[n->gridtype].egcs[egcidx]) <= 0){
return -1;
}
// FIXME this ought fall out naturally. that it does not indicates, i
// think, an error above...
if(egcidx != states - 1){
break;
}
}
idx = (idx + 1) % n->slotcount;
}
if(ncplane_cursor_move_yx(ncplot_plane(n), 0, 0)){
return -1;
}
if(ncplane_stain(ncplot_plane(n), dimy - 1, dimx - 1, n->maxchannel,
n->maxchannel, n->minchannel, n->minchannel) <= 0){
return -1;
}
return 0;
}
// Add to or set the value corresponding to this x. If x is beyond the current // Add to or set the value corresponding to this x. If x is beyond the current
// x window, the x window is advanced to include x, and values passing beyond // x window, the x window is advanced to include x, and values passing beyond
// the window are lost. The first call will place the initial window. The plot // the window are lost. The first call will place the initial window. The plot
// will be redrawn, but notcurses_render() is not called. // will be redrawn, but notcurses_render() is not called.
int ncplot_add_sample(ncplot* n, uint64_t x, int64_t y){ int ncplot_add_sample(ncplot* n, uint64_t x, uint64_t y){
if(window_slide(n, x)){ if(window_slide(n, x)){
return -1; return -1;
} }
@ -214,7 +219,7 @@ int ncplot_add_sample(ncplot* n, uint64_t x, int64_t y){
return redraw_plot(n); return redraw_plot(n);
} }
int ncplot_set_sample(ncplot* n, uint64_t x, int64_t y){ int ncplot_set_sample(ncplot* n, uint64_t x, uint64_t y){
if(window_slide(n, x)){ if(window_slide(n, x)){
return -1; return -1;
} }

@ -63,6 +63,7 @@ int main(void){
std::unique_ptr<Plane> nstd(nc.get_stdplane()); std::unique_ptr<Plane> nstd(nc.get_stdplane());
int y, dimy, dimx; int y, dimy, dimx;
nc.get_term_dim(&dimy, &dimx); nc.get_term_dim(&dimy, &dimx);
nstd->set_scrolling(true);
do{ do{
nstd->putstr(c); nstd->putstr(c);
nstd->get_cursor_yx(&y, nullptr); nstd->get_cursor_yx(&y, nullptr);

@ -118,17 +118,6 @@ int main(void){
int averr; int averr;
struct ncvisual* ncv = ncplane_visual_open(n, "../data/ebolavirus_wide-0723bc3f01c644976b4df7e146a1d795aaf9d55e.jpg", &averr);
if(!ncv){
goto err;
}
if(!ncvisual_decode(ncv, &averr)){
goto err;
}
if(ncvisual_render(ncv, 0, 0, -1, -1) <= 0){
goto err;
}
uint64_t channels = 0; uint64_t channels = 0;
channels_set_fg(&channels, 0x88aa00); channels_set_fg(&channels, 0x88aa00);
channels_set_bg(&channels, 0x000088); channels_set_bg(&channels, 0x000088);
@ -144,18 +133,6 @@ int main(void){
run_menu(nc, top); run_menu(nc, top);
ncplane_erase(n); ncplane_erase(n);
ncvisual_destroy(ncv);
ncv = ncplane_visual_open(n, "../data/aidsrobots.jpeg", &averr);
if(!ncv){
goto err;
}
if(!ncvisual_decode(ncv, &averr)){
goto err;
}
if(ncvisual_render(ncv, 0, 0, -1, -1) <= 0){
goto err;
}
mopts.bottom = true; mopts.bottom = true;
struct ncmenu* bottom = ncmenu_create(nc, &mopts); struct ncmenu* bottom = ncmenu_create(nc, &mopts);
@ -167,7 +144,6 @@ int main(void){
} }
run_menu(nc, bottom); run_menu(nc, bottom);
ncvisual_destroy(ncv);
if(notcurses_stop(nc)){ if(notcurses_stop(nc)){
return EXIT_FAILURE; return EXIT_FAILURE;
} }

@ -3,6 +3,7 @@
#include <locale.h> #include <locale.h>
#include <stdlib.h> #include <stdlib.h>
#include <notcurses/notcurses.h> #include <notcurses/notcurses.h>
#include "version.h"
// http://theboomerbible.com/tbb112.html // http://theboomerbible.com/tbb112.html
static struct mselector_item items[] = { static struct mselector_item items[] = {
@ -81,6 +82,7 @@ int main(void){
channels_set_bg_alpha(&sopts.bgchannels, CELL_ALPHA_BLEND); channels_set_bg_alpha(&sopts.bgchannels, CELL_ALPHA_BLEND);
struct ncplane* n = notcurses_stdplane(nc); struct ncplane* n = notcurses_stdplane(nc);
#ifdef USE_FFMPEG
int averr; int averr;
struct ncvisual* ncv = ncplane_visual_open(n, "../data/covid19.jpg", &averr); struct ncvisual* ncv = ncplane_visual_open(n, "../data/covid19.jpg", &averr);
if(!ncv){ if(!ncv){
@ -92,6 +94,7 @@ int main(void){
if(ncvisual_render(ncv, 0, 0, -1, -1) <= 0){ if(ncvisual_render(ncv, 0, 0, -1, -1) <= 0){
goto err; goto err;
} }
#endif
ncplane_set_fg(n, 0x40f040); ncplane_set_fg(n, 0x40f040);
ncplane_putstr_aligned(n, 0, NCALIGN_RIGHT, "multiselect widget demo"); ncplane_putstr_aligned(n, 0, NCALIGN_RIGHT, "multiselect widget demo");

@ -3,6 +3,7 @@
#include <locale.h> #include <locale.h>
#include <stdlib.h> #include <stdlib.h>
#include <notcurses/notcurses.h> #include <notcurses/notcurses.h>
#include "version.h"
static struct selector_item items[] = { static struct selector_item items[] = {
{ "first", "this is the first option", }, { "first", "this is the first option", },
@ -80,6 +81,7 @@ int main(void){
channels_set_bg_alpha(&sopts.bgchannels, CELL_ALPHA_BLEND); channels_set_bg_alpha(&sopts.bgchannels, CELL_ALPHA_BLEND);
struct ncplane* n = notcurses_stdplane(nc); struct ncplane* n = notcurses_stdplane(nc);
#ifdef USE_FFMPEG
int averr; int averr;
struct ncvisual* ncv = ncplane_visual_open(n, "../data/changes.jpg", &averr); struct ncvisual* ncv = ncplane_visual_open(n, "../data/changes.jpg", &averr);
if(!ncv){ if(!ncv){
@ -91,7 +93,7 @@ int main(void){
if(ncvisual_render(ncv, 0, 0, -1, -1) <= 0){ if(ncvisual_render(ncv, 0, 0, -1, -1) <= 0){
goto err; goto err;
} }
#endif
ncplane_set_fg(n, 0x40f040); ncplane_set_fg(n, 0x40f040);
ncplane_putstr_aligned(n, 0, NCALIGN_RIGHT, "selector widget demo"); ncplane_putstr_aligned(n, 0, NCALIGN_RIGHT, "selector widget demo");

@ -1,4 +1,5 @@
void DrawBackground(const std::string& s) { // drawn to the standard plane void DrawBackground(const std::string& s) { // drawn to the standard plane
#ifdef USE_FFMPEG
int averr; int averr;
try{ try{
backg_ = std::make_unique<ncpp::Visual>(s.c_str(), &averr, 0, 0, ncpp::NCScale::Stretch); backg_ = std::make_unique<ncpp::Visual>(s.c_str(), &averr, 0, 0, ncpp::NCScale::Stretch);
@ -12,6 +13,9 @@ void DrawBackground(const std::string& s) { // drawn to the standard plane
throw TetrisNotcursesErr("render(): " + s); throw TetrisNotcursesErr("render(): " + s);
} }
backg_->get_plane()->greyscale(); backg_->get_plane()->greyscale();
#else
(void)s;
#endif
} }
void DrawBoard() { // draw all fixed components of the game void DrawBoard() { // draw all fixed components of the game

@ -54,8 +54,7 @@ public:
#include "stain.h" #include "stain.h"
#include "lock.h" #include "lock.h"
#include "movedown.h" #include "movedown.h"
#include "moveleft.h" #include "movelateral.h"
#include "moveright.h"
#include "rotate.h" #include "rotate.h"
private: private:

@ -1,8 +1,9 @@
void MoveLeft() { void MoveLateral(int direction) { // pass in -1 for left, 1 for right
int shift = 2 * direction;
const std::lock_guard<std::mutex> lock(mtx_); const std::lock_guard<std::mutex> lock(mtx_);
int y, x; int y, x;
if(PrepForMove(&y, &x)){ if(PrepForMove(&y, &x)){
if(!curpiece_->move(y, x - 2)){ if(!curpiece_->move(y, x + shift)){
throw TetrisNotcursesErr("move()"); throw TetrisNotcursesErr("move()");
} }
if(InvalidMove()){ if(InvalidMove()){
@ -10,10 +11,18 @@ void MoveLeft() {
throw TetrisNotcursesErr("move()"); throw TetrisNotcursesErr("move()");
} }
}else{ }else{
x -= 2; x += shift;
if(!nc_.render()){ if(!nc_.render()){
throw TetrisNotcursesErr("render()"); throw TetrisNotcursesErr("render()");
} }
} }
} }
} }
inline void MoveLeft() {
MoveLateral(-1);
}
inline void MoveRight() {
MoveLateral(1);
}

@ -1,19 +0,0 @@
void MoveRight() {
const std::lock_guard<std::mutex> lock(mtx_);
int y, x;
if(PrepForMove(&y, &x)){
if(!curpiece_->move(y, x + 2)){
throw TetrisNotcursesErr("move()");
}
if(InvalidMove()){
if(!curpiece_->move(y, x)){
throw TetrisNotcursesErr("move()");
}
}else{
x += 2;
if(!nc_.render()){
throw TetrisNotcursesErr("render()");
}
}
}
}

@ -40,6 +40,7 @@ TEST_CASE("Fade") {
c.gcluster = '*'; c.gcluster = '*';
cell_set_fg_rgb(&c, 0xff, 0xff, 0xff); cell_set_fg_rgb(&c, 0xff, 0xff, 0xff);
unsigned rgb = 0xffffffu; unsigned rgb = 0xffffffu;
CHECK(!ncplane_set_scrolling(n_, true));
for(int y = 0 ; y < dimy ; ++y){ for(int y = 0 ; y < dimy ; ++y){
for(int x = 0 ; x < dimx ; ++x){ for(int x = 0 ; x < dimx ; ++x){
rgb -= 32; rgb -= 32;

@ -211,6 +211,7 @@ TEST_CASE("NCPlane") {
L"🍺🚬🌿💉💊🔫💣🤜🤛🐌🐎🐑🐒🐔🐗🐘🐙🐚" L"🍺🚬🌿💉💊🔫💣🤜🤛🐌🐎🐑🐒🐔🐗🐘🐙🐚"
"🐛🐜🐝🐞🐟🐠🐡🐢🐣🐤🐥🐦🐧🐨🐩🐫🐬🐭🐮" "🐛🐜🐝🐞🐟🐠🐡🐢🐣🐤🐥🐦🐧🐨🐩🐫🐬🐭🐮"
"🐯🐰🐱🐲🐳🐴🐵🐶🐷🐹🐺🐻🐼🦉🐊🦕🦖🐬🐙🦠🦀"; "🐯🐰🐱🐲🐳🐴🐵🐶🐷🐹🐺🐻🐼🦉🐊🦕🦖🐬🐙🦠🦀";
CHECK(!ncplane_set_scrolling(n_, true));
int wrote = ncplane_putwstr(n_, e); int wrote = ncplane_putwstr(n_, e);
CHECK(0 < wrote); CHECK(0 < wrote);
int x, y; int x, y;
@ -539,20 +540,20 @@ TEST_CASE("NCPlane") {
ncplane_styles_set(n_, 0); ncplane_styles_set(n_, 0);
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0)); REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
REQUIRE(0 < ncplane_putstr(n_, STR1)); REQUIRE(0 < ncplane_putstr(n_, STR1));
cell testcell = CELL_TRIVIAL_INITIALIZER;
REQUIRE(0 == ncplane_at_cursor(n_, &testcell)); // want nothing at the cursor
CHECK(0 == testcell.gcluster);
CHECK(0 == testcell.attrword);
CHECK(0 == testcell.channels);
int dimy, dimx; int dimy, dimx;
ncplane_dim_yx(n_, &dimy, &dimx); ncplane_dim_yx(n_, &dimy, &dimx);
REQUIRE(0 == ncplane_cursor_move_yx(n_, 1, dimx - strlen(STR2))); REQUIRE(0 == ncplane_cursor_move_yx(n_, 1, dimx - strlen(STR2)));
REQUIRE(0 < ncplane_putstr(n_, STR2)); REQUIRE(0 < ncplane_putstr(n_, STR2));
int y, x; int y, x;
ncplane_cursor_yx(n_, &y, &x); ncplane_cursor_yx(n_, &y, &x);
REQUIRE(2 == y); REQUIRE(1 == y);
REQUIRE(0 == x); REQUIRE(dimx == x);
REQUIRE(0 < ncplane_putstr(n_, STR3)); REQUIRE(0 == ncplane_putstr(n_, STR3));
cell testcell = CELL_TRIVIAL_INITIALIZER;
REQUIRE(0 == ncplane_at_cursor(n_, &testcell)); // want nothing at the cursor
CHECK(0 == testcell.gcluster);
CHECK(0 == testcell.attrword);
CHECK(0 == testcell.channels);
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0)); REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
REQUIRE(0 < ncplane_at_cursor(n_, &testcell)); // want first char of STR1 REQUIRE(0 < ncplane_at_cursor(n_, &testcell)); // want first char of STR1
CHECK(STR1[0] == testcell.gcluster); CHECK(STR1[0] == testcell.gcluster);
@ -575,20 +576,20 @@ TEST_CASE("NCPlane") {
ncplane_styles_set(n_, 0); ncplane_styles_set(n_, 0);
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0)); REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
REQUIRE(0 < ncplane_putstr(n_, STR1)); REQUIRE(0 < ncplane_putstr(n_, STR1));
cell testcell = CELL_TRIVIAL_INITIALIZER;
ncplane_at_cursor(n_, &testcell); // should be nothing at the cursor
CHECK(0 == testcell.gcluster);
CHECK(0 == testcell.attrword);
CHECK(0 == testcell.channels);
int dimy, dimx; int dimy, dimx;
ncplane_dim_yx(n_, &dimy, &dimx); ncplane_dim_yx(n_, &dimy, &dimx);
REQUIRE(0 == ncplane_cursor_move_yx(n_, 1, dimx - mbstowcs(NULL, STR2, 0))); REQUIRE(0 == ncplane_cursor_move_yx(n_, 1, dimx - mbstowcs(NULL, STR2, 0)));
REQUIRE(0 < ncplane_putstr(n_, STR2)); REQUIRE(0 < ncplane_putstr(n_, STR2));
int y, x; int y, x;
ncplane_cursor_yx(n_, &y, &x); ncplane_cursor_yx(n_, &y, &x);
REQUIRE(2 == y); REQUIRE(1 == y);
REQUIRE(0 == x); REQUIRE(dimx == x);
REQUIRE(0 < ncplane_putstr(n_, STR3)); REQUIRE(0 == ncplane_putstr(n_, STR3));
cell testcell = CELL_TRIVIAL_INITIALIZER;
ncplane_at_cursor(n_, &testcell); // should be nothing at the cursor
CHECK(0 == testcell.gcluster);
CHECK(0 == testcell.attrword);
CHECK(0 == testcell.channels);
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0)); REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
REQUIRE(0 < ncplane_at_cursor(n_, &testcell)); // want first char of STR1 REQUIRE(0 < ncplane_at_cursor(n_, &testcell)); // want first char of STR1
CHECK(!strcmp("Σ", cell_extended_gcluster(n_, &testcell))); CHECK(!strcmp("Σ", cell_extended_gcluster(n_, &testcell)));
@ -916,7 +917,7 @@ TEST_CASE("NCPlane") {
int dimx, dimy; int dimx, dimy;
ncplane_dim_yx(n_, &dimy, &dimx); ncplane_dim_yx(n_, &dimy, &dimx);
CHECK(0 == ncplane_rounded_box_sized(ncp, 0, 0, 3, 4, 0)); CHECK(0 == ncplane_rounded_box_sized(ncp, 0, 0, 3, 4, 0));
CHECK(0 < ncplane_putegc_yx(ncp, 1, 1, "\xf0\x9f\xa6\x82", NULL)); CHECK(2 == ncplane_putegc_yx(ncp, 1, 1, "\xf0\x9f\xa6\x82", NULL)); // scorpion
CHECK(0 == notcurses_render(nc_)); CHECK(0 == notcurses_render(nc_));
cell c = CELL_TRIVIAL_INITIALIZER; cell c = CELL_TRIVIAL_INITIALIZER;
REQUIRE(0 < ncplane_at_yx(ncp, 1, 0, &c)); REQUIRE(0 < ncplane_at_yx(ncp, 1, 0, &c));

@ -0,0 +1,120 @@
#include "main.h"
#include <array>
#include <cstdlib>
#include "internal.h"
TEST_CASE("Scrolling") {
if(getenv("TERM") == nullptr){
return;
}
notcurses_options nopts{};
nopts.inhibit_alternate_screen = true;
nopts.suppress_banner = true;
FILE* outfp_ = fopen("/dev/tty", "wb");
REQUIRE(outfp_);
struct notcurses* nc_ = notcurses_init(&nopts, outfp_);
REQUIRE(nc_);
struct ncplane* n_ = notcurses_stdplane(nc_);
REQUIRE(n_);
// verify that the standard plane has scrolling disabled initially, and that
// we can enable it at runtime.
SUBCASE("ScollingDisabledStdplane"){
CHECK(!ncplane_set_scrolling(n_, true));
CHECK(ncplane_set_scrolling(n_, false));
}
SUBCASE("ScrollingStr"){
struct ncplane* n = ncplane_new(nc_, 2, 20, 1, 1, nullptr);
REQUIRE(n);
// verify that the new plane was started without scrolling
CHECK(!ncplane_set_scrolling(n, false));
// try to write 40 EGCs; it ought fail
CHECK(-20 == ncplane_putstr(n, "0123456789012345678901234567890123456789"));
int y, x;
ncplane_cursor_yx(n, &y, &x);
CHECK(0 == y);
CHECK(20 == x);
CHECK(0 == ncplane_cursor_move_yx(n, 0, 0));
CHECK(!ncplane_set_scrolling(n, true)); // enable scrolling
// try to write 40 EGCs; it ought succeed
CHECK(40 == ncplane_putstr(n, "0123456789012345678901234567890123456789"));
ncplane_cursor_yx(n, &y, &x);
CHECK(1 == y);
CHECK(20 == x);
CHECK(0 == notcurses_render(nc_));
}
// even when scrolling is enabled, you aren't allowed to move the cursor
// off-plane, or initiate output there
SUBCASE("NoScrollingManually"){
struct ncplane* n = ncplane_new(nc_, 2, 20, 1, 1, nullptr);
REQUIRE(n);
CHECK(!ncplane_set_scrolling(n, true)); // enable scrolling
CHECK(0 > ncplane_cursor_move_yx(n, 0, 20));
CHECK(0 > ncplane_cursor_move_yx(n, 1, 20));
CHECK(0 > ncplane_cursor_move_yx(n, 2, 2));
CHECK(0 > ncplane_putsimple_yx(n, 0, 20, 'c'));
CHECK(0 > ncplane_putsimple_yx(n, 1, 20, 'c'));
CHECK(0 > ncplane_putsimple_yx(n, 2, 0, 'c'));
}
// verify that two strings, each the length of the plane, can be output when
// scrolling is enabled (the second ought get an error without scrolling)
SUBCASE("ScrollingSplitStr"){
struct ncplane* n = ncplane_new(nc_, 2, 20, 1, 1, nullptr);
REQUIRE(n);
CHECK(20 == ncplane_putstr(n, "01234567890123456789"));
int y, x;
ncplane_cursor_yx(n, &y, &x);
CHECK(0 == y);
CHECK(20 == x);
CHECK(0 == ncplane_putstr(n, "01234567890123456789"));
CHECK(!ncplane_set_scrolling(n, true)); // enable scrolling
CHECK(20 == ncplane_putstr(n, "01234567890123456789"));
ncplane_cursor_yx(n, &y, &x);
CHECK(1 == y);
CHECK(20 == x);
CHECK(0 == notcurses_render(nc_));
}
// verify that a single string the size of the plane can be output when
// scrolling is enabled (it ought be an error without scrolling)
SUBCASE("ScrollingEGC"){
const char* out = "0123456789012345678901234567890123456789";
struct ncplane* n = ncplane_new(nc_, 2, 20, 1, 1, nullptr);
REQUIRE(n);
// verify that the new plane was started without scrolling
CHECK(!ncplane_set_scrolling(n, false));
// try to write 40 EGCs; the last 20 ought fail
for(const char* c = out ; *c ; ++c){
int ret = ncplane_putsimple(n, *c);
if(c - out < 20){
CHECK(1 == ret);
}else{
CHECK(0 > ret);
}
}
int y, x;
ncplane_cursor_yx(n, &y, &x);
CHECK(0 == y);
CHECK(20 == x);
CHECK(0 == ncplane_cursor_move_yx(n, 0, 0));
CHECK(!ncplane_set_scrolling(n, true)); // enable scrolling
// try to write 40 EGCs; all ought succeed
for(const char* c = out ; *c ; ++c){
CHECK(1 == ncplane_putsimple(n, *c));
}
ncplane_cursor_yx(n, &y, &x);
CHECK(1 == y);
CHECK(20 == x);
CHECK(0 == notcurses_render(nc_));
}
// FIXME add one verifying boxes don't exceed the right side
// FIXME add one where we go past the end of the plane
CHECK(0 == notcurses_stop(nc_));
CHECK(0 == fclose(outfp_));
}

@ -0,0 +1,50 @@
Name: notcurses
Version: 1.2.5
Release: 1
Summary: Character graphics and TUI library
License: ASL 2.0
Source0: https://github.com/dankamongmen/%{name}/archive/v%{version}.tar.gz
Source1: https://github.com/dankamongmen/%{name}/releases/v%{version}/v%{version}.tar.gz.asc
Source2: https://dank.qemfd.net/dankamongmen.gpg
BuildRequires: gnupg2 cmake make gcc-c++ ncurses-devel pandoc python3-devel
%description
notcurses facilitates the creation of modern TUI programs,
making full use of Unicode and 24-bit direct color. It presents
an API similar to that of Curses, and rides atop libtinfo.
%prep
%{gpgverify} --keyring='%{SOURCE2}' --signature='%{SOURCE1}' --data='%{SOURCE0}'
%setup
%build
%cmake -DUSE_FFMPEG=off -DUSE_TEST=off .
%make_build
%install
%make_install
%files
/usr/bin/notcurses-demo
/usr/bin/notcurses-input
/usr/bin/notcurses-keyplot
/usr/bin/notcurses-ncreel
/usr/bin/notcurses-pydemo
/usr/bin/notcurses-tester
/usr/bin/notcurses-tetris
/usr/bin/notcurses-view
/usr/include/notcurses/nckeys.h
/usr/include/notcurses/notcurses.h
/usr/lib/x86_64-linux-gnu/libnotcurses.so.{version}
/usr/lib/x86_64-linux-gnu/libnotcurses.so.1
/usr/lib/x86_64-linux-gnu/libnotcurses.so
/usr/lib/x86_64-linux-gnu/cmake/notcurses/notcursesConfig.cmake
/usr/lib/x86_64-linux-gnu/cmake/notcurses/notcursesConfigVersion.cmake
/usr/lib/x86_64-linux-gnu/libnotcurses.a
/usr/lib/x86_64-linux-gnu/pkgconfig
/usr/lib/x86_64-linux-gnu/pkgconfig/notcurses.pc
%license LICENSE
%changelog
* Tue, Apr 07 2020 Nick Black <dankamongmen@gmail.com> - 1.2.5-1
- Initial Fedora packaging
Loading…
Cancel
Save